From fc3fa24cc128697e88147c80e3ba673803170e12 Mon Sep 17 00:00:00 2001 From: Zoltan Ujhelyi Date: Fri, 1 Mar 2019 17:28:48 +0100 Subject: [PATCH 1/3] Fixes MagicDraw project-based scope implementation #25 * Fixes copy-paste error in customized NavigationHelper implementation * Provides an explicit manager for IProjectChangedListener instances --- .../com/incquerylabs/v4md/V4MDPlugin.java | 14 ++++---- .../internal/IProjectChangedListener.java | 33 +++++++++++++++++++ .../MagicDrawProjectEngineContext.java | 7 ++-- .../v4md/internal/MagicDrawProjectScope.java | 11 ------- 4 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/IProjectChangedListener.java diff --git a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/V4MDPlugin.java b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/V4MDPlugin.java index cd388b9..6b86246 100644 --- a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/V4MDPlugin.java +++ b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/V4MDPlugin.java @@ -1,6 +1,7 @@ package com.incquerylabs.v4md; import com.incquerylabs.v4md.expressions.BinaryVQLExpression; +import com.incquerylabs.v4md.internal.IProjectChangedListener; import com.nomagic.ci.persistence.IProject; import com.nomagic.magicdraw.core.Application; import com.nomagic.magicdraw.core.Project; @@ -11,8 +12,9 @@ import com.nomagic.magicdraw.expressions.evaluation.ExpressionEvaluationConfigurator; public class V4MDPlugin extends com.nomagic.magicdraw.plugins.Plugin { - + private final class V4MDProjectListener extends ProjectEventListenerAdapter implements ProjectPartListener { + @Override public void projectOpened(Project project) { ViatraQueryAdapter.getOrCreateAdapter(project); @@ -22,29 +24,29 @@ public void projectOpened(Project project) { public void projectPreClosed(Project project) { ViatraQueryAdapter.disposeAdapter(project); } - + @Override public void projectPartLoaded(Project project, IProject storage) { - ViatraQueryAdapter.getAdapter(project).ifPresent(ViatraQueryAdapter::projectStructureUpdated); + IProjectChangedListener.MANAGER.notifyProjectListeners(project); } @Override public void projectPartAttached(ModuleUsage usage) { Project project = ProjectUtilities.getProject(usage.getUsed()); - ViatraQueryAdapter.getAdapter(project).ifPresent(ViatraQueryAdapter::projectStructureUpdated); + IProjectChangedListener.MANAGER.notifyProjectListeners(project); } @Override public void projectPartDetached(ModuleUsage usage) { Project project = ProjectUtilities.getProject(usage.getUsed()); - ViatraQueryAdapter.getAdapter(project).ifPresent(ViatraQueryAdapter::projectStructureUpdated); + IProjectChangedListener.MANAGER.notifyProjectListeners(project); } @Override public void projectPartRemoved(IProject project) { Project modelProject = ProjectUtilities.getProject(project); - ViatraQueryAdapter.getAdapter(modelProject).ifPresent(ViatraQueryAdapter::projectStructureUpdated); + IProjectChangedListener.MANAGER.notifyProjectListeners(modelProject); } } diff --git a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/IProjectChangedListener.java b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/IProjectChangedListener.java new file mode 100644 index 0000000..80facf3 --- /dev/null +++ b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/IProjectChangedListener.java @@ -0,0 +1,33 @@ +package com.incquerylabs.v4md.internal; + +import com.google.common.collect.ArrayListMultimap; +import com.nomagic.magicdraw.core.Project; + +public interface IProjectChangedListener { + void modelSetUpdated(); + + public static final Manager MANAGER = new Manager(); + + public class Manager { + ArrayListMultimap listenerMap = ArrayListMultimap.create(); + + + private Manager() { + // Private constructor for singleton class + } + + public void notifyProjectListeners(Project project) { + for (IProjectChangedListener listener : listenerMap.get(project)) { + listener.modelSetUpdated(); + } + } + + public boolean addProjectChangeListener(Project project, IProjectChangedListener listener) { + return listenerMap.put(project, listener); + } + + public boolean removeProjectChangeListener(Project project, IProjectChangedListener listener) { + return listenerMap.remove(project, listener); + } + } +} \ No newline at end of file diff --git a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectEngineContext.java b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectEngineContext.java index 5d20880..25a4637 100644 --- a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectEngineContext.java +++ b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectEngineContext.java @@ -27,7 +27,6 @@ import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; import com.google.common.collect.Sets; -import com.incquerylabs.v4md.internal.MagicDrawProjectScope.IProjectChangedListener; /** * Provides a specific engine context implementation for MagicDraw projects. @@ -101,7 +100,7 @@ public void removeRoot(Notifier root) { return; // no veto by filters - modelRoots.add(root); + modelRoots.remove(root); // TODO contentAdapter.removeAdapter(root); removeAdapter is not visible here Method method; try { @@ -120,7 +119,7 @@ public MagicDrawProjectEngineContext(MagicDrawProjectScope scope, ViatraQueryEng this.engine = engine; this.logger = logger; this.taintListener = taintListener; - scope.addProjectChangeListener(scopeListener); + IProjectChangedListener.MANAGER.addProjectChangeListener(scope.getProject(), scopeListener); } /** @@ -169,7 +168,7 @@ public void dispose() { if (runtimeContext != null) runtimeContext.dispose(); if (navHelper != null) navHelper.dispose(); - scope.removeProjectChangeListener(scopeListener); + IProjectChangedListener.MANAGER.removeProjectChangeListener(scope.getProject(), scopeListener); this.baseIndex = null; this.engine = null; diff --git a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java index 153809d..5c2350c 100644 --- a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java +++ b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java @@ -33,9 +33,6 @@ public class MagicDrawProjectScope extends EMFScope { && ((EReference) reference).isContainment() && reference.getName().contains("_from_")) .withStrictNotificationMode(false); - public interface IProjectChangedListener { - void modelSetUpdated(); - } static Stream getProjectModels(Project projectModel) { return projectModel.getModels().stream(); } @@ -60,14 +57,6 @@ protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexing Logger logger) { return new MagicDrawProjectEngineContext(this, engine, errorListener, logger); } - - boolean addProjectChangeListener(IProjectChangedListener listener) { - return listeners.add(listener); - } - - boolean removeProjectChangeListener(IProjectChangedListener listener) { - return listeners.remove(listener); - } public void projectStructureUpdated() { for (IProjectChangedListener listener : listeners) { From d668958b1022a9e773d5608d9088b03be9f96a59 Mon Sep 17 00:00:00 2001 From: Zoltan Ujhelyi Date: Fri, 1 Mar 2019 17:53:19 +0100 Subject: [PATCH 2/3] Avoids adding packages to the scope that are already added #26 This avoids _some_ duplicate addition/deletion events, but there are still more issues that need further debugging to avoid. --- .../com/incquerylabs/v4md/internal/MagicDrawProjectScope.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java index 5c2350c..8a72b5e 100644 --- a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java +++ b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java @@ -19,6 +19,7 @@ import org.eclipse.viatra.query.runtime.emf.EMFScope; import com.nomagic.magicdraw.core.Project; +import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Package; public class MagicDrawProjectScope extends EMFScope { @@ -34,7 +35,8 @@ public class MagicDrawProjectScope extends EMFScope { .withStrictNotificationMode(false); static Stream getProjectModels(Project projectModel) { - return projectModel.getModels().stream(); + Package primaryModel = projectModel.getPrimaryModel(); + return projectModel.getModels().stream().filter(pkg -> pkg == primaryModel || !EcoreUtil.isAncestor(primaryModel, pkg)); } static Stream getCustomNotifiers(Notifier... notifiers) { From 9a82bf569d4173d25bb958023b3c1cdb2347dea9 Mon Sep 17 00:00:00 2001 From: Zoltan Ujhelyi Date: Mon, 4 Mar 2019 14:45:07 +0100 Subject: [PATCH 3/3] Further updates related to event handling #25 * Ignore events received when event firing is disabled * Explicitly mark feature names starting with '_' as unindexable --- .../internal/MagicDrawProjectEngineContext.java | 14 +++++++++++++- .../v4md/internal/MagicDrawProjectScope.java | 10 ++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectEngineContext.java b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectEngineContext.java index 25a4637..f95c5fa 100644 --- a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectEngineContext.java +++ b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectEngineContext.java @@ -6,6 +6,7 @@ import java.util.stream.Collectors; import org.apache.log4j.Logger; +import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; @@ -18,6 +19,7 @@ import org.eclipse.viatra.query.runtime.base.api.NavigationHelper; import org.eclipse.viatra.query.runtime.base.api.filters.IBaseIndexObjectFilter; import org.eclipse.viatra.query.runtime.base.api.filters.IBaseIndexResourceFilter; +import org.eclipse.viatra.query.runtime.base.core.NavigationHelperContentAdapter; import org.eclipse.viatra.query.runtime.base.core.NavigationHelperImpl; import org.eclipse.viatra.query.runtime.base.exception.ViatraBaseException; import org.eclipse.viatra.query.runtime.emf.DynamicEMFQueryRuntimeContext; @@ -76,6 +78,16 @@ private class MagicDrawProjectNavigationHelper extends NavigationHelperImpl { public MagicDrawProjectNavigationHelper(Notifier emfRoot, BaseIndexOptions options, Logger logger) { super(emfRoot, options, logger); + this.contentAdapter = new NavigationHelperContentAdapter(this) { + + @Override + public void notifyChanged(Notification notification) { + if (scope.getProject().getRepository().getEventSupport().isEnableEventFiring()) { + super.notifyChanged(notification); + } + } + + }; } Set getModelRoots() { @@ -113,7 +125,7 @@ public void removeRoot(Notifier root) { notifyBaseIndexChangeListeners(); } } - + public MagicDrawProjectEngineContext(MagicDrawProjectScope scope, ViatraQueryEngine engine, IIndexingErrorListener taintListener, Logger logger) { this.scope = scope; this.engine = engine; diff --git a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java index 8a72b5e..9af2fb4 100644 --- a/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java +++ b/com.incquerylabs.v4md/src/main/com/incquerylabs/v4md/internal/MagicDrawProjectScope.java @@ -30,10 +30,16 @@ public class MagicDrawProjectScope extends EMFScope { // XXX Omitting references can cause semantic errors (so far we are in the clear though) // these references are only present in UML profiles, typically their contents are equal to the original references inherited from the UML type hierarchy, however there are some cases when this might not be the case. private static final BaseIndexOptions BASE_OPTIONS = new BaseIndexOptions() - .withFeatureFilterConfiguration(reference -> reference instanceof EReference - && ((EReference) reference).isContainment() && reference.getName().contains("_from_")) + .withFeatureFilterConfiguration(reference -> reference instanceof EReference && isReferenceToBeFiltered((EReference) reference)) .withStrictNotificationMode(false); + private static boolean isReferenceToBeFiltered(EReference reference) { + String name = reference.getName(); + return (reference.isContainment() && name.contains("_from_")) + || + name.startsWith("_"); + } + static Stream getProjectModels(Project projectModel) { Package primaryModel = projectModel.getPrimaryModel(); return projectModel.getModels().stream().filter(pkg -> pkg == primaryModel || !EcoreUtil.isAncestor(primaryModel, pkg));