com.aptana.portal.ui.dispatch.configurationProcessors.JavaScriptLibraryInstallProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.aptana.portal.ui.dispatch.configurationProcessors.JavaScriptLibraryInstallProcessor.java

Source

/**
 * Aptana Studio
 * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions).
 * Please see the license.html included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
package com.aptana.portal.ui.dispatch.configurationProcessors;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.progress.UIJob;
import org.osgi.framework.Version;

import com.aptana.configurations.processor.ConfigurationStatus;
import com.aptana.core.logging.IdeLog;
import com.aptana.core.util.EclipseUtil;
import com.aptana.core.util.IOUtil;
import com.aptana.core.util.VersionUtil;
import com.aptana.portal.ui.PortalUIPlugin;
import com.aptana.portal.ui.dispatch.configurationProcessors.installer.JavaScriptImporterOptionsDialog;

/**
 * An installer (import) processor for JavaScript libraries, such as jQuery and Prototype.<br>
 * This processor download and place the JS library under a custom javascript folder in the selected (or active)
 * project. It also allows the use to select the location manually.
 * 
 * @author Shalom Gibly <sgibly@aptana.com>
 */
public class JavaScriptLibraryInstallProcessor extends InstallerConfigurationProcessor {
    private static final String JS_LIBRARY = "JS Library"; //$NON-NLS-1$
    private static boolean installationInProgress;
    private String libraryName;
    private IProject targetProject;

    /**
     * Returns the JS Library name.
     */
    @Override
    protected String getApplicationName() {
        return libraryName;
    }

    /**
     * Returns the library's version.<br>
     * The version extraction will begin by trying to find a version in the library name. If failed, this call will try
     * to locate a version pattern in the download URLs. And if that fails, the method returns null.
     * 
     * @return The library's version; Null, if none is found.
     */
    protected Version getLibraryVersion() {
        Version version = VersionUtil.parseVersion(getApplicationName());
        if (version == null) {
            for (String url : this.urls) {
                if (version == null) {
                    version = VersionUtil.parseVersion(url);
                } else {
                    break;
                }
            }
        }
        return version;
    }

    /**
     * Install a JavaScript library into a user-specified project.<br>
     * The configuration will grab the name and the location of the library from the given attributes. <br>
     * We expect an array of attributes with the same structure described at {@link #loadAttributes(Object)}.
     * 
     * @param attributes
     *            A non-empty string array, which contains the URLs for the JS library file(s) and an optional Map of
     *            additional attributes.
     * @see com.aptana.configurations.processor.AbstractConfigurationProcessor#configure(org.eclipse.core.runtime.IProgressMonitor,
     *      java.lang.Object)
     * @see #loadAttributes(Object)
     */
    @Override
    public ConfigurationStatus configure(IProgressMonitor progressMonitor, Object attributes) {
        // Get a Class lock to avoid multiple installations at the same time even with multiple instances of this
        // RubyInstallProcessor
        synchronized (this.getClass()) {
            if (installationInProgress) {
                return configurationStatus;
            }
            installationInProgress = true;
        }
        try {
            configurationStatus.removeAttribute(CONFIG_ATTR);
            clearErrorAttributes();

            // Load the installer's attributes
            IStatus loadingStatus = loadAttributes(attributes);
            if (!loadingStatus.isOK()) {
                String message = loadingStatus.getMessage();
                applyErrorAttributes(message);
                IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(message));
                return configurationStatus;
            }

            // Check that we got the expected single install URL

            if (urls.length == 0) {
                // structure error
                String err = NLS.bind(Messages.InstallProcessor_wrongNumberOfInstallLinks,
                        new Object[] { JS_LIBRARY, 1, urls.length });
                applyErrorAttributes(err);
                IdeLog.logError(PortalUIPlugin.getDefault(), new Exception(err));
                return configurationStatus;
            }
            // Try to get the library name from the optional attributes. If it's not there, we log a warning and use a
            // default one.
            libraryName = attributesMap.get(NAME_ATTRIBUTE);
            if (libraryName == null) {
                // just in case
                libraryName = JS_LIBRARY;
                IdeLog.logWarning(PortalUIPlugin.getDefault(),
                        "Expected a name attribute for the JS library, but got null."); //$NON-NLS-1$
            }
            // Start the installation...
            configurationStatus.setStatus(ConfigurationStatus.PROCESSING);
            IStatus status = download(urls, progressMonitor);
            if (status.isOK()) {
                status = install(progressMonitor);
            }
            switch (status.getSeverity()) {
            case IStatus.OK:
            case IStatus.INFO:
            case IStatus.WARNING:
                displayMessageInUIThread(MessageDialog.INFORMATION,
                        NLS.bind(Messages.InstallProcessor_installerTitle, libraryName),
                        NLS.bind(Messages.InstallProcessor_installationSuccessful, libraryName));
                configurationStatus.setStatus(ConfigurationStatus.OK);
                break;
            case IStatus.ERROR:
                configurationStatus.setStatus(ConfigurationStatus.ERROR);
                break;
            case IStatus.CANCEL:
                configurationStatus.setStatus(ConfigurationStatus.INCOMPLETE);
                break;
            default:
                configurationStatus.setStatus(ConfigurationStatus.UNKNOWN);
            }
            return configurationStatus;
        } finally {
            synchronized (this.getClass()) {
                installationInProgress = false;
            }
        }
    }

    /**
     * Install the library.<br>
     * The installation will display a selection dialog, displaying the projects in the workspace, and selecting the
     * active project by default. It also takes into account the type of the project (nature) when suggesting the
     * location to save the JS libraries.
     * 
     * @param progressMonitor
     * @return A status indication of the process success or failure.
     */
    protected IStatus install(IProgressMonitor progressMonitor) {
        Job job = new UIJob(Messages.JSLibraryInstallProcessor_directorySelection) {
            @Override
            public IStatus runInUIThread(IProgressMonitor monitor) {
                JavaScriptImporterOptionsDialog dialog = new JavaScriptImporterOptionsDialog(
                        Display.getDefault().getActiveShell(), libraryName);
                if (dialog.open() == Window.OK) {
                    String selectedLocation = dialog.getSelectedLocation();
                    IPath path = Path.fromOSString(selectedLocation);
                    targetProject = ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0));
                    // Making sure that the project is not null, although this should never happen
                    if (targetProject != null) {
                        String fullPath = targetProject.getLocation().append(path.removeFirstSegments(1))
                                .toOSString();
                        File targetFolder = new File(fullPath);
                        if (!targetFolder.exists() && !targetFolder.mkdirs()) {
                            // could not create the directories needed!
                            IdeLog.logError(PortalUIPlugin.getDefault(),
                                    "Failed to create directories when importing JS slibrary!", //$NON-NLS-1$
                                    new Exception("Failed to create '" + fullPath + '\'')); //$NON-NLS-1$
                            return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID,
                                    Messages.JSLibraryInstallProcessor_directoriesCreationFailed);
                        }
                        // Copy the downloaded content into the created directory
                        List<IStatus> errors = new ArrayList<IStatus>();
                        for (String f : downloadedPaths) {
                            try {
                                File sourceLocation = new File(f);
                                File targetLocation = new File(targetFolder, sourceLocation.getName());
                                if (targetLocation.exists()) {
                                    if (!MessageDialog.openQuestion(Display.getDefault().getActiveShell(),
                                            Messages.JSLibraryInstallProcessor_fileConflictTitle,
                                            Messages.JSLibraryInstallProcessor_fileConflictMessage
                                                    + sourceLocation.getName()
                                                    + Messages.JSLibraryInstallProcessor_overwriteQuestion)) {
                                        continue;
                                    }
                                }
                                IOUtil.copyFile(sourceLocation, targetLocation);
                            } catch (IOException e) {
                                errors.add(new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, e.getMessage(), e));
                            }
                        }
                        if (!errors.isEmpty()) {
                            return new MultiStatus(PortalUIPlugin.PLUGIN_ID, 0,
                                    errors.toArray(new IStatus[errors.size()]),
                                    Messages.JSLibraryInstallProcessor_multipleErrorsWhileImportingJS, null);
                        }
                        // Since we don't cache the installed location for javascript libraries, we pass null here. This
                        // will only mark for deletion the downloaded content.
                        finalizeInstallation(null);
                    } else {
                        IdeLog.logError(PortalUIPlugin.getDefault(),
                                "Unexpected null project when importing a JS library!", new Exception()); //$NON-NLS-1$
                        return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID,
                                Messages.JSLibraryInstallProcessor_unexpectedNull);
                    }
                    try {
                        targetProject.refreshLocal(IResource.DEPTH_INFINITE, SubMonitor.convert(monitor));
                    } catch (CoreException e) {
                        IdeLog.logError(PortalUIPlugin.getDefault(), "Error while refreshing the project.", e); //$NON-NLS-1$
                    }
                    return Status.OK_STATUS;
                } else {
                    return Status.CANCEL_STATUS;
                }
            }
        };
        EclipseUtil.setSystemForJob(job);
        job.schedule();
        try {
            job.join();
        } catch (InterruptedException e) {
            IdeLog.logError(PortalUIPlugin.getDefault(), e);
        }
        return job.getResult();
    }
}