Explorar el Código

Issue performance (#1526)

* Added URI2ResourceCache
* Asynchronous Content Assist
* added missing copyright and author tags
* dispose the workspace synchronizer
* added missing final
* Removed async content assist since it is not available for Mars and Neon
* handle null editing domain
* might be the case in headless or test execution
* Added Asynchronous content assist
* missing final added
* added missing final
* added missing final
* synchronize cache access
Andreas Mülder hace 8 años
padre
commit
3cb136c2e1

+ 1 - 1
plugins/org.yakindu.base.expressions/src/org/yakindu/base/expressions/scoping/AbstractLibraryGlobalScopeProvider.java

@@ -78,7 +78,7 @@ public abstract class AbstractLibraryGlobalScopeProvider extends AbstractGlobalS
 		for (URI uri : getValidLibraries(context)) {
 			try {
 				Iterables.addAll(descriptions, libraryCache.get(uri));
-			} catch (ExecutionException e) {
+			} catch (Exception e) {
 				e.printStackTrace();
 			}
 		}

+ 13 - 0
plugins/org.yakindu.sct.model.stext.ui/src/org/yakindu/sct/model/stext/ui/STextUiModule.java

@@ -10,11 +10,13 @@
 */
 package org.yakindu.sct.model.stext.ui;
 
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.eclipse.xtext.documentation.IEObjectDocumentationProvider;
 import org.eclipse.xtext.resource.clustering.DynamicResourceClusteringPolicy;
 import org.eclipse.xtext.resource.clustering.IResourceClusteringPolicy;
 import org.eclipse.xtext.tasks.ITaskFinder;
+import org.eclipse.xtext.ui.editor.contentassist.IContentAssistantFactory;
 import org.eclipse.xtext.ui.editor.contentassist.antlr.ParserBasedContentAssistContextFactory.StatefulFactory;
 import org.eclipse.xtext.ui.editor.hover.DispatchingEObjectTextHover;
 import org.eclipse.xtext.ui.editor.hover.IEObjectHover;
@@ -30,6 +32,8 @@ import org.eclipse.xtext.ui.resource.SimpleResourceSetProvider;
 import org.eclipse.xtext.ui.resource.XtextResourceSetProvider;
 import org.eclipse.xtext.ui.shared.Access;
 import org.yakindu.base.utils.jface.help.CrossRefObjectTextHover;
+import org.yakindu.sct.model.stext.ui.contentassist.AsyncContentAssistContextFactory;
+import org.yakindu.sct.model.stext.ui.contentassist.AsyncXtextContentAssistProcessor;
 import org.yakindu.sct.model.stext.ui.contentassist.STextStatefulFactory;
 import org.yakindu.sct.model.stext.ui.help.CustomCSSHelpHoverProvider;
 import org.yakindu.sct.model.stext.ui.help.STextUserHelpDocumentationProvider;
@@ -124,4 +128,13 @@ public class STextUiModule extends org.yakindu.sct.model.stext.ui.AbstractSTextU
 		return PackageImportHyperlinkHelper.class;
 	}
 
+	@Override
+	public Class<? extends IContentAssistantFactory> bindIContentAssistantFactory() {
+		return AsyncContentAssistContextFactory.class;
+	}
+
+	@Override
+	public Class<? extends IContentAssistProcessor> bindIContentAssistProcessor() {
+		return AsyncXtextContentAssistProcessor.class;
+	}
 }

+ 35 - 0
plugins/org.yakindu.sct.model.stext.ui/src/org/yakindu/sct/model/stext/ui/contentassist/AsyncContentAssistContextFactory.java

@@ -0,0 +1,35 @@
+/** 
+ * 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.model.stext.ui.contentassist;
+
+import java.lang.reflect.Constructor;
+
+import org.eclipse.jface.text.contentassist.ContentAssistant;
+import org.eclipse.xtext.ui.editor.contentassist.DefaultContentAssistantFactory;
+
+/**
+ * 
+ * @author andreas muelder - Initial contribution and API
+ * 
+ */
+public class AsyncContentAssistContextFactory extends DefaultContentAssistantFactory {
+
+	@Override
+	protected ContentAssistant createAssistant() {
+		try {
+			//Async ContentAssist is only available since Oxygen
+			Constructor<ContentAssistant> asyncConstructor = ContentAssistant.class.getConstructor(Boolean.TYPE);
+			return asyncConstructor.newInstance(true);
+		} catch (Exception e) {
+			return new ContentAssistant();
+		}
+	}
+}

+ 40 - 0
plugins/org.yakindu.sct.model.stext.ui/src/org/yakindu/sct/model/stext/ui/contentassist/AsyncXtextContentAssistProcessor.java

@@ -0,0 +1,40 @@
+/** 
+ * 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.model.stext.ui.contentassist;
+
+import java.util.Arrays;
+
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.xtext.ui.editor.contentassist.CompletionProposalComputer;
+import org.eclipse.xtext.ui.editor.contentassist.XtextContentAssistProcessor;
+import org.eclipse.xtext.ui.editor.model.IXtextDocument;
+
+/**
+ * 
+ * @author andreas muelder - Initial contribution and API
+ * 
+ */
+public class AsyncXtextContentAssistProcessor extends XtextContentAssistProcessor {
+
+	@Override
+	public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
+		if (getContentProposalProvider() == null)
+			return null;
+		IXtextDocument document = (IXtextDocument) viewer.getDocument();
+		CompletionProposalComputer computer = createCompletionProposalComputer(viewer, offset);
+		ICompletionProposal[] result = document.readOnly(computer);
+		Arrays.sort(result, getCompletionProposalComparator());
+		result = getCompletionProposalPostProcessor().postProcess(result);
+		return result;
+	}
+
+}

+ 25 - 8
plugins/org.yakindu.sct.model.stext.ui/src/org/yakindu/sct/model/stext/ui/contentassist/STextStatefulFactory.java

@@ -10,9 +10,14 @@
 */
 package org.yakindu.sct.model.stext.ui.contentassist;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.xtext.nodemodel.INode;
 import org.eclipse.xtext.parser.IParseResult;
 import org.eclipse.xtext.resource.XtextResource;
@@ -30,21 +35,33 @@ public class STextStatefulFactory extends StatefulFactory {
 	private IParseResult parseResult;
 
 	@Override
-	public ContentAssistContext[] create(ITextViewer viewer, int offset,
-			XtextResource resource) throws BadLocationException {
+	public ContentAssistContext[] create(final ITextViewer viewer, final int offset, final XtextResource resource)
+			throws BadLocationException {
 		this.parseResult = resource.getParseResult();
+		if (Display.getCurrent() == null) {
+			final List<ContentAssistContext> result = new ArrayList<>();
+			Display.getDefault().syncExec(new Runnable() {
+				@Override
+				public void run() {
+					try {
+						result.addAll(Arrays.asList(STextStatefulFactory.super.create(viewer, offset, resource)));
+					} catch (BadLocationException e) {
+						e.printStackTrace();
+					}
+				}
+			});
+			return result.toArray(new ContentAssistContext[] {});
+		}
 		return super.create(viewer, offset, resource);
 	}
 
 	@Override
-	public Builder doCreateContext(INode lastCompleteNode,
-			EObject currentModel, EObject previousModel, INode currentNode,
-			String prefix) {
+	public Builder doCreateContext(INode lastCompleteNode, EObject currentModel, EObject previousModel,
+			INode currentNode, String prefix) {
 		if (currentModel == null) {
 			currentModel = parseResult.getRootASTElement();
 		}
-		Builder result = super.doCreateContext(lastCompleteNode, currentModel,
-				previousModel, currentNode, prefix);
+		Builder result = super.doCreateContext(lastCompleteNode, currentModel, previousModel, currentNode, prefix);
 		return result;
 	}
-}
+}

+ 2 - 1
plugins/org.yakindu.sct.model.stext/META-INF/MANIFEST.MF

@@ -19,7 +19,8 @@ Require-Bundle: org.eclipse.xtext;visibility:=reexport,
  org.yakindu.sct.model.sgraph;visibility:=reexport,
  org.yakindu.base.types,
  org.yakindu.base.expressions;visibility:=reexport,
- org.yakindu.sct.domain
+ org.yakindu.sct.domain,
+ org.eclipse.emf.workspace
 Import-Package: org.apache.commons.logging,
  org.apache.log4j,
  org.eclipse.xtext.xbase.lib

+ 16 - 0
plugins/org.yakindu.sct.model.stext/src/org/yakindu/sct/model/stext/scoping/STextGlobalScopeProvider.java

@@ -16,6 +16,7 @@ import java.util.LinkedHashSet;
 
 import org.eclipse.emf.common.util.EList;
 import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
 import org.eclipse.emf.ecore.EReference;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.URIConverter;
@@ -23,10 +24,13 @@ import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.xtext.EcoreUtil2;
 import org.eclipse.xtext.naming.IQualifiedNameProvider;
 import org.eclipse.xtext.resource.IEObjectDescription;
+import org.eclipse.xtext.resource.IResourceDescription;
+import org.eclipse.xtext.resource.IResourceDescriptions;
 import org.eclipse.xtext.scoping.IScope;
 import org.eclipse.xtext.scoping.impl.DefaultGlobalScopeProvider;
 import org.eclipse.xtext.scoping.impl.FilteringScope;
 import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider;
+import org.eclipse.xtext.scoping.impl.SelectableBasedScope;
 import org.eclipse.xtext.scoping.impl.SimpleScope;
 import org.eclipse.xtext.util.IAcceptor;
 import org.eclipse.xtext.util.IResourceScopeCache;
@@ -66,6 +70,8 @@ public class STextGlobalScopeProvider extends ImportUriGlobalScopeProvider {
 	private STextLibraryGlobalScopeProvider libraryScope;
 	@Inject
 	private IPackageImport2URIMapper mapper;
+	@Inject
+	private URI2ResourceDescriptionCache resourceDescriptionCache;
 
 	public void setCache(IResourceScopeCache cache) {
 		this.cache = cache;
@@ -170,6 +176,15 @@ public class STextGlobalScopeProvider extends ImportUriGlobalScopeProvider {
 		}
 	}
 
+	@Override
+	protected IScope createLazyResourceScope(IScope parent, URI uri, IResourceDescriptions descriptions, EClass type,
+			Predicate<IEObjectDescription> filter, boolean ignoreCase) {
+		IResourceDescription description = resourceDescriptionCache.get(uri);
+		if(description == null)
+			return IScope.NULLSCOPE;
+		return SelectableBasedScope.createScope(parent, description, filter, type, ignoreCase);
+	}
+
 	/**
 	 * Filter all Elements that are part of an SCT file from other resources to
 	 * avoid cross document referencing
@@ -189,4 +204,5 @@ public class STextGlobalScopeProvider extends ImportUriGlobalScopeProvider {
 		});
 		return parentScope;
 	}
+	
 }

+ 116 - 0
plugins/org.yakindu.sct.model.stext/src/org/yakindu/sct/model/stext/scoping/URI2ResourceDescriptionCache.java

@@ -0,0 +1,116 @@
+/**
+ * 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.model.stext.scoping;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
+import org.eclipse.emf.workspace.util.WorkspaceSynchronizer.Delegate;
+import org.eclipse.xtext.resource.IResourceDescription;
+import org.eclipse.xtext.resource.IResourceDescription.Manager;
+import org.eclipse.xtext.resource.IResourceServiceProvider;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * 
+ * @author andreas muelder - Initial contribution and API
+ * 
+ */
+@Singleton
+public class URI2ResourceDescriptionCache implements Delegate {
+
+	private static final String DOMAIN_ID = "StatechartDomain";
+
+	@Inject
+	private IResourceServiceProvider.Registry serviceProviderRegistry;
+
+	private LoadingCache<String, IResourceDescription> cache;
+
+	private WorkspaceSynchronizer workspaceSynchronizer;
+
+	public URI2ResourceDescriptionCache() {
+		cache = CacheBuilder.newBuilder().build(new CacheLoader<String, IResourceDescription>() {
+			@Override
+			public IResourceDescription load(String key) throws Exception {
+				return getInternal(URI.createURI(key));
+			}
+		});
+		TransactionalEditingDomain editingDomain = getEditingDomain();
+		if (editingDomain != null)
+		workspaceSynchronizer = new WorkspaceSynchronizer(editingDomain, this);
+	}
+
+	protected TransactionalEditingDomain getEditingDomain() {
+		return TransactionalEditingDomain.Registry.INSTANCE.getEditingDomain(DOMAIN_ID);
+	}
+
+	public synchronized IResourceDescription get(URI uri) {
+		try {
+			IResourceDescription descrpition = cache.get(uri.toString());
+			return descrpition;
+		} catch (ExecutionException e) {
+			e.printStackTrace();
+		}
+		return null;
+
+	}
+
+	protected IResourceDescription getInternal(URI uri) {
+		ResourceSet set = getEditingDomain().getResourceSet();
+		Resource resource = set.getResource(uri, true);
+		if (resource != null) {
+			IResourceServiceProvider serviceProvider = serviceProviderRegistry.getResourceServiceProvider(uri);
+			if (serviceProvider == null)
+				return null;
+			final Manager resourceDescriptionManager = serviceProvider.getResourceDescriptionManager();
+			if (resourceDescriptionManager == null)
+				return null;
+			IResourceDescription result = resourceDescriptionManager.getResourceDescription(resource);
+			return result;
+		}
+		return null;
+	}
+
+	@Override
+	public synchronized boolean handleResourceDeleted(Resource resource) {
+		cache.invalidate(resource.getURI().toString());
+		return true;
+	}
+
+	@Override
+	public synchronized boolean handleResourceMoved(Resource resource, URI newURI) {
+		cache.invalidate(resource.getURI().toString());
+		return true;
+	}
+
+	@Override
+	public synchronized boolean handleResourceChanged(Resource resource) {
+		cache.invalidate(resource.getURI().toString());
+		return true;
+	}
+
+	@Override
+	public synchronized void dispose() {
+		if (workspaceSynchronizer != null)
+			workspaceSynchronizer.dispose();
+		cache.invalidateAll();
+	}
+
+}

+ 11 - 34
plugins/org.yakindu.sct.ui.editor/src/org/yakindu/sct/ui/editor/validation/ShadowModelValidationJob.java

@@ -10,6 +10,10 @@
  */
 package org.yakindu.sct.ui.editor.validation;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.core.commands.ExecutionException;
@@ -17,13 +21,9 @@ 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;
@@ -33,7 +33,6 @@ 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
@@ -45,9 +44,6 @@ import com.google.inject.Inject;
  */
 public class ShadowModelValidationJob extends ValidationJob {
 
-	@Inject
-	private ResourceCopier copier;
-
 	@Override
 	protected IStatus runInternal(final IProgressMonitor monitor) {
 		ResourceSet set = new ResourceSetImpl();
@@ -85,13 +81,15 @@ public class ShadowModelValidationJob extends ValidationJob {
 
 	protected void cloneResource(final IProgressMonitor monitor, final Resource shadowResource)
 			throws ExecutionException {
+		final ByteArrayOutputStream bout = new ByteArrayOutputStream();
 		AbstractTransactionalCommand cmd = new AbstractTransactionalCommand(TransactionUtil.getEditingDomain(resource),
 				"", null) {
 			@Override
 			protected CommandResult doExecuteWithResult(final IProgressMonitor monitor, IAdaptable info)
 					throws ExecutionException {
 				try {
-					copier.cloneResource(resource, shadowResource);
+					resource.save(bout, Collections.emptyMap());
+					bout.flush();
 				} catch (Throwable t) {
 					return CommandResult.newErrorCommandResult(t.getMessage());
 				}
@@ -99,32 +97,11 @@ public class ShadowModelValidationJob extends ValidationJob {
 			}
 		};
 		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);
+		try {
+			shadowResource.load(new ByteArrayInputStream(bout.toByteArray()), Collections.emptyMap());
+		} catch (IOException e) {
+			e.printStackTrace();
 		}
 
-		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));
-				}
-			}
-		}
 	}
 }