blob: 9da5dc2258876aed6a9be3af30fb2ba164e41ca5 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2012-2014 BMW Car IT, itemis and others.
* 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:
* BMW Car IT - Initial API and implementation
* itemis - [434954] Hook for overwriting conversion of EMF Diagnostics to IMarkers
*
* </copyright>
*/
package org.eclipse.sphinx.platform.resources;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.eclipse.core.resources.IMarker;
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.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.sphinx.platform.internal.Activator;
import org.eclipse.sphinx.platform.messages.PlatformMessages;
import org.eclipse.sphinx.platform.util.PlatformLogUtil;
/**
* A job which can be used to asynchronously create and delete markers.
* <p>
* The job is useful to avoid deadlocks related to the global workspace lock which is needed to manipulate resource
* markers.
* <p>
* The job maintains an internal queue of marker manipulation tasks when the job gets executed this queue will be
* processed. To execute the job asynchronously use the {@link MarkerJob#schedule() schedule method}.
*/
public class MarkerJob extends WorkspaceJob {
protected static abstract class MarkerTask extends MarkerDescriptor {
protected IResource resource;
public MarkerTask(IResource resource, String type) {
super(type);
this.resource = resource;
}
public MarkerTask(IResource resource, String type, Map<String, Object> attributes) {
super(type, attributes);
this.resource = resource;
}
abstract void execute() throws CoreException;
}
protected static class CreateMarkerTask extends MarkerTask {
public CreateMarkerTask(IResource resource, String type, Map<String, Object> attributes) {
super(resource, type, attributes);
}
public CreateMarkerTask(IResource resource, String type, int severity, String message) {
super(resource, type);
getAttributes().put(IMarker.SEVERITY, severity);
getAttributes().put(IMarker.MESSAGE, message);
}
@Override
void execute() throws CoreException {
IMarker marker = resource.createMarker(getType());
marker.setAttributes(getAttributes());
}
}
protected static class DeleteMarkerTask extends MarkerTask {
public DeleteMarkerTask(IResource resource, String type) {
super(resource, type);
}
@Override
void execute() throws CoreException {
resource.deleteMarkers(getType(), false, IResource.DEPTH_ZERO);
}
}
/**
* Singleton instance of marker job that can be used to manipulate resource markers asynchronously without risking
* to run into deadlocks. After queuing marker manipulations with this marker job instance it must be explicitly
* scheduled by the caller.
*
* @see MarkerJob#schedule()
*/
public static final MarkerJob INSTANCE = new MarkerJob();
protected Queue<MarkerTask> taskQueue = new ConcurrentLinkedQueue<MarkerTask>();
/**
* Protected constructor for the singleton pattern that prevents from instantiation by clients.
*/
protected MarkerJob() {
super(PlatformMessages.job_updatingProblemMarkers);
setSystem(true);
setPriority(Job.BUILD);
setRule(ResourcesPlugin.getWorkspace().getRoot());
}
/**
* Processes the internal task queue.
*/
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
MarkerTask mt = null;
while ((mt = taskQueue.poll()) != null) {
try {
mt.execute();
} catch (CoreException ex) {
if (mt.resource.isAccessible() == false || mt.resource.isSynchronized(IResource.DEPTH_ZERO) == false) {
// do not log errors for inaccessible or out-of-sync resources
continue;
}
PlatformLogUtil.logAsError(Activator.getDefault(), ex);
}
}
return Status.OK_STATUS;
}
/**
* Adds a create marker task to the internal queue.
*
* @param resource
* the resource for which the marker will be created
* @param type
* the marker type
* @param severity
* the marker severity
* @param severity
* the marker message
* @see IResource#createMarker(String)
*/
public void addCreateMarkerTask(IResource resource, String type, int severity, String message) {
CreateMarkerTask cmt = new CreateMarkerTask(resource, type, severity, message);
synchronized (taskQueue) {
taskQueue.add(cmt);
}
}
/**
* Adds a create marker task to the internal queue.
*
* @param resource
* the resource for which the marker will be created
* @param type
* the marker type
* @param attributes
* marker attributes that will be passed to the newly created marker using
* {@link IMarker#setAttributes(Map)}.
* @see IResource#createMarker(String)
*/
public void addCreateMarkerTask(IResource resource, String type, Map<String, Object> attributes) {
CreateMarkerTask cmt = new CreateMarkerTask(resource, type, attributes);
synchronized (taskQueue) {
taskQueue.add(cmt);
}
}
/**
* Adds a create marker task to the internal queue.
*
* @param resource
* the resource for which the marker will be created
* @param markerDescriptor
* the marker descriptor which holds the marker type and the marker attributes that will be passed to the
* newly created marker using {@link IMarker#setAttributes(Map)}.
* @see IResource#createMarker(String)
*/
public void addCreateMarkerTask(IResource resource, MarkerDescriptor markerDescriptor) {
addCreateMarkerTask(resource, markerDescriptor.getType(), markerDescriptor.getAttributes());
}
/**
* Adds a delete marker task to the internal queue which will delete all existing markers of the specified type.
*
* @param resource
* the resource for which markers will be deleted
* @param type
* the marker type to delete
* @see IResource#deleteMarkers(String, boolean, int)
*/
public void addDeleteMarkerTask(IResource resource, String type) {
DeleteMarkerTask dmt = new DeleteMarkerTask(resource, type);
synchronized (taskQueue) {
taskQueue.add(dmt);
}
}
}