/* * 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) 2011 Pentaho Corporation.. All rights reserved. * * @author Ezequiel Cuellar */ package org.pentaho.platform.dataaccess.datasource.wizard.sources.multitable; import org.pentaho.agilebi.modeler.gwt.BogoPojo; import org.pentaho.metadata.model.Domain; import org.pentaho.platform.dataaccess.datasource.IConnection; import org.pentaho.platform.dataaccess.datasource.wizard.IDatasourceSummary; import org.pentaho.platform.dataaccess.datasource.wizard.IWizardDatasource; import org.pentaho.platform.dataaccess.datasource.wizard.IWizardStep; import org.pentaho.platform.dataaccess.datasource.wizard.controllers.MessageHandler; import org.pentaho.platform.dataaccess.datasource.wizard.models.DatasourceModel; 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.platform.dataaccess.datasource.wizard.sources.query.QueryPhysicalStep; import org.pentaho.ui.xul.XulComponent; import org.pentaho.ui.xul.XulDomContainer; import org.pentaho.ui.xul.XulException; import org.pentaho.ui.xul.XulServiceCallback; import org.pentaho.ui.xul.binding.Binding; import org.pentaho.ui.xul.binding.BindingConvertor; import org.pentaho.ui.xul.binding.BindingFactory; import org.pentaho.ui.xul.components.XulLabel; import org.pentaho.ui.xul.components.XulRadio; import org.pentaho.ui.xul.containers.XulDialog; 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.impl.AbstractXulEventHandler; import org.pentaho.ui.xul.stereotype.Bindable; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; public class MultiTableDatasource extends AbstractXulEventHandler implements IWizardDatasource { private boolean finishable; private MultitableGuiModel joinGuiModel; private JoinSelectionServiceGwtImpl joinSelectionServiceGwtImpl; private QueryPhysicalStep connectionSelectionStep; private TablesSelectionStep tablesSelectionStep; private JoinDefinitionsStep joinDefinitionsStep; private IConnection connection; private BindingFactory bf; private IWizardModel wizardModel; private JoinValidator validator; private XulDialog errorDialog; private XulLabel errorLabel; public MultiTableDatasource(DatasourceModel datasourceModel) { this.joinGuiModel = new MultitableGuiModel(); this.joinSelectionServiceGwtImpl = new JoinSelectionServiceGwtImpl(); this.validator = new JoinValidator(this.joinGuiModel, wizardModel); this.joinSelectionServiceGwtImpl.gwtWorkaround(new BogoPojo(), new XulServiceCallback<BogoPojo>() { public void error(String message, Throwable error) { error.printStackTrace(); } public void success(BogoPojo bogoPojo) { bogoPojo.getJoinDTO(); } }); connectionSelectionStep = new QueryPhysicalStep(datasourceModel, MultiTableDatasource.this, false); tablesSelectionStep = new TablesSelectionStep(joinGuiModel, joinSelectionServiceGwtImpl, MultiTableDatasource.this); joinDefinitionsStep = new JoinDefinitionsStep(joinGuiModel, joinSelectionServiceGwtImpl, MultiTableDatasource.this); } @Override public void activating() throws XulException { this.connectionSelectionStep.activating(); this.tablesSelectionStep.activating(); this.joinDefinitionsStep.activating(); XulVbox queryVbox = (XulVbox) document.getElementById("queryBox"); queryVbox.setVisible(false); XulVbox metadataVbox = (XulVbox) document.getElementById("metadata"); metadataVbox.setVisible(true); XulVbox connectionsVbox = (XulVbox) document.getElementById("connectionsLbl"); connectionsVbox.setVisible(true); XulListbox connections = (XulListbox) document.getElementById("connectionList"); connections.setWidth(568); connections.setHeight(275); // conditionally hiding the selection of reporting vs reporting+olap in the case where reporting only makes no sense. try { bf.createBinding(wizardModel, "reportingOnlyValid", "metadata", "visible").fireSourceChanged(); } catch (Exception e) { e.printStackTrace(); } // Use a binding to keep the radio buttons in sync XulRadio olapRadio = (XulRadio) document.getElementById("reporting_analysis"); bf.createBinding(olapRadio, "checked", joinGuiModel, "doOlap"); // Non-star is the default, change that if relational only is not an option joinGuiModel.setDoOlap(wizardModel.isReportingOnlyValid() == false); this.errorDialog = (XulDialog) document.getElementById("errorDialog"); this.errorLabel = (XulLabel) document.getElementById("errorLabel"); this.connectionSelectionStep.setValid(true); this.setConnection(connectionSelectionStep.getConnection()); } @Override public void deactivating() { this.connectionSelectionStep.deactivate(); this.tablesSelectionStep.deactivate(); this.joinDefinitionsStep.deactivate(); } @Override public void init(final XulDomContainer container, final IWizardModel wizardModel) throws XulException { this.wizardModel = wizardModel; document = container.getDocumentRoot(); this.bf = new GwtBindingFactory(document); bf.setBindingType(Binding.Type.ONE_WAY); container.addEventHandler(connectionSelectionStep); container.addEventHandler(tablesSelectionStep); container.addEventHandler(joinDefinitionsStep); connectionSelectionStep.init(wizardModel); tablesSelectionStep.init(wizardModel); joinDefinitionsStep.init(wizardModel); bf.createBinding(connectionSelectionStep, "connection", this, "connection"); } @Override @Bindable public String getName() { return MessageHandler.getString("multitable.DATABASE_TABLES"); } @Override public List<IWizardStep> getSteps() { List<IWizardStep> steps = new ArrayList<IWizardStep>(); steps.add(this.connectionSelectionStep); steps.add(this.tablesSelectionStep); steps.add(this.joinDefinitionsStep); return steps; } protected void displayErrors(JoinError error) { this.errorDialog.setTitle(error.getTitle()); this.errorLabel.setValue(error.getError()); this.errorDialog.show(); } @Override public void onFinish(final XulServiceCallback<IDatasourceSummary> callback) { if (this.validator.allTablesJoined()) { String dsName = this.wizardModel.getDatasourceName(); MultiTableDatasourceDTO dto = this.joinGuiModel.createMultiTableDatasourceDTO(dsName); dto.setSelectedConnection(this.connection); joinSelectionServiceGwtImpl.serializeJoins(dto, this.connection, new XulServiceCallback<IDatasourceSummary>() { public void error(String message, Throwable error) { error.printStackTrace(); } public void success(IDatasourceSummary value) { callback.success(value); } }); } else { MessageHandler.getInstance().closeWaitingDialog(); XulDialog wizardDialog = (XulDialog) document.getElementById("main_wizard_window"); wizardDialog.show(); this.displayErrors(this.validator.getError()); } } @Override public String getId() { return "MULTI-TABLE-DS"; } @Override public boolean isFinishable() { return finishable; } @Bindable public void setFinishable(boolean finishable) { this.finishable = finishable; firePropertyChange("finishable", !finishable, finishable); } @Override public void restoreSavedDatasource(final Domain previousDomain, final XulServiceCallback<Void> callback) { String serializedDatasource = (String) previousDomain.getLogicalModels().get(0).getProperty("datasourceModel"); joinSelectionServiceGwtImpl.deSerializeModelState(serializedDatasource, new XulServiceCallback<MultiTableDatasourceDTO>() { public void success(final MultiTableDatasourceDTO datasourceDTO) { wizardModel.setDatasourceName(datasourceDTO.getDatasourceName()); // This sets up a race. populateJoinGuiModel relies on the // available tables being populated, with is async MultiTableDatasource.this.connectionSelectionStep.selectConnectionByName(datasourceDTO.getSelectedConnection().getName()); // We'll get out of the race by making the same async call now // and tailing off it's success // TODO: investigate a better way around this race condition. // This service is being called twice on edit as is joinSelectionServiceGwtImpl.getDatabaseTables(connection, new XulServiceCallback<List>() { public void error(String message, Throwable error) { error.printStackTrace(); } public void success(List tables) { joinGuiModel.processAvailableTables(tables); joinGuiModel.populateJoinGuiModel(previousDomain, datasourceDTO); tablesSelectionStep.setValid(true); if(joinGuiModel.isDoOlap()) { tablesSelectionStep.setFactTable(joinGuiModel.getFactTable()); } callback.success(null); } }); } public void error(String s, Throwable throwable) { MessageHandler.getInstance().showErrorDialog(MessageHandler.getString("ERROR"), MessageHandler.getString("DatasourceEditor.ERROR_0002_UNABLE_TO_SHOW_DIALOG", throwable.getLocalizedMessage())); callback.error(s, throwable); } }); } class NotDisabledBindingConvertor extends BindingConvertor<Boolean, Boolean> { public Boolean sourceToTarget(Boolean value) { return Boolean.valueOf(!value.booleanValue()); } public Boolean targetToSource(Boolean value) { return Boolean.valueOf(!value.booleanValue()); } } @Override public void reset() { this.joinGuiModel.reset(); } @Bindable public IConnection getConnection() { return connection; } @Bindable public void setConnection(IConnection connection) { this.connection = connection; this.joinGuiModel.reset(); this.joinDefinitionsStep.resetComponents(); this.tablesSelectionStep.processAvailableTables(connection); } }