瀏覽代碼

Issue 1194 (#1268)

* Do not execute validation as exclusive read on the Transactional domain

* Added variants of Validation Job

* sysouts for profiling

* Removed unneccesary Crossreference adapter

* Removed DirtyStateValidationJob

* removed sysouts

* Basic synchronization for default issue store, changed visibility
Andreas Mülder 8 年之前
父節點
當前提交
e22de98ea0

+ 13 - 7
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/validation/DefaultValidationIssueStore.java

@@ -69,17 +69,23 @@ public class DefaultValidationIssueStore implements IValidationIssueStore, IFile
 
 	@Override
 	public void addIssueStoreListener(IResourceIssueStoreListener listener) {
-		this.listener.add(listener);
+		synchronized (this.listener) {
+			this.listener.add(listener);
+		}
 	}
 
 	@Override
 	public void removeIssueStoreListener(IResourceIssueStoreListener listener) {
-		this.listener.remove(listener);
+		synchronized (this.listener) {
+			this.listener.remove(listener);
+		}
 	}
 
 	protected void notifyListeners() {
-		for (IResourceIssueStoreListener iResourceIssueStoreListener : listener) {
-			iResourceIssueStoreListener.issuesChanged();
+		synchronized (this.listener) {
+			for (IResourceIssueStoreListener iResourceIssueStoreListener : listener) {
+				iResourceIssueStoreListener.issuesChanged();
+			}
 		}
 	}
 
@@ -96,7 +102,7 @@ public class DefaultValidationIssueStore implements IValidationIssueStore, IFile
 		reloadMarkerIssues();
 	}
 
-	protected void reloadMarkerIssues() {
+	protected synchronized void reloadMarkerIssues() {
 		persistentIssues.clear();
 		List<IMarker> markers = new ArrayList<IMarker>();
 		try {
@@ -132,7 +138,7 @@ public class DefaultValidationIssueStore implements IValidationIssueStore, IFile
 	}
 
 	@Override
-	public void processIssues(List<Issue> issues, IProgressMonitor monitor) {
+	public synchronized void processIssues(List<Issue> issues, IProgressMonitor monitor) {
 		liveIssues.clear();
 		for (Issue issue : issues) {
 			if (issue instanceof SCTIssue) {
@@ -144,7 +150,7 @@ public class DefaultValidationIssueStore implements IValidationIssueStore, IFile
 	}
 
 	@Override
-	public List<SCTIssue> getIssues(String uri) {
+	public synchronized List<SCTIssue> getIssues(String uri) {
 		List<SCTIssue> result = Lists.newArrayList();
 		if (!liveValidationEnabled()) {
 			result.addAll(persistentIssues.get(uri));

+ 6 - 42
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/validation/SCTValidationJob.java

@@ -18,14 +18,12 @@ import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.transaction.RunnableWithResult;
 import org.eclipse.emf.transaction.TransactionalEditingDomain;
 import org.eclipse.emf.transaction.util.TransactionUtil;
 import org.eclipse.gmf.runtime.common.core.command.CommandResult;
 import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
-import org.eclipse.xtext.ui.editor.validation.IValidationIssueProcessor;
 import org.eclipse.xtext.util.CancelIndicator;
 import org.eclipse.xtext.validation.CheckMode;
 import org.eclipse.xtext.validation.IResourceValidator;
@@ -33,29 +31,16 @@ import org.eclipse.xtext.validation.Issue;
 import org.yakindu.sct.model.sgraph.resource.AbstractSCTResource;
 import org.yakindu.sct.ui.editor.DiagramActivator;
 
-import com.google.inject.Inject;
-
 /**
+ * The default implementation executes the validation within a readonly
+ * transaction on the transactional editing domain. during validation the model
+ * is locked and can not be changed.
  * 
  * @author andreas muelder - Initial contribution and API
  * 
  */
-public class SCTValidationJob extends Job {
-
-	@Inject
-	private IResourceValidator validator;
-
-	private IValidationIssueProcessor validationIssueProcessor;
+public class DefaultValidationJob extends ValidationJob {
 
-	private Resource resource;
-
-	/**
-	 * Wrappes the {@link IResourceValidator} validate within a
-	 * {@link RunnableWithResult} to execute within a read only transaction
-	 * 
-	 * @author andreas muelder - Initial contribution and API
-	 * 
-	 */
 	public static class TransactionalValidationRunner extends RunnableWithResult.Impl<List<Issue>> {
 
 		private IResourceValidator validator;
@@ -83,13 +68,8 @@ public class SCTValidationJob extends Job {
 		}
 	}
 
-	public SCTValidationJob() {
-		super("validate model...");
-		setUser(false);
-	}
-
 	@Override
-	public IStatus run(final IProgressMonitor monitor) {
+	protected IStatus runInternal(final IProgressMonitor monitor) {
 		try {
 			if (!resource.isLoaded())
 				return Status.CANCEL_STATUS;
@@ -127,9 +107,6 @@ public class SCTValidationJob extends Job {
 		return Status.OK_STATUS;
 	}
 
-	/**
-	 * relinks the model before validation is executed
-	 */
 	protected void relinkModel(final IProgressMonitor monitor, final AbstractSCTResource eResource)
 			throws ExecutionException {
 		AbstractTransactionalCommand cmd = new AbstractTransactionalCommand(TransactionUtil.getEditingDomain(eResource),
@@ -144,17 +121,4 @@ public class SCTValidationJob extends Job {
 		};
 		cmd.execute(monitor, null);
 	}
-
-	public Resource getResource() {
-		return resource;
-	}
-
-	public void setResource(Resource resource) {
-		this.resource = resource;
-	}
-	
-	public void setValidationIssueProcessor(IValidationIssueProcessor validationIssueProcessor) {
-		this.validationIssueProcessor = validationIssueProcessor;
-	}
-
-}
+}

+ 1 - 1
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/validation/LiveValidationListener.java

@@ -32,7 +32,7 @@ public class LiveValidationListener extends ResourceSetListenerImpl {
 	private static final int DELAY = 200; // ms
 
 	@Inject
-	private SCTValidationJob validationJob;
+	private ValidationJob validationJob;
 
 	@Override
 	public void resourceSetChanged(ResourceSetChangeEvent event) {

+ 126 - 0
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/validation/ShadowModelValidationJob.java

@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2017 committers of YAKINDU 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:
+ * 	committers of YAKINDU - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.ui.editor.validation;
+
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
+import org.eclipse.xtext.util.CancelIndicator;
+import org.eclipse.xtext.validation.CheckMode;
+import org.eclipse.xtext.validation.Issue;
+import org.yakindu.sct.ui.editor.DiagramActivator;
+
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+/**
+ * Copies the resource contents to a shadow model that is validated then. Does
+ * not block UI during validation but consumes more memory since the whole model
+ * is duplicated.
+ * 
+ * @author andreas muelder - Initial contribution and API
+ * 
+ */
+public class ShadowModelValidationJob extends ValidationJob {
+
+	@Inject
+	private ResourceCopier copier;
+
+	@Override
+	protected IStatus runInternal(final IProgressMonitor monitor) {
+		ResourceSet set = new ResourceSetImpl();
+		try {
+			if (!resource.isLoaded())
+				return Status.CANCEL_STATUS;
+			final Resource shadowResource = set.createResource(resource.getURI());
+			cloneResource(monitor, shadowResource);
+			if (monitor.isCanceled())
+				return Status.CANCEL_STATUS;
+
+			final List<Issue> issues = Lists.newArrayList();
+			try {
+				issues.addAll(validator.validate(shadowResource, CheckMode.FAST_ONLY, new CancelIndicator() {
+					public boolean isCanceled() {
+						return monitor.isCanceled();
+					}
+				}));
+			} catch (Throwable ex) {
+				return Status.CANCEL_STATUS;
+			}
+
+			validationIssueProcessor.processIssues(issues, monitor);
+
+		} catch (Exception ex) {
+			ex.printStackTrace();
+			return new Status(IStatus.ERROR, DiagramActivator.PLUGIN_ID, ex.getMessage());
+		}
+		return Status.OK_STATUS;
+	}
+
+	private void cloneResource(final IProgressMonitor monitor, final Resource shadowResource)
+			throws ExecutionException {
+		AbstractTransactionalCommand cmd = new AbstractTransactionalCommand(TransactionUtil.getEditingDomain(resource),
+				"", null) {
+			@Override
+			protected CommandResult doExecuteWithResult(final IProgressMonitor monitor, IAdaptable info)
+					throws ExecutionException {
+				try {
+					copier.cloneResource(resource, shadowResource);
+				} catch (Throwable t) {
+					return CommandResult.newErrorCommandResult(t.getMessage());
+				}
+				return CommandResult.newOKCommandResult();
+			}
+		};
+		cmd.execute(monitor, null);
+	}
+
+	public static class ResourceCopier extends Copier {
+
+		private static final long serialVersionUID = 1L;
+
+		public void cloneResource(Resource original, Resource clone) {
+			clone.setURI(original.getURI());
+			clone.getContents().addAll(super.copyAll(original.getContents()));
+			copyReferences();
+			copyXMIIds(original, clone);
+		}
+
+		protected void copyXMIIds(Resource original, Resource clone) {
+			if (original instanceof XMLResource) {
+				TreeIterator<EObject> iterator = original.getAllContents();
+				TreeIterator<EObject> cloneIterator = clone.getAllContents();
+				while (iterator.hasNext()) {
+					EObject next = iterator.next();
+					EObject nextClone = cloneIterator.next();
+					if (next.eClass() != nextClone.eClass()) {
+						throw new IllegalStateException("Models are out of sync!");
+					}
+					((XMLResource) clone).setID(nextClone, ((XMLResource) original).getID(next));
+				}
+			}
+		}
+	}
+}

+ 62 - 0
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/validation/ValidationJob.java

@@ -0,0 +1,62 @@
+/** 
+ * Copyright (c) 2017 committers of YAKINDU 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:
+ * committers of YAKINDU - initial API and implementation
+ *
+*/
+package org.yakindu.sct.ui.editor.validation;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.ui.editor.validation.IValidationIssueProcessor;
+import org.eclipse.xtext.validation.IResourceValidator;
+
+import com.google.inject.ImplementedBy;
+import com.google.inject.Inject;
+
+/**
+ * @author andreas muelder - Initial contribution and API
+ * 
+ */
+@ImplementedBy(ShadowModelValidationJob.class)
+public abstract class ValidationJob extends Job {
+
+	@Inject
+	protected IResourceValidator validator;
+
+	protected IValidationIssueProcessor validationIssueProcessor;
+
+	protected Resource resource;
+
+	protected abstract IStatus runInternal(final IProgressMonitor monitor);
+
+	public ValidationJob() {
+		super("validate model...");
+		setUser(false);
+	}
+
+	@Override
+	public final IStatus run(final IProgressMonitor monitor) {
+		IStatus status = runInternal(monitor);
+		return status;
+	}
+
+	public Resource getResource() {
+		return resource;
+	}
+
+	public void setResource(Resource resource) {
+		this.resource = resource;
+	}
+
+	public void setValidationIssueProcessor(IValidationIssueProcessor validationIssueProcessor) {
+		this.validationIssueProcessor = validationIssueProcessor;
+	}
+
+}