blob: 594124d1e15dd86fe7324dd9415631a2f8f7276a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017, 2019 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - Initial API and implementation based on org.eclipse.xtext.builder.nature.XtextNature
*******************************************************************************/
package org.eclipse.ocl.xtext.base.ui.builder;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
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.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.plugin.EcorePlugin;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EObjectValidator;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.ocl.pivot.internal.manager.MetamodelManagerInternal;
import org.eclipse.ocl.pivot.internal.utilities.PivotDiagnostician;
import org.eclipse.ocl.pivot.internal.utilities.PivotDiagnostician.BasicDiagnosticWithRemove;
import org.eclipse.ocl.pivot.resource.CSResource;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.LabelUtil;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.OCL;
import org.eclipse.ocl.pivot.utilities.TracingOption;
import org.eclipse.ocl.xtext.base.ui.BaseUiModule;
import org.eclipse.ocl.xtext.base.ui.BaseUiPluginHelper;
import org.eclipse.ocl.xtext.base.ui.messages.BaseUIMessages;
import org.eclipse.ocl.xtext.base.utilities.PivotDiagnosticConverter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.xtext.diagnostics.Severity;
import org.eclipse.xtext.util.IAcceptor;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.validation.IDiagnosticConverter;
import org.eclipse.xtext.validation.Issue;
import org.osgi.framework.Bundle;
import org.osgi.framework.wiring.BundleWiring;
/**
* A MultiValidationJob maintains a queue of workspaceRelativeFileNames in need of validation.
*
* Validations are performed in a separate job from the builder since the success/failure of an OCL validation
* does not need to force users to wait as occurs for builder active.
*/
public class MultiValidationJob extends Job
{
public static final @NonNull TracingOption VALIDATOR = new TracingOption(BaseUiPluginHelper.PLUGIN_ID, "validator");
/**
* An AddMarkersOperation accumulates the future markers for an IResource via the accept methods.
* Old markers are deleted and the new markers are installed by a single execution per resource.
*/
protected static class AddMarkersOperation extends WorkspaceModifyOperation implements IAcceptor<@NonNull Issue>
{
protected final @NonNull IResource resource;
protected final @NonNull String issueMarkerType;
protected final @NonNull List<@NonNull MarkerData> markerDatas = new ArrayList<>();
public AddMarkersOperation(@NonNull IResource resource, @NonNull String issueMarkerType) {
this.resource = resource;
this.issueMarkerType = issueMarkerType;
}
public void accept(@NonNull Diagnostic diagnostic, @Nullable Diagnostic parentDiagnostic) {
if (diagnostic.getSeverity() != Diagnostic.OK) {
markerDatas.add(new DiagnosticMarkerData(diagnostic, issueMarkerType, parentDiagnostic));
}
}
public void accept(Resource.@NonNull Diagnostic diagnostic, int severity) {
markerDatas.add(new ResourceDiagnosticMarkerData(diagnostic, issueMarkerType, severity));
}
@Override
public void accept(@NonNull Issue issue) {
markerDatas.add(new IssueMarkerData(resource, issueMarkerType, issue));
}
public void addMessage(/*@NonNull*/ String markerType, int severity, @NonNull String message) {
assert markerType != null;
markerDatas.add(new SimpleMarkerData(markerType, severity, message));
}
@Override
protected void execute(final IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException {
if (!resource.exists()) {
return;
}
resource.deleteMarkers(issueMarkerType, true, IResource.DEPTH_INFINITE);
for (@NonNull MarkerData markerData : markerDatas) {
if (monitor.isCanceled()) {
return;
}
markerData.createMarker(resource);
}
}
public @NonNull List<@NonNull MarkerData> getMarkerDatas() {
return markerDatas;
}
public boolean isEMF() {
return issueMarkerType == EValidator.MARKER;
}
}
public interface MarkerData
{
@NonNull IMarker createMarker(@NonNull IResource resource) throws CoreException;
@NonNull String getMessageText();
}
/**
* A DiagnosticMarkerData describes the future Marker created from a Diagnostic.
*/
//This class is based on org.eclipse.emf.edit.ui.action.ValidateAction.EclipseResourcesUtil
protected static class DiagnosticMarkerData /*extends ValidateAction.EclipseResourcesUtil*/ implements MarkerData
{
protected final @NonNull String markerType;
protected final @NonNull Object severity;
protected final /*@NonNull*/ String message;
protected @Nullable String location = null;
protected /*@NonNull*/ Integer lineNumber = null;
protected @Nullable String uriAttribute = null;
protected final @Nullable String relatedURIsAttribute;
public DiagnosticMarkerData(@NonNull Diagnostic diagnostic, @NonNull String markerType, @Nullable Diagnostic parentDiagnostic) {
this.markerType = markerType;
//
// MarkerHelper.createMarkers
//
int severity = diagnostic.getSeverity();
if (severity < Diagnostic.WARNING) {
this.severity = IMarker.SEVERITY_INFO;
}
else if (severity < Diagnostic.ERROR) {
this.severity = IMarker.SEVERITY_WARNING;
}
else {
this.severity = IMarker.SEVERITY_ERROR;
}
// this.message = composeMessage(diagnostic, parentDiagnostic);
this.message = diagnostic.getMessage();
//
// Logic from EditUIMarkerHelper.adjustMarker
//
List<?> data = diagnostic.getData();
if ((data == null) && (parentDiagnostic != null)) {
data = parentDiagnostic.getData();
}
StringBuilder relatedURIs = null;
if (data != null) {
boolean first = true;
for (Object element : data) {
if (element instanceof EObject) // ValidateAction.adjustMarker
{
EObject eObject = (EObject)element;
if (first) {
first = false;
uriAttribute = EcoreUtil.getURI(eObject).toString();
}
else
{
if (relatedURIs == null) {
relatedURIs = new StringBuilder();
}
else {
relatedURIs.append(' ');
}
relatedURIs.append(URI.encodeFragment(EcoreUtil.getURI(eObject).toString(), false));
}
}
else if (element instanceof Resource.Diagnostic) { // FIXME is this needed?
Resource.Diagnostic resourceDiagnostic = (Resource.Diagnostic)element;
if (resourceDiagnostic.getLocation() != null) {
String lineString = Integer.toString(resourceDiagnostic.getLine());
String columnString = Integer.toString(resourceDiagnostic.getColumn());
this.location = EMFEditUIPlugin.getPlugin().getString("_UI_MarkerLocation", new String[] { lineString, columnString });
this.lineNumber = resourceDiagnostic.getLine();
try {
Method getObjectMethod = resourceDiagnostic.getClass().getMethod("getObject");
Object object = getObjectMethod.invoke(resourceDiagnostic);
if (object instanceof EObject) {
this.uriAttribute = EcoreUtil.getURI((EObject)object).toString();
Method getFeatureMethod = resourceDiagnostic.getClass().getMethod("getFeature");
Object feature = getFeatureMethod.invoke(resourceDiagnostic);
if (feature instanceof EObject)
{
if (relatedURIs == null) {
relatedURIs = new StringBuilder();
}
else {
relatedURIs.append(' ');
}
relatedURIs.append(URI.encodeFragment(EcoreUtil.getURI((EObject)feature).toString(), false));
}
}
}
catch (Throwable throwable) {
// Ignore.
}
break;
}
}
}
}
this.relatedURIsAttribute = relatedURIs != null ? relatedURIs.toString() : null;
}
@Override
public @NonNull IMarker createMarker(@NonNull IResource resource) throws CoreException {
IMarker marker = resource.createMarker(markerType);
marker.setAttribute(IMarker.LOCATION, location);
marker.setAttribute(IMarker.SEVERITY, severity);
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
marker.setAttribute(IMarker.MESSAGE, message);
if (uriAttribute != null) {
marker.setAttribute(EValidator.URI_ATTRIBUTE, uriAttribute);
}
if (relatedURIsAttribute != null) {
marker.setAttribute(EValidator.RELATED_URIS_ATTRIBUTE, relatedURIsAttribute);
}
return marker;
}
@Override
public @NonNull String getMessageText() {
return String.valueOf(message);
}
}
/**
* An IssueMarkerData describes the future Marker created from an Issue.
*/
//This class is based on org.eclipse.xtext.ui.editor.validation.MarkerCreator
protected static class IssueMarkerData implements MarkerData
{
// private static final String FIXABLE_KEY = "FIXABLE_KEY"; // FIXME this is MarkerCreator.FIXABLE_KEY
protected final @NonNull String markerType;
protected final @NonNull String location;
protected final /*@NonNull*/ String codeKey;
protected final @NonNull Object severity;
protected final /*@NonNull*/ Integer charStart;
protected @Nullable Integer charEnd;
protected final /*@NonNull*/ Integer lineNumber;
protected final /*@NonNull*/ Integer columnKey;
protected final /*@NonNull*/ String message;
protected @Nullable String uriKey;
protected @Nullable String dataKey;
// protected final @Nullable Boolean fixableKey;
protected final @Nullable String uriAttribute;
protected @Nullable String relatedURIsAttribute = null;
public IssueMarkerData(@NonNull IResource resource, @NonNull String markerType, @NonNull Issue issue) {
this.markerType = markerType;
String lineNR = "";
if (issue.getLineNumber() != null) {
lineNR = "line: " + issue.getLineNumber() + " ";
}
this.location = lineNR + resource.getFullPath().toString();
this.codeKey = issue.getCode();
switch (issue.getSeverity()) {
case ERROR : this.severity = IMarker.SEVERITY_ERROR; break;
case WARNING : this.severity = IMarker.SEVERITY_WARNING; break;
case INFO : this.severity = IMarker.SEVERITY_INFO; break;
default: throw new IllegalArgumentException(String.valueOf(issue.getSeverity()));
}
this.charStart = issue.getOffset();
if (issue.getOffset() != null && issue.getLength() != null) {
this.charEnd = issue.getOffset() + issue.getLength();
}
this.lineNumber = issue.getLineNumber();
this.columnKey = issue.getColumn();
this.message = issue.getMessage();
if (issue.getUriToProblem() != null) {
this.uriKey = issue.getUriToProblem().toString();
}
if (issue.getData() != null && issue.getData().length > 0) {
this.dataKey = Strings.pack(issue.getData());
}
// if (resolutionProvider != null && resolutionProvider.hasResolutionFor(issue.getCode())) {
// attributeKey2value.put(FIXABLE_KEY, true);
// }
String[] data = issue.getData();
StringBuilder relatedURIs = null;
String uriAttribute = null;
boolean first = true;
if (data != null) {
for (String string : data) {
if (first) {
first = false;
uriAttribute = string;
}
else {
if (relatedURIs == null) {
relatedURIs = new StringBuilder();
}
else {
relatedURIs.append(' ');
}
relatedURIs.append(URI.encodeFragment(string, false));
}
}
}
this.uriAttribute = uriAttribute;
if (relatedURIs != null) {
this.relatedURIsAttribute = relatedURIs.toString();
}
}
@Override
public @NonNull IMarker createMarker(@NonNull IResource resource) throws CoreException {
IMarker marker = resource.createMarker(markerType);
marker.setAttribute(IMarker.LOCATION, location);
marker.setAttribute(Issue.CODE_KEY, codeKey);
marker.setAttribute(IMarker.SEVERITY, severity);
marker.setAttribute(IMarker.CHAR_START, charStart);
if (charEnd != null) {
marker.setAttribute(IMarker.CHAR_END, charEnd);
}
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
marker.setAttribute(Issue.COLUMN_KEY, columnKey);
marker.setAttribute(IMarker.MESSAGE, message);
if (uriKey != null) {
marker.setAttribute(Issue.URI_KEY, uriKey);
}
if (dataKey != null) {
marker.setAttribute(Issue.DATA_KEY, dataKey);
}
// if (fixableKey != null) {
// marker.setAttribute(FIXABLE_KEY, fixableKey);
// }
if (uriAttribute != null) {
marker.setAttribute(EValidator.URI_ATTRIBUTE, uriAttribute);
}
if (relatedURIsAttribute != null) {
marker.setAttribute(EValidator.RELATED_URIS_ATTRIBUTE, relatedURIsAttribute);
}
return marker;
}
@Override
public @NonNull String getMessageText() {
return String.valueOf(message);
}
}
/**
* A DiagnosticMarkerData describes the future Marker created from a Diagnostic.
*/
//This class is based on org.eclipse.emf.edit.ui.util.EditUIMarkerHelper
protected static class ResourceDiagnosticMarkerData implements MarkerData
{
protected final @NonNull String markerType;
protected final @NonNull Object severity;
protected final /*@NonNull*/ String message;
protected @Nullable String location = null;
protected /*@NonNull*/ Integer lineNumber = null;
protected @Nullable String uriAttribute = null;
protected final @Nullable String relatedURIsAttribute;
public ResourceDiagnosticMarkerData(Resource.@NonNull Diagnostic diagnostic, @NonNull String markerType, int severity) {
this.markerType = markerType;
//
// MarkerHelper.createMarkers
//
if (severity < Diagnostic.WARNING) {
this.severity = IMarker.SEVERITY_INFO;
}
else if (severity < Diagnostic.ERROR) {
this.severity = IMarker.SEVERITY_WARNING;
}
else {
this.severity = IMarker.SEVERITY_ERROR;
}
// this.message = composeMessage(diagnostic, parentDiagnostic);
this.message = diagnostic.getMessage();
String relatedURIsAttribute = null;
if (diagnostic.getLocation() != null) {
String lineString = Integer.toString(diagnostic.getLine());
String columnString = Integer.toString(diagnostic.getColumn());
this.location = EMFEditUIPlugin.getPlugin().getString("_UI_MarkerLocation", new String[] { lineString, columnString });
this.lineNumber = diagnostic.getLine();
try {
Method getObjectMethod = diagnostic.getClass().getMethod("getObject");
Object object = getObjectMethod.invoke(diagnostic);
if (object instanceof EObject)
{
this.uriAttribute = EcoreUtil.getURI((EObject)object).toString();
Method getFeatureMethod = diagnostic.getClass().getMethod("getFeature");
Object feature = getFeatureMethod.invoke(diagnostic);
if (feature instanceof EObject) {
relatedURIsAttribute = EcoreUtil.getURI((EObject)feature).toString();
}
}
}
catch (Throwable throwable) {
// Ignore.
}
}
this.relatedURIsAttribute = relatedURIsAttribute;
}
@Override
public @NonNull IMarker createMarker(@NonNull IResource resource) throws CoreException {
IMarker marker = resource.createMarker(markerType);
marker.setAttribute(IMarker.LOCATION, location);
marker.setAttribute(IMarker.SEVERITY, severity);
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
marker.setAttribute(IMarker.MESSAGE, message);
if (uriAttribute != null) {
marker.setAttribute(EValidator.URI_ATTRIBUTE, uriAttribute);
}
if (relatedURIsAttribute != null) {
marker.setAttribute(EValidator.RELATED_URIS_ATTRIBUTE, relatedURIsAttribute);
}
return marker;
}
@Override
public @NonNull String getMessageText() {
return String.valueOf(message);
}
}
/**
* A SimpleMarkerData describes the future Marker for a simple message.
*/
protected static class SimpleMarkerData implements MarkerData
{
protected final @NonNull String markerType;
protected final @NonNull Object severity;
protected final @NonNull String message;
public SimpleMarkerData(@NonNull String markerType, int severity, @NonNull String message) {
this.markerType = markerType;
this.severity = severity;
this.message = message;
}
@Override
public @NonNull IMarker createMarker(@NonNull IResource resource) throws CoreException {
IMarker marker = resource.createMarker(markerType);
marker.setAttribute(IMarker.SEVERITY, severity);
marker.setAttribute(IMarker.MESSAGE, message);
return marker;
}
@Override
public @NonNull String getMessageText() {
return message;
}
}
/**
* ValidationQueue ensures that all accesses to the inter-thread queue are synchronized.
*/
private static final class ValidationQueue
{
private final @NonNull Set<@NonNull ValidationEntry> queue = new HashSet<>();
public synchronized boolean addAll(@NonNull Iterable<@NonNull ValidationEntry> entries) {
boolean added = false;
for (@NonNull ValidationEntry entry : entries) {
if (queue.add(entry)) {
added = true;
}
}
return added;
}
public synchronized void clear() {
queue.clear();
}
public synchronized @NonNull List<@NonNull ValidationEntry> getValidationList() {
return new ArrayList<>(queue);
}
public synchronized void remove(@NonNull ValidationEntry entry) {
queue.remove(entry);
}
}
private static final Logger log = Logger.getLogger(MultiValidationJob.class);
private static final @NonNull IDiagnosticConverter converter = new PivotDiagnosticConverter();
private final @NonNull ValidationQueue validationQueue = new ValidationQueue();
public MultiValidationJob() {
super(BaseUIMessages.MultiValidationJob_Name);
}
/**
* Add the files to the queue of validations. If the validation job is not
* already running, it is scheduled to run.
*/
public void addValidations(@NonNull Iterable<@NonNull ValidationEntry> entries) {
if (validationQueue.addAll(entries)) {
int state = getState();
if (state == Job.NONE) {
schedule();
}
}
}
@Override
protected synchronized void canceling() {
validationQueue.clear();
super.canceling();
}
protected boolean checkResourceErrors(@NonNull AddMarkersOperation operation, @NonNull Resource resource, @NonNull IProgressMonitor monitor) {
if (operation.isEMF()) {
for (Resource.@NonNull Diagnostic error : resource.getErrors()) {
if (monitor.isCanceled()) {
return false;
}
operation.accept(error, Diagnostic.ERROR);
}
for (Resource.@NonNull Diagnostic warning : resource.getWarnings()) {
if (monitor.isCanceled()) {
return false;
}
operation.accept(warning, Diagnostic.WARNING);
}
}
else {
for (Resource.@NonNull Diagnostic error : resource.getErrors()) {
if (monitor.isCanceled()) {
return false;
}
converter.convertResourceDiagnostic(error, Severity.ERROR, operation);
}
for (Resource.@NonNull Diagnostic warning : resource.getWarnings()) {
if (monitor.isCanceled()) {
return false;
}
converter.convertResourceDiagnostic(warning, Severity.WARNING, operation);
}
}
return true;
}
protected boolean checkValidatorDiagnostics(@NonNull AddMarkersOperation operation, @NonNull Resource resource, @NonNull IProgressMonitor monitor) {
Map<Object, Object> validationContext = LabelUtil.createDefaultContext(Diagnostician.INSTANCE);
BasicDiagnostic diagnostics = new BasicDiagnosticWithRemove(EObjectValidator.DIAGNOSTIC_SOURCE, 0, EcorePlugin.INSTANCE.getString("_UI_DiagnosticRoot_diagnostic", new Object[] { resource.getURI() }), new Object [] { resource });
ResourceSet resourceSet = resource.getResourceSet();
assert resourceSet != null;
Diagnostician instance = PivotDiagnostician.createDiagnostician(resourceSet, EValidator.Registry.INSTANCE, null/*adapterFactory*/, monitor);
for (EObject eObject : resource.getContents()) {
if (monitor.isCanceled()) {
return false;
}
instance.validate(eObject, diagnostics, validationContext);
}
convertValidatorDiagnostics(operation, diagnostics, null);
return true;
}
protected void convertValidatorDiagnostics(@NonNull AddMarkersOperation operation, @NonNull Diagnostic diagnostic, @Nullable Diagnostic parentDiagnostic) {
//
// The logic here replicates that in the Runnable body of MarkerHelper.createMarkers
//
if (diagnostic.getChildren().isEmpty()) {
operation.accept(diagnostic, null);
}
else {
List<@NonNull Diagnostic> childDiagnostics = ClassUtil.nullFree(diagnostic.getChildren());
if (diagnostic.getMessage() == null) {
for (Diagnostic childDiagnostic : childDiagnostics) {
convertValidatorDiagnostics(operation, childDiagnostic, null);
}
}
else {
for (Diagnostic childDiagnostic : childDiagnostics) {
operation.accept(childDiagnostic, diagnostic);
}
}
}
}
protected void doValidate(final @NonNull ValidationEntry entry, @NonNull SubMonitor monitor) throws CoreException {
Throwable throwable = null;
AddMarkersOperation operation = null;
try {
final @NonNull IFile file = entry.getFile();
IProject project = file.getProject();
if ((project == null) || !project.isOpen()) {
return;
}
//
// Ensure entry's project's class loader is useable (to resolve JavaClassCS references)
//
OCL ocl = entry.createOCL();
ClassLoader classLoader = getClassLoader(project);
if (classLoader != null) {
((MetamodelManagerInternal)ocl.getMetamodelManager()).addClassLoader(classLoader);
}
monitor.worked(1); // Work Item 1 - Initialize done
final @NonNull String markerType = entry.getMarkerId();
URI uri = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
// System.out.println("OCL:Validating " + uri.toString());
ResourceSet resourceSet = ocl.getResourceSet();
Resource resource = null;
try {
resource = resourceSet.getResource(uri, true);
}
catch (Exception e) {
throwable = e;
}
monitor.worked(1); // Work Item 2 - Load done
operation = new AddMarkersOperation(file, markerType);
if (resource != null) {
EcoreUtil.resolveAll(resourceSet);
monitor.worked(3); // Work Item 3 - Resolve done
if (!checkResourceErrors(operation, resource, monitor)) {
return;
}
if (resource instanceof CSResource) {
Resource asResource = ((CSResource)resource).getASResource();
if (!checkResourceErrors(operation, asResource, monitor)) {
return;
}
if (!checkValidatorDiagnostics(operation, asResource, monitor)) {
return;
}
// FIXME accumulate/cache dependencies
}
else {
if (!checkValidatorDiagnostics(operation, resource, monitor)) {
return;
}
}
} else {
monitor.worked(1); // Work Item 3 - Resolve 'done'
operation.addMessage(BaseUiModule.MARKER_ID, IMarker.SEVERITY_ERROR, "Failed to create EMF Resource for '" + uri + "'");
}
monitor.worked(1); // Work Item 4 - Validate 'done'
try {
operation.run(monitor);
} catch (InvocationTargetException e) {
log.error("Could not create marker.", e);
} catch (InterruptedException e) {
// cancelled by user; ok
}
monitor.worked(1); // Work Item 5 - Add Markers 'done'
}
catch (Throwable e) {
if (throwable == null) {
throwable = e;
}
throw e;
}
finally {
synchronized (entry) {
if (throwable != null) {
if (throwable instanceof WrappedException) {
entry.setThrowable(((WrappedException)throwable).getCause());
}
else {
entry.setThrowable(throwable);
}
}
else if (operation != null) {
entry.setMarkerDatas(operation.getMarkerDatas());
}
entry.notifyAll();
}
}
}
/**
* Return the ClassLoader for the bundle/workspace project.
*/
protected @Nullable ClassLoader getClassLoader(@NonNull IProject project) throws CoreException {
Bundle bundle = Platform.getBundle(project.getName());
if (bundle != null) {
BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
if (bundleWiring != null) {
return bundleWiring.getClassLoader();
}
else {
return null;
}
}
else { // from org.eclipse.jdt.internal.compiler.apt.util.EclipseFileManager.getClassLoader
// and https://sdqweb.ipd.kit.edu/wiki/JDT_Tutorial:_Class_Loading_in_a_running_plugin
IJavaProject javaProject = JavaCore.create(project);
String[] defaultRuntimeClassPath= null;
try {
defaultRuntimeClassPath = JavaRuntime.computeDefaultRuntimeClassPath(javaProject);
}
catch (JavaModelException e) {
// maybe not a Java project
}
if (defaultRuntimeClassPath == null) {
return null;
}
List<@NonNull URL> urlList = new ArrayList<>();
for (String classPathEntry : defaultRuntimeClassPath) {
IPath classPathEntryPath = new Path(classPathEntry);
java.net.URI classPathEntryURI = classPathEntryPath.toFile().toURI();
try {
urlList.add(classPathEntryURI.toURL());
}
catch (MalformedURLException e) {
// the url is malformed - this should not happen
throw new RuntimeException(e);
}
}
@NonNull URL[] urlArray = urlList.toArray(new @NonNull URL[urlList.size()]);
return new URLClassLoader(urlArray, javaProject.getClass().getClassLoader());
}
}
@Override
protected IStatus run(IProgressMonitor monitor) {
List<@NonNull ValidationEntry> validationList;
while (!(validationList = validationQueue.getValidationList()).isEmpty()) {
SubMonitor subMonitor = SubMonitor.convert(monitor, 5 * validationList.size());
// System.out.println(Thread.currentThread().getName() + " " + NameUtil.debugSimpleName(subMonitor) + " converted from: " + NameUtil.debugSimpleName(monitor));
Collections.sort(validationList, NameUtil.TO_STRING_COMPARATOR);
for (@NonNull ValidationEntry entry : validationList) {
if (subMonitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
long start = System.currentTimeMillis();
try {
String message = NLS.bind(BaseUIMessages.MultiValidationJob_Validating, entry.getFile().getFullPath().toString());
// if (VALIDATOR.isActive()) {
// VALIDATOR.println(Thread.currentThread().getName() + " " + NameUtil.debugSimpleName(subMonitor) + " subTask: " + message);
// VALIDATOR.println(entry.getFile().getFullPath().toString());
// }
subMonitor.subTask(message);
doValidate(entry, subMonitor);
} catch (OperationCanceledException canceled) {
return Status.CANCEL_STATUS;
} catch (Throwable e) {
log.error("Error running " + getName(), e);
// return Status.OK_STATUS;
}
finally {
if (VALIDATOR.isActive()) {
long end = System.currentTimeMillis();
VALIDATOR.println((end -start) + " ms for \"" + entry.getFile().getFullPath().toString() + "\" on \"" + Thread.currentThread().getName() + "\"");
}
}
validationQueue.remove(entry); // Remove so that failure does not repeat
// System.out.println(Thread.currentThread().getName() + " " + NameUtil.debugSimpleName(subMonitor) + " worked: " + 1);
subMonitor.worked(1);
}
// System.out.println(Thread.currentThread().getName() + " " + NameUtil.debugSimpleName(subMonitor) + " done");
subMonitor.done();
}
if (monitor != null) {
// System.out.println(Thread.currentThread().getName() + " " + NameUtil.debugSimpleName(monitor) + " done");
monitor.done();
}
return Status.OK_STATUS;
}
}