/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2013 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.trans.dialog; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.widgets.Shell; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.logging.KettleLogStore; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.debug.BreakPointListener; 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.dialog.ErrorDialog; /** * Takes care of displaying a dialog that will handle the wait while previewing a transformation... * * @author Matt * @since 13-jan-2006 */ public class TransPreviewProgressDialog { private static Class<?> PKG = TransDialog.class; // for i18n purposes, needed by Translator2!! private Shell shell; private TransMeta transMeta; private String[] previewStepNames; private int[] previewSize; private Trans trans; private boolean cancelled; private String loggingText; private TransDebugMeta transDebugMeta; /** * Creates a new dialog that will handle the wait while previewing a transformation... */ public TransPreviewProgressDialog( Shell shell, TransMeta transMeta, String[] previewStepNames, int[] previewSize ) { this.shell = shell; this.transMeta = transMeta; this.previewStepNames = previewStepNames; this.previewSize = previewSize; cancelled = false; } public TransMeta open() { IRunnableWithProgress op = new IRunnableWithProgress() { public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException { doPreview( monitor ); } }; try { final ProgressMonitorDialog pmd = new ProgressMonitorDialog( shell ); // Run something in the background to cancel active database queries, forecably if needed! Runnable run = new Runnable() { public void run() { IProgressMonitor monitor = pmd.getProgressMonitor(); while ( pmd.getShell() == null || ( !pmd.getShell().isDisposed() && !monitor.isCanceled() ) ) { try { Thread.sleep( 100 ); } catch ( InterruptedException e ) { // Ignore } } if ( monitor.isCanceled() ) { // Disconnect and see what happens! try { trans.stopAll(); } catch ( Exception e ) { /* Ignore */ } } } }; // Start the cancel tracker in the background! new Thread( run ).start(); pmd.run( true, true, op ); } catch ( InvocationTargetException e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "TransPreviewProgressDialog.ErrorLoadingTransformation.DialogTitle" ), BaseMessages.getString( PKG, "TransPreviewProgressDialog.ErrorLoadingTransformation.DialogMessage" ), e ); transMeta = null; } catch ( InterruptedException e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "TransPreviewProgressDialog.ErrorLoadingTransformation.DialogTitle" ), BaseMessages.getString( PKG, "TransPreviewProgressDialog.ErrorLoadingTransformation.DialogMessage" ), e ); transMeta = null; } return transMeta; } private void doPreview( final IProgressMonitor progressMonitor ) { progressMonitor.beginTask( BaseMessages.getString( PKG, "TransPreviewProgressDialog.Monitor.BeginTask.Title" ), 100 ); // This transformation is ready to run in preview! trans = new Trans( transMeta ); trans.setPreview( true ); // Prepare the execution... // try { trans.prepareExecution( null ); } catch ( final KettleException e ) { shell.getDisplay().asyncExec( new Runnable() { public void run() { new ErrorDialog( shell, BaseMessages.getString( PKG, "System.Dialog.Error.Title" ), BaseMessages.getString( PKG, "TransPreviewProgressDialog.Exception.ErrorPreparingTransformation" ), e ); } } ); // It makes no sense to continue, so just stop running... // return; } // Add the preview / debugging information... // transDebugMeta = new TransDebugMeta( transMeta ); for ( int i = 0; i < previewStepNames.length; i++ ) { StepMeta stepMeta = transMeta.findStep( previewStepNames[i] ); StepDebugMeta stepDebugMeta = new StepDebugMeta( stepMeta ); stepDebugMeta.setReadingFirstRows( true ); stepDebugMeta.setRowCount( previewSize[i] ); transDebugMeta.getStepDebugMetaMap().put( stepMeta, stepDebugMeta ); } // set the appropriate listeners on the transformation... // transDebugMeta.addRowListenersToTransformation( trans ); // Fire off the step threads... start running! // try { trans.startThreads(); } catch ( final KettleException e ) { shell.getDisplay().asyncExec( new Runnable() { public void run() { new ErrorDialog( shell, BaseMessages.getString( PKG, "System.Dialog.Error.Title" ), BaseMessages .getString( PKG, "TransPreviewProgressDialog.Exception.ErrorPreparingTransformation" ), e ); } } ); // It makes no sense to continue, so just stop running... // return; } int previousPct = 0; final List<String> previewComplete = new ArrayList<String>(); while ( previewComplete.size() < previewStepNames.length && !trans.isFinished() && !progressMonitor.isCanceled() ) { // We add a break-point that is called every time we have a step with a full preview row buffer // That makes it easy and fast to see if we have all the rows we need // transDebugMeta.addBreakPointListers( new BreakPointListener() { public void breakPointHit( TransDebugMeta transDebugMeta, StepDebugMeta stepDebugMeta, RowMetaInterface rowBufferMeta, List<Object[]> rowBuffer ) { String stepName = stepDebugMeta.getStepMeta().getName(); previewComplete.add( stepName ); progressMonitor.subTask( BaseMessages.getString( PKG, "TransPreviewProgressDialog.SubTask.StepPreviewFinished", stepName ) ); } } ); // How many rows are done? int nrDone = 0; int nrTotal = 0; for ( StepDebugMeta stepDebugMeta : transDebugMeta.getStepDebugMetaMap().values() ) { nrDone += stepDebugMeta.getRowBuffer().size(); nrTotal += stepDebugMeta.getRowCount(); } int pct = 100 * nrDone / nrTotal; int worked = pct - previousPct; if ( worked > 0 ) { progressMonitor.worked( worked ); } previousPct = pct; // Change the percentage... try { Thread.sleep( 500 ); } catch ( InterruptedException e ) { // Ignore errors } if ( progressMonitor.isCanceled() ) { cancelled = true; trans.stopAll(); } } trans.stopAll(); // Capture preview activity to a String: loggingText = KettleLogStore.getAppender().getBuffer( trans.getLogChannel().getLogChannelId(), true ).toString(); progressMonitor.done(); } /** * @param stepname * the name of the step to get the preview rows for * @return A list of rows as the result of the preview run. */ public List<Object[]> getPreviewRows( String stepname ) { if ( transDebugMeta == null ) { return null; } for ( StepMeta stepMeta : transDebugMeta.getStepDebugMetaMap().keySet() ) { if ( stepMeta.getName().equals( stepname ) ) { StepDebugMeta stepDebugMeta = transDebugMeta.getStepDebugMetaMap().get( stepMeta ); return stepDebugMeta.getRowBuffer(); } } return null; } /** * @param stepname * the name of the step to get the preview rows for * @return A description of the row (metadata) */ public RowMetaInterface getPreviewRowsMeta( String stepname ) { if ( transDebugMeta == null ) { return null; } for ( StepMeta stepMeta : transDebugMeta.getStepDebugMetaMap().keySet() ) { if ( stepMeta.getName().equals( stepname ) ) { StepDebugMeta stepDebugMeta = transDebugMeta.getStepDebugMetaMap().get( stepMeta ); return stepDebugMeta.getRowBufferMeta(); } } return null; } /** * @return true is the preview was canceled by the user */ public boolean isCancelled() { return cancelled; } /** * @return The logging text from the latest preview run */ public String getLoggingText() { return loggingText; } /** * * @return The transformation object that executed the preview TransMeta */ public Trans getTrans() { return trans; } /** * @return the transDebugMeta */ public TransDebugMeta getTransDebugMeta() { return transDebugMeta; } }