/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.dataaccess.datasource.wizard.sources.multitable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.pentaho.agilebi.modeler.models.JoinFieldModel; import org.pentaho.agilebi.modeler.models.JoinRelationshipModel; import org.pentaho.agilebi.modeler.models.JoinTableModel; import org.pentaho.agilebi.modeler.models.SchemaModel; import org.pentaho.metadata.model.Domain; import org.pentaho.metadata.model.LogicalColumn; import org.pentaho.metadata.model.LogicalRelationship; import org.pentaho.metadata.model.LogicalTable; import org.pentaho.metadata.model.concept.types.LocalizedString; import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.MultiTableDatasourceDTO; import org.pentaho.ui.xul.XulEventSourceAdapter; import org.pentaho.ui.xul.stereotype.Bindable; import org.pentaho.ui.xul.util.AbstractModelList; public class MultitableGuiModel extends XulEventSourceAdapter { private List<String> schemas; private AbstractModelList<JoinRelationshipModel> joins; private AbstractModelList<JoinTableModel> selectedTables; private AbstractModelList<JoinTableModel> availableTables; private AbstractModelList<JoinTableModel> leftTables; private AbstractModelList<JoinTableModel> rightTables; private JoinTableModel leftJoinTable; private JoinTableModel rightJoinTable; private JoinFieldModel leftKeyField; private JoinFieldModel rightKeyField; private JoinRelationshipModel selectedJoin; private JoinTableModel factTable; private boolean doOlap; public MultitableGuiModel() { this.availableTables = new AbstractModelList<JoinTableModel>(); this.selectedTables = new AbstractModelList<JoinTableModel>(); this.leftTables = new AbstractModelList<JoinTableModel>(); this.rightTables = new AbstractModelList<JoinTableModel>(); this.joins = new AbstractModelList<JoinRelationshipModel>(); this.leftJoinTable = new JoinTableModel(); this.rightJoinTable = new JoinTableModel(); this.selectedJoin = new JoinRelationshipModel(); this.schemas = new AbstractModelList<String>(); } @Bindable public AbstractModelList<JoinTableModel> getAvailableTables() { return this.availableTables; } @Bindable public void setAvailableTables( AbstractModelList<JoinTableModel> availableTables ) { this.availableTables.setChildren( availableTables ); } @Bindable public void setSchemas( List<String> schemas ) { List<String> previousValue = this.schemas; this.schemas = schemas; this.firePropertyChange( "schemas", previousValue, schemas ); } @Bindable public List<String> getSchemas() { return this.schemas; } @Bindable public AbstractModelList<JoinTableModel> getSelectedTables() { return this.selectedTables; } @Bindable public void setSelectedTables( AbstractModelList<JoinTableModel> selectedTables ) { this.selectedTables = selectedTables; } @Bindable public JoinTableModel getLeftJoinTable() { return this.leftJoinTable; } @Bindable public void setLeftJoinTable( JoinTableModel leftJoinTable ) { this.leftJoinTable = leftJoinTable; } @Bindable public JoinTableModel getRightJoinTable() { return this.rightJoinTable; } @Bindable public void setRightJoinTable( JoinTableModel rightJoinTable ) { this.rightJoinTable = rightJoinTable; } @Bindable public JoinFieldModel getLeftKeyField() { return this.leftKeyField; } @Bindable public void setLeftKeyField( JoinFieldModel leftKeyField ) { this.leftKeyField = leftKeyField; } @Bindable public JoinFieldModel getRightKeyField() { return this.rightKeyField; } @Bindable public void setRightKeyField( JoinFieldModel rightKeyField ) { this.rightKeyField = rightKeyField; } @Bindable public AbstractModelList<JoinRelationshipModel> getJoins() { return this.joins; } @Bindable public void setJoins( AbstractModelList<JoinRelationshipModel> joins ) { this.joins = joins; } @Bindable public JoinRelationshipModel getSelectedJoin() { return this.selectedJoin; } @Bindable public void setSelectedJoin( JoinRelationshipModel selectedJoin ) { this.selectedJoin = selectedJoin; } @Bindable public JoinTableModel getFactTable() { return factTable; } @Bindable public void setFactTable( JoinTableModel factTable ) { this.factTable = factTable; } public void addJoin( JoinRelationshipModel join ) { this.joins.add( join ); this.selectedJoin = join; } public void removeSelectedJoin() { this.joins.remove( this.selectedJoin ); this.selectedJoin = ( joins == null || joins.asList().isEmpty() ) ? null : joins.asList().get( 0 ); } public void addSelectedTable( JoinTableModel table ) { this.availableTables.remove( table ); this.selectedTables.add( table ); } public void addSelectedTables( List<JoinTableModel> selected ) { this.availableTables.removeAll( selected ); this.selectedTables.addAll( selected ); } public void removeSelectedTables( List<JoinTableModel> selected ) { this.selectedTables.removeAll( selected ); this.availableTables.addAll( selected ); } public void removeSelectedTable( JoinTableModel table ) { this.selectedTables.remove( table ); this.availableTables.add( table ); } @Bindable public AbstractModelList<JoinTableModel> getLeftTables() { return this.leftTables; } @Bindable public AbstractModelList<JoinTableModel> getRightTables() { return this.rightTables; } @Bindable public boolean isDoOlap() { return this.doOlap; } @Bindable public void setDoOlap( boolean isStar ) { boolean origStar = this.doOlap; this.doOlap = isStar; firePropertyChange( "doOlap", origStar, isStar ); } public void computeJoinDefinitionStepTables() { this.leftTables.clear(); this.rightTables.clear(); if ( this.doOlap ) { this.leftTables.add( this.factTable ); for ( JoinTableModel table : this.selectedTables ) { if ( table.equals( this.factTable ) ) { continue; } else { this.rightTables.add( table ); } } } else { this.leftTables.addAll( this.selectedTables ); this.rightTables.addAll( this.selectedTables ); } } public void processAvailableTables( List<String> tables ) { List<JoinTableModel> joinTables = new ArrayList<JoinTableModel>(); if ( tables.size() > 0 ) { mainLoop: for ( String table : tables ) { JoinTableModel joinTable = new JoinTableModel(); joinTable.setName( table ); for ( JoinTableModel selectedTable : selectedTables.getChildren() ) { if ( selectedTable.equals( joinTable ) ) { continue mainLoop; } } joinTables.add( joinTable ); } Collections.sort( joinTables, new Comparator<JoinTableModel>() { @Override public int compare( JoinTableModel joinTableModel, JoinTableModel joinTableModel1 ) { return joinTableModel.getName().compareTo( joinTableModel1.getName() ); } } ); } setAvailableTables( new AbstractModelList<JoinTableModel>( joinTables ) ); } @Deprecated public List<LogicalRelationship> generateLogicalRelationships( List<JoinRelationshipModel> joins ) { String locale = LocalizedString.DEFAULT_LOCALE; List<LogicalRelationship> logicalRelationships = new ArrayList<LogicalRelationship>(); for ( JoinRelationshipModel join : joins ) { LogicalTable fromTable = new LogicalTable(); fromTable.setName( new LocalizedString( locale, join.getLeftKeyFieldModel().getParentTable().getName() ) ); LogicalTable toTable = new LogicalTable(); toTable.setName( new LocalizedString( locale, join.getRightKeyFieldModel().getParentTable().getName() ) ); LogicalColumn fromColumn = new LogicalColumn(); fromColumn.setName( new LocalizedString( locale, join.getLeftKeyFieldModel().getName() ) ); LogicalColumn toColumn = new LogicalColumn(); toColumn.setName( new LocalizedString( locale, join.getRightKeyFieldModel().getName() ) ); LogicalRelationship logicalRelationship = new LogicalRelationship(); logicalRelationship.setFromTable( fromTable ); logicalRelationship.setToTable( toTable ); logicalRelationship.setFromColumn( fromColumn ); logicalRelationship.setToColumn( toColumn ); logicalRelationships.add( logicalRelationship ); } return logicalRelationships; } public MultiTableDatasourceDTO createMultiTableDatasourceDTO( String dsName ) { MultiTableDatasourceDTO dto = new MultiTableDatasourceDTO(); dto.setDoOlap( this.doOlap ); dto.setDatasourceName( dsName ); List<String> selectedTables = new ArrayList<String>(); for ( JoinTableModel tbl : this.selectedTables ) { selectedTables.add( tbl.getName() ); } dto.setSelectedTables( selectedTables ); SchemaModel schema = new SchemaModel(); schema.setJoins( this.getJoins() ); schema.setFactTable( this.factTable ); dto.setSchemaModel( schema ); return dto; } public void populateJoinGuiModel( Domain domain, MultiTableDatasourceDTO dto, List tables ) { this.selectedTables.clear(); // Populate "selectedTables" from availableTables using logicalRelationships. AbstractModelList<JoinTableModel> selectedTablesList = new AbstractModelList<JoinTableModel>(); if ( dto != null ) { for ( String selectedTable : dto.getSelectedTables() ) { this.selectTable( selectedTable, selectedTablesList, tables ); } this.selectedTables.addAll( selectedTablesList ); // Populates joins. this.computeJoins( dto ); // Populate fact table. if ( dto.isDoOlap() ) { for ( JoinTableModel table : this.selectedTables ) { if ( tablesAreEqual( table.getName(), dto.getSchemaModel().getFactTable().getName() ) ) { this.setFactTable( table ); break; } } } } // Populate available tables discarding selected tables. this.processAvailableTables( tables ); if ( domain != null ) { // Existing joinTableModels will not have fields. We can add these from the domain. this.addFieldsToTables( domain, this.availableTables ); } } private void computeJoins( MultiTableDatasourceDTO dto ) { this.joins.clear(); for ( JoinRelationshipModel join : dto.getSchemaModel().getJoins() ) { for ( JoinTableModel selectedTable : this.selectedTables ) { if ( tablesAreEqual( selectedTable.getName(), join.getLeftKeyFieldModel().getParentTable().getName() ) ) { join.getLeftKeyFieldModel().getParentTable().setName( selectedTable.getName() ); } else { if ( tablesAreEqual( selectedTable.getName(), join.getRightKeyFieldModel().getParentTable().getName() ) ) { join.getRightKeyFieldModel().getParentTable().setName( selectedTable.getName() ); } } } } this.joins.addAll( dto.getSchemaModel().getJoins() ); } /** * try to identify the correct selected table index from the joins * * @return int > 0 if found */ public int getTableIndex( JoinTableModel joinTable ) { return ( this.getSelectedTables() == null || this.getSelectedTables().isEmpty() ) ? 0 : this.getSelectedTables().indexOf( joinTable ); } private void addFieldsToTables( Domain domain, AbstractModelList<JoinTableModel> availableTables ) { String locale = LocalizedString.DEFAULT_LOCALE; Outter: for ( JoinTableModel table : availableTables ) { for ( LogicalTable tbl : domain.getLogicalModels().get( 0 ).getLogicalTables() ) { if ( tbl.getPhysicalTable().getProperty( "target_table" ).equals( table.getName() ) ) { for ( LogicalColumn col : tbl.getLogicalColumns() ) { JoinFieldModel field = new JoinFieldModel(); field.setName( col.getName( locale ) ); field.setParentTable( table ); table.getFields().add( field ); } continue Outter; } } } } private void selectTable( String selectedTable, AbstractModelList<JoinTableModel> selectedTablesList, List databaseTables ) { for ( Object table : databaseTables ) { if ( tablesAreEqual( table.toString(), selectedTable ) ) { if ( !selectedTablesList.contains( table ) ) { JoinTableModel joinTable = new JoinTableModel(); joinTable.setName( table.toString() ); selectedTablesList.add( joinTable ); } } } } public void reset() { this.availableTables.clear(); this.selectedTables.clear(); this.joins.clear(); this.schemas.clear(); this.leftTables.clear(); this.rightTables.clear(); this.leftKeyField = null; this.rightKeyField = null; this.selectedJoin = null; this.factTable = null; this.leftJoinTable = null; this.rightJoinTable = null; } private boolean tablesAreEqual( String table1, String table2 ) { String tableName1 = getSchemaTablePair( table1 )[ 1 ]; String tableName2 = getSchemaTablePair( table2 )[ 1 ]; return tableName1.equals( tableName2 ); } private String[] getSchemaTablePair( String table ) { if ( table.indexOf( "." ) < 0 ) { return new String[] { "", table }; } String[] pair = new String[ 2 ]; String[] parts = table.split( "\\." ); pair[ 0 ] = parts[ 0 ]; String tableName = ""; for ( int i = 1; i < parts.length; i++ ) { tableName = tableName + "." + parts[ i ]; } pair[ 1 ] = tableName.substring( 1 ); return pair; } }