org.eclipse.jubula.client.ui.rcp.handlers.project.SaveProjectAsHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jubula.client.ui.rcp.handlers.project.SaveProjectAsHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2010 BREDEX GmbH.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     BREDEX GmbH - initial API and implementation and/or initial documentation
 *******************************************************************************/
package org.eclipse.jubula.client.ui.rcp.handlers.project;

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

import org.apache.commons.lang.StringUtils;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.window.Window;
import org.eclipse.jubula.client.archive.XmlStorage;
import org.eclipse.jubula.client.archive.output.NullImportOutput;
import org.eclipse.jubula.client.core.businessprocess.ComponentNamesDecorator;
import org.eclipse.jubula.client.core.businessprocess.INameMapper;
import org.eclipse.jubula.client.core.businessprocess.IWritableComponentNameCache;
import org.eclipse.jubula.client.core.businessprocess.IWritableComponentNameMapper;
import org.eclipse.jubula.client.core.businessprocess.ParamNameBP;
import org.eclipse.jubula.client.core.businessprocess.ParamNameBPDecorator;
import org.eclipse.jubula.client.core.businessprocess.ProjectComponentNameMapper;
import org.eclipse.jubula.client.core.businessprocess.ProjectNameBP;
import org.eclipse.jubula.client.core.events.DataEventDispatcher;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.DataState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.ProjectState;
import org.eclipse.jubula.client.core.events.DataEventDispatcher.UpdateState;
import org.eclipse.jubula.client.core.model.IProjectPO;
import org.eclipse.jubula.client.core.model.ProjectVersion;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.persistence.NodePM;
import org.eclipse.jubula.client.core.persistence.PMException;
import org.eclipse.jubula.client.core.persistence.PMSaveException;
import org.eclipse.jubula.client.core.persistence.ProjectPM;
import org.eclipse.jubula.client.ui.constants.ContextHelpIds;
import org.eclipse.jubula.client.ui.constants.IconConstants;
import org.eclipse.jubula.client.ui.handlers.project.AbstractProjectHandler;
import org.eclipse.jubula.client.ui.rcp.Plugin;
import org.eclipse.jubula.client.ui.rcp.controllers.PMExceptionHandler;
import org.eclipse.jubula.client.ui.rcp.dialogs.VersionDialog;
import org.eclipse.jubula.client.ui.rcp.i18n.Messages;
import org.eclipse.jubula.client.ui.rcp.utils.Utils;
import org.eclipse.jubula.client.ui.utils.DialogUtils;
import org.eclipse.jubula.client.ui.utils.ErrorHandlingUtil;
import org.eclipse.jubula.tools.internal.exception.JBVersionException;
import org.eclipse.jubula.tools.internal.exception.ProjectDeletedException;
import org.eclipse.jubula.tools.internal.jarutils.IVersion;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.PlatformUI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author BREDEX GmbH
 * @created 11.05.2005
 */
@SuppressWarnings("synthetic-access")
public class SaveProjectAsHandler extends AbstractProjectHandler {
    /** standard logging */
    private static Logger log = LoggerFactory.getLogger(SaveProjectAsHandler.class);

    /**
     * Worker operation for SaveProjectAs action.
     * 
     * @author BREDEX GmbH
     * @created Dec 4, 2007
     */
    private class SaveAsOperation implements IRunnableWithProgress {

        /** the total work for the operation */
        private static final int TOTAL_WORK = 100;

        /** the work for gathering project data from the database*/
        private static final int WORK_GET_PROJECT_FROM_DB = 5;

        /** the work for creating the domain objects for the project */
        private static final int WORK_PROJECT_CREATION = 10;

        /** the work for saving the project to the database */
        private static final int WORK_PROJECT_SAVE = TOTAL_WORK - WORK_PROJECT_CREATION - WORK_GET_PROJECT_FROM_DB;

        /** The name for the new project */
        private String m_newProjectName;

        /** The version for the new project */
        private ProjectVersion m_newProjectVersion;

        /**
         * Constructor
         * 
         * @param newProjectName name of new project
         * @param version version of the new project
         */
        public SaveAsOperation(String newProjectName, ProjectVersion version) {
            m_newProjectName = newProjectName;
            m_newProjectVersion = version;
        }

        /**
         * {@inheritDoc}
         */
        public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException {
            String cProjectName = GeneralStorage.getInstance().getProject().getName();
            SubMonitor subMonitor = SubMonitor.convert(monitor,
                    NLS.bind(Messages.SaveProjectAsOperationSavingProject,
                            new Object[] { cProjectName, m_newProjectName }),
                    TOTAL_WORK);
            final ParamNameBPDecorator paramNameMapper = new ParamNameBPDecorator(ParamNameBP.getInstance());
            final IWritableComponentNameCache compNameCache = new ComponentNamesDecorator(null);
            try {
                NodePM.getInstance().setUseCache(true);
                InputStream contentStream = getContentForNewProject(subMonitor.newChild(WORK_GET_PROJECT_FROM_DB));
                if (monitor.isCanceled()) {
                    throw new InterruptedException();
                }
                if (contentStream != null) {
                    final IProjectPO duplicatedProject = XmlStorage.load(contentStream, true,
                            m_newProjectVersion.getMajorNumber(), m_newProjectVersion.getMinorNumber(),
                            m_newProjectVersion.getMicroNumber(), m_newProjectVersion.getVersionQualifier(),
                            paramNameMapper, compNameCache, subMonitor.newChild(WORK_PROJECT_CREATION),
                            new NullImportOutput(), true);
                    IWritableComponentNameMapper compNameMapper = new ProjectComponentNameMapper(compNameCache,
                            duplicatedProject);
                    try {
                        duplicatedProject.setClientMetaDataVersion(IVersion.JB_CLIENT_METADATA_VERSION);
                        attachProjectWithProgress(subMonitor.newChild(WORK_PROJECT_SAVE), paramNameMapper,
                                compNameMapper, duplicatedProject);
                    } catch (PMSaveException e) {
                        Plugin.stopLongRunning();
                        PMExceptionHandler.handlePMExceptionForMasterSession(
                                new PMSaveException(e.getMessage(), MessageIDs.E_SAVE_AS_PROJECT_FAILED));
                        throw new InvocationTargetException(e);
                    } catch (PMException e) {
                        Plugin.stopLongRunning();
                        PMExceptionHandler.handlePMExceptionForMasterSession(e);
                        throw new InvocationTargetException(e);
                    } catch (ProjectDeletedException e) {
                        Plugin.stopLongRunning();
                        PMExceptionHandler.handleProjectDeletedException();
                        throw new InvocationTargetException(e);
                    }
                }
            } catch (PMSaveException e) {
                Plugin.stopLongRunning();
                PMExceptionHandler.handlePMExceptionForMasterSession(
                        new PMSaveException(e.getMessage(), MessageIDs.E_SAVE_AS_PROJECT_FAILED));
            } catch (PMException e) {
                Plugin.stopLongRunning();
                PMExceptionHandler.handlePMExceptionForMasterSession(e);
            } catch (ProjectDeletedException e) {
                Plugin.stopLongRunning();
                PMExceptionHandler.handleProjectDeletedException();
            } catch (JBVersionException e) {
                // should not be occur, that a used toolkit of current project
                // has a version conflict with installed Toolkit Plugin.
                log.error(Messages.ToolkitVersionConflictWhileSaveProjectAsAction);
            } finally {
                NodePM.getInstance().setUseCache(false);
                Plugin.stopLongRunning();
                monitor.done();
            }
        }

        /**
         * Attaches the given project to the Master Session and database using
         * the given parameter name mapper. Reports progress during the
         * operation.
         * 
         * @param monitor
         *            The progress monitor for the operation.
         * @param paramNameMapper
         *            The parameter name mapper to use when adding the project
         *            to the database.
         * @param compNameMapper
         *            The component name mapper to use when adding the project
         *            to the database.
         * @param project
         *            The project to add to the database
         * @throws PMException
         *             in case of any database error
         * @throws ProjectDeletedException
         *             if project is already deleted
         * @throws InterruptedException
         *             if the operation was canceled.
         */
        private void attachProjectWithProgress(IProgressMonitor monitor, final ParamNameBPDecorator paramNameMapper,
                IWritableComponentNameMapper compNameMapper, final IProjectPO project)
                throws PMException, ProjectDeletedException, InterruptedException {

            // We need to clear the current project data so 
            // we are in a known state if the operation is 
            // canceled.
            IProjectPO clearedProject = GeneralStorage.getInstance().getProject();
            if (clearedProject != null) {
                Utils.clearClient();
                GeneralStorage.getInstance().setProject(null);
                final DataEventDispatcher ded = DataEventDispatcher.getInstance();
                ded.fireDataChangedListener(clearedProject, DataState.Deleted, UpdateState.all);
            }
            List<INameMapper> mapperList = new ArrayList<INameMapper>();
            List<IWritableComponentNameMapper> compNameCacheList = new ArrayList<IWritableComponentNameMapper>();
            mapperList.add(paramNameMapper);
            compNameCacheList.add(compNameMapper);
            ProjectPM.attachProjectToROSession(project, m_newProjectName, mapperList, compNameCacheList, monitor);

            Plugin.stopLongRunning();
        }
    }

    /**
     * @param newProjectName name of new project
     * @param version version of the new projct
     * @return a new operation for project import
     */
    private IRunnableWithProgress createOperation(final String newProjectName, ProjectVersion version) {
        return new SaveAsOperation(newProjectName, version);
    }

    /**
     * Opens the dialog to change the project name
     * 
     * @return the dialog
     */
    private VersionDialog openInputDialog() {
        VersionDialog dialog = new VersionDialog(getActiveShell(), Messages.SaveProjectAsActionTitle,
                Messages.SaveProjectAsActionMessage, IconConstants.BIG_PROJECT_STRING,
                Messages.SaveProjectAsActionShellTitle, true) {

            /**
             * {@inheritDoc}
             */
            protected boolean isInputAllowed() {
                final String newProjectName = getProjectNameFieldValue();
                boolean isInputAllowed = true;
                if (StringUtils.isBlank(newProjectName)
                        || !ProjectNameBP.isValidProjectName(newProjectName, true)) {
                    setErrorMessage(Messages.SaveProjectAsActionInvalidName);
                    isInputAllowed = false;
                }
                if (ProjectPM.doesProjectNameExist(newProjectName)) {
                    setErrorMessage(Messages.SaveProjectAsActionDoubleOrInvalidName);
                    isInputAllowed = false;
                }
                return isInputAllowed;
            }

            /**
             * {@inheritDoc}
             */
            protected void okPressed() {
                String newProjectName = getProjectNameFieldValue();
                if (ProjectPM.doesProjectNameExist(newProjectName) || StringUtils.isBlank(newProjectName)) {
                    ErrorHandlingUtil.createMessageDialog(MessageIDs.E_PROJECTNAME_ALREADY_EXISTS,
                            new Object[] { getProjectNameFieldValue() }, null);
                    return;
                }
                super.okPressed();
            }
        };
        dialog.setHelpAvailable(true);
        dialog.create();
        DialogUtils.setWidgetNameForModalDialog(dialog);
        Plugin.getHelpSystem().setHelp(dialog.getShell(), ContextHelpIds.DIALOG_PROJECT_SAVEAS);
        dialog.open();
        return dialog;
    }

    /**
     * call this if the "save as" has ended to update the GUI.
     */
    private void fireReady() {
        DataEventDispatcher ded = DataEventDispatcher.getInstance();
        ded.fireProjectLoadedListener(new NullProgressMonitor());
        ded.fireProjectStateChanged(ProjectState.opened);
    }

    /**
     * @param monitor
     *            The progress monitor for this potentially long-running
     *            operation.
     * @return content for new project to create, or <code>null</code> if the
     *         operation was cancelled.
     * @throws PMException
     *             if saving of project as xml file failed
     * @throws ProjectDeletedException
     *             if current project is already deleted
     * @throws InterruptedException
     *             if the operation was canceled.
     */
    private InputStream getContentForNewProject(IProgressMonitor monitor)
            throws ProjectDeletedException, InterruptedException, PMException {
        GeneralStorage.getInstance().validateProjectExists(GeneralStorage.getInstance().getProject());
        InputStream projectStream = XmlStorage.save(GeneralStorage.getInstance().getProject(), null, false, monitor,
                false, null);

        if (monitor.isCanceled()) {
            throw new InterruptedException();
        }
        if (projectStream != null) {
            return projectStream;
        }

        return null;
    }

    /**
     * {@inheritDoc}
     */
    public Object executeImpl(ExecutionEvent event) {
        VersionDialog dialog = openInputDialog();
        if (dialog.getReturnCode() == Window.OK) {
            final String newProjectName = dialog.getProjectName();
            IRunnableWithProgress op = createOperation(newProjectName, dialog.getProjectVersion());
            try {
                PlatformUI.getWorkbench().getProgressService().busyCursorWhile(op);
                fireReady();
            } catch (InvocationTargetException ite) {
                // Exception occurred during operation
                log.error(ite.getLocalizedMessage(), ite.getCause());
            } catch (InterruptedException e) {
                // Operation was canceled.
                // We have to clear the GUI because all of
                // the save work was done in the Master Session, which has been
                // rolled back.
                Utils.clearClient();
            }
        }
        return null;
    }
}