org.pentaho.big.data.kettle.plugins.job.AbstractJobEntryController.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.big.data.kettle.plugins.job.AbstractJobEntryController.java

Source

/*******************************************************************************
 *
 * Pentaho Big Data
 *
 * Copyright (C) 2002-2017 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.big.data.kettle.plugins.job;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.pentaho.big.data.api.cluster.NamedCluster;
import org.pentaho.big.data.plugins.common.ui.VfsFileChooserHelper;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleFileException;
import org.pentaho.di.core.plugins.JobEntryPluginType;
import org.pentaho.di.core.plugins.PluginInterface;
import org.pentaho.di.core.plugins.PluginRegistry;
import org.pentaho.di.core.vfs.KettleVFS;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.job.JobMeta;
import org.pentaho.di.job.entry.JobEntryInterface;
import org.pentaho.di.ui.core.PropsUI;
import org.pentaho.di.ui.core.dialog.ErrorDialog;
import org.pentaho.di.ui.core.gui.WindowProperty;
import org.pentaho.di.ui.spoon.Spoon;
import org.pentaho.di.ui.util.HelpUtils;
import org.pentaho.ui.xul.XulDomContainer;
import org.pentaho.ui.xul.XulException;
import org.pentaho.ui.xul.binding.Binding;
import org.pentaho.ui.xul.binding.BindingFactory;
import org.pentaho.ui.xul.containers.XulDeck;
import org.pentaho.ui.xul.containers.XulDialog;
import org.pentaho.ui.xul.impl.AbstractXulEventHandler;
import org.pentaho.ui.xul.stereotype.Bindable;
import org.pentaho.ui.xul.swt.tags.SwtDialog;

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

/**
 * User: RFellows Date: 6/6/12
 */
public abstract class AbstractJobEntryController<C extends BlockableJobConfig, E extends AbstractJobEntry<C>>
        extends AbstractXulEventHandler {

    public static final String[] DEFAULT_FILE_FILTERS = new String[] { "*.*" };

    // Generically typed fields
    protected C config; // BlockableJobConfig
    protected E jobEntry; // AbstractJobEntry<BlockableJobConfig>

    // common fields
    protected XulDomContainer container;
    protected BindingFactory bindingFactory;
    protected List<Binding> bindings;
    protected JobMeta jobMeta;

    protected JobEntryMode jobEntryMode = JobEntryMode.QUICK_SETUP;

    @SuppressWarnings("unchecked")
    public AbstractJobEntryController(JobMeta jobMeta, XulDomContainer container, E jobEntry,
            BindingFactory bindingFactory) {
        super();
        this.jobMeta = jobMeta;
        this.jobEntry = jobEntry;
        this.container = container;
        this.config = (C) jobEntry.getJobConfig().clone();
        this.bindingFactory = bindingFactory;
    }

    /**
     * @return the simple name for this controller. This controller can be referenced by this name in the XUL document.
     */
    @Override
    public String getName() {
        return "controller";
    }

    /**
     * Opens the dialog
     * 
     * @return
     */
    public JobEntryInterface open() {
        XulDialog dialog = (XulDialog) container.getDocumentRoot().getElementById(getDialogElementId());
        // Update the Variable Space so the latest are available when the dialog is show (for test evaluation)
        jobEntry.copyVariablesFrom(jobMeta);
        dialog.show();
        return jobEntry;
    }

    /**
     * Initialize the dialog by loading model data, creating bindings and firing initial sync (
     * {@link Binding#fireSourceChanged()}.
     *
     * @throws XulException
     *
     * @throws InvocationTargetException
     *
     */
    public void init() throws XulException, InvocationTargetException {
        bindings = new ArrayList<Binding>();

        // override hook
        beforeInit();

        try {

            createBindings(config, container, bindingFactory, bindings);
            syncModel();

            for (Binding binding : bindings) {
                binding.fireSourceChanged();
            }
        } finally {
            // override hook
            afterInit();
        }

    }

    /**
     * Accept and apply the changes made in the dialog. Also, close the dialog
     */
    @Bindable
    public void accept() {
        jobEntry.setJobConfig(config);
        jobEntry.setChanged();
        cancel();
    }

    /**
     * Close the dialog without saving any changes
     */
    @Bindable
    public void cancel() {
        removeBindings();
        XulDialog xulDialog = getDialog();

        Shell shell = (Shell) xulDialog.getRootObject();
        if (!shell.isDisposed()) {
            WindowProperty winprop = new WindowProperty(shell);
            PropsUI.getInstance().setScreen(winprop);
            ((Composite) xulDialog.getManagedObject()).dispose();
            shell.dispose();
        }
    }

    /**
     * Call help dialog
     */
    public void help() {
        XulDialog xulDialog = getDialog();
        Shell shell = (Shell) xulDialog.getRootObject();
        HelpUtils.openHelpDialog(shell, getPlugin());
    }

    /**
     * Find a plugin for a corresponding job entry
     */
    protected PluginInterface getPlugin() {
        return PluginRegistry.getInstance().findPluginWithName(JobEntryPluginType.class, jobEntry.getName());
    }

    /**
     * Remove and destroy all bindings from {@link #bindings}.
     */
    protected void removeBindings() {
        if (bindings == null) {
            return;
        }
        for (Binding binding : bindings) {
            binding.destroyBindings();
        }
        bindings.clear();
    }

    /**
     * Look up the dialog reference from the document.
     *
     * @return The dialog element referred to by {@link #getDialogElementId()}
     */
    protected SwtDialog getDialog() {
        return (SwtDialog) getXulDomContainer().getDocumentRoot().getElementById(getDialogElementId());
    }

    /**
     * @return the job entry this controller will modify configuration for
     */
    protected E getJobEntry() {
        return jobEntry;
    }

    /**
     * Override this to execute some code prior to the init function running
     */
    protected void beforeInit() {
        return;
    }

    /**
     * Override this to execute some code after the init function is complete
     */
    protected void afterInit() {
        return;
    }

    protected boolean showConfirmationDialog(String title, String message) {
        return MessageDialog.openConfirm(getShell(), title, message);
    }

    /**
     * Show an information dialog with the title and message provided.
     *
     * @param title
     *          Dialog window title
     * @param message
     *          Dialog message
     */
    protected void showInfoDialog(String title, String message) {
        MessageBox mb = new MessageBox(getShell(), SWT.OK | SWT.ICON_INFORMATION);
        mb.setText(title);
        mb.setMessage(message);
        mb.open();
    }

    /**
     * Show an error dialog with the title and message provided.
     *
     * @param title
     *          Dialog window title
     * @param message
     *          Dialog message
     */
    protected void showErrorDialog(String title, String message) {
        MessageBox mb = new MessageBox(getShell(), SWT.OK | SWT.ICON_ERROR);
        mb.setText(title);
        mb.setMessage(message);
        mb.open();
    }

    /**
     * Show an error dialog with the title, message, and toggle button to see the entire stacktrace produced by {@code t}.
     *
     * @param title
     *          Dialog window title
     * @param message
     *          Dialog message
     * @param t
     *          Cause for this error
     */
    protected void showErrorDialog(String title, String message, Throwable t) {
        new ErrorDialog(getShell(), title, message, t);
    }

    /**
     * @return the shell for the currently visible dialog. This will be used to display additional dialogs/popups.
     */
    protected Shell getShell() {
        return getDialog().getShell();
    }

    /**
     * Browse for a file or directory with the VFS Browser.
     *
     * @param root
     *          Root object
     * @param initial
     *          Initial file or folder the browser should open to
     * @param dialogMode
     *          Mode to open dialog in: e.g.
     *          {@link org.pentaho.vfs.ui .VfsFileChooserDialog#VFS_DIALOG_OPEN_FILE_OR_DIRECTORY}
     * @param schemeRestriction
     *          Scheme to limit the user to browsing from
     * @param defaultScheme
     *          Scheme to select by default in the selection dropdown
     * @return The selected file object, {@code null} if no object is selected
     * @throws KettleFileException
     *           Error accessing the root file using the initial file, when {@code root} is not provided
     */
    protected FileObject browseVfs(FileObject root, FileObject initial, int dialogMode, String schemeRestriction,
            String defaultScheme, boolean showFileScheme) throws KettleFileException {
        String[] schemeRestrictions = new String[1];
        schemeRestrictions[0] = schemeRestriction;
        return browseVfs(root, initial, dialogMode, schemeRestrictions, showFileScheme, defaultScheme);
    }

    protected FileObject browseVfs(FileObject root, FileObject initial, int dialogMode, String[] schemeRestrictions,
            boolean showFileScheme, String defaultScheme) throws KettleFileException {
        return browseVfs(root, initial, dialogMode, schemeRestrictions, showFileScheme, defaultScheme, null);
    }

    protected FileObject browseVfs(FileObject root, FileObject initial, int dialogMode, String[] schemeRestrictions,
            boolean showFileScheme, String defaultScheme, NamedCluster namedCluster) throws KettleFileException {
        return browseVfs(root, initial, dialogMode, schemeRestrictions, showFileScheme, defaultScheme, namedCluster,
                true, true);
    }

    protected FileObject browseVfs(FileObject root, FileObject initial, int dialogMode, String[] schemeRestrictions,
            boolean showFileScheme, String defaultScheme, NamedCluster namedCluster, boolean showLocation)
            throws KettleFileException {
        return browseVfs(root, initial, dialogMode, schemeRestrictions, showFileScheme, defaultScheme, namedCluster,
                showLocation, true);
    }

    protected FileObject browseVfs(FileObject root, FileObject initial, int dialogMode, String[] schemeRestrictions,
            boolean showFileScheme, String defaultScheme, NamedCluster namedCluster, boolean showLocation,
            boolean showCustomUI) throws KettleFileException {
        if (initial == null) {
            initial = KettleVFS.getFileObject(Spoon.getInstance().getLastFileOpened());
        }
        if (root == null) {
            try {
                root = initial.getFileSystem().getRoot();
            } catch (FileSystemException e) {
                throw new KettleFileException(e);
            }
        }

        VfsFileChooserHelper fileChooserHelper = new VfsFileChooserHelper(getShell(),
                Spoon.getInstance().getVfsFileChooserDialog(root, initial), jobEntry);
        fileChooserHelper.setDefaultScheme(defaultScheme);
        fileChooserHelper.setSchemeRestrictions(schemeRestrictions);
        fileChooserHelper.setShowFileScheme(showFileScheme);
        if (namedCluster != null) {
            fileChooserHelper.setNamedCluster(namedCluster);
        }
        try {
            return fileChooserHelper.browse(getFileFilters(), getFileFilterNames(), initial.getName().getURI(),
                    dialogMode, showLocation, showCustomUI);
        } catch (KettleException e) {
            throw new KettleFileException(e);
        } catch (FileSystemException e) {
            throw new KettleFileException(e);
        }
    }

    protected String[] getFileFilters() {
        return DEFAULT_FILE_FILTERS;
    }

    /**
     * Used by browseVfs method as names corresponding to the file filters. Override if {@code getFileFilters} is
     * overridden.
     * 
     * @return
     */
    protected String[] getFileFilterNames() {
        return new String[] { BaseMessages.getString(getClass(), "System.FileType.AllFiles") };
    }

    /**
     * @return the current configuration object. This configuration may be discarded if the dialog is canceled.
     */
    public C getConfig() {
        return config;
    }

    public void setConfig(C config) {
        this.config = config;
    }

    /**
     * @return the job meta for the job entry we're editing
     */
    public JobMeta getJobMeta() {
        return jobMeta;
    }

    public void setJobMeta(JobMeta jobMeta) {
        this.jobMeta = jobMeta;
    }

    public JobEntryMode getJobEntryMode() {
        return jobEntryMode;
    }

    /**
     * Toggle between Advanced and Basic configuration modes
     */
    public void toggleMode() {
        JobEntryMode mode = (jobEntryMode == JobEntryMode.ADVANCED_LIST ? JobEntryMode.QUICK_SETUP
                : JobEntryMode.ADVANCED_LIST);
        setMode(mode);
    }

    protected void setMode(JobEntryMode mode) {

        // if switching from Advanced to Quick mode, warn the user that any changes made in Advanced mode will be lost
        if (this.jobEntryMode == JobEntryMode.ADVANCED_LIST && mode == JobEntryMode.QUICK_SETUP) {
            boolean confirmed = showConfirmationDialog(
                    BaseMessages.getString(AbstractJobEntryController.class,
                            "JobExecutor.Confirm.Toggle.Quick.Mode.Title"),
                    BaseMessages.getString(AbstractJobEntryController.class,
                            "JobExecutor.Confirm.Toggle.Quick.Mode.Message"));
            if (!confirmed) {
                return;
            }
        }

        JobEntryMode opposite = mode == JobEntryMode.QUICK_SETUP ? JobEntryMode.ADVANCED_LIST
                : JobEntryMode.QUICK_SETUP;
        this.jobEntryMode = mode;
        XulDeck deck = (XulDeck) getXulDomContainer().getDocumentRoot().getElementById(getModeDeckElementId());

        deck.setSelectedIndex(mode == JobEntryMode.QUICK_SETUP ? 0 : 1);
        // Synchronize the model every time we swap modes so the UI is always up to date. This is required since we don't
        // set argument item values directly or listen for their changes
        syncModel();

        // Swap the label on the button
        setModeToggleLabel(opposite);
    }

    /**
     * The mode deck element defined in your xul. Override this to customize the element id
     * 
     * @return
     */
    protected String getModeDeckElementId() {
        return "modeDeck";
    }

    // //////////////////
    // abstract methods
    // //////////////////
    protected abstract void syncModel();

    protected abstract void createBindings(C config, XulDomContainer container, BindingFactory bindingFactory,
            Collection<Binding> bindings);

    protected abstract String getDialogElementId();

    protected abstract void setModeToggleLabel(JobEntryMode mode);

}