com.wt.studio.plugin.platform.actions.MavenClasspathUpdateJob.java Source code

Java tutorial

Introduction

Here is the source code for com.wt.studio.plugin.platform.actions.MavenClasspathUpdateJob.java

Source

/*******************************************************************************
 *  Copyright (c) 2012 VMware, Inc.
 *  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:
 *      VMware, Inc. - initial API and implementation
 *******************************************************************************/
package com.wt.studio.plugin.platform.actions;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
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.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.ui.RefreshTab;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.m2e.actions.MavenLaunchConstants;
import org.eclipse.m2e.core.internal.IMavenConstants;

import com.wt.studio.plugin.platform.Activator;

/**
 * @author Christian Dupuis
 */
@SuppressWarnings("restriction")
public class MavenClasspathUpdateJob extends WorkspaceJob {

    /** Internal cache of scheduled and <b>unfinished</b> update jobs */
    private static final Queue<IJavaProject> SCHEDULED_PROJECTS = new ConcurrentLinkedQueue<IJavaProject>();

    /** The {@link IJavaProject} this jobs should refresh the class path container for */
    private final IJavaProject javaProject;

    /**
     * Private constructor to create an instance
     * @param javaProject the {@link IJavaProject} the class path container should be updated for
     * @param types the change types happened to the manifest
     */
    private MavenClasspathUpdateJob(IJavaProject javaProject) {
        super("Updating Maven dependencies for project '" + javaProject.getElementName() + "'");
        this.javaProject = javaProject;
    }

    /**
     * Returns the internal {@link IJavaProject}
     */
    public IJavaProject getJavaProject() {
        return javaProject;
    }

    /**
     * Runs the job in the context of the workspace. Simply delegates refreshing of the class path container to
     * {@link ClasspathUtils#updateClasspathContainer(IJavaProject, IProgressMonitor)}.
     */
    @Override
    public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
        if (!javaProject.getProject().isOpen() || monitor.isCanceled()) {
            return Status.CANCEL_STATUS;
        }
        try {
            IContainer basedir = findPomXmlBasedir(javaProject.getProject());
            if (basedir == null) {
                return Status.CANCEL_STATUS;
            }
            ILaunchConfiguration configuration = createLaunchConfiguration(basedir,
                    "eclipse:clean eclipse:eclipse -U -Dsvn-revision-number.failOnError=false");
            if (configuration != null) {
                ILaunch launch = configuration.launch(ILaunchManager.RUN_MODE, new SubProgressMonitor(monitor, 75));
                DebugPlugin.getDefault().addDebugEventListener(
                        new MavenProcessListener(launch.getProcesses()[0], javaProject.getProject()));
            }
        } catch (Exception e) {
            return Status.CANCEL_STATUS;
        }

        return new Status(IStatus.OK, Activator.PLUGIN_ID, "Updated Maven dependencies");
    }

    private IContainer findPomXmlBasedir(IContainer dir) {
        if (dir == null) {
            return null;
        }

        try {
            // loop upwards through the parents as long as we do not cross the project boundary
            while (dir.exists() && dir.getProject() != null && dir.getProject() != dir) {
                // see if pom.xml exists
                if (dir.getType() == IResource.FOLDER) {
                    IFolder folder = (IFolder) dir;
                    if (folder.findMember(IMavenConstants.POM_FILE_NAME) != null) {
                        return folder;
                    }
                } else if (dir.getType() == IResource.FILE) {
                    if (((IFile) dir).getName().equals(IMavenConstants.POM_FILE_NAME)) {
                        return dir.getParent();
                    }
                }
                dir = dir.getParent();
            }
        } catch (Exception e) {
            return dir;
        }
        return dir;
    }

    private ILaunchConfiguration createLaunchConfiguration(IContainer basedir, String goal) {
        try {
            ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
            ILaunchConfigurationType launchConfigurationType = launchManager
                    .getLaunchConfigurationType(MavenLaunchConstants.LAUNCH_CONFIGURATION_TYPE_ID);

            ILaunchConfigurationWorkingCopy workingCopy = launchConfigurationType.newInstance(basedir, //
                    "Updating Maven dependencies for '" + basedir.getName() + "'");
            workingCopy.setAttribute(MavenLaunchConstants.ATTR_POM_DIR, basedir.getLocation().toOSString());
            workingCopy.setAttribute(MavenLaunchConstants.ATTR_GOALS, goal);
            workingCopy.setAttribute(MavenLaunchConstants.ATTR_WORKSPACE_RESOLUTION, true);

            workingCopy.setAttribute(RefreshTab.ATTR_REFRESH_SCOPE, "${project}");
            workingCopy.setAttribute(RefreshTab.ATTR_REFRESH_RECURSIVE, true);

            String vmArguments = workingCopy.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, "");
            vmArguments += "-Declipse.workspace=\"${workspace_loc}\"";
            workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, vmArguments);

            IPath path = getJREContainerPath(basedir);
            if (path != null) {
                workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH,
                        path.toPortableString());
            }

            return workingCopy;
        } catch (CoreException ex) {
            Activator.getDefault().getLog()
                    .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error occured", ex));
        }
        return null;
    }

    private IPath getJREContainerPath(IContainer basedir) throws CoreException {
        IProject project = basedir.getProject();
        if (project != null && project.hasNature(JavaCore.NATURE_ID)) {
            IJavaProject javaProject = JavaCore.create(project);
            IClasspathEntry[] entries = javaProject.getRawClasspath();
            for (int i = 0; i < entries.length; i++) {
                IClasspathEntry entry = entries[i];
                if (JavaRuntime.JRE_CONTAINER.equals(entry.getPath().segment(0))) {
                    return entry.getPath();
                }
            }
        }
        return null;
    }

    /**
     * Helper method to schedule a new {@link MavenClasspathUpdateJob}.
     * @param javaProject the {@link IJavaProject} the class path container should be updated for
     * @param types the change types of the manifest
     */
    public static void scheduleClasspathContainerUpdateJob(IJavaProject javaProject) {
        if (javaProject != null && !SCHEDULED_PROJECTS.contains(javaProject)) {
            newClasspathContainerUpdateJob(javaProject);
        }
    }

    public static void scheduleClasspathContainerUpdateJob(IProject oroject) {
        scheduleClasspathContainerUpdateJob(JavaCore.create(oroject));
    }

    /**
     * Creates a new instance of {@link MavenClasspathUpdateJob} and configures required properties and schedules it to
     * the workbench.
     */
    private static MavenClasspathUpdateJob newClasspathContainerUpdateJob(IJavaProject javaProject) {
        MavenClasspathUpdateJob job = new MavenClasspathUpdateJob(javaProject);
        job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
        job.setPriority(Job.BUILD);
        job.addJobChangeListener(new DuplicateJobListener());
        job.schedule();
        return job;
    }

    /**
     * Internal {@link IJobChangeListener} to detect duplicates in the scheduled list of {@link MavenClasspathUpdateJob
     * Jobs}.
     */
    private static class DuplicateJobListener extends JobChangeAdapter implements IJobChangeListener {

        @Override
        public void done(IJobChangeEvent event) {
            SCHEDULED_PROJECTS.remove(((MavenClasspathUpdateJob) event.getJob()).getJavaProject());
        }

        @Override
        public void scheduled(IJobChangeEvent event) {
            SCHEDULED_PROJECTS.add(((MavenClasspathUpdateJob) event.getJob()).getJavaProject());
        }
    }

    private class MavenProcessListener implements IDebugEventSetListener {

        private final IProject project;

        private final IProcess newProcess;

        public MavenProcessListener(IProcess process, IProject project) {
            this.project = project;
            this.newProcess = process;
        }

        public void handleDebugEvents(DebugEvent[] events) {
            if (events != null && project != null) {
                int size = events.length;
                for (int i = 0; i < size; i++) {
                    if (newProcess != null && newProcess.equals(events[i].getSource())
                            && events[i].getKind() == DebugEvent.TERMINATE) {

                        DebugPlugin.getDefault().removeDebugEventListener(this);

                        Job job = new Job("refresh project") {

                            @Override
                            protected IStatus run(IProgressMonitor monitor) {
                                try {
                                    project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
                                } catch (CoreException e) {
                                }
                                return Status.OK_STATUS;
                            }

                        };
                        job.setSystem(true);
                        job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
                        job.setPriority(Job.INTERACTIVE);
                        job.schedule();
                    }
                }
            }
        }
    }

}