Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable indexing contents of diagrams #64

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,14 @@
public class V4MDSpecificEnvironmentOptionsGroup extends AbstractPropertyOptionsGroup implements EnvironmentChangeListener {

private static final String V4MD_DEVELOPER_MODE_REQUIRED = "Developer Mode is required. ";
private static final String V4MD_GROUP_ADVANCED_NAME = "Advanced";
private static final String V4MD_GROUP_DEBUGGING_NAME = "Debugging";
private static final String V4MD_GROUP_ID = "V4MD";
private static final String V4MD_GROUP_NAME = "V4MD";
public static final String INDEX_DIAGRAM_ID = "INDEX_DIAGRAM_ID";
private static final String INDEX_DIAGRAM_NAME = "Enable Diagram Content Indexing";
private static final String INDEX_DIAGRAM_DESCRIPTION = "By default, contents of the diagrams are not indexed. When diagram content indexing is enabled, diagram related queries can be defined. However, performance issues may occur due to the fact that more elements need to be indexed. After changing the property, you have to reload the currently open projects.";
private static final String INDEX_DIAGRAM_DESCRIPTION_ID = "INDEX_DIAGRAM_DESCRIPTION_ID";
public static final String USE_EMPTY_QUERY_SCOPE_ID = "USE_EMPTY_QUERY_SCOPE";
private static final String USE_EMPTY_QUERY_SCOPE_NAME = "Disable Model Indexing";
private static final String USE_EMPTY_QUERY_SCOPE_DESCRIPTION = "For debugging purposes, this property disables model indexing by V4MD and all queries will return an empty result. After changing the property, you have to reload the currently open projects.";
Expand Down Expand Up @@ -77,7 +82,8 @@ public void loadOptions(Style style, boolean paramBoolean) {
@Override
public void setDefaultValues() {
super.setDefaultValues();
createUseEmptyQueryScope(false);
createDiagramContentIndexingProperty(false);
createUseEmptyQueryScopeProperty(false);
setEditability(getProperty(USE_EMPTY_QUERY_SCOPE_ID));
}

Expand All @@ -100,7 +106,7 @@ public boolean isEmptyQueryScopeRequired() {
return returnValue;
}

public void createUseEmptyQueryScope(boolean value) {
public void createUseEmptyQueryScopeProperty(boolean value) {
Property emptyScopeProperty = new BooleanProperty(USE_EMPTY_QUERY_SCOPE_ID, value);
emptyScopeProperty.setGroup(V4MD_GROUP_DEBUGGING_NAME);
emptyScopeProperty.setResourceProvider(new PropertyResourceProvider() {
Expand All @@ -117,6 +123,38 @@ public String getString(String key, Property property) {
addProperty(emptyScopeProperty, USE_EMPTY_QUERY_SCOPE_DESCRIPTION_ID);
}

@Used
public boolean isDiagramContentIndexingEnabled() {

Property p = getProperty(INDEX_DIAGRAM_ID);
if (p == null) {
logger.info("Diagram Content Indexing property is not yet set.");
return false; // This property is not yet set.
}

Boolean returnValue = (Boolean) p.getValue();
logger.info("Diagram Content Indexing property is currently set to " + returnValue.toString() + ".");
return returnValue;
}

public void createDiagramContentIndexingProperty(boolean value) {
Property emptyScopeProperty = new BooleanProperty(INDEX_DIAGRAM_ID, value);
emptyScopeProperty.setGroup(V4MD_GROUP_ADVANCED_NAME);
emptyScopeProperty.setResourceProvider(new PropertyResourceProvider() {

@Override
public String getString(String key, Property property) {
if (Objects.equals(INDEX_DIAGRAM_ID, key))
return INDEX_DIAGRAM_NAME;
if (Objects.equals(INDEX_DIAGRAM_DESCRIPTION_ID, key))
return INDEX_DIAGRAM_DESCRIPTION;
return key;
}
});
addProperty(emptyScopeProperty, INDEX_DIAGRAM_DESCRIPTION_ID);
logger.info("Diagram Content Indexing property is set to default.");
}

private void setEditability(@CheckForNull Property p) {
if(p == null) return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ private static MagicDrawProjectScope createMagicDrawProjectScope(Project project
if(V4MDSpecificEnvironmentOptionsGroup.getCurrentGroup().isEmptyQueryScopeRequired()) {
return MagicDrawProjectScope.createMagicDrawEmptyProjectScope(project);
}
return new MagicDrawProjectScope(project, ViatraQueryAdapterOptions.getInstance().isEnableEngineProfiling(), notifiers);

boolean enableDiagramContentIndexing = V4MDSpecificEnvironmentOptionsGroup.getCurrentGroup().isDiagramContentIndexingEnabled();
boolean enableProfiler = ViatraQueryAdapterOptions.getInstance().isEnableEngineProfiling();
LOGGER.info("Initializing MagicDrawProject Scope with parameters enableProfiler=" + enableProfiler +" enableDiagramContentIndexing=" + enableDiagramContentIndexing);
return new MagicDrawProjectScope(project, enableProfiler, enableDiagramContentIndexing, notifiers);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,55 +31,88 @@ public class MagicDrawProjectScope extends EMFScope {
private List<IProjectChangedListener> listeners = new ArrayList<>();
private boolean useEmptyQueryScope = false;

// 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 && isReferenceToBeFiltered((EReference) reference))
// 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 && isReferenceToBeFiltered((EReference) reference, false))
.withStrictNotificationMode(false);
private static final BaseIndexOptions BASE_OPTIONS_WITH_PROFILER = BASE_OPTIONS.withIndexProfilerMode(ProfilerMode.START_DISABLED);

private static boolean isReferenceToBeFiltered(EReference reference) {
private static final BaseIndexOptions BASE_OPTIONS_ENABLE_DIAGRAM = new BaseIndexOptions()
.withFeatureFilterConfiguration(
reference -> reference instanceof EReference && isReferenceToBeFiltered((EReference) reference, true))
.withStrictNotificationMode(false);
private static final BaseIndexOptions BASE_OPTIONS_WITH_PROFILER = BASE_OPTIONS
.withIndexProfilerMode(ProfilerMode.START_DISABLED);
private static final BaseIndexOptions BASE_OPTIONS_ENABLE_DIAGRAM_WITH_PROFILER = BASE_OPTIONS_ENABLE_DIAGRAM
.withIndexProfilerMode(ProfilerMode.START_DISABLED);

private static boolean isReferenceToBeFiltered(EReference reference, boolean enableDiagramContentIndexing) {
String name = reference.getName();
return (reference.isContainment() && name.contains("_from_"))
||
name.startsWith("_");
if (reference.isContainment() && name.contains("_from_")) {
return true;
} else if (enableDiagramContentIndexing && name.equals("_representation")) {
/*
* "_representation" is a special feature of the MagicDraw metamodel that
* describes the containment of diagram related representation elements
*/
return false;
} else if (name.startsWith("_")) {
return true;
}
return false;
}

static BaseIndexOptions getBaseIndexOptions(boolean enableProfiler, boolean enableDiagramContentIndexing) {
if(enableProfiler) {
if(enableDiagramContentIndexing)
return BASE_OPTIONS_ENABLE_DIAGRAM_WITH_PROFILER;
return BASE_OPTIONS_WITH_PROFILER;
} else {
if(enableDiagramContentIndexing)
return BASE_OPTIONS_ENABLE_DIAGRAM;
return BASE_OPTIONS;
}
}

static Stream<? extends Notifier> getProjectModels(Project projectModel) {
Package primaryModel = projectModel.getPrimaryModel();
return projectModel.getModels().stream().filter(pkg -> pkg == primaryModel || !EcoreUtil.isAncestor(primaryModel, pkg));
}

static Stream<Notifier> getCustomNotifiers(Notifier... notifiers) {
return Arrays.stream(notifiers);
}

/**
* A special constructor that provides the ability to create empty scope.
*/
private MagicDrawProjectScope(Project project) {
super(new ResourceSetImpl(), BASE_OPTIONS); //Mocking a dummy notifier
super(new ResourceSetImpl(), BASE_OPTIONS); // Mocking a dummy notifier
this.project = project;
this.customNotifiers = new Notifier[0];
this.useEmptyQueryScope = true;
}

/**
* Returns a special empty project scope associated to the given project where only a dummy notifier is indexed.
* Returns a special empty project scope associated to the given project where
* only a dummy notifier is indexed.
*
* @param project associated to the empty scope
* @return a special empty project scope
*/
public static MagicDrawProjectScope createMagicDrawEmptyProjectScope(Project project) {
return new MagicDrawProjectScope(project);
}

public MagicDrawProjectScope(Project project, Notifier... notifiers) {
this(project, false, notifiers);
this(project, false, false, notifiers);
}
public MagicDrawProjectScope(Project project, boolean enableProfiler, Notifier... notifiers) {

public MagicDrawProjectScope(Project project, boolean enableProfiler, boolean enableDiagramContentIndexing, Notifier... notifiers) {
super(Stream.concat(getProjectModels(project), getCustomNotifiers(notifiers)).collect(Collectors.toSet()),
enableProfiler ? BASE_OPTIONS_WITH_PROFILER : BASE_OPTIONS);
getBaseIndexOptions(enableProfiler, enableDiagramContentIndexing));
this.project = project;
this.customNotifiers = notifiers;
}
Expand All @@ -93,25 +126,28 @@ protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexing
Logger logger) {
return new MagicDrawProjectEngineContext(this, errorListener, logger, useEmptyQueryScope);
}

public void projectStructureUpdated() {
for (IProjectChangedListener listener : listeners) {
listener.modelSetUpdated();
}
}

Stream<? extends Notifier> getProjectModels() {
return getProjectModels(project);
}

Stream<Notifier> getCustomNotifiers() {
return getCustomNotifiers(customNotifiers);
}

public static MagicDrawProjectNavigationHelper extractNavigationHelper(ViatraQueryEngine engine) {
final QueryScope scope = engine.getScope();
if (scope instanceof MagicDrawProjectScope)
return (MagicDrawProjectNavigationHelper) ((EMFBaseIndexWrapper)AdvancedViatraQueryEngine.from(engine).getBaseIndex()).getNavigationHelper();
else throw new IllegalArgumentException("Cannot extract EMF base index from VIATRA Query engine instantiated on non-EMF scope " + scope);
if (scope instanceof MagicDrawProjectScope)
return (MagicDrawProjectNavigationHelper) ((EMFBaseIndexWrapper) AdvancedViatraQueryEngine.from(engine)
.getBaseIndex()).getNavigationHelper();
else
throw new IllegalArgumentException(
"Cannot extract EMF base index from VIATRA Query engine instantiated on non-EMF scope " + scope);
}
}