/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed 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.pentaho.di.ui.spoon.delegates; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.pentaho.di.cluster.SlaveServer; import org.pentaho.di.core.Const; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.EngineMetaInterface; import org.pentaho.di.core.NotePadMeta; import org.pentaho.di.core.Result; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.extension.ExtensionPointHandler; import org.pentaho.di.core.extension.KettleExtensionPoint; import org.pentaho.di.core.gui.Point; import org.pentaho.di.core.gui.SpoonInterface; import org.pentaho.di.core.logging.LogLevel; import org.pentaho.di.core.logging.TransLogTable; import org.pentaho.di.core.undo.TransAction; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransExecutionConfiguration; import org.pentaho.di.trans.TransHopMeta; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.cluster.TransSplitter; import org.pentaho.di.trans.debug.StepDebugMeta; import org.pentaho.di.trans.debug.TransDebugMeta; import org.pentaho.di.trans.step.StepMeta; import org.pentaho.di.ui.core.PropsUI; import org.pentaho.di.ui.core.gui.GUIResource; import org.pentaho.di.ui.spoon.Spoon; import org.pentaho.di.ui.spoon.TabMapEntry; import org.pentaho.di.ui.spoon.TabMapEntry.ObjectType; import org.pentaho.di.ui.spoon.job.JobGraph; import org.pentaho.di.ui.spoon.trans.TransGraph; import org.pentaho.di.ui.trans.debug.TransDebugDialog; import org.pentaho.di.ui.trans.dialog.TransExecutionConfigurationDialog; import org.pentaho.xul.swt.tab.TabItem; public class SpoonTransformationDelegate extends SpoonDelegate { private static Class<?> PKG = Spoon.class; // for i18n purposes, needed by Translator2!! /** * This contains a map between the name of a transformation and the TransMeta object. If the transformation has no * name it will be mapped under a number [1], [2] etc. */ private List<TransMeta> transformationMap; /** * Remember the debugging configuration per transformation */ private Map<TransMeta, TransDebugMeta> transDebugMetaMap; /** * Remember the preview configuration per transformation */ private Map<TransMeta, TransDebugMeta> transPreviewMetaMap; public SpoonTransformationDelegate( Spoon spoon ) { super( spoon ); transformationMap = new ArrayList<TransMeta>(); transDebugMetaMap = new Hashtable<TransMeta, TransDebugMeta>(); transPreviewMetaMap = new Hashtable<TransMeta, TransDebugMeta>(); } /** * Add a transformation to the * * @param transMeta * the transformation to add to the map * @return true if the transformation was added, false if it couldn't be added (already loaded) **/ public boolean addTransformation( TransMeta transMeta ) { int index = getTransformationList().indexOf( transMeta ); if ( index < 0 ) { getTransformationList().add( transMeta ); return true; } else { /* * ShowMessageDialog dialog = new ShowMessageDialog(spoon.getShell(), SWT.OK | SWT.ICON_INFORMATION, * BaseMessages.getString(PKG, "Spoon.Dialog.TransAlreadyLoaded.Title"), "'" + transMeta.toString() + "'" + * Const.CR + Const.CR + BaseMessages.getString(PKG, "Spoon.Dialog.TransAlreadyLoaded.Message")); * dialog.setTimeOut(6); dialog.open(); */ return false; } } /** * @param transMeta * the transformation to close, make sure it's ok to dispose of it BEFORE you call this. */ public synchronized void closeTransformation( TransMeta transMeta ) { // Close the associated tabs... // TabMapEntry entry = getSpoon().delegates.tabs.findTabMapEntry( transMeta ); if ( entry != null ) { getSpoon().delegates.tabs.removeTab( entry ); } // Also remove it from the item from the transformationMap // Otherwise it keeps showing up in the objects tree // Look for the transformation, not the key (name might have changed) // int index = getTransformationList().indexOf( transMeta ); while ( index >= 0 ) { getTransformationList().remove( index ); index = getTransformationList().indexOf( transMeta ); } getSpoon().refreshTree(); getSpoon().enableMenus(); } public Spoon getSpoon() { return this.spoon; } public void addTransGraph( TransMeta transMeta ) { boolean added = addTransformation( transMeta ); if ( added ) { // See if there already is a tab for this graph with the short default name. // If there is, set that one to show the location as well. // If not, simply add it without // If no, add it // If yes, select that tab // boolean showLocation = false; boolean addTab = true; String tabName = spoon.delegates.tabs.makeTabName( transMeta, showLocation ); TabMapEntry tabEntry = spoon.delegates.tabs.findTabMapEntry( tabName, ObjectType.TRANSFORMATION_GRAPH ); if ( tabEntry != null ) { // We change the already loaded transformation to also show the location. // showLocation = true; // Try again, including the location of the object... // tabName = spoon.delegates.tabs.makeTabName( transMeta, showLocation ); TabMapEntry exactSameEntry = spoon.delegates.tabs.findTabMapEntry( tabName, ObjectType.TRANSFORMATION_GRAPH ); if ( exactSameEntry != null ) { // Already loaded, simply select the tab item in question... // addTab = false; } else { // We might need to rename the tab of the entry already loaded! // tabEntry.setShowingLocation( true ); String newTabName = spoon.delegates.tabs.makeTabName( tabEntry.getObject().getMeta(), showLocation ); tabEntry.getTabItem().setText( newTabName ); } } TransGraph transGraph = null; if ( addTab ) { transGraph = new TransGraph( spoon.tabfolder.getSwtTabset(), spoon, transMeta ); PropsUI props = PropsUI.getInstance(); TabItem tabItem = new TabItem( spoon.tabfolder, tabName, tabName, props.getSashWeights() ); String toolTipText = BaseMessages.getString( PKG, "Spoon.TabTrans.Tooltip", spoon.delegates.tabs.makeTabName( transMeta, showLocation ) ); if ( !Utils.isEmpty( transMeta.getFilename() ) ) { toolTipText += Const.CR + Const.CR + transMeta.getFilename(); } tabItem.setToolTipText( toolTipText ); tabItem.setImage( GUIResource.getInstance().getImageTransGraph() ); tabItem.setControl( transGraph ); TransLogTable logTable = transMeta.getTransLogTable(); String versionLabel = transMeta.getObjectRevision() == null ? null : transMeta.getObjectRevision().getName(); tabEntry = new TabMapEntry( tabItem, transMeta.getFilename(), transMeta.getName(), transMeta.getRepositoryDirectory(), versionLabel, transGraph, ObjectType.TRANSFORMATION_GRAPH ); tabEntry.setShowingLocation( showLocation ); spoon.delegates.tabs.addTab( tabEntry ); } int idx = spoon.tabfolder.indexOf( tabEntry.getTabItem() ); // keep the focus on the graph spoon.tabfolder.setSelected( idx ); if ( addTab ) { TransLogTable logTable = transMeta.getTransLogTable(); // OK, also see if we need to open a new history window. if ( isLogTableDefined( logTable ) && !transMeta.isSlaveTransformation() ) { addTabsToTransGraph( transGraph ); } } spoon.setUndoMenu( transMeta ); spoon.enableMenus(); } else { TabMapEntry tabEntry = spoon.delegates.tabs.findTabMapEntry( transMeta ); if ( tabEntry != null ) { int idx = spoon.tabfolder.indexOf( tabEntry.getTabItem() ); // keep the focus on the graph spoon.tabfolder.setSelected( idx ); spoon.setUndoMenu( transMeta ); spoon.enableMenus(); } } } boolean isLogTableDefined( TransLogTable logTable ) { return logTable.getDatabaseMeta() != null && !Utils.isEmpty( logTable.getTableName() ); } void addTabsToTransGraph( TransGraph transGraph ) { transGraph.addAllTabs(); transGraph.extraViewTabFolder.setSelection( transGraph.transHistoryDelegate.getTransHistoryTab() ); } public void tabSelected( TabItem item ) { List<TabMapEntry> collection = spoon.delegates.tabs.getTabs(); // See which core objects to show // for ( TabMapEntry entry : collection ) { if ( item.equals( entry.getTabItem() ) ) { // TabItemInterface itemInterface = entry.getObject(); // // Another way to implement this may be to keep track of the // state of the core object tree in method // addCoreObjectsToTree() // if ( entry.getObject() instanceof TransGraph || entry.getObject() instanceof JobGraph ) { EngineMetaInterface meta = entry.getObject().getMeta(); if ( meta != null ) { meta.setInternalKettleVariables(); } if ( spoon.getCoreObjectsState() != SpoonInterface.STATE_CORE_OBJECTS_SPOON ) { spoon.refreshCoreObjects(); } } } } // Also refresh the tree spoon.refreshTree(); spoon.enableMenus(); } public List<TransMeta> getTransformationList() { return transformationMap; } public TransMeta getTransformation( String name ) { TabMapEntry entry = spoon.delegates.tabs.findTabMapEntry( name, ObjectType.TRANSFORMATION_GRAPH ); if ( entry != null ) { return (TransMeta) entry.getObject().getManagedObject(); } // Try again, TODO: remove part below // for ( TransMeta xform : transformationMap ) { if ( name != null && name.equals( xform.getName() ) ) { return xform; } } return null; } public void removeTransformation( TransMeta transMeta ) { transformationMap.remove( transMeta ); } public TransMeta[] getLoadedTransformations() { return transformationMap.toArray( new TransMeta[transformationMap.size()] ); } public TransGraph findTransGraphOfTransformation( TransMeta transMeta ) { // Now loop over the entries in the tab-map for ( TabMapEntry mapEntry : spoon.delegates.tabs.getTabs() ) { if ( mapEntry.getObject() instanceof TransGraph ) { TransGraph transGraph = (TransGraph) mapEntry.getObject(); if ( transGraph.getMeta().equals( transMeta ) ) { return transGraph; } } } return null; } public boolean isDefaultTransformationName( String name ) { if ( !name.startsWith( Spoon.STRING_TRANSFORMATION ) ) { return false; } // see if there are only digits behind the transformation... // This will detect: // "Transformation" // "Transformation " // "Transformation 1" // "Transformation 2" // ... for ( int i = Spoon.STRING_TRANSFORMATION.length() + 1; i < name.length(); i++ ) { if ( !Character.isDigit( name.charAt( i ) ) ) { return false; } } return true; } public void undoTransformationAction( TransMeta transMeta, TransAction transAction ) { switch ( transAction.getType() ) { // We created a new step : undo this... case TransAction.TYPE_ACTION_NEW_STEP: // Delete the step at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeStep( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We created a new connection : undo this... case TransAction.TYPE_ACTION_NEW_CONNECTION: // Delete the connection at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeDatabase( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We created a new note : undo this... case TransAction.TYPE_ACTION_NEW_NOTE: // Delete the note at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeNote( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We created a new hop : undo this... case TransAction.TYPE_ACTION_NEW_HOP: // Delete the hop at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeTransHop( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We created a new slave : undo this... case TransAction.TYPE_ACTION_NEW_SLAVE: // Delete the slave at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.getSlaveServers().remove( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We created a new slave : undo this... case TransAction.TYPE_ACTION_NEW_CLUSTER: // Delete the slave at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.getClusterSchemas().remove( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; // // DELETE // // We delete a step : undo this... case TransAction.TYPE_ACTION_DELETE_STEP: // un-Delete the step at correct location: re-insert for ( int i = 0; i < transAction.getCurrent().length; i++ ) { StepMeta stepMeta = (StepMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.addStep( idx, stepMeta ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We deleted a connection : undo this... case TransAction.TYPE_ACTION_DELETE_CONNECTION: // re-insert the connection at correct location: for ( int i = 0; i < transAction.getCurrent().length; i++ ) { DatabaseMeta ci = (DatabaseMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.addDatabase( idx, ci ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We delete new note : undo this... case TransAction.TYPE_ACTION_DELETE_NOTE: // re-insert the note at correct location: for ( int i = 0; i < transAction.getCurrent().length; i++ ) { NotePadMeta ni = (NotePadMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.addNote( idx, ni ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We deleted a hop : undo this... case TransAction.TYPE_ACTION_DELETE_HOP: // re-insert the hop at correct location: for ( int i = 0; i < transAction.getCurrent().length; i++ ) { TransHopMeta hi = (TransHopMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; // Build a new hop: StepMeta from = transMeta.findStep( hi.getFromStep().getName() ); StepMeta to = transMeta.findStep( hi.getToStep().getName() ); TransHopMeta hinew = new TransHopMeta( from, to ); transMeta.addTransHop( idx, hinew ); } spoon.refreshTree(); spoon.refreshGraph(); break; // // CHANGE // // We changed a step : undo this... case TransAction.TYPE_ACTION_CHANGE_STEP: // Delete the current step, insert previous version. for ( int i = 0; i < transAction.getCurrent().length; i++ ) { StepMeta prev = (StepMeta) ( (StepMeta) transAction.getPrevious()[i] ).clone(); int idx = transAction.getCurrentIndex()[i]; transMeta.getStep( idx ).replaceMeta( prev ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We changed a connection : undo this... case TransAction.TYPE_ACTION_CHANGE_CONNECTION: // Delete & re-insert for ( int i = 0; i < transAction.getCurrent().length; i++ ) { DatabaseMeta prev = (DatabaseMeta) transAction.getPrevious()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.getDatabase( idx ).replaceMeta( (DatabaseMeta) prev.clone() ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We changed a note : undo this... case TransAction.TYPE_ACTION_CHANGE_NOTE: // Delete & re-insert for ( int i = 0; i < transAction.getCurrent().length; i++ ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeNote( idx ); NotePadMeta prev = (NotePadMeta) transAction.getPrevious()[i]; transMeta.addNote( idx, (NotePadMeta) prev.clone() ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We changed a hop : undo this... case TransAction.TYPE_ACTION_CHANGE_HOP: // Delete & re-insert for ( int i = 0; i < transAction.getCurrent().length; i++ ) { TransHopMeta prev = (TransHopMeta) transAction.getPrevious()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.removeTransHop( idx ); transMeta.addTransHop( idx, (TransHopMeta) prev.clone() ); } spoon.refreshTree(); spoon.refreshGraph(); break; // // POSITION // // The position of a step has changed: undo this... case TransAction.TYPE_ACTION_POSITION_STEP: // Find the location of the step: for ( int i = 0; i < transAction.getCurrentIndex().length; i++ ) { StepMeta stepMeta = transMeta.getStep( transAction.getCurrentIndex()[i] ); stepMeta.setLocation( transAction.getPreviousLocation()[i] ); } spoon.refreshGraph(); break; // The position of a note has changed: undo this... case TransAction.TYPE_ACTION_POSITION_NOTE: for ( int i = 0; i < transAction.getCurrentIndex().length; i++ ) { int idx = transAction.getCurrentIndex()[i]; NotePadMeta npi = transMeta.getNote( idx ); Point prev = transAction.getPreviousLocation()[i]; npi.setLocation( prev ); } spoon.refreshGraph(); break; default: break; } // OK, now check if we need to do this again... if ( transMeta.viewNextUndo() != null ) { if ( transMeta.viewNextUndo().getNextAlso() ) { spoon.undoAction( transMeta ); } } } public void redoTransformationAction( TransMeta transMeta, TransAction transAction ) { switch ( transAction.getType() ) { case TransAction.TYPE_ACTION_NEW_STEP: // re-delete the step at correct location: for ( int i = 0; i < transAction.getCurrent().length; i++ ) { StepMeta stepMeta = (StepMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.addStep( idx, stepMeta ); spoon.refreshTree(); spoon.refreshGraph(); } break; case TransAction.TYPE_ACTION_NEW_CONNECTION: // re-insert the connection at correct location: for ( int i = 0; i < transAction.getCurrent().length; i++ ) { DatabaseMeta ci = (DatabaseMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.addDatabase( idx, ci ); spoon.refreshTree(); spoon.refreshGraph(); } break; case TransAction.TYPE_ACTION_NEW_NOTE: // re-insert the note at correct location: for ( int i = 0; i < transAction.getCurrent().length; i++ ) { NotePadMeta ni = (NotePadMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.addNote( idx, ni ); spoon.refreshTree(); spoon.refreshGraph(); } break; case TransAction.TYPE_ACTION_NEW_HOP: // re-insert the hop at correct location: for ( int i = 0; i < transAction.getCurrent().length; i++ ) { TransHopMeta hi = (TransHopMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.addTransHop( idx, hi ); spoon.refreshTree(); spoon.refreshGraph(); } break; // // DELETE // case TransAction.TYPE_ACTION_DELETE_STEP: // re-remove the step at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeStep( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; case TransAction.TYPE_ACTION_DELETE_CONNECTION: // re-remove the connection at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeDatabase( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; case TransAction.TYPE_ACTION_DELETE_NOTE: // re-remove the note at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeNote( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; case TransAction.TYPE_ACTION_DELETE_HOP: // re-remove the hop at correct location: for ( int i = transAction.getCurrent().length - 1; i >= 0; i-- ) { int idx = transAction.getCurrentIndex()[i]; transMeta.removeTransHop( idx ); } spoon.refreshTree(); spoon.refreshGraph(); break; // // CHANGE // // We changed a step : undo this... case TransAction.TYPE_ACTION_CHANGE_STEP: // Delete the current step, insert previous version. for ( int i = 0; i < transAction.getCurrent().length; i++ ) { StepMeta stepMeta = (StepMeta) ( (StepMeta) transAction.getCurrent()[i] ).clone(); transMeta.getStep( transAction.getCurrentIndex()[i] ).replaceMeta( stepMeta ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We changed a connection : undo this... case TransAction.TYPE_ACTION_CHANGE_CONNECTION: // Delete & re-insert for ( int i = 0; i < transAction.getCurrent().length; i++ ) { DatabaseMeta databaseMeta = (DatabaseMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.getDatabase( idx ).replaceMeta( (DatabaseMeta) databaseMeta.clone() ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We changed a note : undo this... case TransAction.TYPE_ACTION_CHANGE_NOTE: // Delete & re-insert for ( int i = 0; i < transAction.getCurrent().length; i++ ) { NotePadMeta ni = (NotePadMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.removeNote( idx ); transMeta.addNote( idx, (NotePadMeta) ni.clone() ); } spoon.refreshTree(); spoon.refreshGraph(); break; // We changed a hop : undo this... case TransAction.TYPE_ACTION_CHANGE_HOP: // Delete & re-insert for ( int i = 0; i < transAction.getCurrent().length; i++ ) { TransHopMeta hi = (TransHopMeta) transAction.getCurrent()[i]; int idx = transAction.getCurrentIndex()[i]; transMeta.removeTransHop( idx ); transMeta.addTransHop( idx, (TransHopMeta) hi.clone() ); } spoon.refreshTree(); spoon.refreshGraph(); break; // // CHANGE POSITION // case TransAction.TYPE_ACTION_POSITION_STEP: for ( int i = 0; i < transAction.getCurrentIndex().length; i++ ) { // Find & change the location of the step: StepMeta stepMeta = transMeta.getStep( transAction.getCurrentIndex()[i] ); stepMeta.setLocation( transAction.getCurrentLocation()[i] ); } spoon.refreshGraph(); break; case TransAction.TYPE_ACTION_POSITION_NOTE: for ( int i = 0; i < transAction.getCurrentIndex().length; i++ ) { int idx = transAction.getCurrentIndex()[i]; NotePadMeta npi = transMeta.getNote( idx ); Point curr = transAction.getCurrentLocation()[i]; npi.setLocation( curr ); } spoon.refreshGraph(); break; default: break; } // OK, now check if we need to do this again... if ( transMeta.viewNextUndo() != null ) { if ( transMeta.viewNextUndo().getNextAlso() ) { spoon.redoAction( transMeta ); } } } public void executeTransformation( final TransMeta transMeta, final boolean local, final boolean remote, final boolean cluster, final boolean preview, final boolean debug, final Date replayDate, final boolean safe, LogLevel logLevel ) throws KettleException { if ( transMeta == null ) { return; } // See if we need to ask for debugging information... // TransDebugMeta transDebugMeta = null; TransExecutionConfiguration executionConfiguration = null; if ( preview ) { executionConfiguration = spoon.getTransPreviewExecutionConfiguration(); } else if ( debug ) { executionConfiguration = spoon.getTransDebugExecutionConfiguration(); } else { executionConfiguration = spoon.getTransExecutionConfiguration(); } // Set defaults so the run configuration can set it up correctly executionConfiguration.setExecutingLocally( true ); executionConfiguration.setExecutingRemotely( false ); executionConfiguration.setExecutingClustered( false ); // Set repository and safe mode information in both the exec config and the metadata transMeta.setRepository( spoon.rep ); transMeta.setMetaStore( spoon.metaStore ); executionConfiguration.setRepository( spoon.rep ); executionConfiguration.setSafeModeEnabled( safe ); if ( debug ) { // See if we have debugging information stored somewhere? // transDebugMeta = transDebugMetaMap.get( transMeta ); if ( transDebugMeta == null ) { transDebugMeta = new TransDebugMeta( transMeta ); transDebugMetaMap.put( transMeta, transDebugMeta ); } // Set the default number of rows to retrieve on all selected steps... // List<StepMeta> selectedSteps = transMeta.getSelectedSteps(); if ( selectedSteps != null && selectedSteps.size() > 0 ) { transDebugMeta.getStepDebugMetaMap().clear(); for ( StepMeta stepMeta : transMeta.getSelectedSteps() ) { StepDebugMeta stepDebugMeta = new StepDebugMeta( stepMeta ); stepDebugMeta.setRowCount( PropsUI.getInstance().getDefaultPreviewSize() ); stepDebugMeta.setPausingOnBreakPoint( true ); stepDebugMeta.setReadingFirstRows( false ); transDebugMeta.getStepDebugMetaMap().put( stepMeta, stepDebugMeta ); } } } else if ( preview ) { // See if we have preview information stored somewhere? // transDebugMeta = transPreviewMetaMap.get( transMeta ); if ( transDebugMeta == null ) { transDebugMeta = new TransDebugMeta( transMeta ); transPreviewMetaMap.put( transMeta, transDebugMeta ); } // Set the default number of preview rows on all selected steps... // List<StepMeta> selectedSteps = transMeta.getSelectedSteps(); if ( selectedSteps != null && selectedSteps.size() > 0 ) { transDebugMeta.getStepDebugMetaMap().clear(); for ( StepMeta stepMeta : transMeta.getSelectedSteps() ) { StepDebugMeta stepDebugMeta = new StepDebugMeta( stepMeta ); stepDebugMeta.setRowCount( PropsUI.getInstance().getDefaultPreviewSize() ); stepDebugMeta.setPausingOnBreakPoint( false ); stepDebugMeta.setReadingFirstRows( true ); transDebugMeta.getStepDebugMetaMap().put( stepMeta, stepDebugMeta ); } } } int debugAnswer = TransDebugDialog.DEBUG_CONFIG; if ( debug || preview ) { transDebugMeta.getTransMeta().setRepository( spoon.rep ); // pass repository for mappings TransDebugDialog transDebugDialog = new TransDebugDialog( spoon.getShell(), transDebugMeta ); debugAnswer = transDebugDialog.open(); if ( debugAnswer != TransDebugDialog.DEBUG_CANCEL ) { executionConfiguration.setExecutingLocally( true ); executionConfiguration.setExecutingRemotely( false ); executionConfiguration.setExecutingClustered( false ); } else { // If we cancel the debug dialog, we don't go further with the execution either. // return; } } Object[] data = spoon.variables.getData(); String[] fields = spoon.variables.getRowMeta().getFieldNames(); Map<String, String> variableMap = new HashMap<String, String>(); variableMap.putAll( executionConfiguration.getVariables() ); // the default for ( int idx = 0; idx < fields.length; idx++ ) { String value = executionConfiguration.getVariables().get( fields[idx] ); if ( Utils.isEmpty( value ) ) { value = data[idx].toString(); } variableMap.put( fields[idx], value ); } executionConfiguration.setVariables( variableMap ); executionConfiguration.getUsedVariables( transMeta ); executionConfiguration.getUsedArguments( transMeta, spoon.getArguments() ); executionConfiguration.setReplayDate( replayDate ); executionConfiguration.setLogLevel( logLevel ); boolean execConfigAnswer = true; if ( debugAnswer == TransDebugDialog.DEBUG_CONFIG && replayDate == null && transMeta.isShowDialog() ) { TransExecutionConfigurationDialog dialog = new TransExecutionConfigurationDialog( spoon.getShell(), executionConfiguration, transMeta ); execConfigAnswer = dialog.open(); } if ( execConfigAnswer ) { ExtensionPointHandler.callExtensionPoint( log, KettleExtensionPoint.SpoonTransMetaExecutionStart.id, transMeta ); ExtensionPointHandler.callExtensionPoint( log, KettleExtensionPoint.SpoonTransExecutionConfiguration.id, executionConfiguration ); try { ExtensionPointHandler.callExtensionPoint( log, KettleExtensionPoint.SpoonTransBeforeStart.id, new Object[] { executionConfiguration, transMeta, transMeta } ); } catch ( KettleException e ) { log.logError( e.getMessage(), transMeta.getFilename() ); return; } // Verify if there is at least one step specified to debug or preview... // if ( debug || preview ) { if ( transDebugMeta.getNrOfUsedSteps() == 0 ) { MessageBox box = new MessageBox( spoon.getShell(), SWT.ICON_WARNING | SWT.YES | SWT.NO ); box.setText( BaseMessages.getString( PKG, "Spoon.Dialog.Warning.NoPreviewOrDebugSteps.Title" ) ); box.setMessage( BaseMessages.getString( PKG, "Spoon.Dialog.Warning.NoPreviewOrDebugSteps.Message" ) ); int answer = box.open(); if ( answer != SWT.YES ) { return; } } } // addTransLog(transMeta, executionConfiguration.isExecutingLocally()); // TransLog transLog = spoon.getActiveTransLog(); // TransGraph activeTransGraph = spoon.getActiveTransGraph(); // Is this a local execution? // if ( executionConfiguration.isExecutingLocally() ) { if ( debug || preview ) { activeTransGraph.debug( executionConfiguration, transDebugMeta ); } else { activeTransGraph.start( executionConfiguration ); } // Are we executing remotely? // } else if ( executionConfiguration.isExecutingRemotely() ) { activeTransGraph.handleTransMetaChanges( transMeta ); if ( transMeta.hasChanged() ) { showSaveTransformationBeforeRunningDialog( spoon.getShell() ); } else if ( executionConfiguration.getRemoteServer() != null ) { String carteObjectId = Trans.sendToSlaveServer( transMeta, executionConfiguration, spoon.rep, spoon.metaStore ); monitorRemoteTrans( transMeta, carteObjectId, executionConfiguration.getRemoteServer() ); spoon.delegates.slaves.addSpoonSlave( executionConfiguration.getRemoteServer() ); } else { MessageBox mb = new MessageBox( spoon.getShell(), SWT.OK | SWT.ICON_INFORMATION ); mb.setMessage( BaseMessages.getString( PKG, "Spoon.Dialog.NoRemoteServerSpecified.Message" ) ); mb.setText( BaseMessages.getString( PKG, "Spoon.Dialog.NoRemoteServerSpecified.Title" ) ); mb.open(); } // Are we executing clustered? // } else if ( executionConfiguration.isExecutingClustered() ) { activeTransGraph.handleTransMetaChanges( transMeta ); if ( transMeta.hasChanged() ) { showSaveTransformationBeforeRunningDialog( spoon.getShell() ); } else { splitTrans( transMeta, executionConfiguration ); } } } } private static void showSaveTransformationBeforeRunningDialog( Shell shell ) { MessageBox m = new MessageBox( shell, SWT.OK | SWT.ICON_WARNING ); m.setText( BaseMessages.getString( PKG, "TransLog.Dialog.SaveTransformationBeforeRunning.Title" ) ); m.setMessage( BaseMessages.getString( PKG, "TransLog.Dialog.SaveTransformationBeforeRunning.Message" ) ); m.open(); } private void monitorRemoteTrans( final TransMeta transMeta, final String carteObjectId, final SlaveServer remoteSlaveServer ) { // There is a transformation running in the background. When it finishes, clean it up and log the result on the // console. // Launch in a separate thread to prevent GUI blocking... // Thread thread = new Thread( new Runnable() { public void run() { Trans.monitorRemoteTransformation( spoon.getLog(), carteObjectId, transMeta.toString(), remoteSlaveServer ); } } ); thread.setName( "Monitor remote transformation '" + transMeta.getName() + "', carte object id=" + carteObjectId + ", slave server: " + remoteSlaveServer.getName() ); thread.start(); } protected void splitTrans( final TransMeta transMeta, final TransExecutionConfiguration executionConfiguration ) throws KettleException { try { final TransSplitter transSplitter = new TransSplitter( transMeta ); transSplitter.splitOriginalTransformation(); TransMeta master = transSplitter.getMaster(); SlaveServer masterServer = null; List<StepMeta> masterSteps = master.getTransHopSteps( false ); // add transgraph of transmetas if showing is true SlaveServer[] slaves = transSplitter.getSlaveTargets(); if ( executionConfiguration.isClusterShowingTransformation() ) { if ( masterSteps.size() > 0 ) { // If there is something that needs to be done on the master... masterServer = transSplitter.getMasterServer(); addTransGraph( master ); } // Then the slaves... // for ( int i = 0; i < slaves.length; i++ ) { TransMeta slaveTrans = transSplitter.getSlaveTransMap().get( slaves[i] ); addTransGraph( slaveTrans ); } } // Inject certain internal variables to make it more intuitive. // for ( String var : Const.INTERNAL_TRANS_VARIABLES ) { executionConfiguration.getVariables().put( var, transMeta.getVariable( var ) ); } for ( String var : Const.INTERNAL_JOB_VARIABLES ) { executionConfiguration.getVariables().put( var, transMeta.getVariable( var ) ); } // Parameters override the variables. // For the time being we're passing the parameters over the wire as variables... // TransMeta ot = transSplitter.getOriginalTransformation(); for ( String param : ot.listParameters() ) { String value = Const.NVL( ot.getParameterValue( param ), Const.NVL( ot.getParameterDefault( param ), ot.getVariable( param ) ) ); if ( !Utils.isEmpty( value ) ) { executionConfiguration.getVariables().put( param, value ); } } try { Trans.executeClustered( transSplitter, executionConfiguration ); } catch ( Exception e ) { // Something happened posting the transformation to the cluster. // We need to make sure to de-allocate ports and so on for the next try... // We don't want to suppress original exception here. try { Trans.cleanupCluster( log, transSplitter ); } catch ( Exception ee ) { throw new Exception( "Error executing transformation and error to clenaup cluster", e ); } // we still have execution error but cleanup ok here... throw e; } if ( executionConfiguration.isClusterPosting() ) { // Now add monitors for the master and all the slave servers // if ( masterServer != null ) { spoon.addSpoonSlave( masterServer ); for ( int i = 0; i < slaves.length; i++ ) { spoon.addSpoonSlave( slaves[i] ); } } } // OK, we should also start monitoring of the cluster in the background. // Stop them all if one goes bad. // Also clean up afterwards, close sockets, etc. // // Launch in a separate thread to prevent GUI blocking... // new Thread( new Runnable() { public void run() { Trans.monitorClusteredTransformation( log, transSplitter, null ); Result result = Trans.getClusteredTransformationResult( log, transSplitter, null ); log.logBasic( "-----------------------------------------------------" ); log.logBasic( "Got result back from clustered transformation:" ); log.logBasic( transMeta.toString() + "-----------------------------------------------------" ); log.logBasic( transMeta.toString() + " Errors : " + result.getNrErrors() ); log.logBasic( transMeta.toString() + " Input : " + result.getNrLinesInput() ); log.logBasic( transMeta.toString() + " Output : " + result.getNrLinesOutput() ); log.logBasic( transMeta.toString() + " Updated : " + result.getNrLinesUpdated() ); log.logBasic( transMeta.toString() + " Read : " + result.getNrLinesRead() ); log.logBasic( transMeta.toString() + " Written : " + result.getNrLinesWritten() ); log.logBasic( transMeta.toString() + " Rejected : " + result.getNrLinesRejected() ); log.logBasic( transMeta.toString() + "-----------------------------------------------------" ); } } ).start(); } catch ( Exception e ) { throw new KettleException( e ); } } }