/** * Copyright (c) 2004-2011 Wang Jinbao(Julian Wong), http://www.ralasafe.com * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php */ package org.ralasafe.db.impl; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.ralasafe.ObjectNewer; import org.ralasafe.db.Column; import org.ralasafe.db.ComplexTable; import org.ralasafe.db.ComplexTableDBHelper; import org.ralasafe.db.ComplexTableSelector; import org.ralasafe.db.ComplexTableValueCombiner; import org.ralasafe.db.DBLevelException; import org.ralasafe.db.InnerWhereElement; import org.ralasafe.db.MultiValueTableAdapter; import org.ralasafe.db.SelectCondition; import org.ralasafe.db.SelectConditionUtil; import org.ralasafe.db.SingleValueTableAdapter; import org.ralasafe.db.Table; import org.ralasafe.util.DBUtil; import org.ralasafe.util.Util; public class ComplexTableSelectorImpl implements ComplexTableSelector { private ComplexTable complexTable; private ObjectNewer mainTableObjectNewer; private SingleValueTableAdapter[] singleValueAdapters; private MultiValueTableAdapter[] multiValueAdapters; private TableSelectorImpl mainTableSelector; private TableSelectorImpl[] singleValueTableSelectors; private TableSelectorImpl[] multiValueTableSelectors; private SelectCondition byIdColumnsSelectCdtn; private static Log logger=LogFactory.getLog( ComplexTableSelectorImpl.class ); public ComplexTable getComplexTable() { return complexTable; } public void setComplexTable( ComplexTable complexTable ) { this.complexTable=complexTable; byIdColumnsSelectCdtn=SelectConditionUtil.simplyConnectColumns( complexTable.getMainTable().getIdColumns() ); Table mainTable=complexTable.getMainTable(); mainTableSelector=new TableSelectorImpl(); mainTableSelector.setTable( mainTable ); innerSetMainTableObjectNewer(); Table[] singleValueTables=complexTable.getSingleValueTables(); singleValueTableSelectors=getTableSelectors( singleValueTables ); innerSetSingleValueTableObjectNewer(); Table[] multiValueTables=complexTable.getMultiValueTables(); multiValueTableSelectors=getTableSelectors( multiValueTables ); innerSetMultiValueTableObjectNewer(); } public void setMainTableObjectNewer( ObjectNewer mainTableObjectNewer ) { this.mainTableObjectNewer=mainTableObjectNewer; innerSetMainTableObjectNewer(); } private void innerSetMainTableObjectNewer() { if( mainTableSelector!=null ) { mainTableSelector.setObjectNewer( mainTableObjectNewer ); } } private void innerSetSingleValueTableObjectNewer() { if( Util.isEmpty( singleValueAdapters ) || Util.isEmpty( singleValueTableSelectors ) ) return; for( int i=0; i<singleValueAdapters.length; i++ ) { singleValueTableSelectors[i].setObjectNewer( singleValueAdapters[i].getObjectNewer() ); } } private void innerSetMultiValueTableObjectNewer() { if( Util.isEmpty( multiValueAdapters ) || Util.isEmpty( multiValueTableSelectors ) ) return; for( int i=0; i<multiValueAdapters.length; i++ ) { multiValueTableSelectors[i].setObjectNewer( multiValueAdapters[i].getObjectNewer() ); } } private TableSelectorImpl[] getTableSelectors( Table[] tables ) { if( Util.isEmpty( tables ) ) return null; TableSelectorImpl[] impls=new TableSelectorImpl[ tables.length ]; for( int i=0; i<tables.length; i++ ) { TableSelectorImpl impl=new TableSelectorImpl(); impl.setTable( tables[i] ); impls[i]=impl; } return impls; } public SingleValueTableAdapter[] getSingleValueAdapters() { return singleValueAdapters; } public void setSingleValueAdapters( SingleValueTableAdapter[] singleValueAdapters ) { this.singleValueAdapters=singleValueAdapters; innerSetSingleValueTableObjectNewer(); } public MultiValueTableAdapter[] getMultiValueAdapters() { return multiValueAdapters; } public void setMultiValueAdapters( MultiValueTableAdapter[] adapters ) { this.multiValueAdapters=adapters; innerSetMultiValueTableObjectNewer(); } public Object selectByIdColumns( Object o ) throws DBLevelException { // load main table values Object selectValue=mainTableSelector.selectByIdColumns( o ); if( selectValue==null ) return null; // load single value table values if( !Util.isEmpty( singleValueTableSelectors ) ) { for( int i=0; i<singleValueTableSelectors.length; i++ ) { Object temp=singleValueAdapters[i].extractEvenNoValueExist( o ); Object tableSelectValue=singleValueTableSelectors[i].selectByIdColumns( temp ); if( tableSelectValue!=null ) { singleValueAdapters[i].combine( selectValue, tableSelectValue ); } } } // load multi value table values if( !Util.isEmpty( multiValueTableSelectors ) ) { for( int i=0; i<multiValueTableSelectors.length; i++ ) { Object temp=multiValueAdapters[i].extractEvenNoValueExist( o ); Collection tableSelectValue=multiValueTableSelectors[i].select( byIdColumnsSelectCdtn, temp ); if( tableSelectValue.size()>0 ) { multiValueAdapters[i].combine( selectValue, tableSelectValue.toArray() ); } } } return selectValue; } public Object selectByUniqueColumns( Object o ) throws DBLevelException { // load main table values Object selectValue=mainTableSelector.selectByUniqueColumns( o ); if( selectValue==null ) return null; // load single value table values if( !Util.isEmpty( singleValueTableSelectors ) ) { for( int i=0; i<singleValueTableSelectors.length; i++ ) { Object temp=singleValueAdapters[i].extractEvenNoValueExist( o ); Object tableSelectValue=singleValueTableSelectors[i].selectByIdColumns( temp ); if( tableSelectValue!=null ) { singleValueAdapters[i].combine( selectValue, tableSelectValue ); } } } // load multi value table values if( !Util.isEmpty( multiValueTableSelectors ) ) { for( int i=0; i<multiValueTableSelectors.length; i++ ) { Object temp=multiValueAdapters[i].extractEvenNoValueExist( o ); Collection tableSelectValue=multiValueTableSelectors[i].select( byIdColumnsSelectCdtn, temp ); if( tableSelectValue.size()>0 ) { multiValueAdapters[i].combine( selectValue, tableSelectValue.toArray() ); } } } return selectValue; } public Collection select( SelectCondition cdtn, Object hint ) throws DBLevelException { Map tempTableNameConnMap=null; ComplexTableDBHelper helper=new ComplexTableDBHelper(); helper.setComplexTable( complexTable ); try { helper.getConnections(); helper.beginTransaction(); // select main table Collection coll=mainTableSelector.select( helper.getMainTableConn(), cdtn, hint ); if( coll.isEmpty() ) { return coll; } ComplexTableValueCombiner combiner=new ComplexTableValueCombiner( complexTable ); combiner.setMainTableValues( coll ); combiner.setSingleValueTableAdapters( singleValueAdapters ); combiner.setMultiValueTableAdapters( multiValueAdapters ); // save idColumns as a temp table Column[] idColumns=complexTable.getMainTable().getIdColumns(); //Collection pks=combiner.getGeneralPks(); tempTableNameConnMap=new HashMap(); createTempTables( helper.getSingleValueTableConns(), idColumns, coll, tempTableNameConnMap ); createTempTables( helper.getMultiValueTableConns(), idColumns, coll, tempTableNameConnMap ); // according to temp table, query singlevaluetables and multivaluetables Collection[] readSingleValueTables=readSingleValueTables( helper.getSingleValueTableConns(), tempTableNameConnMap ); Collection[] readMultiValueTables=readMultiValueTables( helper.getMultiValueTableConns(), tempTableNameConnMap ); combiner.setSingleValueTableValues( readSingleValueTables ); combiner.setMultiValueTableValues( readMultiValueTables ); return combiner.combine(); } catch( SQLException e ) { logger.error( "", e ); throw new DBLevelException( e ); } finally { // drop temp tables if( tempTableNameConnMap!=null ) { for( Iterator iter=tempTableNameConnMap.entrySet().iterator(); iter.hasNext(); ) { Entry entry=(Entry) iter.next(); Connection conn=(Connection) entry.getKey(); String tempTableName=(String) entry.getValue(); try { DBUtil.exec( conn, "DROP TABLE " + tempTableName ); } catch( SQLException e ) { logger.error( "", e ); } } } helper.closeConnections(); } } public Collection selectByPage( SelectCondition cdtn, Object hint, int startIndex, int pageSize ) throws DBLevelException { Map tempTableNameConnMap=null; ComplexTableDBHelper helper=new ComplexTableDBHelper(); helper.setComplexTable( complexTable ); try { helper.getConnections(); helper.beginTransaction(); // query main table Collection coll=mainTableSelector.selectByPage( helper.getMainTableConn(), cdtn, hint, startIndex, pageSize ); if( coll.isEmpty() ) { return coll; } ComplexTableValueCombiner combiner=new ComplexTableValueCombiner( complexTable ); combiner.setMainTableValues( coll ); combiner.setSingleValueTableAdapters( singleValueAdapters ); combiner.setMultiValueTableAdapters( multiValueAdapters ); // save idColumns as a temp table Column[] idColumns=complexTable.getMainTable().getIdColumns(); //Collection pks=combiner.getGeneralPks(); tempTableNameConnMap=new HashMap(); createTempTables( helper.getSingleValueTableConns(), idColumns, coll, tempTableNameConnMap ); createTempTables( helper.getMultiValueTableConns(), idColumns, coll, tempTableNameConnMap ); // according temp table, query singlevalue and multivalue tables Collection[] readSingleValueTables=readSingleValueTables( helper.getSingleValueTableConns(), tempTableNameConnMap ); Collection[] readMultiValueTables=readMultiValueTables( helper.getMultiValueTableConns(), tempTableNameConnMap ); combiner.setSingleValueTableValues( readSingleValueTables ); combiner.setMultiValueTableValues( readMultiValueTables ); return combiner.combine(); } catch( SQLException e ) { logger.error( "", e ); throw new DBLevelException( e ); } finally { // drop temp tables if( tempTableNameConnMap!=null ) { for( Iterator iter=tempTableNameConnMap.entrySet().iterator(); iter.hasNext(); ) { Entry entry=(Entry) iter.next(); Connection conn=(Connection) entry.getKey(); String tempTableName=(String) entry.getValue(); try { DBUtil.exec( conn, "DROP TABLE " + tempTableName ); } catch( SQLException e ) { logger.error( "", e ); } } } helper.closeConnections(); } } private Collection[] readSingleValueTables( Connection[] conns, Map tempTableNameConnMap ) { Collection[] readResult=null; Table[] tables=complexTable.getSingleValueTables(); TableSelectorImpl[] selectors=singleValueTableSelectors; if( !Util.isEmpty( tables ) ) { readResult=new Collection[tables.length]; for( int i=0; i<tables.length; i++ ) { Connection conn=conns[i]; String tempTableName=(String) tempTableNameConnMap.get( conn ); InnerWhereElement whereEmt=new InnerWhereElement(); whereEmt.setColumns( complexTable.getMainTable().getIdColumns() ); whereEmt.setInnerTableColumnNames( complexTable.getMainTable().getIdColumnNames() ); whereEmt.setTableName( tempTableName ); SelectCondition cdtn=new SelectCondition(); cdtn.setWhereElement( whereEmt ); Collection coll=selectors[i].select( conn, cdtn, null ); readResult[i]=coll; } } return readResult; } private Collection[] readMultiValueTables( Connection[] conns, Map tempTableNameConnMap ) { Collection[] readResult=null; Table[] tables=complexTable.getMultiValueTables(); TableSelectorImpl[] selectors=multiValueTableSelectors; if( !Util.isEmpty( tables ) ) { readResult=new Collection[tables.length]; for( int i=0; i<tables.length; i++ ) { Connection conn=conns[i]; String tempTableName=(String) tempTableNameConnMap.get( conn ); InnerWhereElement whereEmt=new InnerWhereElement(); whereEmt.setColumns( complexTable.getMainTable().getIdColumns() ); whereEmt.setInnerTableColumnNames( complexTable.getMainTable().getIdColumnNames() ); whereEmt.setTableName( tempTableName ); SelectCondition cdtn=new SelectCondition(); cdtn.setWhereElement( whereEmt ); Collection coll=selectors[i].select( conn, cdtn, null ); readResult[i]=coll; } } return readResult; } private void createTempTables( Connection[] conns, Column[] idColumns, Collection tableValues, Map tempTableNameConnMap ) { if( !Util.isEmpty( conns ) ) { for( int i=0; i<conns.length; i++ ) { Connection conn=conns[i]; if( tempTableNameConnMap.containsKey( conn ) ) { // already done } else { // create and insert value String table=createTempTable( conn, idColumns, tableValues ); tempTableNameConnMap.put( conn, table ); } } } } private String createTempTable( Connection conn, Column[] insertColumns, Collection tableValues ) { String tempTableName="Tmp_"+System.currentTimeMillis()+((int)(Math.random()*100)); String[] columnNames=new String[insertColumns.length]; String[] columnSqlTypes=new String[insertColumns.length]; for( int i=0; i<insertColumns.length; i++ ) { Column column=insertColumns[i]; columnNames[i]=column.getName(); columnSqlTypes[i]=column.getType().getSqlType(); } String createSql=DBUtil.createTableSql( tempTableName, columnNames, columnSqlTypes ); PreparedStatement pstmt=null; try { pstmt=conn.prepareStatement( createSql ); pstmt.execute(); } catch( SQLException e ) { logger.error( "", e ); throw new DBLevelException( e ); } finally { DBUtil.close( pstmt ); } Table table=new Table(); table.setColumnNames( columnNames ); table.setColumns( insertColumns ); table.setExceptIdColumnNames( columnNames ); table.setExceptIdColumns( insertColumns ); table.setName( tempTableName ); TableSaverImpl saver=new TableSaverImpl(); saver.setTable( table ); saver.batchSave( conn, tableValues ); return tempTableName; } public int selectCount() throws DBLevelException { return mainTableSelector.selectCount( null, null ); } public int selectCount( SelectCondition cdtn, Object hint ) throws DBLevelException { return mainTableSelector.selectCount( cdtn, hint ); } }