org.kalypso.afgui.wizards.UnpackProjectTemplateOperation.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.afgui.wizards.UnpackProjectTemplateOperation.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.afgui.wizards;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.commons.lang3.ArrayUtils;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.kalypso.afgui.KalypsoAFGUIFrameworkPlugin;
import org.kalypso.afgui.internal.i18n.Messages;
import org.kalypso.commons.eclipse.core.resources.ProjectUtilities;
import org.kalypso.commons.java.util.zip.ZipUtilities;
import org.kalypso.contribs.eclipse.core.resources.ProjectTemplate;
import org.kalypso.contribs.eclipse.ui.progress.ProgressUtilities;
import org.kalypso.module.INewProjectHandler;
import org.kalypso.module.nature.ModuleNature;

public final class UnpackProjectTemplateOperation extends WorkspaceModifyOperation {
    private static final String FILE_ABOUT_HTML = "about.html"; //$NON-NLS-1$

    private final NewProjectData m_data;

    public UnpackProjectTemplateOperation(final NewProjectData data) {
        super(ResourcesPlugin.getWorkspace().getRoot());

        m_data = data;

    }

    @Override
    public void execute(final IProgressMonitor monitor)
            throws CoreException, InvocationTargetException, InterruptedException {
        final IProject project = m_data.getProject();
        final ProjectTemplate template = m_data.getTemplate();
        final URL dataLocation = template.getData();

        final SubMonitor progress = SubMonitor.convert(monitor,
                Messages.getString("org.kalypso.afgui.wizards.NewProjectWizard.2"), 100); //$NON-NLS-1$
        try {
            // REMARK: we unpack into a closed project here (not using unzip(URL, IFolder)), as else
            // the project description will not be up-to-date in time, resulting in missing natures.
            project.close(progress.newChild(10));

            /* Unpack project from template */
            monitor.subTask(Messages.getString("UnpackProjectTemplateOperation.1")); //$NON-NLS-1$
            final File destinationDir = project.getLocation().toFile();
            unpackProjectData(dataLocation, destinationDir);
            ProgressUtilities.worked(progress, 30);

            /* Reset project to its own value, else we get the name from the zip, which leads to problems later. */
            ProjectUtilities.setProjectName(project, project.getName());

            project.open(progress.newChild(10));

            /* Necessary to remove all build specs from the data projects (we have at least the manifest builder now) */
            removeBuildspec(project);

            // IMPORTANT: As the project was already open once before, we need to refresh here, else
            // not all resources are up-to-date
            project.refreshLocal(IResource.DEPTH_INFINITE, progress.newChild(10));

            /* Let inherited wizards change the project */
            final INewProjectHandler handler = m_data.getHandler();
            if (handler == null)
                return;

            final IStatus postCreateStatus = handler.postCreateProject(project, template,
                    progress.newChild(30, SubMonitor.SUPPRESS_NONE));
            if (!postCreateStatus.matches(IStatus.ERROR))
                handler.openProject(project);

            if (postCreateStatus != Status.OK_STATUS)
                throw new CoreException(postCreateStatus);

            /* Enforce and cleanup natures and description */
            final String moduleID = m_data.getModuleID();
            ModuleNature.enforceNature(project, moduleID);

            final String[] natureIds = cleanDescription(project, progress);
            configureNatures(project, natureIds, progress);
        } catch (final CoreException t) {
            final IStatus status = t.getStatus();
            if (status.matches(IStatus.ERROR | IStatus.CANCEL)) {
                // If anything went wrong, clean up the project
                // We use new monitor, else delete will not work if the monitor is already cancelled.
                project.delete(true, new NullProgressMonitor());
            }

            if (status.matches(IStatus.CANCEL))
                throw new InterruptedException(Messages.getString("UnpackProjectTemplateOperation.2")); //$NON-NLS-1$

            throw t;
        } catch (final Throwable t) {
            // If anything went wrong, clean up the project
            progress.setWorkRemaining(10);
            project.delete(true, progress);

            throw new InvocationTargetException(t);
        }
    }

    private void removeBuildspec(final IProject project) throws CoreException {
        final IProjectDescription description = project.getDescription();
        description.setBuildSpec(new ICommand[0]);
        project.setDescription(description, null);
    }

    /**
     * Cleans the description of the freshly created project: reset the name and remove PDE-nature if it was configured.
     */
    private String[] cleanDescription(final IProject project, final SubMonitor progress) throws CoreException {
        /* Re-set name to new name, as un-zipping probably did change the internal name */
        final IProjectDescription description = project.getDescription();
        description.setName(project.getName());
        final String[] natureIds = description.getNatureIds();
        /* Also remove the PDE-nature, if it is present. This is needed for self-hosted project templates. */
        final String[] cleanedNatureIds = ArrayUtils.removeElement(natureIds, NewProjectWizard.PDE_NATURE_ID);
        description.setNatureIds(cleanedNatureIds);

        project.setDescription(description, IResource.FORCE /* | IResource.AVOID_NATURE_CONFIG */,
                progress.newChild(10));
        return cleanedNatureIds;
    }

    private void configureNatures(final IProject project, final String[] natureIds, final SubMonitor progress)
            throws CoreException {
        /* validate and configure all natures of this project. */
        final IStatus validateNatureSetStatus = project.getWorkspace().validateNatureSet(natureIds);
        if (!validateNatureSetStatus.isOK())
            throw new CoreException(validateNatureSetStatus);

        progress.setWorkRemaining(natureIds.length + 1);

        for (final String natureId : natureIds) {
            final IProjectNature nature = project.getNature(natureId);
            nature.configure();
            ProgressUtilities.worked(progress, 1);
        }
    }

    private void unpackProjectData(final URL data, final File destinationDir) throws IOException, CoreException {
        final String location = data.toString();
        final String extension = FilenameUtils.getExtension(location);
        if ("zip".equalsIgnoreCase(extension)) //$NON-NLS-1$
            ZipUtilities.unzip(data, destinationDir);
        else {
            final URL fileURL = FileLocator.toFileURL(data);
            final File dataDir = FileUtils.toFile(fileURL);
            if (dataDir == null) {
                final String msg = String.format("Invalid dataLocation: %s", data); //$NON-NLS-1$
                final IStatus status = new Status(IStatus.ERROR, KalypsoAFGUIFrameworkPlugin.PLUGIN_ID, msg);
                throw new CoreException(status);
            }

            if (dataDir.isDirectory()) {
                FileUtils.copyDirectory(dataDir, destinationDir, FileFilterUtils.makeSVNAware(null));
                removePDEfiles(destinationDir);
            } else {
                final String msg = String.format("Invalid dataLocation (not a directory): %s", data); //$NON-NLS-1$
                final IStatus status = new Status(IStatus.ERROR, KalypsoAFGUIFrameworkPlugin.PLUGIN_ID, msg);
                throw new CoreException(status);
            }
        }
    }

    /**
     * A bit hacky: remove all PDE-specific files from project templates.
     */
    private void removePDEfiles(final File destinationDir) throws IOException {
        final File manifestDir = new File(destinationDir, "META-INF"); //$NON-NLS-1$
        FileUtils.deleteDirectory(manifestDir);

        new File(destinationDir, "plugin.xml").delete(); //$NON-NLS-1$
        new File(destinationDir, "build.properties").delete(); //$NON-NLS-1$

        final File[] propertyFiles = destinationDir
                .listFiles((FilenameFilter) new WildcardFileFilter("plugin*.properties")); //$NON-NLS-1$
        if (propertyFiles != null) {
            for (final File file : propertyFiles)
                file.delete();
        }

        /* Purge the code licence, we only want it in the sources */
        new File(destinationDir, FILE_ABOUT_HTML).delete();
    }
}