| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.tuscany.das.rdb.impl; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.apache.tuscany.das.rdb.config.ResultDescriptor; |
| import org.apache.tuscany.das.rdb.config.impl.ResultDescriptorImpl; |
| import org.apache.tuscany.das.rdb.config.wrapper.MappingWrapper; |
| import org.apache.tuscany.das.rdb.graphbuilder.impl.GraphBuilderMetadata; |
| import org.apache.tuscany.das.rdb.graphbuilder.impl.ResultSetProcessor; |
| import org.apache.tuscany.sdo.api.SDOUtil; |
| |
| import commonj.sdo.ChangeSummary; |
| import commonj.sdo.DataGraph; |
| import commonj.sdo.DataObject; |
| |
| public class ReadCommandImpl extends CommandImpl { |
| |
| private int startRow = 1; |
| |
| private int endRow = Integer.MAX_VALUE; |
| |
| private List resultDescriptors = null; |
| |
| public ReadCommandImpl(org.apache.tuscany.das.rdb.config.Command command, MappingWrapper mapping, List resultDescriptor) { |
| super(command); |
| this.configWrapper = mapping; |
| |
| if (resultDescriptor != null && !resultDescriptor.isEmpty()) { |
| this.resultSetShape = new ResultSetShape(resultDescriptor, configWrapper.getConfig());//JIRA-952 |
| } |
| } |
| |
| public ReadCommandImpl(String sqlString, MappingWrapper mapping, List resultDescriptor) { |
| super(sqlString); |
| this.configWrapper = mapping; |
| |
| if (resultDescriptor != null && !resultDescriptor.isEmpty()) { |
| this.resultSetShape = new ResultSetShape(resultDescriptor, configWrapper.getConfig());//JIRA-952 |
| } |
| } |
| |
| private void refreshResultSetShape(){ |
| //sort descriptor and use in ResultSetShape |
| sortResultDescriptors(); |
| this.resultSetShape = new ResultSetShape(this.resultDescriptors, configWrapper.getConfig()); |
| } |
| |
| private void sortResultDescriptors(){ |
| if(this.resultDescriptors == null) { |
| return; |
| } |
| |
| if( this.resultDescriptors.size()==0) { |
| return; |
| } |
| |
| //when any index is found not set, do not sort |
| for(Iterator it = this.resultDescriptors.iterator() ; it.hasNext();){ |
| ResultDescriptor resultDescriptor = (ResultDescriptor) it.next(); |
| if(resultDescriptor.getColumnIndex() <= -1){ |
| return; |
| } |
| } |
| |
| //now is time to sort |
| Object[] resultDescAry = this.resultDescriptors.toArray(); |
| for(int i=0; i<resultDescAry.length; i++){ |
| for(int j=i+1; j<resultDescAry.length; j++){ |
| if( ((ResultDescriptor)resultDescAry[j]).getColumnIndex() |
| < ((ResultDescriptor)resultDescAry[i]).getColumnIndex()){ |
| ResultDescriptor tmpResDesc = (ResultDescriptor)resultDescAry[i]; |
| resultDescAry[i] = resultDescAry[j]; |
| resultDescAry[j] = tmpResDesc; |
| } |
| |
| if( ((ResultDescriptor)resultDescAry[j]).getColumnIndex() |
| == ((ResultDescriptor)resultDescAry[i]).getColumnIndex()){ |
| throw new RuntimeException("Two columns in Result Descriptor can not have same index"); |
| } |
| } |
| } |
| |
| this.resultDescriptors.clear(); |
| for(int i=0; i<resultDescAry.length; i++){ |
| this.resultDescriptors.add(resultDescAry[i]); |
| } |
| |
| return; |
| } |
| |
| private ResultDescriptor deepCopyResultDescriptor(ResultDescriptor inObj){ |
| ResultDescriptorImpl outObj = new ResultDescriptorImpl(); |
| outObj.setColumnIndex(inObj.getColumnIndex()); |
| outObj.setColumnName(inObj.getColumnName()); |
| outObj.setColumnType(inObj.getColumnType()); |
| outObj.setTableName(inObj.getTableName()); |
| outObj.setSchemaName(inObj.getSchemaName()); |
| return outObj; |
| } |
| |
| private List deepCopyResultDescriptors(List resultDescriptors){ |
| if(resultDescriptors == null || resultDescriptors.size() == 0) |
| return null; |
| |
| ArrayList copyList = new ArrayList(); |
| |
| for(Iterator it = resultDescriptors.iterator() ; it.hasNext();){ |
| copyList.add( deepCopyResultDescriptor( (ResultDescriptorImpl) it.next())); |
| } |
| return copyList; |
| } |
| |
| /** |
| * When any columnIndex == -ve, sorting will not happen in ResultShapeSorter (old way) |
| * When null is passed, set this.resultSetShape to null, this will later trigger, dbms metadata |
| * based shaping of result |
| */ |
| public void setResultDescriptors(List resultDescriptors){ |
| this.resultDescriptors = deepCopyResultDescriptors(resultDescriptors); |
| if(this.resultDescriptors == null || this.resultDescriptors.size()==0){ |
| this.resultSetShape = null; |
| } |
| else{ |
| //below will go away with List<> JDK5 |
| for(Iterator it = this.resultDescriptors.iterator() ; it.hasNext();){ |
| |
| if(!(it.next() instanceof ResultDescriptor)){ |
| throw new RuntimeException("Elements in List not of type ResultDescriptor!"); |
| } |
| |
| } |
| refreshResultSetShape(); |
| } |
| } |
| |
| public List getResultDescriptors(){ |
| return this.resultDescriptors; |
| } |
| |
| public void addResultDescriptor(ResultDescriptor resultDescriptor){ |
| //if >= 0 columnIndex, add/replace for given index |
| //if < 0 columnIndex, add at end of current list |
| if(resultDescriptor == null) { |
| return; |
| } |
| |
| if(this.resultDescriptors == null){ |
| this.resultDescriptors = new ArrayList(); |
| } |
| |
| if(resultDescriptor.getColumnIndex() <0){ |
| this.resultDescriptors.add(deepCopyResultDescriptor(resultDescriptor));//dont care about columnIndex,add at end, old way |
| } |
| else{ |
| ResultDescriptor existing = getResultDescriptor(resultDescriptor.getColumnIndex()); |
| if(existing != null){ |
| removeResultDescriptor(resultDescriptor.getColumnIndex()); |
| } |
| this.resultDescriptors.add(deepCopyResultDescriptor(resultDescriptor));//add at end, sorting will happen below |
| } |
| |
| refreshResultSetShape(); |
| } |
| |
| |
| public ResultDescriptor removeResultDescriptor(int columnIndex){ |
| //if < 0 index return null |
| //if >=0 index and available at given index, remove and return same |
| //if >=0 index and not available at given index, return null |
| ResultDescriptor existing = null; |
| if(columnIndex >=0 && ((existing = getResultDescriptor(columnIndex)) != null) ){ |
| this.resultDescriptors.remove(existing); |
| refreshResultSetShape(); |
| return existing; |
| } |
| return null; |
| } |
| |
| public ResultDescriptor removeResultDescriptor(ResultDescriptor resultDescriptor){ |
| //remove and return only if matched for index, name, type, table name, schema name |
| //else return null |
| if(resultDescriptor != null){ |
| ResultDescriptor existing = getResultDescriptor(resultDescriptor.getColumnIndex()); |
| if(existing != null && |
| existing.getColumnName().equals(resultDescriptor.getColumnName()) && |
| existing.getColumnType().equals(resultDescriptor.getColumnType()) && |
| existing.getTableName().equals(resultDescriptor.getTableName()) ) { |
| if(this.configWrapper.getConfig().isDatabaseSchemaNameSupported()){//multi schema support |
| if(resultDescriptor.getSchemaName() != null && existing.getSchemaName() != null |
| && resultDescriptor.getSchemaName().equals(existing.getSchemaName())){ |
| this.resultDescriptors.remove(existing); |
| refreshResultSetShape(); |
| return existing; |
| } |
| return null; |
| } |
| else{ |
| this.resultDescriptors.remove(existing); |
| refreshResultSetShape(); |
| return existing; |
| } |
| } |
| } |
| return null; |
| } |
| |
| public ResultDescriptor getResultDescriptor(int columnIndex){ |
| //if <0 index return null |
| //if >=0 index and available at given index, return same |
| //if >=0 index and not available at given index, return null |
| if(columnIndex >=0 && this.resultDescriptors != null){ |
| |
| for(Iterator it = this.resultDescriptors.iterator() ; it.hasNext();){ |
| ResultDescriptor rs = (ResultDescriptor) it.next(); |
| |
| if( rs.getColumnIndex() == columnIndex){ |
| return rs; |
| } |
| |
| } |
| } |
| |
| return null; |
| } |
| |
| //Utility method |
| public void printResultDescriptors(OutputStream ostrm) throws IOException{ |
| if(this.resultDescriptors != null && this.resultDescriptors.size() != 0){ |
| |
| for(Iterator it = this.resultDescriptors.iterator() ; it.hasNext();){ |
| ostrm.write( it.next().toString().getBytes() ); |
| ostrm.write('\n'); |
| |
| } |
| ostrm.flush(); |
| |
| } |
| } |
| |
| public void execute() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public DataObject executeQuery() { |
| |
| if (statement.getConnection() == null) { |
| throw new RuntimeException("A DASConnection object must be specified before executing the query."); |
| } |
| |
| boolean success = false; |
| try { |
| // execute query |
| List results = statement.executeQuery(parameters); |
| success = true; |
| // if result set contains less columns than result descriptors, crop result descriptors |
| if (resultDescriptors != null && results.size() > 0) { |
| ResultSet resultSet = (ResultSet) results.get(0); |
| ResultSetMetaData resultSetMetadata = resultSet.getMetaData(); |
| int columnCount = resultSetMetadata.getColumnCount(); |
| int resultDescriptorCount = resultDescriptors.size(); |
| if (resultDescriptorCount > columnCount) { |
| resultDescriptors = resultDescriptors.subList(0, columnCount); |
| refreshResultSetShape(); |
| } |
| } |
| // build graph |
| return buildGraph(results); |
| } catch (SQLException e) { |
| throw new RuntimeException(e); |
| } finally { |
| if (success) { |
| statement.getConnection().cleanUp(); |
| } else { |
| statement.getConnection().errorCleanUp(); |
| } |
| } |
| } |
| |
| protected DataObject buildGraph(List results) throws SQLException { |
| |
| // Before we use the mappingModel, do some checking/updating. If |
| // inferrable information |
| // isn't specified, add it in. |
| |
| GraphBuilderMetadata gbmd = new GraphBuilderMetadata(results, configWrapper.getConfig(), |
| resultSetShape); |
| |
| // Create the DataGraph |
| DataGraph g = SDOUtil.createDataGraph(); |
| |
| // Create the root object |
| g.createRootObject(gbmd.getRootType()); |
| |
| SDOUtil.registerDataGraphTypes(g, gbmd.getDefinedTypes()); |
| |
| ChangeSummary summary = g.getChangeSummary(); |
| |
| ResultSetProcessor rsp = new ResultSetProcessor(g.getRootObject(), gbmd); |
| rsp.processResults(getStartRow(), getEndRow()); |
| |
| summary.beginLogging(); |
| |
| return g.getRootObject(); |
| } |
| |
| |
| protected int getStartRow() { |
| return startRow; |
| } |
| |
| protected int getEndRow() { |
| return endRow; |
| } |
| |
| protected void setStartRow(int startRow) { |
| this.startRow = startRow; |
| } |
| |
| protected void setEndRow(int endRow) { |
| this.endRow = endRow; |
| } |
| |
| |
| protected void enablePaging() { |
| statement.enablePaging(); |
| } |
| |
| } |