/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, 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:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.grails.ide.eclipse.core.internal.classpath;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
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.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.grails.ide.eclipse.commands.GrailsCommandUtils;
import org.grails.ide.eclipse.core.GrailsCoreActivator;
import org.grails.ide.eclipse.core.internal.plugins.GrailsCore;
/**
* @author Christian Dupuis
* @author Kris De Volder
* @author Nieraj Singh
* @author Andrew Eisenberg
* @since 2.2.0
*/
public class GrailsClasspathContainerUpdateJob 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;
/** Should the output of the associated process be shown in the Console view? */
private boolean showOutput;
/**
* Private constructor to create an instance
* @param javaProject the {@link IJavaProject} the class path container should be updated for
* @param showOutput
* @param types the change types happened to the manifest
*/
private GrailsClasspathContainerUpdateJob(IJavaProject javaProject, boolean showOutput) {
super("Updating Grails dependencies for project '" + javaProject.getElementName() + "'");
this.javaProject = javaProject;
this.showOutput = showOutput;
}
/**
* 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 GrailsCommandUtils#refreshDependencies(IJavaProject)}.
*/
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
IProject project = javaProject.getProject();
if (!project.isOpen() || monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
// STS-2247 purge all caches for project
GrailsCore.get().disconnectProject(project);
if(!GrailsClasspathUtils.hasClasspathContainer(javaProject)) {
return new Status(IStatus.OK, GrailsCoreActivator.PLUGIN_ID, "Grails dependency management is not enabled.");
}
try {
GrailsCommandUtils.refreshDependencies(javaProject, showOutput);
}
catch (CoreException e) {
return e.getStatus();
}
catch (Throwable e) {
return new Status(IStatus.ERROR, GrailsCoreActivator.PLUGIN_ID, "Refresh dependecies failed", e);
}
return new Status(IStatus.OK, GrailsCoreActivator.PLUGIN_ID, "Updated Grails classpath container");
}
/**
* Helper method to schedule a new {@link GrailsClasspathContainerUpdateJob}.
* @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, boolean showOutput) {
if (javaProject != null && !SCHEDULED_PROJECTS.contains(javaProject)) {
newClasspathContainerUpdateJob(javaProject, showOutput);
}
}
public static void scheduleClasspathContainerUpdateJob(IProject project, boolean showOutput) {
scheduleClasspathContainerUpdateJob(JavaCore.create(project), showOutput);
}
/**
* Creates a new instance of {@link GrailsClasspathContainerUpdateJob} and configures required properties and
* schedules it to the workbench.
* @param showOutput
*/
private static GrailsClasspathContainerUpdateJob newClasspathContainerUpdateJob(IJavaProject javaProject, boolean showOutput) {
GrailsClasspathContainerUpdateJob job = new GrailsClasspathContainerUpdateJob(javaProject, showOutput);
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 GrailsClasspathContainerUpdateJob Jobs}.
*/
private static class DuplicateJobListener extends JobChangeAdapter implements IJobChangeListener {
@Override
public void done(IJobChangeEvent event) {
SCHEDULED_PROJECTS.remove(((GrailsClasspathContainerUpdateJob) event.getJob()).getJavaProject());
}
@Override
public void scheduled(IJobChangeEvent event) {
SCHEDULED_PROJECTS.add(((GrailsClasspathContainerUpdateJob) event.getJob()).getJavaProject());
}
}
}