/*! ****************************************************************************** * * 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; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.TreeEvent; import org.eclipse.swt.events.TreeListener; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.swt.widgets.Widget; 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.Result; import org.pentaho.di.core.logging.LogChannelInterface; import org.pentaho.di.core.row.RowMeta; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.variables.Variables; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.repository.ObjectId; import org.pentaho.di.repository.ObjectRevision; import org.pentaho.di.repository.RepositoryDirectoryInterface; import org.pentaho.di.repository.RepositoryObjectType; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.step.StepStatus; import org.pentaho.di.ui.core.ConstUI; import org.pentaho.di.ui.core.PropsUI; import org.pentaho.di.ui.core.dialog.EnterNumberDialog; import org.pentaho.di.ui.core.dialog.EnterSelectionDialog; import org.pentaho.di.ui.core.dialog.EnterTextDialog; import org.pentaho.di.ui.core.dialog.ErrorDialog; import org.pentaho.di.ui.core.dialog.PreviewRowsDialog; import org.pentaho.di.ui.core.gui.GUIResource; import org.pentaho.di.ui.core.widget.ColumnInfo; import org.pentaho.di.ui.core.widget.TreeMemory; import org.pentaho.di.ui.core.widget.TreeUtil; import org.pentaho.di.ui.trans.step.BaseStepDialog; import org.pentaho.di.www.SlaveServerJobStatus; import org.pentaho.di.www.SlaveServerStatus; import org.pentaho.di.www.SlaveServerTransStatus; import org.pentaho.di.www.SniffStepServlet; import org.pentaho.di.www.WebResult; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * SpoonSlave handles the display of the slave server information in a Spoon tab. * * @see org.pentaho.di.ui.spoon.Spoon * @author Matt * @since 12 nov 2006 */ public class SpoonSlave extends Composite implements TabItemInterface { private static Class<?> PKG = Spoon.class; // for i18n purposes, needed by Translator2!! public static final long UPDATE_TIME_VIEW = 30000L; // 30s public static final String STRING_SLAVE_LOG_TREE_NAME = "SLAVE_LOG : "; private Shell shell; private Display display; private SlaveServer slaveServer; private Map<String, Integer> lastLineMap; private Map<String, String> loggingMap; private Spoon spoon; private Tree wTree; private Text wText; private Button wStart; private Button wPause; private Button wStop; private Button wRemove; private Button wSniff; private boolean refreshBusy; private SlaveServerStatus slaveServerStatus; private Timer timer; private TimerTask timerTask; private TreeItem transParentItem; private TreeItem jobParentItem; private LogChannelInterface log; private class TreeEntry { String itemType; // Transformation or Job String name; String status; String id; String[] path; int length; public TreeEntry( TreeItem treeItem ) { TreeItem treeIt = treeItem; path = ConstUI.getTreeStrings( treeIt ); this.length = path.length; if ( path.length > 0 ) { itemType = path[0]; } if ( path.length > 1 ) { name = path[1]; } if ( path.length == 3 ) { treeIt = treeIt.getParentItem(); } status = treeIt.getText( 9 ); id = treeIt.getText( 13 ); } boolean isTransformation() { return itemType.equals( transParentItem.getText() ); } boolean isJob() { return itemType.equals( jobParentItem.getText() ); } boolean isRunning() { return Trans.STRING_RUNNING.equals( status ); } boolean isStopped() { return Trans.STRING_STOPPED.equals( status ); } boolean isFinished() { if ( Trans.STRING_FINISHED_WITH_ERRORS.equals( status ) ) { return true; } return Trans.STRING_FINISHED.equals( status ); } boolean isPaused() { return Trans.STRING_PAUSED.equals( status ); } boolean isWaiting() { return Trans.STRING_WAITING.equals( status ); } @Override public boolean equals( Object o ) { if ( this == o ) { return true; } if ( !( o instanceof TreeEntry ) ) { return false; } TreeEntry treeEntry = (TreeEntry) o; if ( id != null ? !id.equals( treeEntry.id ) : treeEntry.id != null ) { return false; } if ( itemType != null ? !itemType.equals( treeEntry.itemType ) : treeEntry.itemType != null ) { return false; } if ( name != null ? !name.equals( treeEntry.name ) : treeEntry.name != null ) { return false; } return true; } @Override public int hashCode() { int result = itemType != null ? itemType.hashCode() : 0; result = 31 * result + ( name != null ? name.hashCode() : 0 ); result = 31 * result + ( id != null ? id.hashCode() : 0 ); result = 31 * result + ( path != null ? Arrays.hashCode( path ) : 0 ); result = 31 * result + length; return result; } public TreeItem getTreeItem( Tree tree ) { TreeItem[] items = tree.getItems(); for ( TreeItem item : items ) { TreeItem treeItem = findTreeItem( item, 0 ); if ( treeItem != null ) { return treeItem; } } return null; } private TreeItem findTreeItem( TreeItem treeItem, int level ) { if ( treeItem.getText().equals( path[ level ] ) ) { if ( level == 1 ) { if ( this.equals( getTreeEntry( treeItem ) ) ) { treeItemSelected( treeItem ); treeItem.setExpanded( true ); } else { return null; } } if ( level == path.length - 1 ) { return treeItem; } TreeItem[] items = treeItem.getItems(); for ( TreeItem item : items ) { TreeItem found = findTreeItem( item, level + 1 ); if ( found != null ) { return found; } } } return null; } } public SpoonSlave( Composite parent, int style, final Spoon spoon, SlaveServer slaveServer ) { super( parent, style ); this.shell = parent.getShell(); this.display = shell.getDisplay(); this.spoon = spoon; this.slaveServer = slaveServer; this.log = spoon.getLog(); lastLineMap = new HashMap<String, Integer>(); loggingMap = new HashMap<String, String>(); FormLayout formLayout = new FormLayout(); formLayout.marginWidth = Const.FORM_MARGIN; formLayout.marginHeight = Const.FORM_MARGIN; setLayout( formLayout ); setVisible( true ); spoon.props.setLook( this ); SashForm sash = new SashForm( this, SWT.VERTICAL ); sash.setLayout( new FillLayout() ); //CHECKSTYLE:LineLength:OFF ColumnInfo[] colinf = new ColumnInfo[] { new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Stepname" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Copynr" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Read" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Written" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Input" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Output" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Updated" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Rejected" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Errors" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Active" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Time" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.Speed" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.PriorityBufferSizes" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.CarteObjectId" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), new ColumnInfo( BaseMessages.getString( PKG, "SpoonSlave.Column.LogDate" ), ColumnInfo.COLUMN_TYPE_TEXT, false, true ), }; colinf[1].setAllignement( SWT.RIGHT ); colinf[2].setAllignement( SWT.RIGHT ); colinf[3].setAllignement( SWT.RIGHT ); colinf[4].setAllignement( SWT.RIGHT ); colinf[5].setAllignement( SWT.RIGHT ); colinf[6].setAllignement( SWT.RIGHT ); colinf[7].setAllignement( SWT.RIGHT ); colinf[8].setAllignement( SWT.RIGHT ); colinf[9].setAllignement( SWT.RIGHT ); colinf[10].setAllignement( SWT.RIGHT ); colinf[11].setAllignement( SWT.RIGHT ); colinf[12].setAllignement( SWT.RIGHT ); colinf[13].setAllignement( SWT.RIGHT ); wTree = new Tree( sash, SWT.SINGLE | SWT.V_SCROLL | SWT.H_SCROLL ); wTree.setHeaderVisible( true ); TreeMemory.addTreeListener( wTree, STRING_SLAVE_LOG_TREE_NAME + slaveServer.toString() ); Rectangle bounds = spoon.tabfolder.getSwtTabset().getBounds(); for ( ColumnInfo columnInfo : colinf ) { TreeColumn treeColumn = new TreeColumn( wTree, columnInfo.getAllignement() ); treeColumn.setText( columnInfo.getName() ); treeColumn.setWidth( bounds.width / colinf.length ); } transParentItem = new TreeItem( wTree, SWT.NONE ); transParentItem.setText( Spoon.STRING_TRANSFORMATIONS ); transParentItem.setImage( GUIResource.getInstance().getImageTransGraph() ); jobParentItem = new TreeItem( wTree, SWT.NONE ); jobParentItem.setText( Spoon.STRING_JOBS ); jobParentItem.setImage( GUIResource.getInstance().getImageJobGraph() ); wTree.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { enableButtons(); Widget item = event.item; if ( item != null ) { treeItemSelected( (TreeItem) item ); ( (TreeItem) item ).setExpanded( true ); } showLog(); } } ); wTree.addTreeListener( new TreeListener() { public void treeExpanded( TreeEvent event ) { treeItemSelected( (TreeItem) event.item ); showLog(); } public void treeCollapsed( TreeEvent arg0 ) { } } ); wText = new Text( sash, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY | SWT.BORDER ); spoon.props.setLook( wText ); wText.setVisible( true ); Button wRefresh = new Button( this, SWT.PUSH ); wRefresh.setText( BaseMessages.getString( PKG, "SpoonSlave.Button.Refresh" ) ); wRefresh.setEnabled( true ); wRefresh.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { refreshViewAndLog(); } } ); Button wError = new Button( this, SWT.PUSH ); wError.setText( BaseMessages.getString( PKG, "SpoonSlave.Button.ShowErrorLines" ) ); wError.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { showErrors(); } } ); wSniff = new Button( this, SWT.PUSH ); wSniff.setText( BaseMessages.getString( PKG, "SpoonSlave.Button.Sniff" ) ); wSniff.setEnabled( false ); wSniff.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { sniff(); } } ); wStart = new Button( this, SWT.PUSH ); wStart.setText( BaseMessages.getString( PKG, "SpoonSlave.Button.Start" ) ); wStart.setEnabled( false ); wStart.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { start(); } } ); wPause = new Button( this, SWT.PUSH ); wPause.setText( BaseMessages.getString( PKG, "SpoonSlave.Button.Pause" ) ); wPause.setEnabled( false ); wPause.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { pause(); } } ); wStop = new Button( this, SWT.PUSH ); wStop.setText( BaseMessages.getString( PKG, "SpoonSlave.Button.Stop" ) ); wStop.setEnabled( false ); wStop.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { stop(); } } ); wRemove = new Button( this, SWT.PUSH ); wRemove.setText( BaseMessages.getString( PKG, "SpoonSlave.Button.Remove" ) ); wRemove.setEnabled( false ); wRemove.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { remove(); } } ); BaseStepDialog.positionBottomButtons( this, new Button[] { wRefresh, wSniff, wStart, wPause, wStop, wRemove, wError }, Const.MARGIN, null ); // Put tree on top FormData fdTree = new FormData(); fdTree.left = new FormAttachment( 0, 0 ); fdTree.top = new FormAttachment( 0, 0 ); fdTree.right = new FormAttachment( 100, 0 ); fdTree.bottom = new FormAttachment( 100, 0 ); wTree.setLayoutData( fdTree ); // Put text in the middle FormData fdText = new FormData(); fdText.left = new FormAttachment( 0, 0 ); fdText.top = new FormAttachment( 0, 0 ); fdText.right = new FormAttachment( 100, 0 ); fdText.bottom = new FormAttachment( 100, 0 ); wText.setLayoutData( fdText ); FormData fdSash = new FormData(); fdSash.left = new FormAttachment( 0, 0 ); // First one in the left top corner fdSash.top = new FormAttachment( 0, 0 ); fdSash.right = new FormAttachment( 100, 0 ); fdSash.bottom = new FormAttachment( wRefresh, -5 ); sash.setLayoutData( fdSash ); pack(); // Schedule view and log refresh every UPDATE_TIME_VIEW milliseconds engageViewAndLogUpdateTimer(); addDisposeListener( new DisposeListener() { public void widgetDisposed( DisposeEvent e ) { timer.cancel(); } } ); } public void treeItemSelected( TreeItem item ) { if ( item == null ) { // there is nothing to do return; } // load node upon expansion if ( item.getData( "transStatus" ) != null ) { SlaveServerTransStatus transStatus = (SlaveServerTransStatus) item.getData( "transStatus" ); try { if ( log.isDetailed() ) { log.logDetailed( "Getting transformation status for [{0}] on server [{1}]", transStatus.getTransName(), SpoonSlave.this.slaveServer ); } Integer lastLine = lastLineMap.get( transStatus.getId() ); int lastLineNr = lastLine == null ? 0 : lastLine; SlaveServerTransStatus ts = SpoonSlave.this.slaveServer.getTransStatus( transStatus.getTransName(), transStatus.getId(), lastLineNr ); if ( log.isDetailed() ) { log.logDetailed( "Finished receiving transformation status for [{0}] from server [{1}]", transStatus .getTransName(), SpoonSlave.this.slaveServer ); } List<StepStatus> stepStatusList = ts.getStepStatusList(); transStatus.setStepStatusList( stepStatusList ); lastLineMap.put( transStatus.getId(), ts.getLastLoggingLineNr() ); String logging = loggingMap.get( transStatus.getId() ); if ( logging == null ) { logging = ts.getLoggingString(); } else { logging = logging + ts.getLoggingString(); } String[] lines = logging.split( "\r\n|\r|\n" ); if ( lines.length > PropsUI.getInstance().getMaxNrLinesInLog() ) { // Trim to view the last x lines int offset = lines.length - PropsUI.getInstance().getMaxNrLinesInLog(); StringBuilder trimmedLog = new StringBuilder(); // Keep only the text from offset to the end of the log while ( offset != lines.length ) { trimmedLog.append( lines[offset++] ).append( '\n' ); } logging = trimmedLog.toString(); } loggingMap.put( transStatus.getId(), logging ); item.removeAll(); for ( StepStatus stepStatus : stepStatusList ) { TreeItem stepItem = new TreeItem( item, SWT.NONE ); stepItem.setText( stepStatus.getSpoonSlaveLogFields() ); } } catch ( Exception e ) { transStatus.setErrorDescription( "Unable to access transformation details : " + Const.CR + Const.getStackTracker( e ) ); } } else if ( item.getData( "jobStatus" ) != null ) { SlaveServerJobStatus jobStatus = (SlaveServerJobStatus) item.getData( "jobStatus" ); try { if ( log.isDetailed() ) { log.logDetailed( "Getting job status for [{0}] on server [{1}]", jobStatus.getJobName(), slaveServer ); } Integer lastLine = lastLineMap.get( jobStatus.getId() ); int lastLineNr = lastLine == null ? 0 : lastLine; SlaveServerJobStatus ts = slaveServer.getJobStatus( jobStatus.getJobName(), jobStatus.getId(), lastLineNr ); if ( log.isDetailed() ) { log.logDetailed( "Finished receiving job status for [{0}] from server [{1}]", jobStatus.getJobName(), slaveServer ); } lastLineMap.put( jobStatus.getId(), ts.getLastLoggingLineNr() ); String logging = loggingMap.get( jobStatus.getId() ); if ( logging == null ) { logging = ts.getLoggingString(); } else { logging = logging + ts.getLoggingString(); } String[] lines = logging.split( "\r\n|\r|\n" ); if ( lines.length > PropsUI.getInstance().getMaxNrLinesInLog() ) { // Trim to view the last x lines int offset = lines.length - PropsUI.getInstance().getMaxNrLinesInLog(); StringBuilder trimmedLog = new StringBuilder(); // Keep only the text from offset to the end of the log while ( offset != lines.length ) { trimmedLog.append( lines[offset++] ).append( '\n' ); } logging = trimmedLog.toString(); } loggingMap.put( jobStatus.getId(), logging ); Result result = ts.getResult(); if ( result != null ) { item.setText( 2, "" + result.getNrLinesRead() ); item.setText( 3, "" + result.getNrLinesWritten() ); item.setText( 4, "" + result.getNrLinesInput() ); item.setText( 5, "" + result.getNrLinesOutput() ); item.setText( 6, "" + result.getNrLinesUpdated() ); item.setText( 7, "" + result.getNrLinesRejected() ); item.setText( 8, "" + result.getNrErrors() ); } } catch ( Exception e ) { jobStatus.setErrorDescription( "Unable to access transformation details : " + Const.CR + Const.getStackTracker( e ) ); } } } protected void enableButtons() { TreeEntry treeEntry = getTreeEntry(); boolean isTrans = treeEntry != null && treeEntry.isTransformation(); boolean isJob = treeEntry != null && treeEntry.isJob(); boolean hasId = treeEntry != null && !Utils.isEmpty( treeEntry.id ); boolean isRunning = treeEntry != null && treeEntry.isRunning(); boolean isStopped = treeEntry != null && treeEntry.isStopped(); boolean isFinished = treeEntry != null && treeEntry.isFinished(); boolean isPaused = treeEntry != null && treeEntry.isPaused(); boolean isWaiting = treeEntry != null && treeEntry.isWaiting(); boolean isStep = treeEntry != null && treeEntry.length == 3; wStart.setEnabled( ( isTrans || isJob ) && hasId && !isRunning && ( isFinished || isStopped || isWaiting ) ); wPause.setEnabled( isTrans && hasId && ( isRunning || isPaused ) ); wStop.setEnabled( ( isTrans || isJob ) && hasId && ( isRunning || isPaused ) ); wRemove.setEnabled( ( isTrans || isJob ) && hasId && ( isFinished || isStopped || isWaiting ) ); wSniff.setEnabled( isTrans && hasId && isRunning && isStep ); } protected void refreshViewAndLog() { String[] selectionPath = null; TreeItem selectedItem; TreeEntry treeEntry = null; if ( wTree.getSelectionCount() == 1 ) { selectedItem = wTree.getSelection()[ 0 ]; treeEntry = new TreeEntry( selectedItem ); selectionPath = ConstUI.getTreeStrings( selectedItem ); } refreshView(); if ( treeEntry != null ) { // Select the same one again TreeItem treeItem = treeEntry.getTreeItem( wTree ); if ( treeItem == null ) { treeItem = TreeUtil.findTreeItem( wTree, selectionPath ); } if ( treeItem != null ) { wTree.setSelection( treeItem ); if ( treeEntry.length < 3 ) { wTree.showItem( treeItem ); treeItemSelected( treeItem ); treeItem.setExpanded( true ); } } } showLog(); } public boolean canBeClosed() { // It's OK to close this at any time. // We just have to make sure we stop the timers etc. // spoon.tabfolder.setSelected( 0 ); return true; } /** * Someone clicks on a line: show the log or error message associated with that in the text-box */ public void showLog() { TreeEntry treeEntry = getTreeEntry(); if ( treeEntry == null ) { return; } if ( treeEntry.length <= 1 ) { return; } if ( treeEntry.isTransformation() ) { // Transformation SlaveServerTransStatus transStatus = slaveServerStatus.findTransStatus( treeEntry.name, treeEntry.id ); StringBuilder message = new StringBuilder(); String errorDescription = transStatus.getErrorDescription(); if ( !Utils.isEmpty( errorDescription ) ) { message.append( errorDescription ).append( Const.CR ).append( Const.CR ); } String logging = loggingMap.get( transStatus.getId() ); if ( !Utils.isEmpty( logging ) ) { message.append( logging ).append( Const.CR ); } wText.setText( message.toString() ); wText.setSelection( wText.getText().length() ); wText.showSelection(); } else if ( treeEntry.isJob() ) { // Job SlaveServerJobStatus jobStatus = slaveServerStatus.findJobStatus( treeEntry.name, treeEntry.id ); StringBuilder message = new StringBuilder(); String errorDescription = jobStatus.getErrorDescription(); if ( !Utils.isEmpty( errorDescription ) ) { message.append( errorDescription ).append( Const.CR ).append( Const.CR ); } String logging = loggingMap.get( jobStatus.getId() ); if ( !Utils.isEmpty( logging ) ) { message.append( logging ).append( Const.CR ); } wText.setText( message.toString() ); wText.setSelection( wText.getText().length() ); wText.showSelection(); } } protected void start() { TreeEntry treeEntry = getTreeEntry(); if ( treeEntry == null ) { return; } if ( treeEntry.isTransformation() ) { // Transformation SlaveServerTransStatus transStatus = slaveServerStatus.findTransStatus( treeEntry.name, treeEntry.id ); if ( transStatus != null ) { if ( !transStatus.isRunning() ) { try { WebResult webResult = slaveServer.startTransformation( treeEntry.name, transStatus.getId() ); if ( !WebResult.STRING_OK.equalsIgnoreCase( webResult.getResult() ) ) { EnterTextDialog dialog = new EnterTextDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorStartingTrans.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorStartingTrans.Message" ), webResult.getMessage() ); dialog.setReadOnly(); dialog.open(); } } catch ( Exception e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorStartingTrans.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorStartingTrans.Message" ), e ); } } } } else if ( treeEntry.isJob() ) { // Job SlaveServerJobStatus jobStatus = slaveServerStatus.findJobStatus( treeEntry.name, treeEntry.id ); if ( jobStatus != null ) { if ( !jobStatus.isRunning() ) { try { WebResult webResult = slaveServer.startJob( treeEntry.name, jobStatus.getId() ); if ( !WebResult.STRING_OK.equalsIgnoreCase( webResult.getResult() ) ) { EnterTextDialog dialog = new EnterTextDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorStartingJob.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorStartingJob.Message" ), webResult.getMessage() ); dialog.setReadOnly(); dialog.open(); } } catch ( Exception e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorStartingJob.Title" ), BaseMessages.getString( PKG, "SpoonSlave.ErrorStartingJob.Message" ), e ); } } } } } private TreeEntry getTreeEntry() { TreeItem[] ti = wTree.getSelection(); if ( ti.length == 1 ) { return getTreeEntry( ti[ 0 ] ); } else { return null; } } private TreeEntry getTreeEntry( TreeItem ti ) { TreeEntry treeEntry = new TreeEntry( ti ); if ( treeEntry.length <= 1 ) { return null; } return treeEntry; } protected void stop() { TreeEntry treeEntry = getTreeEntry(); if ( treeEntry == null ) { return; } if ( treeEntry.isTransformation() ) { // Transformation SlaveServerTransStatus transStatus = slaveServerStatus.findTransStatus( treeEntry.name, treeEntry.id ); if ( transStatus != null ) { if ( transStatus.isRunning() || transStatus.isPaused() ) { try { WebResult webResult = slaveServer.stopTransformation( treeEntry.name, transStatus.getId() ); if ( !WebResult.STRING_OK.equalsIgnoreCase( webResult.getResult() ) ) { EnterTextDialog dialog = new EnterTextDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorStoppingTrans.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorStoppingTrans.Message" ), webResult.getMessage() ); dialog.setReadOnly(); dialog.open(); } } catch ( Exception e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorStoppingTrans.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorStoppingTrans.Message" ), e ); } } } } else if ( treeEntry.isJob() ) { // Job SlaveServerJobStatus jobStatus = slaveServerStatus.findJobStatus( treeEntry.name, treeEntry.id ); if ( jobStatus != null ) { if ( jobStatus.isRunning() ) { try { WebResult webResult = slaveServer.stopJob( treeEntry.name, jobStatus.getId() ); if ( !WebResult.STRING_OK.equalsIgnoreCase( webResult.getResult() ) ) { EnterTextDialog dialog = new EnterTextDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorStoppingJob.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorStoppingJob.Message" ), webResult.getMessage() ); dialog.setReadOnly(); dialog.open(); } } catch ( Exception e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorStoppingJob.Title" ), BaseMessages.getString( PKG, "SpoonSlave.ErrorStoppingJob.Message" ), e ); } } } } } protected void remove() { TreeEntry treeEntry = getTreeEntry(); if ( treeEntry == null ) { return; } if ( treeEntry.isTransformation() ) { // Transformation SlaveServerTransStatus transStatus = slaveServerStatus.findTransStatus( treeEntry.name, treeEntry.id ); if ( transStatus != null ) { if ( !transStatus.isRunning() && !transStatus.isPaused() && !transStatus.isStopped() ) { try { WebResult webResult = slaveServer.removeTransformation( treeEntry.name, transStatus.getId() ); if ( WebResult.STRING_OK.equalsIgnoreCase( webResult.getResult() ) ) { // Force refresh in order to give faster visual feedback and reengage the timer wTree.deselectAll(); engageViewAndLogUpdateTimer(); } else { EnterTextDialog dialog = new EnterTextDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorRemovingTrans.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorRemovingTrans.Message" ), webResult.getMessage() ); dialog.setReadOnly(); dialog.open(); } } catch ( Exception e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorRemovingTrans.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorRemovingTrans.Message" ), e ); } } } } else if ( treeEntry.isJob() ) { // Job SlaveServerJobStatus jobStatus = slaveServerStatus.findJobStatus( treeEntry.name, treeEntry.id ); if ( jobStatus != null ) { if ( !jobStatus.isRunning() ) { try { WebResult webResult = slaveServer.removeJob( treeEntry.name, jobStatus.getId() ); if ( WebResult.STRING_OK.equalsIgnoreCase( webResult.getResult() ) ) { // Force refresh in order to give faster visual feedback and reengage the timer wTree.deselectAll(); engageViewAndLogUpdateTimer(); } else { EnterTextDialog dialog = new EnterTextDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorRemovingJob.Title" ), BaseMessages .getString( PKG, "SpoonSlave.ErrorRemovingJob.Message" ), webResult.getMessage() ); dialog.setReadOnly(); dialog.open(); } } catch ( Exception e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorRemovingJob.Title" ), BaseMessages.getString( PKG, "SpoonSlave.ErrorRemovingJob.Message" ), e ); } } } } } protected void pause() { TreeEntry treeEntry = getTreeEntry(); if ( treeEntry == null ) { return; } if ( treeEntry.isTransformation() ) { // Transformation try { WebResult webResult = slaveServer.pauseResumeTransformation( treeEntry.name, treeEntry.id ); if ( !WebResult.STRING_OK.equalsIgnoreCase( webResult.getResult() ) ) { EnterTextDialog dialog = new EnterTextDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorPausingOrResumingTrans.Title" ), BaseMessages.getString( PKG, "SpoonSlave.ErrorPausingOrResumingTrans.Message" ), webResult.getMessage() ); dialog.setReadOnly(); dialog.open(); } } catch ( Exception e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorPausingOrResumingTrans.Title" ), BaseMessages.getString( PKG, "SpoonSlave.ErrorPausingOrResumingTrans.Message" ), e ); } } } private synchronized void refreshView() { if ( wTree.isDisposed() ) { return; } if ( refreshBusy ) { return; } refreshBusy = true; if ( log.isDetailed() ) { log.logDetailed( "Refresh" ); } transParentItem.removeAll(); jobParentItem.removeAll(); wText.setText( "" ); // Determine the transformations on the slave servers try { slaveServerStatus = slaveServer.getStatus(); } catch ( Exception e ) { slaveServerStatus = new SlaveServerStatus( "Error contacting server" ); slaveServerStatus.setErrorDescription( Const.getStackTracker( e ) ); if ( log.isDebug() ) { log.logDebug( slaveServerStatus.getErrorDescription() ); } wText.setText( e.getMessage() ); } List<SlaveServerTransStatus> transStatusList = slaveServerStatus.getTransStatusList(); for ( SlaveServerTransStatus transStatus : transStatusList ) { TreeItem transItem = new TreeItem( transParentItem, SWT.NONE ); transItem.setText( 0, transStatus.getTransName() ); transItem.setText( 9, transStatus.getStatusDescription() ); transItem.setText( 13, Const.NVL( transStatus.getId(), "" ) ); transItem.setText( 14, Const.NVL( XMLHandler.date2string( transStatus.getLogDate() ), "" ) ); transItem.setImage( GUIResource.getInstance().getImageTransGraph() ); transItem.setData( "transStatus", transStatus ); } for ( int i = 0; i < slaveServerStatus.getJobStatusList().size(); i++ ) { SlaveServerJobStatus jobStatus = slaveServerStatus.getJobStatusList().get( i ); TreeItem jobItem = new TreeItem( jobParentItem, SWT.NONE ); jobItem.setText( 0, jobStatus.getJobName() ); jobItem.setText( 9, jobStatus.getStatusDescription() ); jobItem.setText( 13, Const.NVL( jobStatus.getId(), "" ) ); jobItem.setText( 14, Const.NVL( XMLHandler.date2string( jobStatus.getLogDate() ), "" ) ); jobItem.setImage( GUIResource.getInstance().getImageJobGraph() ); jobItem.setData( "jobStatus", jobStatus ); } TreeMemory.setExpandedFromMemory( wTree, STRING_SLAVE_LOG_TREE_NAME + slaveServer.toString() ); TreeUtil.setOptimalWidthOnColumns( wTree ); refreshBusy = false; } public void showErrors() { String all = wText.getText(); List<String> err = new ArrayList<String>(); int i = 0; int startpos = 0; int crlen = Const.CR.length(); while ( i < all.length() - crlen ) { if ( all.substring( i, i + crlen ).equalsIgnoreCase( Const.CR ) ) { String line = all.substring( startpos, i ); if ( lineHasErrors( line ) ) { err.add( line ); } // New start of line startpos = i + crlen; } i++; } String line = all.substring( startpos ); if ( lineHasErrors( line ) ) { // i18n for compatibilty to non translated steps a.s.o. err.add( line ); } if ( err.size() > 0 ) { String[] err_lines = new String[err.size()]; for ( i = 0; i < err_lines.length; i++ ) { err_lines[i] = err.get( i ); } EnterSelectionDialog esd = new EnterSelectionDialog( shell, err_lines, BaseMessages.getString( PKG, "TransLog.Dialog.ErrorLines.Title" ), BaseMessages.getString( PKG, "TransLog.Dialog.ErrorLines.Message" ) ); esd.open(); /* * TODO: we have multiple transformation we can go to: which one should we pick? if (line != null) { for (i = 0; i * < spoon.getTransMeta().nrSteps(); i++) { StepMeta stepMeta = spoon.getTransMeta().getStep(i); if * (line.indexOf(stepMeta.getName()) >= 0) { spoon.editStep(stepMeta.getName()); } } // * System.out.println("Error line selected: "+line); } */ } } private boolean lineHasErrors( String line ) { line = line.toUpperCase(); return line.contains( BaseMessages.getString( PKG, "TransLog.System.ERROR2" ) ) || line.contains( BaseMessages.getString( PKG, "TransLog.System.EXCEPTION2" ) ) || line.contains( "ERROR" ) || // i18n // for // compatibilty // to // non // translated // steps // a.s.o. line.contains( "EXCEPTION" ); } public String toString() { return Spoon.APP_NAME; } public Object getManagedObject() { return slaveServer; } public boolean hasContentChanged() { return false; } public boolean applyChanges() { return true; } public int showChangedWarning() { return SWT.YES; } public EngineMetaInterface getMeta() { return new EngineMetaInterface() { public void setModifiedUser( String user ) { } public void setModifiedDate( Date date ) { } public void setInternalKettleVariables() { } public void setObjectId( ObjectId id ) { } public void setFilename( String filename ) { } public void setCreatedUser( String createduser ) { } public void setCreatedDate( Date date ) { } public void saveSharedObjects() { } public void nameFromFilename() { } public String getXML() { return null; } public boolean canSave() { return true; } public String getName() { return slaveServer.getName(); } public String getModifiedUser() { return null; } public Date getModifiedDate() { return null; } public String[] getFilterNames() { return null; } public String[] getFilterExtensions() { return null; } public String getFilename() { return null; } public String getFileType() { return null; } public RepositoryDirectoryInterface getRepositoryDirectory() { return null; } public String getDefaultExtension() { return null; } public String getCreatedUser() { return null; } public Date getCreatedDate() { return null; } public void clearChanged() { } public ObjectId getObjectId() { return null; } public RepositoryObjectType getRepositoryElementType() { return null; } public void setName( String name ) { } public void setRepositoryDirectory( RepositoryDirectoryInterface repositoryDirectory ) { } public String getDescription() { return null; } public void setDescription( String description ) { } public ObjectRevision getObjectRevision() { return null; } public void setObjectRevision( ObjectRevision objectRevision ) { } }; } public void setControlStates() { // TODO Auto-generated method stub } public boolean canHandleSave() { return false; } protected void sniff() { TreeItem[] ti = wTree.getSelection(); if ( ti.length == 1 ) { TreeItem treeItem = ti[0]; String[] path = ConstUI.getTreeStrings( treeItem ); // Make sure we're positioned on a step if ( path.length <= 2 ) { return; } String name = path[1]; String step = path[2]; String copy = treeItem.getText( 1 ); EnterNumberDialog numberDialog = new EnterNumberDialog( shell, PropsUI.getInstance().getDefaultPreviewSize(), BaseMessages.getString( PKG, "SpoonSlave.SniffSizeQuestion.Title" ), BaseMessages.getString( PKG, "SpoonSlave.SniffSizeQuestion.Message" ) ); int lines = numberDialog.open(); if ( lines <= 0 ) { return; } EnterSelectionDialog selectionDialog = new EnterSelectionDialog( shell, new String[] { SniffStepServlet.TYPE_INPUT, SniffStepServlet.TYPE_OUTPUT, }, BaseMessages.getString( PKG, "SpoonSlave.SniffTypeQuestion.Title" ), BaseMessages.getString( PKG, "SpoonSlave.SniffTypeQuestion.Message" ) ); String type = selectionDialog.open( 1 ); if ( type == null ) { return; } try { String xml = slaveServer.sniffStep( name, step, copy, lines, type ); Document doc = XMLHandler.loadXMLString( xml ); Node node = XMLHandler.getSubNode( doc, SniffStepServlet.XML_TAG ); Node metaNode = XMLHandler.getSubNode( node, RowMeta.XML_META_TAG ); RowMetaInterface rowMeta = new RowMeta( metaNode ); int nrRows = Const.toInt( XMLHandler.getTagValue( node, "nr_rows" ), 0 ); List<Object[]> rowBuffer = new ArrayList<Object[]>(); for ( int i = 0; i < nrRows; i++ ) { Node dataNode = XMLHandler.getSubNodeByNr( node, RowMeta.XML_DATA_TAG, i ); Object[] row = rowMeta.getRow( dataNode ); rowBuffer.add( row ); } PreviewRowsDialog prd = new PreviewRowsDialog( shell, new Variables(), SWT.NONE, step, rowMeta, rowBuffer ); prd.open(); } catch ( Exception e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SpoonSlave.ErrorSniffingStep.Title" ), BaseMessages.getString( PKG, "SpoonSlave.ErrorSniffingStep.Message" ), e ); } } } public ChangedWarningInterface getChangedWarning() { return null; } /** * Cancels current timer task if any and schedules new one to be executed immediately and then every UPDATE_TIME_VIEW * milliseconds. */ private void engageViewAndLogUpdateTimer() { if ( timer == null ) { timer = new Timer( "SpoonSlave: " + getMeta().getName() ); } if ( timerTask != null ) { timerTask.cancel(); } timerTask = new TimerTask() { public void run() { if ( display != null && !display.isDisposed() ) { display.asyncExec( new Runnable() { public void run() { refreshViewAndLog(); } } ); } } }; timer.schedule( timerTask, 0L, UPDATE_TIME_VIEW ); } }