/*! * 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-2016 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.dataaccess.datasource.wizard.sources.multitable; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.pentaho.agilebi.modeler.models.JoinRelationshipModel; import org.pentaho.agilebi.modeler.models.JoinTableModel; import org.pentaho.database.model.IDatabaseConnection; import org.pentaho.metadata.model.Domain; import org.pentaho.platform.dataaccess.datasource.wizard.AbstractWizardStep; import org.pentaho.platform.dataaccess.datasource.wizard.controllers.MessageHandler; import org.pentaho.platform.dataaccess.datasource.wizard.models.IWizardModel; import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.JoinSelectionServiceGwtImpl; import org.pentaho.platform.dataaccess.datasource.wizard.service.impl.MultiTableDatasourceDTO; import org.pentaho.ui.xul.XulComponent; import org.pentaho.ui.xul.XulException; import org.pentaho.ui.xul.XulServiceCallback; import org.pentaho.ui.xul.binding.BindingConvertor; import org.pentaho.ui.xul.binding.BindingFactory; import org.pentaho.ui.xul.components.XulMenuList; import org.pentaho.ui.xul.containers.XulListbox; import org.pentaho.ui.xul.containers.XulVbox; import org.pentaho.ui.xul.gwt.binding.GwtBindingFactory; import org.pentaho.ui.xul.stereotype.Bindable; import org.pentaho.ui.xul.util.AbstractModelList; @SuppressWarnings( "all" ) public class TablesSelectionStep extends AbstractWizardStep { protected static final String JOIN_STEP_PANEL_ID = "joinSelectionWindow"; private XulVbox tablesSelectionDialog; private XulListbox availableTables; private XulListbox selectedTables; private XulMenuList<JoinTableModel> factTables; private XulMenuList<String> schemas; private MultitableGuiModel joinGuiModel; private JoinSelectionServiceGwtImpl joinSelectionServiceGwtImpl; private SchemaSelection schemaSelection; private MultiTableDatasource mtdatasource; private Domain domain; private MultiTableDatasourceDTO datasourceDTO; public TablesSelectionStep( MultitableGuiModel joinGuiModel, JoinSelectionServiceGwtImpl joinSelectionServiceGwtImpl, MultiTableDatasource parentDatasource ) { super( parentDatasource ); this.joinGuiModel = joinGuiModel; this.joinSelectionServiceGwtImpl = joinSelectionServiceGwtImpl; this.schemaSelection = new SchemaSelection(); this.mtdatasource = parentDatasource; } public String getName() { return "joinSelectionStepController"; } public void retrieveSchemas( final IDatabaseConnection connection ) { joinSelectionServiceGwtImpl.retrieveSchemas( connection, new XulServiceCallback<List>() { public void error( String message, Throwable error ) { error.printStackTrace(); mtdatasource.displayErrors( new JoinError( message, error.getMessage() ) ); } public void success( List schemaValues ) { schemas.removePropertyChangeListener( schemaSelection ); joinGuiModel.setSchemas( schemaValues ); //processAvailableTables(connection, schemaValues.size() > 0 ? schemaValues.get(0).toString() : null); schemas.addPropertyChangeListener( schemaSelection ); } } ); } private void processAvailableTables( IDatabaseConnection connection, String schema ) { joinSelectionServiceGwtImpl.getDatabaseTables( connection, schema, new XulServiceCallback<List>() { public void error( String message, Throwable error ) { error.printStackTrace(); mtdatasource.displayErrors( new JoinError( message, error.getMessage() ) ); closeWaitingDialog(); } public void success( List tables ) { try { if ( tables.size() == 0 ) { return; } if ( domain != null && datasourceDTO != null ) { joinGuiModel.populateJoinGuiModel( domain, datasourceDTO, tables ); if ( joinGuiModel.getFactTable() != null ) { setFactTable( joinGuiModel.getFactTable() ); } } joinGuiModel.processAvailableTables( tables ); } finally { closeWaitingDialog(); } } } ); } @Bindable public void addSelectedTable() { if ( this.availableTables.getSelectedItem() != null ) { List<JoinTableModel> selected = new ArrayList<JoinTableModel>(); for ( Object obj : this.availableTables.getSelectedItems() ) { selected.add( (JoinTableModel) obj ); } this.joinGuiModel.addSelectedTables( selected ); } checkValidState(); } @Bindable public void removeSelectedTable() { if ( this.selectedTables.getSelectedItem() != null ) { List<JoinTableModel> selected = new ArrayList<JoinTableModel>(); for ( Object obj : this.selectedTables.getSelectedItems() ) { selected.add( (JoinTableModel) obj ); } this.joinGuiModel.removeSelectedTables( selected ); } checkValidState(); checkExistingJoinsStillValid(); } private void checkExistingJoinsStillValid() { Set<String> allTables = new HashSet<String>(); for ( JoinTableModel tbl : joinGuiModel.getSelectedTables() ) { allTables.add( tbl.getName() ); } List<JoinRelationshipModel> toRemove = new ArrayList<JoinRelationshipModel>(); for ( JoinRelationshipModel join : joinGuiModel.getJoins() ) { if ( !allTables.contains( join.getLeftKeyFieldModel().getParentTable().getName() ) || !allTables .contains( join.getRightKeyFieldModel().getParentTable().getName() ) ) { toRemove.add( join ); } } for ( JoinRelationshipModel join : toRemove ) { joinGuiModel.getJoins().remove( join ); } } @Override public void init( IWizardModel wizardModel ) throws XulException { this.tablesSelectionDialog = (XulVbox) document.getElementById( JOIN_STEP_PANEL_ID ); this.availableTables = (XulListbox) document.getElementById( "availableTables" ); this.selectedTables = (XulListbox) document.getElementById( "selectedTables" ); this.factTables = (XulMenuList<JoinTableModel>) document.getElementById( "factTables" ); this.schemas = (XulMenuList<String>) document.getElementById( "schemas" ); super.init( wizardModel ); } public void setBindings() { BindingFactory bf = new GwtBindingFactory( document ); bf.createBinding( this.joinGuiModel.getAvailableTables(), "children", this.availableTables, "elements" ); bf.createBinding( this.joinGuiModel.getSelectedTables(), "children", this.selectedTables, "elements" ); bf.createBinding( this.joinGuiModel.getSelectedTables(), "children", this.factTables, "elements", new BindingConvertor<AbstractModelList<JoinTableModel>, Collection<JoinTableModel>>() { @Override public Collection<JoinTableModel> sourceToTarget( AbstractModelList<JoinTableModel> list ) { List<JoinTableModel> tables = new ArrayList<JoinTableModel>(); tables.addAll( list.asList() ); JoinTableModel emptyOption = new JoinTableModel(); emptyOption.setName( MessageHandler.getString( "multitable.SELECT_TABLE" ) ); tables.add( 0, emptyOption ); //Empty option must be always 0. return tables; } @Override public AbstractModelList<JoinTableModel> targetToSource( final Collection<JoinTableModel> list ) { return null; } } ); bf.createBinding( this.joinGuiModel, "schemas", this.schemas, "elements", new BindingConvertor<List<String>, Collection<String>>() { @Override public Collection<String> sourceToTarget( List<String> list ) { List<String> tables = new ArrayList<String>(); tables.addAll( list ); return tables; } @Override public List<String> targetToSource( final Collection<String> list ) { return null; } } ); bf.createBinding( this.factTables, "selectedIndex", this.joinGuiModel, "factTable", new BindingConvertor<Integer, JoinTableModel>() { @Override public JoinTableModel sourceToTarget( final Integer index ) { if ( index == -1 ) { return null; } //Index 0 represents [select table] option. //To be valid index must not be 0. checkValidState(); int i = (int) index; i--; return i < 0 ? null : joinGuiModel.getSelectedTables().get( i ); } @Override public Integer targetToSource( final JoinTableModel value ) { return joinGuiModel.getSelectedTables().indexOf( value ); } } ); // use a binding to handle the visibility state of the schema type radio group try { bf.createBinding( joinGuiModel, "doOlap", "factTableVbox", "visible" ).fireSourceChanged(); } catch ( Exception e ) { e.printStackTrace(); mtdatasource.displayErrors( new JoinError( e.getMessage(), e.getMessage() ) ); } } public String getStepName() { return MessageHandler.getString( "multitable.SELECT_TABLES" ); } public XulComponent getUIComponent() { return this.tablesSelectionDialog; } public void setFactTable( JoinTableModel factTable ) { List<JoinTableModel> tables = new ArrayList<JoinTableModel>(); tables.addAll( this.factTables.getElements() ); if ( factTable != null ) { this.factTables.setSelectedIndex( tables.indexOf( factTable.getName() ) ); } } @Override public void stepActivatingReverse() { super.stepActivatingReverse(); parentDatasource.setFinishable( false ); checkValidState(); } private void checkValidState() { boolean valid = true; boolean finishable = true; if ( joinGuiModel.isDoOlap() ) { valid &= this.factTables.getSelectedIndex() > 0; finishable &= this.factTables.getSelectedIndex() > 0; } valid &= this.selectedTables.getElements().size() > 1; finishable &= this.selectedTables.getElements().size() == 1; super.setValid( valid ); this.parentDatasource.setFinishable( finishable ); } @Override public void stepActivatingForward() { super.stepActivatingForward(); if ( this.joinGuiModel.getAvailableTables() == null || this.joinGuiModel.getAvailableTables().size() == 0 ) { fetchTables(); } checkValidState(); } public Domain getDomain() { return domain; } public void setDomain( Domain domain ) { this.domain = domain; } public MultiTableDatasourceDTO getDatasourceDTO() { return datasourceDTO; } public void setDatasourceDTO( MultiTableDatasourceDTO datasourceDTO ) { this.datasourceDTO = datasourceDTO; } public void closeWaitingDialog() { MessageHandler.getInstance().closeWaitingDialog(); } public void showWaitingDialog() { MessageHandler.getInstance().showWaitingDialog( MessageHandler.getString( "multitable.FETCHING_TABLE_INFO" ) ); } protected void fetchTables() { showWaitingDialog(); IDatabaseConnection connection = ( (MultiTableDatasource) parentDatasource ).getConnection(); processAvailableTables( connection, schemas.getValue() ); } class SchemaSelection implements PropertyChangeListener { public void propertyChange( PropertyChangeEvent evt ) { if ( evt.getNewValue() instanceof String && TablesSelectionStep.this.activated ) { fetchTables(); } } } @Override public void refresh() { IDatabaseConnection connection = ( (MultiTableDatasource) parentDatasource ).getConnection(); joinSelectionServiceGwtImpl.retrieveSchemas( connection, new XulServiceCallback<List>() { public void error( String message, Throwable error ) { error.printStackTrace(); mtdatasource.displayErrors( new JoinError( message, error.getMessage() ) ); } public void success( List schemaValues ) { schemas.removePropertyChangeListener( schemaSelection ); joinGuiModel.setSchemas( schemaValues ); schemas.addPropertyChangeListener( schemaSelection ); fetchTables(); } } ); } }