org.pentaho.di.ui.trans.dialog.TransPreviewProgressDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.di.ui.trans.dialog.TransPreviewProgressDialog.java

Source

/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2019 by Hitachi Vantara : 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 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;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

/**
 * 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() {
        return open(true);
    }

    /**
     * Opens the progress dialog
     * @param showErrorDialogs dictates whether error dialogs should be shown when errors occur - can be set to false
     *                         to let the caller control error dialogs instead.
     * @return a {@link TransMeta}
     */
    public TransMeta open(final boolean showErrorDialogs) {
        IRunnableWithProgress op = new IRunnableWithProgress() {
            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                doPreview(monitor, showErrorDialogs);
            }
        };

        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) {
            if (showErrorDialogs) {
                new ErrorDialog(shell,
                        BaseMessages.getString(PKG,
                                "TransPreviewProgressDialog.ErrorLoadingTransformation.DialogTitle"),
                        BaseMessages.getString(PKG,
                                "TransPreviewProgressDialog.ErrorLoadingTransformation.DialogMessage"),
                        e);
            }
            transMeta = null;
        } catch (InterruptedException e) {
            if (showErrorDialogs) {
                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, final boolean showErrorDialogs) {
        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) {
            if (showErrorDialogs) {
                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);
        }

        int previousPct = 0;
        final List<String> previewComplete = new ArrayList<String>();
        // 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));
            }
        });
        // 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;
        }

        while (previewComplete.size() < previewStepNames.length && !trans.isFinished()
                && !progressMonitor.isCanceled()) {

            // 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;
    }
}