aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime/src/main
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-19 03:00:23 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-19 03:00:23 +0200
commitfc7e3dc61a2ac8de32914af331c1144e4fa843e6 (patch)
treef17f58c9a14700e76c4b54b242c0bca061199e1f /subprojects/viatra-runtime/src/main
parentchore: import VIATRA source (diff)
downloadrefinery-fc7e3dc61a2ac8de32914af331c1144e4fa843e6.tar.gz
refinery-fc7e3dc61a2ac8de32914af331c1144e4fa843e6.tar.zst
refinery-fc7e3dc61a2ac8de32914af331c1144e4fa843e6.zip
refactor: remove unused VIATRA code
We don't need Eclipse platform support, table-based scopes, and EMF support.
Diffstat (limited to 'subprojects/viatra-runtime/src/main')
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/IExtensions.java24
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/ViatraQueryRuntimePlugin.java32
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java163
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IModelConnectorTypeEnum.java18
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IRunOnceQueryEngine.java68
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/LazyLoadingQueryGroup.java64
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/PackageBasedQueryGroup.java133
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java2
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java77
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFPQuery.java110
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFQuerySpecification.java40
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFQuerySpecificationWithGenericMatcher.java58
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java40
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/RunOnceQueryEngine.java140
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java8
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/DynamicEMFQueryRuntimeContext.java47
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFBaseIndexWrapper.java160
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFEngineContext.java110
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFQueryMetaContext.java405
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFQueryRuntimeContext.java839
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFScope.java199
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/helper/ViatraQueryRuntimeHelper.java161
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/BaseEMFTypeKey.java34
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassExactInstancesKey.java51
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassTransitiveInstancesKey.java47
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassUnscopedTransitiveInstancesKey.java46
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EDataTypeInSlotsKey.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EStructuralFeatureInstancesKey.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/IQueryGroupProvider.java40
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/IQuerySpecificationProvider.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/PQueryExtensionFactory.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonExtensionFactory.java62
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonQueryGroupProvider.java46
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonQuerySpecificationProvider.java42
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/ViatraQueryRuntimeConstants.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/ExtensionBasedSurrogateQueryLoader.java148
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/ExtensionBasedSystemDefaultBackendLoader.java60
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java15
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/ExtensionBasedQuerySpecificationLoader.java303
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IConnectorListener.java40
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IDefaultRegistryView.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistry.java74
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistryChangeListener.java35
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistryEntry.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistrySourceConnector.java50
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryView.java72
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryViewFactory.java34
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryViewFilter.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/QuerySpecificationRegistry.java112
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/AbstractRegistrySourceConnector.java81
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/QueryGroupProviderSourceConnector.java80
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/SpecificationMapSourceConnector.java147
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/QuerySpecificationStore.java38
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/RegistryEntryImpl.java81
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/RegistrySourceImpl.java73
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/FilteringRegistryView.java43
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/GlobalRegistryView.java65
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/QuerySpecificationRegistryImpl.java177
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/RegistryChangeMultiplexer.java58
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/view/AbstractRegistryView.java150
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/EcoreIndexHost.java166
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/TabularEngineContext.java107
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/TabularIndexHost.java145
64 files changed, 145 insertions, 5822 deletions
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/IExtensions.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/IExtensions.java
deleted file mode 100644
index d5e0d51f..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/IExtensions.java
+++ /dev/null
@@ -1,24 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime;
11
12/**
13 * Interface for storing string constants related to VIATRA Query's extension points.
14 *
15 * @author Istvan Rath
16 *
17 */
18public interface IExtensions {
19
20 public static final String QUERY_SPECIFICATION_EXTENSION_POINT_ID = ViatraQueryRuntimePlugin.PLUGIN_ID + ".queryspecification";
21
22 public static final String INJECTOREXTENSIONID = ViatraQueryRuntimePlugin.PLUGIN_ID + ".injectorprovider";
23
24}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/ViatraQueryRuntimePlugin.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/ViatraQueryRuntimePlugin.java
deleted file mode 100644
index 5fbcdad0..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/ViatraQueryRuntimePlugin.java
+++ /dev/null
@@ -1,32 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime;
10
11import org.eclipse.core.runtime.Plugin;
12import tools.refinery.viatra.runtime.internal.ExtensionBasedSurrogateQueryLoader;
13import tools.refinery.viatra.runtime.internal.ExtensionBasedSystemDefaultBackendLoader;
14import tools.refinery.viatra.runtime.registry.ExtensionBasedQuerySpecificationLoader;
15import org.osgi.framework.BundleContext;
16
17/**
18 * The activator class controls the plug-in life cycle
19 */
20public class ViatraQueryRuntimePlugin extends Plugin {
21
22 public static final String PLUGIN_ID = "tools.refinery.viatra.runtime";
23
24 @Override
25 public void start(BundleContext context) throws Exception {
26 super.start(context);
27 ExtensionBasedSurrogateQueryLoader.instance().loadKnownSurrogateQueriesIntoRegistry();
28 ExtensionBasedQuerySpecificationLoader.getInstance().loadRegisteredQuerySpecificationsIntoRegistry();
29 ExtensionBasedSystemDefaultBackendLoader.instance().loadKnownBackends();
30 }
31
32}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java
index 21e7dfa3..32a3430d 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java
@@ -3,32 +3,27 @@
3 * This program and the accompanying materials are made available under the 3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at 4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 5 * http://www.eclipse.org/legal/epl-v20.html.
6 * 6 *
7 * SPDX-License-Identifier: EPL-2.0 7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/ 8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api; 9package tools.refinery.viatra.runtime.api;
10 10
11import java.lang.reflect.InvocationTargetException;
12import java.util.concurrent.Callable;
13
14import tools.refinery.viatra.runtime.api.scope.QueryScope; 11import tools.refinery.viatra.runtime.api.scope.QueryScope;
15import tools.refinery.viatra.runtime.emf.EMFScope;
16import tools.refinery.viatra.runtime.internal.apiimpl.ViatraQueryEngineImpl; 12import tools.refinery.viatra.runtime.internal.apiimpl.ViatraQueryEngineImpl;
17import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; 13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
18import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability; 14import tools.refinery.viatra.runtime.matchers.backend.*;
19import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend; 15
20import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory; 16import java.lang.reflect.InvocationTargetException;
21import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider; 17import java.util.concurrent.Callable;
22import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
23 18
24/** 19/**
25 * Advanced interface to a VIATRA incremental evaluation engine. 20 * Advanced interface to a VIATRA incremental evaluation engine.
26 * 21 *
27 * <p> 22 * <p>
28 * You can create a new, private, unmanaged {@link AdvancedViatraQueryEngine} instance using 23 * You can create a new, private, unmanaged {@link AdvancedViatraQueryEngine} instance using
29 * {@link #createUnmanagedEngine(QueryScope)}. Additionally, you can access the advanced interface on any 24 * {@link #createUnmanagedEngine(QueryScope)}. Additionally, you can access the advanced interface on any
30 * {@link ViatraQueryEngine} by {@link AdvancedViatraQueryEngine#from(ViatraQueryEngine)}. 25 * {@link ViatraQueryEngine} by {@link AdvancedViatraQueryEngine#from(ViatraQueryEngine)}.
31 * 26 *
32 * <p> 27 * <p>
33 * While the default interface {@link ViatraQueryEngine}, is suitable for most users, this advanced interface provides more 28 * While the default interface {@link ViatraQueryEngine}, is suitable for most users, this advanced interface provides more
34 * control over the engine. The most important added functionality is the following: 29 * control over the engine. The most important added functionality is the following:
@@ -45,29 +40,29 @@ import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
45 * register a callback using {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client 40 * register a callback using {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client
46 * has called the destructive methods {@link #dispose()} or {@link #wipe()}. 41 * has called the destructive methods {@link #dispose()} or {@link #wipe()}.
47 * </ul> 42 * </ul>
48 * 43 *
49 * @author Bergmann Gabor 44 * @author Bergmann Gabor
50 * @noextend This class is not intended to be subclassed by clients. 45 * @noextend This class is not intended to be subclassed by clients.
51 */ 46 */
52public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine { 47public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
53 48
54 /** 49 /**
55 * Creates a new unmanaged VIATRA Query engine to evaluate queries over a given scope specified by an {@link QueryScope}. 50 * Creates a new unmanaged VIATRA Query engine to evaluate queries over a given scope specified by an {@link QueryScope}.
56 * 51 *
57 * <p> Repeated invocations will return different instances, so other clients are unable to independently access 52 * <p> Repeated invocations will return different instances, so other clients are unable to independently access
58 * and influence the returned engine. Note that unmanaged engines do not benefit from some performance improvements 53 * and influence the returned engine. Note that unmanaged engines do not benefit from some performance improvements
59 * that stem from sharing incrementally maintained indices and caches between multiple clients using the same managed 54 * that stem from sharing incrementally maintained indices and caches between multiple clients using the same managed
60 * engine instance. 55 * engine instance.
61 * 56 *
62 * <p> 57 * <p>
63 * Client is responsible for the lifecycle of the returned engine, hence the usage of the advanced interface 58 * Client is responsible for the lifecycle of the returned engine, hence the usage of the advanced interface
64 * {@link AdvancedViatraQueryEngine}. 59 * {@link AdvancedViatraQueryEngine}.
65 * 60 *
66 * <p> 61 * <p>
67 * The match set of any patterns will be incrementally refreshed upon updates from this scope. 62 * The match set of any patterns will be incrementally refreshed upon updates from this scope.
68 * 63 *
69 * @param scope 64 * @param scope
70 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on. 65 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
71 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model. 66 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
72 * @return the advanced interface to a newly created unmanaged engine 67 * @return the advanced interface to a newly created unmanaged engine
73 * @since 0.9 68 * @since 0.9
@@ -75,24 +70,24 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
75 public static AdvancedViatraQueryEngine createUnmanagedEngine(QueryScope scope) { 70 public static AdvancedViatraQueryEngine createUnmanagedEngine(QueryScope scope) {
76 return new ViatraQueryEngineImpl(null, scope); 71 return new ViatraQueryEngineImpl(null, scope);
77 } 72 }
78 73
79 /** 74 /**
80 * Creates a new unmanaged VIATRA Query engine to evaluate queries over a given scope specified by an {@link QueryScope}. 75 * Creates a new unmanaged VIATRA Query engine to evaluate queries over a given scope specified by an {@link QueryScope}.
81 * 76 *
82 * <p> Repeated invocations will return different instances, so other clients are unable to independently access 77 * <p> Repeated invocations will return different instances, so other clients are unable to independently access
83 * and influence the returned engine. Note that unmanaged engines do not benefit from some performance improvements 78 * and influence the returned engine. Note that unmanaged engines do not benefit from some performance improvements
84 * that stem from sharing incrementally maintained indices and caches between multiple clients using the same managed 79 * that stem from sharing incrementally maintained indices and caches between multiple clients using the same managed
85 * engine instance. 80 * engine instance.
86 * 81 *
87 * <p> 82 * <p>
88 * Client is responsible for the lifecycle of the returned engine, hence the usage of the advanced interface 83 * Client is responsible for the lifecycle of the returned engine, hence the usage of the advanced interface
89 * {@link AdvancedViatraQueryEngine}. 84 * {@link AdvancedViatraQueryEngine}.
90 * 85 *
91 * <p> 86 * <p>
92 * The match set of any patterns will be incrementally refreshed upon updates from this scope. 87 * The match set of any patterns will be incrementally refreshed upon updates from this scope.
93 * 88 *
94 * @param scope 89 * @param scope
95 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on. 90 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
96 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model. 91 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
97 * @return the advanced interface to a newly created unmanaged engine 92 * @return the advanced interface to a newly created unmanaged engine
98 * @since 1.4 93 * @since 1.4
@@ -103,11 +98,11 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
103 98
104 /** 99 /**
105 * Provides access to a given existing engine through the advanced interface. 100 * Provides access to a given existing engine through the advanced interface.
106 * 101 *
107 * <p> 102 * <p>
108 * Caveat: if the referenced engine is managed (i.e. created via {@link ViatraQueryEngine#on(QueryScope)}), the advanced 103 * Caveat: if the referenced engine is managed (i.e. created via {@link ViatraQueryEngine#on(QueryScope)}), the advanced
109 * methods {@link #dispose()} and {@link #wipe()} will not be allowed. 104 * methods {@link #dispose()} and {@link #wipe()} will not be allowed.
110 * 105 *
111 * @param engine 106 * @param engine
112 * the engine to access using the advanced interface 107 * the engine to access using the advanced interface
113 * @return a reference to the same engine conforming to the advanced interface 108 * @return a reference to the same engine conforming to the advanced interface
@@ -118,7 +113,7 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
118 113
119 /** 114 /**
120 * Add an engine lifecycle listener to this engine instance. 115 * Add an engine lifecycle listener to this engine instance.
121 * 116 *
122 * @param listener 117 * @param listener
123 * the {@link ViatraQueryEngineLifecycleListener} that should listen to lifecycle events from this engine 118 * the {@link ViatraQueryEngineLifecycleListener} that should listen to lifecycle events from this engine
124 */ 119 */
@@ -126,7 +121,7 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
126 121
127 /** 122 /**
128 * Remove an existing lifecycle listener from this engine instance. 123 * Remove an existing lifecycle listener from this engine instance.
129 * 124 *
130 * @param listener 125 * @param listener
131 * the {@link ViatraQueryEngineLifecycleListener} that should not listen to lifecycle events from this 126 * the {@link ViatraQueryEngineLifecycleListener} that should not listen to lifecycle events from this
132 * engine anymore 127 * engine anymore
@@ -136,7 +131,7 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
136 /** 131 /**
137 * Add an model update event listener to this engine instance (that fires its callbacks according to its 132 * Add an model update event listener to this engine instance (that fires its callbacks according to its
138 * notification level). 133 * notification level).
139 * 134 *
140 * @param listener 135 * @param listener
141 * the {@link ViatraQueryModelUpdateListener} that should listen to model update events from this engine. 136 * the {@link ViatraQueryModelUpdateListener} that should listen to model update events from this engine.
142 */ 137 */
@@ -144,7 +139,7 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
144 139
145 /** 140 /**
146 * Remove an existing model update event listener to this engine instance. 141 * Remove an existing model update event listener to this engine instance.
147 * 142 *
148 * @param listener 143 * @param listener
149 * the {@link ViatraQueryModelUpdateListener} that should not listen to model update events from this engine 144 * the {@link ViatraQueryModelUpdateListener} that should not listen to model update events from this engine
150 * anymore 145 * anymore
@@ -153,20 +148,20 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
153 148
154 /** 149 /**
155 * Registers low-level callbacks for match appearance and disappearance on this pattern matcher. 150 * Registers low-level callbacks for match appearance and disappearance on this pattern matcher.
156 * 151 *
157 * <p> 152 * <p>
158 * <b>Caution: </b> This is a low-level callback that is invoked when the pattern matcher is not necessarily in a 153 * <b>Caution: </b> This is a low-level callback that is invoked when the pattern matcher is not necessarily in a
159 * consistent state yet. Importantly, no model modification permitted during the callback. Most users should use the 154 * consistent state yet. Importantly, no model modification permitted during the callback. Most users should use the
160 * databinding support ({@link org.eclipse.viatra.addon.databinding.runtime.api.ViatraObservables ViatraObservables}) or the event-driven API 155 * databinding support ({@link org.eclipse.viatra.addon.databinding.runtime.api.ViatraObservables ViatraObservables}) or the event-driven API
161 * ({@link org.eclipse.viatra.transformation.evm.api.EventDrivenVM EventDrivenVM}) instead. 156 * ({@link org.eclipse.viatra.transformation.evm.api.EventDrivenVM EventDrivenVM}) instead.
162 * 157 *
163 * <p> 158 * <p>
164 * Performance note: expected to be much more efficient than polling at {@link #addCallbackAfterUpdates(Runnable)}, 159 * Performance note: expected to be much more efficient than polling at {@link #addCallbackAfterUpdates(Runnable)},
165 * but prone to "signal hazards", e.g. spurious match appearances that will disappear immediately afterwards. 160 * but prone to "signal hazards", e.g. spurious match appearances that will disappear immediately afterwards.
166 * 161 *
167 * <p> 162 * <p>
168 * The callback can be unregistered via {@link #removeCallbackOnMatchUpdate(IMatchUpdateListener)}. 163 * The callback can be unregistered via {@link #removeCallbackOnMatchUpdate(IMatchUpdateListener)}.
169 * 164 *
170 * @param fireNow 165 * @param fireNow
171 * if true, appearCallback will be immediately invoked on all current matches as a one-time effect. See 166 * if true, appearCallback will be immediately invoked on all current matches as a one-time effect. See
172 * also {@link ViatraQueryMatcher#forEachMatch(IMatchProcessor)}. 167 * also {@link ViatraQueryMatcher#forEachMatch(IMatchProcessor)}.
@@ -180,7 +175,7 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
180 175
181 /** 176 /**
182 * Remove an existing match update event listener to this engine instance. 177 * Remove an existing match update event listener to this engine instance.
183 * 178 *
184 * @param matcher 179 * @param matcher
185 * the {@link ViatraQueryMatcher} for which this listener should not be active anymore 180 * the {@link ViatraQueryMatcher} for which this listener should not be active anymore
186 * @param listener 181 * @param listener
@@ -189,15 +184,15 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
189 public abstract <Match extends IPatternMatch> void removeMatchUpdateListener(ViatraQueryMatcher<Match> matcher, 184 public abstract <Match extends IPatternMatch> void removeMatchUpdateListener(ViatraQueryMatcher<Match> matcher,
190 IMatchUpdateListener<? super Match> listener); 185 IMatchUpdateListener<? super Match> listener);
191 186
192 187
193 /** 188 /**
194 * Access a pattern matcher based on a {@link IQuerySpecification}, overriding some of the default query evaluation hints. 189 * Access a pattern matcher based on a {@link IQuerySpecification}, overriding some of the default query evaluation hints.
195 * Multiple calls may return the same matcher depending on the actual evaluation hints. 190 * Multiple calls may return the same matcher depending on the actual evaluation hints.
196 * 191 *
197 * <p> It is guaranteed that this method will always return a matcher instance which is functionally compatible 192 * <p> It is guaranteed that this method will always return a matcher instance which is functionally compatible
198 * with the requested functionality (see {@link IMatcherCapability}). 193 * with the requested functionality (see {@link IMatcherCapability}).
199 * Otherwise, the query evaluator is free to ignore any hints. 194 * Otherwise, the query evaluator is free to ignore any hints.
200 * 195 *
201 * <p> For stateful query backends (Rete), hints may be effective only the first time a matcher is created. 196 * <p> For stateful query backends (Rete), hints may be effective only the first time a matcher is created.
202 * @param querySpecification a {@link IQuerySpecification} that describes a VIATRA query 197 * @param querySpecification a {@link IQuerySpecification} that describes a VIATRA query
203 * @return a pattern matcher corresponding to the specification 198 * @return a pattern matcher corresponding to the specification
@@ -206,20 +201,20 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
206 * @since 0.9 201 * @since 0.9
207 */ 202 */
208 public abstract <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getMatcher( 203 public abstract <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getMatcher(
209 IQuerySpecification<Matcher> querySpecification, 204 IQuerySpecification<Matcher> querySpecification,
210 QueryEvaluationHint optionalEvaluationHints); 205 QueryEvaluationHint optionalEvaluationHints);
211 206
212 /** 207 /**
213 * Initializes matchers for a group of patterns as one step (optionally overriding some of the default query evaluation hints). 208 * Initializes matchers for a group of patterns as one step (optionally overriding some of the default query evaluation hints).
214 * If some of the pattern matchers are already 209 * If some of the pattern matchers are already
215 * constructed in the engine, no task is performed for them. 210 * constructed in the engine, no task is performed for them.
216 * 211 *
217 * <p> 212 * <p>
218 * This preparation step has the advantage that it prepares pattern matchers for an arbitrary number of patterns in a 213 * This preparation step has the advantage that it prepares pattern matchers for an arbitrary number of patterns in a
219 * single-pass traversal of the model. 214 * single-pass traversal of the model.
220 * This is typically more efficient than traversing the model each time an individual pattern matcher is initialized on demand. 215 * This is typically more efficient than traversing the model each time an individual pattern matcher is initialized on demand.
221 * The performance benefit only manifests itself if the engine is not in wildcard mode. 216 * The performance benefit only manifests itself if the engine is not in wildcard mode.
222 * 217 *
223 * @param queryGroup a {@link IQueryGroup} identifying a set of VIATRA queries 218 * @param queryGroup a {@link IQueryGroup} identifying a set of VIATRA queries
224 * @param optionalEvaluationHints additional / overriding options on query evaluation; passing null means default options associated with each query 219 * @param optionalEvaluationHints additional / overriding options on query evaluation; passing null means default options associated with each query
225 * @throws ViatraQueryRuntimeException 220 * @throws ViatraQueryRuntimeException
@@ -227,23 +222,23 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
227 * @since 0.9 222 * @since 0.9
228 */ 223 */
229 public abstract void prepareGroup(IQueryGroup queryGroup, QueryEvaluationHint optionalEvaluationHints); 224 public abstract void prepareGroup(IQueryGroup queryGroup, QueryEvaluationHint optionalEvaluationHints);
230 225
231 /** 226 /**
232 * Indicates whether the engine is managed, i.e. the default engine assigned to the given scope root by 227 * Indicates whether the engine is managed, i.e. the default engine assigned to the given scope root by
233 * {@link ViatraQueryEngine#on(QueryScope)}. 228 * {@link ViatraQueryEngine#on(QueryScope)}.
234 * 229 *
235 * <p> 230 * <p>
236 * If the engine is managed, there may be other clients using it, as all calls to 231 * If the engine is managed, there may be other clients using it, as all calls to
237 * {@link ViatraQueryEngine#on(QueryScope)} return the same managed engine instance for a given scope root. Therefore the 232 * {@link ViatraQueryEngine#on(QueryScope)} return the same managed engine instance for a given scope root. Therefore the
238 * destructive methods {@link #wipe()} and {@link #dispose()} are not allowed. 233 * destructive methods {@link #wipe()} and {@link #dispose()} are not allowed.
239 * 234 *
240 * <p> 235 * <p>
241 * On the other hand, if the engine is unmanaged (i.e. a private instance created using 236 * On the other hand, if the engine is unmanaged (i.e. a private instance created using
242 * {@link #createUnmanagedEngine(QueryScope)}), then {@link #wipe()} and {@link #dispose()} can be called. If you 237 * {@link #createUnmanagedEngine(QueryScope)}), then {@link #wipe()} and {@link #dispose()} can be called. If you
243 * explicitly share a private, unmanaged engine between multiple sites, register a callback using 238 * explicitly share a private, unmanaged engine between multiple sites, register a callback using
244 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called these 239 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called these
245 * destructive methods. 240 * destructive methods.
246 * 241 *
247 * @return true if the engine is managed, and therefore potentially shared with other clients querying the same EMF 242 * @return true if the engine is managed, and therefore potentially shared with other clients querying the same EMF
248 * model 243 * model
249 */ 244 */
@@ -252,11 +247,11 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
252 /** 247 /**
253 * Indicates whether the engine is in a tainted, inconsistent state due to some internal errors. If true, results 248 * Indicates whether the engine is in a tainted, inconsistent state due to some internal errors. If true, results
254 * are no longer reliable; engine should be disposed. 249 * are no longer reliable; engine should be disposed.
255 * 250 *
256 * <p> 251 * <p>
257 * The engine is in a tainted state if any of its internal processes report back a fatal error. The 252 * The engine is in a tainted state if any of its internal processes report back a fatal error. The
258 * {@link ViatraQueryEngineLifecycleListener} interface provides a callback method for entering the tainted state. 253 * {@link ViatraQueryEngineLifecycleListener} interface provides a callback method for entering the tainted state.
259 * 254 *
260 * @return the tainted state 255 * @return the tainted state
261 */ 256 */
262 public abstract boolean isTainted(); 257 public abstract boolean isTainted();
@@ -265,7 +260,7 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
265 * Discards any pattern matcher caches and forgets known patterns. The base index built directly on the underlying 260 * Discards any pattern matcher caches and forgets known patterns. The base index built directly on the underlying
266 * EMF model, however, is kept in memory to allow reuse when new pattern matchers are built. Use this method if you 261 * EMF model, however, is kept in memory to allow reuse when new pattern matchers are built. Use this method if you
267 * have e.g. new versions of the same patterns, to be matched on the same model. 262 * have e.g. new versions of the same patterns, to be matched on the same model.
268 * 263 *
269 * <p> 264 * <p>
270 * Matcher objects will continue to return stale results. If no references are retained to the matchers, they can 265 * Matcher objects will continue to return stale results. If no references are retained to the matchers, they can
271 * eventually be GC'ed. 266 * eventually be GC'ed.
@@ -275,7 +270,7 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
275 * If you explicitly share a private, unmanaged engine between multiple sites, register a callback using 270 * If you explicitly share a private, unmanaged engine between multiple sites, register a callback using
276 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called this 271 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called this
277 * destructive method. 272 * destructive method.
278 * 273 *
279 * @throws UnsupportedOperationException 274 * @throws UnsupportedOperationException
280 * if engine is managed 275 * if engine is managed
281 */ 276 */
@@ -295,12 +290,12 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
295 * If you explicitly share a private, unmanaged engine between multiple sites, register a callback using 290 * If you explicitly share a private, unmanaged engine between multiple sites, register a callback using
296 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called this 291 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called this
297 * destructive method. 292 * destructive method.
298 * 293 *
299 * @throws UnsupportedOperationException 294 * @throws UnsupportedOperationException
300 * if engine is managed 295 * if engine is managed
301 */ 296 */
302 public abstract void dispose(); 297 public abstract void dispose();
303 298
304 /** 299 /**
305 * Provides access to the selected query backend component of the VIATRA Query engine. 300 * Provides access to the selected query backend component of the VIATRA Query engine.
306 * @noreference for internal use only 301 * @noreference for internal use only
@@ -316,45 +311,45 @@ public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
316 * @since 1.4 311 * @since 1.4
317 */ 312 */
318 public abstract <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getExistingMatcher(IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalOverrideHints); 313 public abstract <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getExistingMatcher(IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalOverrideHints);
319 314
320 /** 315 /**
321 * Returns the immutable {@link ViatraQueryEngineOptions} of the engine. 316 * Returns the immutable {@link ViatraQueryEngineOptions} of the engine.
322 * 317 *
323 * @return the engine options 318 * @return the engine options
324 * @since 1.4 319 * @since 1.4
325 */ 320 */
326 public abstract ViatraQueryEngineOptions getEngineOptions(); 321 public abstract ViatraQueryEngineOptions getEngineOptions();
327 322
328 /** 323 /**
329 * Return the underlying result provider for the given matcher. 324 * Return the underlying result provider for the given matcher.
330 * 325 *
331 * @beta This method may change in future versions 326 * @beta This method may change in future versions
332 * @since 1.4 327 * @since 1.4
333 * @noreference This method is considered internal API 328 * @noreference This method is considered internal API
334 */ 329 */
335 public abstract IQueryResultProvider getResultProviderOfMatcher(ViatraQueryMatcher<? extends IPatternMatch> matcher); 330 public abstract IQueryResultProvider getResultProviderOfMatcher(ViatraQueryMatcher<? extends IPatternMatch> matcher);
336 331
337 /** 332 /**
338 * The given callable will be executed, and all update propagation in stateful query backends 333 * The given callable will be executed, and all update propagation in stateful query backends
339 * will be delayed until the execution is done. Within the callback, these backends will provide stale results. 334 * will be delayed until the execution is done. Within the callback, these backends will provide stale results.
340 * 335 *
341 * <p> It is optional for a {@link IQueryBackend} to support the delaying of update propagation; stateless backends will display up-to-date results. 336 * <p> It is optional for a {@link IQueryBackend} to support the delaying of update propagation; stateless backends will display up-to-date results.
342 * In this case, the given callable shall be executed, and the update propagation shall happen just like in non-delayed execution. 337 * In this case, the given callable shall be executed, and the update propagation shall happen just like in non-delayed execution.
343 * 338 *
344 * <p> Example: in the Rete network, no messages will be propagated until the given callable is executed. 339 * <p> Example: in the Rete network, no messages will be propagated until the given callable is executed.
345 * After the execution of the callable, all accumulated messages will be delivered. 340 * After the execution of the callable, all accumulated messages will be delivered.
346 * 341 *
347 * <p> The purpose of this method is that stateful query backends may save work when multiple model modifications are performed within the callback that partially cancel each other out. 342 * <p> The purpose of this method is that stateful query backends may save work when multiple model modifications are performed within the callback that partially cancel each other out.
348 * 343 *
349 * @param callable the callable to be executed 344 * @param callable the callable to be executed
350 * @return the result of the callable 345 * @return the result of the callable
351 * @since 1.6 346 * @since 1.6
352 */ 347 */
353 public abstract <V> V delayUpdatePropagation(Callable<V> callable) throws InvocationTargetException; 348 public abstract <V> V delayUpdatePropagation(Callable<V> callable) throws InvocationTargetException;
354 349
355 /** 350 /**
356 * Returns true if the update propagation in this engine is currently delayed, false otherwise. 351 * Returns true if the update propagation in this engine is currently delayed, false otherwise.
357 * 352 *
358 * @see {@link #delayUpdatePropagation(Callable)} 353 * @see {@link #delayUpdatePropagation(Callable)}
359 * @since 1.6 354 * @since 1.6
360 */ 355 */
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IModelConnectorTypeEnum.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IModelConnectorTypeEnum.java
deleted file mode 100644
index e672a6e2..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IModelConnectorTypeEnum.java
+++ /dev/null
@@ -1,18 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Andras Okros, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api;
10
11/**
12 * This enum represents the possible notifier types which a model input should provide for the ui.
13 */
14public enum IModelConnectorTypeEnum {
15
16 RESOURCESET, RESOURCE;
17
18}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java
index 9b84b031..326d2202 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java
@@ -3,14 +3,13 @@
3 * This program and the accompanying materials are made available under the 3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at 4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 5 * http://www.eclipse.org/legal/epl-v20.html.
6 * 6 *
7 * SPDX-License-Identifier: EPL-2.0 7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/ 8 *******************************************************************************/
9 9
10package tools.refinery.viatra.runtime.api; 10package tools.refinery.viatra.runtime.api;
11 11
12import tools.refinery.viatra.runtime.api.scope.QueryScope; 12import tools.refinery.viatra.runtime.api.scope.QueryScope;
13import tools.refinery.viatra.runtime.emf.EMFScope;
14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; 13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery; 14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQueryHeader; 15import tools.refinery.viatra.runtime.matchers.psystem.queries.PQueryHeader;
@@ -18,8 +17,8 @@ import tools.refinery.viatra.runtime.matchers.psystem.queries.PQueryHeader;
18/** 17/**
19 * API interface for a VIATRA query specification. Each query is associated with a pattern. Methods instantiate a matcher 18 * API interface for a VIATRA query specification. Each query is associated with a pattern. Methods instantiate a matcher
20 * of the pattern with various parameters. 19 * of the pattern with various parameters.
21 * 20 *
22 * <p> As of 0.9.0, some internal details (mostly relevant for query evaluator backends) have been moved to {@link #getInternalQueryRepresentation()}. 21 * <p> As of 0.9.0, some internal details (mostly relevant for query evaluator backends) have been moved to {@link #getInternalQueryRepresentation()}.
23 * 22 *
24 * @author Bergmann Gábor 23 * @author Bergmann Gábor
25 * 24 *
@@ -39,49 +38,49 @@ public interface IQuerySpecification<Matcher extends ViatraQueryMatcher<? extend
39 */ 38 */
40 public Matcher getMatcher(ViatraQueryEngine engine); 39 public Matcher getMatcher(ViatraQueryEngine engine);
41 40
42 41
43 /** 42 /**
44 * Returns an empty, mutable Match compatible with matchers of this query. 43 * Returns an empty, mutable Match compatible with matchers of this query.
45 * Fields of the mutable match can be filled to create a partial match, usable as matcher input. 44 * Fields of the mutable match can be filled to create a partial match, usable as matcher input.
46 * This can be used to call the matcher with a partial match 45 * This can be used to call the matcher with a partial match
47 * even if the specific class of the matcher or the match is unknown. 46 * even if the specific class of the matcher or the match is unknown.
48 * 47 *
49 * @return the empty match 48 * @return the empty match
50 */ 49 */
51 public abstract IPatternMatch newEmptyMatch(); 50 public abstract IPatternMatch newEmptyMatch();
52 51
53 /** 52 /**
54 * Returns a new (partial) Match object compatible with matchers of this query. 53 * Returns a new (partial) Match object compatible with matchers of this query.
55 * This can be used e.g. to call the matcher with a partial 54 * This can be used e.g. to call the matcher with a partial
56 * match. 55 * match.
57 * 56 *
58 * <p>The returned match will be immutable. Use {@link #newEmptyMatch()} to obtain a mutable match object. 57 * <p>The returned match will be immutable. Use {@link #newEmptyMatch()} to obtain a mutable match object.
59 * 58 *
60 * @param parameters 59 * @param parameters
61 * the fixed value of pattern parameters, or null if not bound. 60 * the fixed value of pattern parameters, or null if not bound.
62 * @return the (partial) match object. 61 * @return the (partial) match object.
63 */ 62 */
64 public abstract IPatternMatch newMatch(Object... parameters); 63 public abstract IPatternMatch newMatch(Object... parameters);
65 64
66 /** 65 /**
67 * The query is formulated over this kind of modeling platform. 66 * The query is formulated over this kind of modeling platform.
68 * E.g. for queries over EMF models, the {@link EMFScope} class is returned. 67 * E.g. for queries over EMF models, the {@link EMFScope} class is returned.
69 */ 68 */
70 public Class<? extends QueryScope> getPreferredScopeClass(); 69 public Class<? extends QueryScope> getPreferredScopeClass();
71 70
72 /** 71 /**
73 * Returns the definition of the query in a format intended for consumption by the query evaluator. 72 * Returns the definition of the query in a format intended for consumption by the query evaluator.
74 * @return the internal representation of the query. 73 * @return the internal representation of the query.
75 */ 74 */
76 public PQuery getInternalQueryRepresentation(); 75 public PQuery getInternalQueryRepresentation();
77 76
78 /** 77 /**
79 * Creates a new uninitialized matcher, which is not functional until an engine initializes it. Clients 78 * Creates a new uninitialized matcher, which is not functional until an engine initializes it. Clients
80 * should not call this method, it is used by the {@link ViatraQueryEngine} instance to instantiate matchers. 79 * should not call this method, it is used by the {@link ViatraQueryEngine} instance to instantiate matchers.
81 * @throws ViatraQueryRuntimeException 80 * @throws ViatraQueryRuntimeException
82 * @noreference This method is not intended to be referenced by clients. 81 * @noreference This method is not intended to be referenced by clients.
83 * @since 1.4 82 * @since 1.4
84 */ 83 */
85 public Matcher instantiate(); 84 public Matcher instantiate();
86 85
87} 86}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IRunOnceQueryEngine.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IRunOnceQueryEngine.java
deleted file mode 100644
index b625980b..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IRunOnceQueryEngine.java
+++ /dev/null
@@ -1,68 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api;
10
11import java.util.Collection;
12
13import org.eclipse.emf.common.notify.Notifier;
14import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
15import tools.refinery.viatra.runtime.base.api.NavigationHelper;
16
17/**
18 * A run-once query engine is used to get matches for queries without incremental support.
19 * Users can create a query engine with a given {@link Notifier} as scope and use a query specification
20 * to retrieve the current match set with this scope (see {@link #getAllMatches}).
21 *
22 * @author Abel Hegedus
23 *
24 */
25public interface IRunOnceQueryEngine {
26
27 /**
28 * Returns the set of all matches for the given query in the scope of the engine.
29 *
30 * @param querySpecification the query that is evaluated
31 * @return matches represented as a Match object.
32 */
33 <Match extends IPatternMatch> Collection<Match> getAllMatches(
34 final IQuerySpecification<? extends ViatraQueryMatcher<Match>> querySpecification);
35
36 /**
37 * @return the scope of pattern matching, i.e. the root of the EMF model tree that this engine is attached to.
38 */
39 Notifier getScope();
40
41 /**
42 * The base index options specifies how the base index is built, including wildcard mode (defaults to false) and
43 * dynamic EMF mode (defaults to false). See {@link NavigationHelper} for the explanation of wildcard mode and
44 * dynamic EMF mode.
45 *
46 * <p/> The returned options can be modified in order to affect subsequent calls of {@link #getAllMatches}.
47 *
48 * @return the base index options used by the engine.
49 */
50 BaseIndexOptions getBaseIndexOptions();
51
52 /**
53 * When set to true, the run-once query engine will not dispose it's engine and will resample the values of derived
54 * features before returning matches if the model changed since the last call.
55 *
56 * If the values of derived features may change without any model modification, call {@link #resampleOnNextCall()}
57 * before subsequent calls of {@link #getAllMatches}.
58 *
59 * @param automaticResampling
60 */
61 void setAutomaticResampling(boolean automaticResampling);
62
63 /**
64 * If automatic resampling is enabled and the value of derived features may change without model modifications,
65 * calling this method will make sure that re-sampling will occur before returning match results.
66 */
67 void resampleOnNextCall();
68}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/LazyLoadingQueryGroup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/LazyLoadingQueryGroup.java
deleted file mode 100644
index 6ae44b7c..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/LazyLoadingQueryGroup.java
+++ /dev/null
@@ -1,64 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api;
10
11import java.util.Collections;
12import java.util.Objects;
13import java.util.Set;
14import java.util.function.Supplier;
15import java.util.stream.Collectors;
16
17import tools.refinery.viatra.runtime.api.impl.BaseQueryGroup;
18import tools.refinery.viatra.runtime.matchers.util.Preconditions;
19import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
20
21/**
22 * Initializes a query group from a set of query providers. The query providers are not executed until the queries
23 * themselves are asked in the {@link #getSpecifications()} method.
24 *
25 * @author Zoltan Ujhelyi
26 * @since 1.3
27 *
28 */
29public class LazyLoadingQueryGroup extends BaseQueryGroup {
30
31 private final Set<? extends Supplier<IQuerySpecification<?>>> providers;
32 private Set<IQuerySpecification<?>> specifications = null;
33
34 /**
35 * @param providers a non-null set to initialize the group
36 */
37 public LazyLoadingQueryGroup(Set<? extends Supplier<IQuerySpecification<?>>> providers) {
38 Preconditions.checkArgument(providers != null, "The set of providers must not be null");
39 this.providers = providers;
40 }
41
42 /**
43 * @param providers a non-null set to initialize the group
44 */
45 public static IQueryGroup of(Set<? extends Supplier<IQuerySpecification<?>>> querySpecifications) {
46 return new LazyLoadingQueryGroup(querySpecifications);
47 }
48
49 @Override
50 public Set<IQuerySpecification<?>> getSpecifications() {
51 if (specifications == null) {
52 try {
53 specifications = providers.stream().filter(Objects::nonNull).map(Supplier::get).filter(Objects::nonNull).collect(Collectors.toSet());
54 } catch (Exception e) {
55 // TODO maybe store in issue list and provide better error reporting in general
56 String errorMessage = "Exception occurred while accessing query specification from provider: " + e.getMessage();
57 ViatraQueryLoggingUtil.getLogger(getClass()).error(errorMessage);
58 return Collections.emptySet();
59 }
60 }
61 return specifications;
62 }
63
64}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/PackageBasedQueryGroup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/PackageBasedQueryGroup.java
deleted file mode 100644
index 252bb7fd..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/PackageBasedQueryGroup.java
+++ /dev/null
@@ -1,133 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Abel Hegedus, Mark Czotter, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api;
10
11import java.util.Collections;
12import java.util.HashSet;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.api.impl.BaseQueryGroup;
16import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistry;
17import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryEntry;
18import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryChangeListener;
19import tools.refinery.viatra.runtime.registry.IRegistryView;
20import tools.refinery.viatra.runtime.registry.IRegistryViewFilter;
21import tools.refinery.viatra.runtime.registry.QuerySpecificationRegistry;
22
23/**
24 * Package based {@link BaseQueryGroup} implementation. It handles patterns as a group within the same package.
25 *
26 * @author Abel Hegedus, Mark Czotter
27 *
28 */
29public class PackageBasedQueryGroup extends BaseQueryGroup {
30
31 private final Set<IQuerySpecification<?>> querySpecifications = new HashSet<>();
32 private final String packageName;
33 private final boolean includeSubPackages;
34 private IRegistryView view;
35
36 /**
37 * Creates a query group with specifications of a given package from the {@link QuerySpecificationRegistry}. Only
38 * query specifications with the exact package fully qualified name are included.
39 *
40 * @param packageName
41 * that contains the specifications
42 */
43 public PackageBasedQueryGroup(String packageName) {
44 this(packageName, false);
45 }
46
47 /**
48 * Creates a query group with specifications of a given package from the {@link QuerySpecificationRegistry}.
49 *
50 * @param packageName
51 * that contain the specifications
52 * @param includeSubPackages
53 * if true all query specifications with package names starting with the given package are included
54 */
55 public PackageBasedQueryGroup(String packageName, boolean includeSubPackages) {
56 super();
57 this.packageName = packageName;
58 this.includeSubPackages = includeSubPackages;
59 IQuerySpecificationRegistry registry = QuerySpecificationRegistry.getInstance();
60 view = registry.createView(new PackageNameBasedViewFilter());
61 for (IQuerySpecificationRegistryEntry entry : view.getEntries()) {
62 this.querySpecifications.add(entry.get());
63 }
64 SpecificationSetUpdater listener = new SpecificationSetUpdater();
65 view.addViewListener(listener);
66 }
67
68 @Override
69 public Set<IQuerySpecification<?>> getSpecifications() {
70 return Collections.unmodifiableSet(new HashSet<>(querySpecifications));
71 }
72
73 public String getPackageName() {
74 return packageName;
75 }
76
77 public boolean isIncludeSubPackages() {
78 return includeSubPackages;
79 }
80
81 /**
82 * Refreshes the pattern group from the query specification registry based on the parameters used during the
83 * initialization.
84 */
85 public void refresh() {
86 // do nothing, view is automatically refreshed
87 }
88
89 /**
90 * Listener to update the specification set
91 *
92 * @author Abel Hegedus
93 *
94 */
95 private final class SpecificationSetUpdater implements IQuerySpecificationRegistryChangeListener {
96 @Override
97 public void entryAdded(IQuerySpecificationRegistryEntry entry) {
98 querySpecifications.add(entry.get());
99 }
100
101 @Override
102 public void entryRemoved(IQuerySpecificationRegistryEntry entry) {
103 querySpecifications.remove(entry.get());
104 }
105 }
106
107 /**
108 * Registry view filter that checks FQNs against the given package name.
109 *
110 * @author Abel Hegedus
111 *
112 */
113 private final class PackageNameBasedViewFilter implements IRegistryViewFilter {
114 @Override
115 public boolean isEntryRelevant(IQuerySpecificationRegistryEntry entry) {
116 String fqn = entry.getFullyQualifiedName();
117 if (packageName.length() + 1 < fqn.length()) {
118 if (includeSubPackages) {
119 if (fqn.startsWith(packageName + '.')) {
120 return true;
121 }
122 } else {
123 String name = fqn.substring(fqn.lastIndexOf('.') + 1, fqn.length());
124 if (fqn.equals(packageName + '.' + name)) {
125 return true;
126 }
127 }
128 }
129 return false;
130 }
131 }
132
133}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
index fd8ff848..ebae57a7 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
@@ -12,8 +12,6 @@ package tools.refinery.viatra.runtime.api;
12import org.eclipse.emf.common.notify.Notifier; 12import org.eclipse.emf.common.notify.Notifier;
13import tools.refinery.viatra.runtime.api.scope.IBaseIndex; 13import tools.refinery.viatra.runtime.api.scope.IBaseIndex;
14import tools.refinery.viatra.runtime.api.scope.QueryScope; 14import tools.refinery.viatra.runtime.api.scope.QueryScope;
15import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
16import tools.refinery.viatra.runtime.emf.EMFScope;
17import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; 15import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
18 16
19import java.util.Set; 17import java.util.Set;
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java
index ca709b02..4a256aea 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java
@@ -3,47 +3,42 @@
3 * This program and the accompanying materials are made available under the 3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at 4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 5 * http://www.eclipse.org/legal/epl-v20.html.
6 * 6 *
7 * SPDX-License-Identifier: EPL-2.0 7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/ 8 *******************************************************************************/
9 9
10package tools.refinery.viatra.runtime.api; 10package tools.refinery.viatra.runtime.api;
11 11
12import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument;
13
14import java.lang.ref.WeakReference;
15import java.util.Collections;
16import java.util.HashSet;
17import java.util.Map;
18import java.util.Set;
19import java.util.WeakHashMap;
20
21import tools.refinery.viatra.runtime.api.scope.QueryScope; 12import tools.refinery.viatra.runtime.api.scope.QueryScope;
22import tools.refinery.viatra.runtime.emf.EMFScope;
23import tools.refinery.viatra.runtime.internal.apiimpl.ViatraQueryEngineImpl; 13import tools.refinery.viatra.runtime.internal.apiimpl.ViatraQueryEngineImpl;
24import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil; 14import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
25 15
16import java.lang.ref.WeakReference;
17import java.util.*;
18
19import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument;
20
26/** 21/**
27 * Global registry of active VIATRA Query Engines. 22 * Global registry of active VIATRA Query Engines.
28 * 23 *
29 * <p> 24 * <p>
30 * Manages an {@link ViatraQueryEngine} for each model (more precisely scope), that is created on demand. Managed engines are shared between 25 * Manages an {@link ViatraQueryEngine} for each model (more precisely scope), that is created on demand. Managed engines are shared between
31 * clients querying the same model. 26 * clients querying the same model.
32 * 27 *
33 * <p> 28 * <p>
34 * It is also possible to create private, unmanaged engines that are not shared between clients. 29 * It is also possible to create private, unmanaged engines that are not shared between clients.
35 * 30 *
36 * <p> 31 * <p>
37 * Only weak references are retained on the managed engines. So if there are no other references to the matchers or the 32 * Only weak references are retained on the managed engines. So if there are no other references to the matchers or the
38 * engine, they can eventually be GC'ed, and they won't block the model from being GC'ed either. 33 * engine, they can eventually be GC'ed, and they won't block the model from being GC'ed either.
39 * 34 *
40 * 35 *
41 * @author Bergmann Gabor 36 * @author Bergmann Gabor
42 * 37 *
43 */ 38 */
44public class ViatraQueryEngineManager { 39public class ViatraQueryEngineManager {
45 private static ViatraQueryEngineManager instance = new ViatraQueryEngineManager(); 40 private static ViatraQueryEngineManager instance = new ViatraQueryEngineManager();
46 41
47 42
48 /** 43 /**
49 * @return the singleton instance 44 * @return the singleton instance
@@ -68,32 +63,32 @@ public class ViatraQueryEngineManager {
68 } 63 }
69 64
70 /** 65 /**
71 * Creates a managed VIATRA Query Engine at a given scope (e.g. an EMF Resource or ResourceSet, as in {@link EMFScope}) 66 * Creates a managed VIATRA Query Engine at a given scope (e.g. an EMF Resource or ResourceSet, as in {@link EMFScope})
72 * or retrieves an already existing one. Repeated invocations for a single model root will return the same engine. 67 * or retrieves an already existing one. Repeated invocations for a single model root will return the same engine.
73 * Consequently, the engine will be reused between different clients querying the same model, providing performance benefits. 68 * Consequently, the engine will be reused between different clients querying the same model, providing performance benefits.
74 * 69 *
75 * <p> 70 * <p>
76 * The match set of any patterns will be incrementally refreshed upon updates from this scope. 71 * The match set of any patterns will be incrementally refreshed upon updates from this scope.
77 * 72 *
78 * @param scope 73 * @param scope
79 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on. 74 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
80 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model. 75 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
81 * @return a new or previously existing engine 76 * @return a new or previously existing engine
82 */ 77 */
83 public ViatraQueryEngine getQueryEngine(QueryScope scope) { 78 public ViatraQueryEngine getQueryEngine(QueryScope scope) {
84 return getQueryEngine(scope, ViatraQueryEngineOptions.getDefault()); 79 return getQueryEngine(scope, ViatraQueryEngineOptions.getDefault());
85 } 80 }
86 81
87 /** 82 /**
88 * Creates a managed VIATRA Query Engine at a given scope (e.g. an EMF Resource or ResourceSet, as in {@link EMFScope}) 83 * Creates a managed VIATRA Query Engine at a given scope (e.g. an EMF Resource or ResourceSet, as in {@link EMFScope})
89 * or retrieves an already existing one. Repeated invocations for a single model root will return the same engine. 84 * or retrieves an already existing one. Repeated invocations for a single model root will return the same engine.
90 * Consequently, the engine will be reused between different clients querying the same model, providing performance benefits. 85 * Consequently, the engine will be reused between different clients querying the same model, providing performance benefits.
91 * 86 *
92 * <p> 87 * <p>
93 * The match set of any patterns will be incrementally refreshed upon updates from this scope. 88 * The match set of any patterns will be incrementally refreshed upon updates from this scope.
94 * 89 *
95 * @param scope 90 * @param scope
96 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on. 91 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
97 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model. 92 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
98 * @return a new or previously existing engine 93 * @return a new or previously existing engine
99 * @since 1.4 94 * @since 1.4
@@ -110,9 +105,9 @@ public class ViatraQueryEngineManager {
110 105
111 /** 106 /**
112 * Retrieves an already existing managed VIATRA Query Engine. 107 * Retrieves an already existing managed VIATRA Query Engine.
113 * 108 *
114 * @param scope 109 * @param scope
115 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on. 110 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
116 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model. 111 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
117 * @return a previously existing engine, or null if no engine is active for the given EMF model root 112 * @return a previously existing engine, or null if no engine is active for the given EMF model root
118 */ 113 */
@@ -122,7 +117,7 @@ public class ViatraQueryEngineManager {
122 117
123 /** 118 /**
124 * Collects all {@link ViatraQueryEngine} instances that still exist. 119 * Collects all {@link ViatraQueryEngine} instances that still exist.
125 * 120 *
126 * @return set of engines if there is any, otherwise EMTPY_SET 121 * @return set of engines if there is any, otherwise EMTPY_SET
127 */ 122 */
128 public Set<ViatraQueryEngine> getExistingQueryEngines(){ 123 public Set<ViatraQueryEngine> getExistingQueryEngines(){
@@ -139,14 +134,14 @@ public class ViatraQueryEngineManager {
139 } 134 }
140 return existingEngines; 135 return existingEngines;
141 } 136 }
142 137
143 private final Set<ViatraQueryEngineInitializationListener> initializationListeners; 138 private final Set<ViatraQueryEngineInitializationListener> initializationListeners;
144 139
145 /** 140 /**
146 * Registers a listener for new engine initialization. 141 * Registers a listener for new engine initialization.
147 * 142 *
148 * <p/> For removal, use {@link #removeQueryEngineInitializationListener} 143 * <p/> For removal, use {@link #removeQueryEngineInitializationListener}
149 * 144 *
150 * @param listener the listener to register 145 * @param listener the listener to register
151 */ 146 */
152 public void addQueryEngineInitializationListener(ViatraQueryEngineInitializationListener listener) { 147 public void addQueryEngineInitializationListener(ViatraQueryEngineInitializationListener listener) {
@@ -156,7 +151,7 @@ public class ViatraQueryEngineManager {
156 151
157 /** 152 /**
158 * Removes a registered listener added with {@link #addQueryEngineInitializationListener} 153 * Removes a registered listener added with {@link #addQueryEngineInitializationListener}
159 * 154 *
160 * @param listener 155 * @param listener
161 */ 156 */
162 public void removeQueryEngineInitializationListener(ViatraQueryEngineInitializationListener listener) { 157 public void removeQueryEngineInitializationListener(ViatraQueryEngineInitializationListener listener) {
@@ -166,7 +161,7 @@ public class ViatraQueryEngineManager {
166 161
167 /** 162 /**
168 * Notifies listeners that a new engine has been initialized. 163 * Notifies listeners that a new engine has been initialized.
169 * 164 *
170 * @param engine the initialized engine 165 * @param engine the initialized engine
171 */ 166 */
172 protected void notifyInitializationListeners(AdvancedViatraQueryEngine engine) { 167 protected void notifyInitializationListeners(AdvancedViatraQueryEngine engine) {
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFPQuery.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFPQuery.java
deleted file mode 100644
index c1fb0622..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFPQuery.java
+++ /dev/null
@@ -1,110 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api.impl;
10
11import org.eclipse.emf.ecore.EClass;
12import org.eclipse.emf.ecore.EClassifier;
13import org.eclipse.emf.ecore.EEnum;
14import org.eclipse.emf.ecore.EEnumLiteral;
15import org.eclipse.emf.ecore.EPackage;
16import org.eclipse.emf.ecore.EStructuralFeature;
17import tools.refinery.viatra.runtime.exception.ViatraQueryException;
18import tools.refinery.viatra.runtime.matchers.psystem.queries.BasePQuery;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PVisibility;
20import tools.refinery.viatra.runtime.matchers.psystem.queries.QueryInitializationException;
21
22/**
23 * Common superclass for EMF-based generated PQueries.
24 * @author Bergmann Gabor
25 *
26 */
27public abstract class BaseGeneratedEMFPQuery extends BasePQuery {
28
29 public BaseGeneratedEMFPQuery() {
30 this(PVisibility.PUBLIC);
31 }
32
33 /**
34 * @since 2.0
35 */
36 public BaseGeneratedEMFPQuery(PVisibility visibility) {
37 super(visibility);
38 }
39
40 protected QueryInitializationException processDependencyException(ViatraQueryException ex) {
41 if (ex.getCause() instanceof QueryInitializationException)
42 return (QueryInitializationException) ex.getCause();
43 return new QueryInitializationException(
44 "Failed to initialize external dependencies of query specification - see 'caused by' for details.",
45 null, "Problem with query dependencies.", this, ex);
46 }
47
48 protected EClassifier getClassifierLiteral(String packageUri, String classifierName) {
49 EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(packageUri);
50 if (ePackage == null)
51 throw new QueryInitializationException(
52 "Query refers to EPackage {1} not found in EPackage Registry.",
53 new String[]{packageUri},
54 "Query refers to missing EPackage.", this);
55 EClassifier literal = ePackage.getEClassifier(classifierName);
56 if (literal == null)
57 throw new QueryInitializationException(
58 "Query refers to classifier {1} not found in EPackage {2}.",
59 new String[]{classifierName, packageUri},
60 "Query refers to missing type in EPackage.", this);
61 return literal;
62 }
63
64 /**
65 * For parameter type retrieval only.
66 *
67 * <p>If parameter type declaration is erroneous, we still get a working parameter list (without the type declaration);
68 * the exception will be thrown again later when the body is processed.
69 */
70 protected EClassifier getClassifierLiteralSafe(String packageURI, String classifierName) {
71 try {
72 return getClassifierLiteral(packageURI, classifierName);
73 } catch (QueryInitializationException e) {
74 return null;
75 }
76 }
77
78 protected EStructuralFeature getFeatureLiteral(String packageUri, String className, String featureName) {
79 EClassifier container = getClassifierLiteral(packageUri, className);
80 if (! (container instanceof EClass))
81 throw new QueryInitializationException(
82 "Query refers to EClass {1} in EPackage {2} which turned out not be an EClass.",
83 new String[]{className, packageUri},
84 "Query refers to missing EClass.", this);
85 EStructuralFeature feature = ((EClass)container).getEStructuralFeature(featureName);
86 if (feature == null)
87 throw new QueryInitializationException(
88 "Query refers to feature {1} not found in EClass {2}.",
89 new String[]{featureName, className},
90 "Query refers to missing feature.", this);
91 return feature;
92 }
93
94 protected EEnumLiteral getEnumLiteral(String packageUri, String enumName, String literalName) {
95 EClassifier enumContainer = getClassifierLiteral(packageUri, enumName);
96 if (! (enumContainer instanceof EEnum))
97 throw new QueryInitializationException(
98 "Query refers to EEnum {1} in EPackage {2} which turned out not be an EEnum.",
99 new String[]{enumName, packageUri},
100 "Query refers to missing enumeration type.", this);
101 EEnumLiteral literal = ((EEnum)enumContainer).getEEnumLiteral(literalName);
102 if (literal == null)
103 throw new QueryInitializationException(
104 "Query refers to enumeration literal {1} not found in EEnum {2}.",
105 new String[]{literalName, enumName},
106 "Query refers to missing enumeration literal.", this);
107 return literal;
108 }
109
110}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFQuerySpecification.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFQuerySpecification.java
deleted file mode 100644
index 9956983d..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFQuerySpecification.java
+++ /dev/null
@@ -1,40 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.api.impl;
11
12import tools.refinery.viatra.runtime.api.IPatternMatch;
13import tools.refinery.viatra.runtime.api.ViatraQueryMatcher;
14import tools.refinery.viatra.runtime.api.scope.QueryScope;
15import tools.refinery.viatra.runtime.emf.EMFScope;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17
18/**
19 * Provides common functionality of pattern-specific generated query specifications over the EMF scope.
20 *
21 * @author Bergmann Gábor
22 * @author Mark Czotter
23 */
24public abstract class BaseGeneratedEMFQuerySpecification<Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> extends
25 BaseQuerySpecification<Matcher> {
26
27
28 /**
29 * Instantiates query specification for the given internal query representation.
30 */
31 public BaseGeneratedEMFQuerySpecification(PQuery wrappedPQuery) {
32 super(wrappedPQuery);
33 }
34
35 @Override
36 public Class<? extends QueryScope> getPreferredScopeClass() {
37 return EMFScope.class;
38 }
39
40}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFQuerySpecificationWithGenericMatcher.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFQuerySpecificationWithGenericMatcher.java
deleted file mode 100644
index 949dd112..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedEMFQuerySpecificationWithGenericMatcher.java
+++ /dev/null
@@ -1,58 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api.impl;
10
11import tools.refinery.viatra.runtime.api.GenericPatternMatch;
12import tools.refinery.viatra.runtime.api.GenericPatternMatcher;
13import tools.refinery.viatra.runtime.api.GenericQuerySpecification;
14import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
15import tools.refinery.viatra.runtime.api.scope.QueryScope;
16import tools.refinery.viatra.runtime.emf.EMFScope;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18
19/**
20 * Provides common functionality of pattern-specific generated query specifications for without generated
21 * pattern-specific match and matcher classes, including private patterns.
22 *
23 * @since 1.7
24 *
25 */
26public abstract class BaseGeneratedEMFQuerySpecificationWithGenericMatcher
27 extends GenericQuerySpecification<GenericPatternMatcher> {
28
29 public BaseGeneratedEMFQuerySpecificationWithGenericMatcher(PQuery wrappedPQuery) {
30 super(wrappedPQuery);
31 }
32
33 @Override
34 public Class<? extends QueryScope> getPreferredScopeClass() {
35 return EMFScope.class;
36 }
37
38 @Override
39 protected GenericPatternMatcher instantiate(final ViatraQueryEngine engine) {
40 return defaultInstantiate(engine);
41 }
42
43 @Override
44 public GenericPatternMatcher instantiate() {
45 return new GenericPatternMatcher(this);
46 }
47
48 @Override
49 public GenericPatternMatch newEmptyMatch() {
50 return GenericPatternMatch.newEmptyMatch(this);
51 }
52
53 @Override
54 public GenericPatternMatch newMatch(final Object... parameters) {
55 return GenericPatternMatch.newMatch(this, parameters);
56 }
57
58} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java
index 7690daf6..182bb466 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java
@@ -3,25 +3,23 @@
3 * This program and the accompanying materials are made available under the 3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at 4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 5 * http://www.eclipse.org/legal/epl-v20.html.
6 * 6 *
7 * SPDX-License-Identifier: EPL-2.0 7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/ 8 *******************************************************************************/
9 9
10package tools.refinery.viatra.runtime.api.impl; 10package tools.refinery.viatra.runtime.api.impl;
11 11
12import tools.refinery.viatra.runtime.api.IPatternMatch;
13
12import java.util.Arrays; 14import java.util.Arrays;
13import java.util.Collections; 15import java.util.Collections;
14import java.util.List; 16import java.util.List;
15 17
16import org.eclipse.emf.ecore.EObject;
17import org.eclipse.emf.ecore.EStructuralFeature;
18import tools.refinery.viatra.runtime.api.IPatternMatch;
19
20/** 18/**
21 * Base implementation of IPatternMatch. 19 * Base implementation of IPatternMatch.
22 * 20 *
23 * @author Bergmann Gábor 21 * @author Bergmann Gábor
24 * 22 *
25 */ 23 */
26public abstract class BasePatternMatch implements IPatternMatch { 24public abstract class BasePatternMatch implements IPatternMatch {
27 25
@@ -29,36 +27,14 @@ public abstract class BasePatternMatch implements IPatternMatch {
29 protected static <T> List<T> makeImmutableList(T... elements) { 27 protected static <T> List<T> makeImmutableList(T... elements) {
30 return Collections.unmodifiableList(Arrays.asList(elements)); 28 return Collections.unmodifiableList(Arrays.asList(elements));
31 } 29 }
32 30
33 public static String prettyPrintValue(Object o) { 31 public static String prettyPrintValue(Object o) {
34 if (o == null) { 32 if (o == null) {
35 return "(null)"; 33 return "(null)";
36 } 34 }
37 String name = prettyPrintFeature(o, "name");
38 if (name != null) {
39 return name;
40 }
41 /*
42 * if (o instanceof EObject) { EStructuralFeature feature = ((EObject)o).eClass().getEStructuralFeature("name");
43 * if (feature != null) { Object name = ((EObject)o).eGet(feature); if (name != null) return name.toString(); }
44 * }
45 */
46 return o.toString(); 35 return o.toString();
47 } 36 }
48 37
49 public static String prettyPrintFeature(Object o, String featureName) {
50 if (o instanceof EObject) {
51 EStructuralFeature feature = ((EObject) o).eClass().getEStructuralFeature(featureName);
52 if (feature != null) {
53 Object value = ((EObject) o).eGet(feature);
54 if (value != null) {
55 return value.toString();
56 }
57 }
58 }
59 return null;
60 }
61
62 // TODO performance can be improved here somewhat 38 // TODO performance can be improved here somewhat
63 39
64 @Override 40 @Override
@@ -83,7 +59,7 @@ public abstract class BasePatternMatch implements IPatternMatch {
83 public String toString() { 59 public String toString() {
84 return "Match<" + patternName() + ">{" + prettyPrint() + "}"; 60 return "Match<" + patternName() + ">{" + prettyPrint() + "}";
85 } 61 }
86 62
87 @Override 63 @Override
88 public boolean isCompatibleWith(IPatternMatch other) { 64 public boolean isCompatibleWith(IPatternMatch other) {
89 if(other == null) { 65 if(other == null) {
@@ -102,7 +78,7 @@ public abstract class BasePatternMatch implements IPatternMatch {
102 } 78 }
103 return true; 79 return true;
104 } 80 }
105 81
106 @Override 82 @Override
107 public String patternName() { 83 public String patternName() {
108 return specification().getFullyQualifiedName(); 84 return specification().getFullyQualifiedName();
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/RunOnceQueryEngine.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/RunOnceQueryEngine.java
deleted file mode 100644
index a97dea5d..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/RunOnceQueryEngine.java
+++ /dev/null
@@ -1,140 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api.impl;
10
11import java.util.Collection;
12
13import org.eclipse.emf.common.notify.Notifier;
14import tools.refinery.viatra.runtime.api.AdvancedViatraQueryEngine;
15import tools.refinery.viatra.runtime.api.IPatternMatch;
16import tools.refinery.viatra.runtime.api.IQuerySpecification;
17import tools.refinery.viatra.runtime.api.IRunOnceQueryEngine;
18import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
19import tools.refinery.viatra.runtime.api.ViatraQueryMatcher;
20import tools.refinery.viatra.runtime.api.ViatraQueryModelUpdateListener;
21import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
22import tools.refinery.viatra.runtime.emf.EMFScope;
23
24/**
25 * Run-once query engines can be used to retrieve the current match set of query specifications
26 * in a given scope. The engine is initialized with a {@link Notifier} as scope and a base index options
27 * that specifically allows traversing derived features that are not well-behaving.
28 *
29 * @author Abel Hegedus
30 *
31 */
32public class RunOnceQueryEngine implements IRunOnceQueryEngine {
33
34 /**
35 * If the model changes, we know that a resampling is required.
36 *
37 * @author Abel Hegedus
38 *
39 */
40 private final class RunOnceSamplingModelUpdateListener implements ViatraQueryModelUpdateListener {
41 @Override
42 public void notifyChanged(ChangeLevel changeLevel) {
43 // any model change may require re-sampling
44 reSamplingNeeded = true;
45 }
46
47 @Override
48 public ChangeLevel getLevel() {
49 return ChangeLevel.MODEL;
50 }
51 }
52
53 /**
54 * Override the default base index options to allow traversing and indexing derived features
55 * that would be problematic in incremental evaluation.
56 *
57 * @author Abel Hegedus
58 *
59 */
60 private static final class RunOnceBaseIndexOptions extends BaseIndexOptions {
61
62 public RunOnceBaseIndexOptions() {
63 this.traverseOnlyWellBehavingDerivedFeatures = false;
64 }
65
66 }
67
68 /**
69 * The scope of the engine that is used when creating one-time {@link ViatraQueryEngine}s.
70 */
71 private Notifier notifier;
72 /**
73 * The options that are used for initializing the {@link ViatraQueryEngine}.
74 */
75 private RunOnceBaseIndexOptions baseIndexOptions;
76 private AdvancedViatraQueryEngine engine;
77 private boolean reSamplingNeeded = false;
78 protected boolean samplingMode = false;
79 private RunOnceSamplingModelUpdateListener modelUpdateListener;
80
81 /**
82 * Creates a run-once query engine on the given notifier.
83 */
84 public RunOnceQueryEngine(Notifier notifier) {
85 this.notifier = notifier;
86 this.baseIndexOptions = new RunOnceBaseIndexOptions();
87 }
88
89 @Override
90 public <Match extends IPatternMatch> Collection<Match> getAllMatches(
91 IQuerySpecification<? extends ViatraQueryMatcher<Match>> querySpecification) {
92
93 if(samplingMode && reSamplingNeeded && engine != null) {
94 // engine exists from earlier, but may need resampling if model changed
95 engine.getBaseIndex().resampleDerivedFeatures();
96 } else {
97 // create new engine if it doesn't exists
98 //TODO correct scope handling
99 engine = AdvancedViatraQueryEngine.createUnmanagedEngine(new EMFScope(notifier, baseIndexOptions));
100 }
101 ViatraQueryMatcher<Match> matcher = engine.getMatcher(querySpecification);
102 Collection<Match> allMatches = matcher.getAllMatches();
103 if(samplingMode) {
104 engine.addModelUpdateListener(modelUpdateListener);
105 } else {
106 engine.dispose();
107 engine = null;
108 }
109 return allMatches;
110 }
111
112 @Override
113 public BaseIndexOptions getBaseIndexOptions() {
114 return baseIndexOptions;
115 }
116
117 @Override
118 public Notifier getScope() {
119 return notifier;
120 }
121
122 @Override
123 public void setAutomaticResampling(boolean automaticResampling) {
124 samplingMode = automaticResampling;
125 if(automaticResampling) {
126 if (modelUpdateListener == null) {
127 modelUpdateListener = new RunOnceSamplingModelUpdateListener();
128 }
129 } else if(engine != null) {
130 engine.dispose();
131 engine = null;
132 }
133 }
134
135 @Override
136 public void resampleOnNextCall() {
137 reSamplingNeeded = true;
138 }
139
140}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java
index d144bba6..f61a5edb 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java
@@ -3,17 +3,15 @@
3 * This program and the accompanying materials are made available under the 3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at 4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 5 * http://www.eclipse.org/legal/epl-v20.html.
6 * 6 *
7 * SPDX-License-Identifier: EPL-2.0 7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/ 8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api.scope; 9package tools.refinery.viatra.runtime.api.scope;
10 10
11import tools.refinery.viatra.runtime.base.api.NavigationHelper;
12
13/** 11/**
14 * 12 *
15 * This interface contains callbacks for various internal errors from the {@link NavigationHelper base index}. 13 * This interface contains callbacks for various internal errors from the {@link NavigationHelper base index}.
16 * 14 *
17 * @author Zoltan Ujhelyi 15 * @author Zoltan Ujhelyi
18 * @since 0.9 16 * @since 0.9
19 * 17 *
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/DynamicEMFQueryRuntimeContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/DynamicEMFQueryRuntimeContext.java
deleted file mode 100644
index a6da213e..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/DynamicEMFQueryRuntimeContext.java
+++ /dev/null
@@ -1,47 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf;
10
11import org.apache.log4j.Logger;
12import tools.refinery.viatra.runtime.base.api.NavigationHelper;
13import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
14import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
15
16/**
17 * In dynamic EMF mode, we need to make sure that EEnum literal constants and values returned by eval() expressions
18 * are canonicalized in the same way as enum literals from the EMF model.
19 *
20 * <p> This canonicalization is a one-way mapping, so
21 * {@link #unwrapElement(Object)} and {@link #unwrapTuple(Object)} remain NOPs.
22 *
23 * @author Bergmann Gabor
24 *
25 */
26public class DynamicEMFQueryRuntimeContext extends EMFQueryRuntimeContext {
27
28 public DynamicEMFQueryRuntimeContext(NavigationHelper baseIndex, Logger logger, EMFScope emfScope) {
29 super(baseIndex, logger, emfScope);
30 }
31
32 @Override
33 public Object wrapElement(Object externalElement) {
34 return baseIndex.toCanonicalValueRepresentation(externalElement);
35 }
36
37 @Override
38 public Tuple wrapTuple(Tuple externalElements) {
39 Object[] elements = externalElements.getElements();
40 for (int i=0; i< elements.length; ++i)
41 elements[i] = wrapElement(elements[i]);
42 return Tuples.flatTupleOf(elements);
43 }
44
45
46
47}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFBaseIndexWrapper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFBaseIndexWrapper.java
deleted file mode 100644
index 433c5f72..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFBaseIndexWrapper.java
+++ /dev/null
@@ -1,160 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf;
10
11import java.lang.reflect.InvocationTargetException;
12import java.util.HashMap;
13import java.util.Map;
14import java.util.concurrent.Callable;
15
16import org.eclipse.emf.common.notify.Notification;
17import org.eclipse.emf.ecore.EObject;
18import org.eclipse.emf.ecore.EStructuralFeature;
19import tools.refinery.viatra.runtime.api.scope.IBaseIndex;
20import tools.refinery.viatra.runtime.api.scope.IIndexingErrorListener;
21import tools.refinery.viatra.runtime.api.scope.IInstanceObserver;
22import tools.refinery.viatra.runtime.api.scope.ViatraBaseIndexChangeListener;
23import tools.refinery.viatra.runtime.base.api.EMFBaseIndexChangeListener;
24import tools.refinery.viatra.runtime.base.api.IEMFIndexingErrorListener;
25import tools.refinery.viatra.runtime.base.api.LightweightEObjectObserver;
26import tools.refinery.viatra.runtime.base.api.NavigationHelper;
27
28/**
29 * Wraps the EMF base index into the IBaseIndex interface.
30 * @author Bergmann Gabor
31 *
32 */
33public class EMFBaseIndexWrapper implements IBaseIndex {
34
35 private final NavigationHelper navigationHelper;
36 /**
37 * @return the underlying index object
38 */
39 public NavigationHelper getNavigationHelper() {
40 return navigationHelper;
41 }
42
43 /**
44 * @param navigationHelper
45 */
46 public EMFBaseIndexWrapper(NavigationHelper navigationHelper) {
47 this.navigationHelper = navigationHelper;
48 }
49
50 @Override
51 public void resampleDerivedFeatures() {
52 navigationHelper.resampleDerivedFeatures();
53 }
54
55
56 @Override
57 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
58 return navigationHelper.coalesceTraversals(callable);
59 }
60
61 Map<IIndexingErrorListener, IEMFIndexingErrorListener> indexErrorListeners =
62 new HashMap<IIndexingErrorListener, IEMFIndexingErrorListener>();
63 @Override
64 public boolean addIndexingErrorListener(final IIndexingErrorListener listener) {
65 if (indexErrorListeners.containsKey(listener)) return false;
66 IEMFIndexingErrorListener emfListener = new IEMFIndexingErrorListener() {
67 @Override
68 public void fatal(String description, Throwable t) {
69 listener.fatal(description, t);
70 }
71 @Override
72 public void error(String description, Throwable t) {
73 listener.error(description, t);
74 }
75 };
76 indexErrorListeners.put(listener, emfListener);
77 return navigationHelper.addIndexingErrorListener(emfListener);
78 }
79 @Override
80 public boolean removeIndexingErrorListener(IIndexingErrorListener listener) {
81 if (!indexErrorListeners.containsKey(listener)) return false;
82 return navigationHelper.removeIndexingErrorListener(indexErrorListeners.remove(listener));
83 }
84
85
86 Map<ViatraBaseIndexChangeListener, EMFBaseIndexChangeListener> indexChangeListeners =
87 new HashMap<ViatraBaseIndexChangeListener, EMFBaseIndexChangeListener>();
88 @Override
89 public void addBaseIndexChangeListener(final ViatraBaseIndexChangeListener listener) {
90 EMFBaseIndexChangeListener emfListener = new EMFBaseIndexChangeListener() {
91 @Override
92 public boolean onlyOnIndexChange() {
93 return listener.onlyOnIndexChange();
94 }
95
96 @Override
97 public void notifyChanged(boolean indexChanged) {
98 listener.notifyChanged(indexChanged);
99 }
100 };
101 indexChangeListeners.put(listener, emfListener);
102 navigationHelper.addBaseIndexChangeListener(emfListener);
103 }
104 @Override
105 public void removeBaseIndexChangeListener(ViatraBaseIndexChangeListener listener) {
106 final EMFBaseIndexChangeListener cListener = indexChangeListeners.remove(listener);
107 if (cListener != null)
108 navigationHelper.removeBaseIndexChangeListener(cListener);
109 }
110
111 Map<IInstanceObserver, EObjectObserver> instanceObservers =
112 new HashMap<IInstanceObserver, EObjectObserver>();
113 @Override
114 public boolean addInstanceObserver(final IInstanceObserver observer,
115 Object observedObject) {
116 if (observedObject instanceof EObject) {
117 EObjectObserver emfObserver = instanceObservers.computeIfAbsent(observer, EObjectObserver::new);
118 boolean success =
119 navigationHelper.addLightweightEObjectObserver(emfObserver, (EObject) observedObject);
120 if (success) emfObserver.usageCount++;
121 return success;
122 } else return false;
123 }
124 @Override
125 public boolean removeInstanceObserver(IInstanceObserver observer,
126 Object observedObject) {
127 if (observedObject instanceof EObject) {
128 EObjectObserver emfObserver = instanceObservers.get(observer);
129 if (emfObserver == null)
130 return false;
131 boolean success =
132 navigationHelper.removeLightweightEObjectObserver(emfObserver, (EObject)observedObject);
133 if (success)
134 if (0 == --emfObserver.usageCount)
135 instanceObservers.remove(observer);
136 return success;
137 } else return false;
138 }
139 private static class EObjectObserver implements LightweightEObjectObserver {
140 /**
141 *
142 */
143 private final IInstanceObserver observer;
144 int usageCount = 0;
145
146 /**
147 * @param observer
148 */
149 private EObjectObserver(IInstanceObserver observer) {
150 this.observer = observer;
151 }
152
153 @Override
154 public void notifyFeatureChanged(EObject host,
155 EStructuralFeature feature, Notification notification) {
156 observer.notifyBinaryChanged(host, feature);
157 }
158 }
159
160} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFEngineContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFEngineContext.java
deleted file mode 100644
index 5fe9e23a..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFEngineContext.java
+++ /dev/null
@@ -1,110 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Denes Harmath, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf;
10
11import org.apache.log4j.Logger;
12import org.eclipse.emf.common.notify.Notifier;
13import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
14import tools.refinery.viatra.runtime.api.scope.IBaseIndex;
15import tools.refinery.viatra.runtime.api.scope.IEngineContext;
16import tools.refinery.viatra.runtime.api.scope.IIndexingErrorListener;
17import tools.refinery.viatra.runtime.base.api.ViatraBaseFactory;
18import tools.refinery.viatra.runtime.base.api.NavigationHelper;
19import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
20import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
21
22/**
23 * Implements an engine context on EMF models.
24 * @author Bergmann Gabor
25 *
26 */
27class EMFEngineContext implements IEngineContext {
28
29 private final EMFScope emfScope;
30 ViatraQueryEngine engine;
31 Logger logger;
32 NavigationHelper navHelper;
33 IBaseIndex baseIndex;
34 IIndexingErrorListener taintListener;
35 private EMFQueryRuntimeContext runtimeContext;
36
37 public EMFEngineContext(EMFScope emfScope, ViatraQueryEngine engine, IIndexingErrorListener taintListener, Logger logger) {
38 this.emfScope = emfScope;
39 this.engine = engine;
40 this.logger = logger;
41 this.taintListener = taintListener;
42 }
43
44 /**
45 * @throws ViatraQueryRuntimeException thrown if the navigation helper cannot be initialized
46 */
47 public NavigationHelper getNavHelper() {
48 return getNavHelper(true);
49 }
50
51 private NavigationHelper getNavHelper(boolean ensureInitialized) {
52 if (navHelper == null) {
53 // sync to avoid crazy compiler reordering which would matter if derived features use VIATRA and call this
54 // reentrantly
55 synchronized (this) {
56 navHelper = ViatraBaseFactory.getInstance().createNavigationHelper(null, this.emfScope.getOptions(),
57 logger);
58 getBaseIndex().addIndexingErrorListener(taintListener);
59 }
60
61 if (ensureInitialized) {
62 ensureIndexLoaded();
63 }
64
65 }
66 return navHelper;
67 }
68
69 private void ensureIndexLoaded() {
70 for (Notifier scopeRoot : this.emfScope.getScopeRoots()) {
71 navHelper.addRoot(scopeRoot);
72 }
73 }
74
75 @Override
76 public IQueryRuntimeContext getQueryRuntimeContext() {
77 NavigationHelper nh = getNavHelper(false);
78 if (runtimeContext == null) {
79 runtimeContext =
80 emfScope.getOptions().isDynamicEMFMode() ?
81 new DynamicEMFQueryRuntimeContext(nh, logger, emfScope) :
82 new EMFQueryRuntimeContext(nh, logger, emfScope);
83
84 ensureIndexLoaded();
85 }
86
87 return runtimeContext;
88 }
89
90 @Override
91 public void dispose() {
92 if (runtimeContext != null) runtimeContext.dispose();
93 if (navHelper != null) navHelper.dispose();
94
95 this.baseIndex = null;
96 this.engine = null;
97 this.logger = null;
98 this.navHelper = null;
99 }
100
101
102 @Override
103 public IBaseIndex getBaseIndex() {
104 if (baseIndex == null) {
105 final NavigationHelper navigationHelper = getNavHelper();
106 baseIndex = new EMFBaseIndexWrapper(navigationHelper);
107 }
108 return baseIndex;
109 }
110} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFQueryMetaContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFQueryMetaContext.java
deleted file mode 100644
index c316d308..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFQueryMetaContext.java
+++ /dev/null
@@ -1,405 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf;
10
11import java.util.Arrays;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Comparator;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.Map;
18import java.util.Set;
19
20import org.eclipse.emf.common.util.EList;
21import org.eclipse.emf.ecore.EAttribute;
22import org.eclipse.emf.ecore.EClass;
23import org.eclipse.emf.ecore.EClassifier;
24import org.eclipse.emf.ecore.EDataType;
25import org.eclipse.emf.ecore.EObject;
26import org.eclipse.emf.ecore.EReference;
27import org.eclipse.emf.ecore.EStructuralFeature;
28import org.eclipse.emf.ecore.EcorePackage;
29import tools.refinery.viatra.runtime.emf.types.BaseEMFTypeKey;
30import tools.refinery.viatra.runtime.emf.types.EClassTransitiveInstancesKey;
31import tools.refinery.viatra.runtime.emf.types.EClassUnscopedTransitiveInstancesKey;
32import tools.refinery.viatra.runtime.emf.types.EDataTypeInSlotsKey;
33import tools.refinery.viatra.runtime.emf.types.EStructuralFeatureInstancesKey;
34import tools.refinery.viatra.runtime.matchers.context.AbstractQueryMetaContext;
35import tools.refinery.viatra.runtime.matchers.context.IInputKey;
36import tools.refinery.viatra.runtime.matchers.context.InputKeyImplication;
37import tools.refinery.viatra.runtime.matchers.context.common.JavaTransitiveInstancesKey;
38
39/**
40 * The meta context information for EMF scopes.
41 *
42 * <p> The runtime context may specialize answers with a given scope.
43 * In a static context, a conservative default version ({@link #DEFAULT}) can be used instead.
44 *
45 * <p> TODO generics?
46 * @author Bergmann Gabor
47 *
48 */
49public final class EMFQueryMetaContext extends AbstractQueryMetaContext {
50
51 /**
52 * Default static instance that only makes conservative assumptions that are valid for any {@link EMFScope} (but not if objects are used).
53 * @since 1.6
54 */
55 public static final EMFQueryMetaContext DEFAULT = new EMFQueryMetaContext(false, true, UnscopedTypeSupport.EMIT_ALWAYS);
56
57 /**
58 * Default static instance that only makes conservative assumptions that are valid for any scope, even with surrogate objects.
59 * Unscoped types are used for inference, but not emitted as replacement candidates, as they cannot be checked at runtime.
60 * @since 2.1
61 */
62 public static final EMFQueryMetaContext DEFAULT_SURROGATE = new EMFQueryMetaContext(false, true, UnscopedTypeSupport.EMIT_EXCEPT_AS_WEAKENED_REPLACEMENT);
63
64
65 private static final EClass EOBJECT_CLASS =
66 EcorePackage.eINSTANCE.getEObject();
67 private static final EClassTransitiveInstancesKey EOBJECT_SCOPED_KEY =
68 new EClassTransitiveInstancesKey(EOBJECT_CLASS);
69 private static final EClassUnscopedTransitiveInstancesKey EOBJECT_UNSCOPED_KEY =
70 new EClassUnscopedTransitiveInstancesKey(EOBJECT_CLASS);
71
72 private boolean assumeNonDangling;
73 private boolean subResourceScopeSplit;
74 private UnscopedTypeSupport emitUnscopedEClassTypes;
75
76 private enum UnscopedTypeSupport {
77 EMIT_ALWAYS,
78 EMIT_EXCEPT_AS_WEAKENED_REPLACEMENT,
79 EMIT_NEVER
80 }
81
82
83 /**
84 * Instantiates a specialized meta information that is aware of scope-specific details.
85 * Note that this API is not stable and thus non-public.
86 *
87 * @param assumeNonDangling assumes that all cross-references are non-dangling (do not lead out of scope), no matter what
88 * @param subResourceScopeSplit the scope granularity may be finer than resource-level, i.e. proxy-non-resolving references can lead out of scope
89 * @param emitUnscopedEClassTypes if requested, the metacontext will suppress unscoped input keys; this is recommended if surrogates are used instead of EObjects
90 */
91 EMFQueryMetaContext(boolean assumeNonDangling, boolean subResourceScopeSplit, UnscopedTypeSupport emitUnscopedEClassTypes) {
92 this.assumeNonDangling = assumeNonDangling;
93 this.subResourceScopeSplit = subResourceScopeSplit;
94 this.emitUnscopedEClassTypes = emitUnscopedEClassTypes;
95 }
96
97 /**
98 * Instantiates a specialized meta information that is aware of scope-specific details.
99 * @since 2.1
100 */
101 public EMFQueryMetaContext(EMFScope scope) {
102 this(scope.getOptions().isDanglingFreeAssumption(),
103 scope.getScopeRoots().size()==1 && scope.getScopeRoots().iterator().next() instanceof EObject,
104 UnscopedTypeSupport.EMIT_ALWAYS);
105 }
106
107
108 @Override
109 public boolean isEnumerable(IInputKey key) {
110 ensureValidKey(key);
111 return key.isEnumerable();
112// if (key instanceof JavaTransitiveInstancesKey)
113// return false;
114// else
115// return true;
116 }
117
118 @Override
119 public boolean canLeadOutOfScope(IInputKey key) {
120 ensureValidKey(key);
121 if (key instanceof EStructuralFeatureInstancesKey) {
122 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
123 if (feature instanceof EReference){
124 return canLeadOutOfScope((EReference) feature);
125 }
126 }
127 return false;
128 }
129
130 /**
131 * Tells whether the given reference may lead out of scope.
132 * @since 2.1
133 */
134 public boolean canLeadOutOfScope(EReference reference) {
135 // Is it possible that this edge is dangling, i.e. its target lies outside of the scope?
136 // Unless non-dangling is globally assumed,
137 // proxy-resolving references (incl. containment) might point to proxies and are thus considered unsafe.
138 // Additionally, if the scope is sub-resource (containment subtree of object),
139 // all non-containment edges are also unsafe.
140 // Note that in case of cross-resource containment,
141 // the scope includes the contained object even if it is in a foreign resource.
142 return (!assumeNonDangling)
143 && (reference.isResolveProxies() || (subResourceScopeSplit && !reference.isContainment()));
144 }
145
146 @Override
147 public boolean isStateless(IInputKey key) {
148 ensureValidKey(key);
149 return key instanceof JavaTransitiveInstancesKey || key instanceof EClassUnscopedTransitiveInstancesKey;
150 }
151
152 @Override
153 public Map<Set<Integer>, Set<Integer>> getFunctionalDependencies(IInputKey key) {
154 ensureValidKey(key);
155 if (key instanceof EStructuralFeatureInstancesKey) {
156 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
157 final Map<Set<Integer>, Set<Integer>> result =
158 new HashMap<Set<Integer>, Set<Integer>>();
159 if (isFeatureMultiplicityToOne(feature))
160 result.put(Collections.singleton(0), Collections.singleton(1));
161 if (isFeatureMultiplicityOneTo(feature))
162 result.put(Collections.singleton(1), Collections.singleton(0));
163 return result;
164 } else {
165 return Collections.emptyMap();
166 }
167 }
168
169 /**
170 * @since 2.1
171 */
172 public EClassTransitiveInstancesKey getSourceTypeKey(EStructuralFeatureInstancesKey key) {
173 return new EClassTransitiveInstancesKey(key.getEmfKey().getEContainingClass());
174 }
175 /**
176 * @since 2.1
177 */
178 public IInputKey getTargetTypeKey(EStructuralFeatureInstancesKey key) {
179 EStructuralFeature feature = key.getEmfKey();
180 if (feature instanceof EAttribute) {
181 return new EDataTypeInSlotsKey(((EAttribute) feature).getEAttributeType());
182 } else if (feature instanceof EReference) {
183 EClass eReferenceType = ((EReference) feature).getEReferenceType();
184 if (canLeadOutOfScope(key)) {
185 return new EClassUnscopedTransitiveInstancesKey(eReferenceType);
186 } else {
187 return new EClassTransitiveInstancesKey(eReferenceType);
188 }
189 } else throw new IllegalArgumentException();
190 }
191
192 @Override
193 public Collection<InputKeyImplication> getImplications(IInputKey implyingKey) {
194 ensureValidKey(implyingKey);
195 Collection<InputKeyImplication> result = new HashSet<InputKeyImplication>();
196
197 if (implyingKey instanceof EClassTransitiveInstancesKey) {
198 EClass eClass = ((EClassTransitiveInstancesKey) implyingKey).getEmfKey();
199
200 // direct eSuperClasses
201 EList<EClass> directSuperTypes = eClass.getESuperTypes();
202 if (!directSuperTypes.isEmpty()) {
203 for (EClass superType : directSuperTypes) {
204 final EClassTransitiveInstancesKey implied = new EClassTransitiveInstancesKey(superType);
205 result.add(new InputKeyImplication(implyingKey, implied, Arrays.asList(0)));
206 }
207 } else {
208 if (!EOBJECT_SCOPED_KEY.equals(implyingKey)) {
209 result.add(new InputKeyImplication(implyingKey, EOBJECT_SCOPED_KEY, Arrays.asList(0)));
210 }
211 }
212 // implies unscoped
213 if (UnscopedTypeSupport.EMIT_NEVER != emitUnscopedEClassTypes)
214 result.add(new InputKeyImplication(implyingKey,
215 new EClassUnscopedTransitiveInstancesKey(eClass),
216 Arrays.asList(0)));
217 } else if (implyingKey instanceof EClassUnscopedTransitiveInstancesKey) {
218 EClass eClass = ((EClassUnscopedTransitiveInstancesKey) implyingKey).getEmfKey();
219
220 // direct eSuperClasses
221 EList<EClass> directSuperTypes = eClass.getESuperTypes();
222 if (!directSuperTypes.isEmpty()) {
223 for (EClass superType : directSuperTypes) {
224 final EClassUnscopedTransitiveInstancesKey implied = new EClassUnscopedTransitiveInstancesKey(
225 superType);
226 result.add(new InputKeyImplication(implyingKey, implied, Arrays.asList(0)));
227 }
228 } else {
229 if (!EOBJECT_UNSCOPED_KEY.equals(implyingKey)) {
230 result.add(new InputKeyImplication(implyingKey, EOBJECT_UNSCOPED_KEY, Arrays.asList(0)));
231 }
232 }
233
234 } else if (implyingKey instanceof JavaTransitiveInstancesKey) {
235 Class<?> instanceClass = ((JavaTransitiveInstancesKey) implyingKey).getInstanceClass();
236 if (instanceClass != null) { // resolution successful
237 // direct Java superClass
238 Class<?> superclass = instanceClass.getSuperclass();
239 if (superclass != null) {
240 JavaTransitiveInstancesKey impliedSuper = new JavaTransitiveInstancesKey(superclass);
241 result.add(new InputKeyImplication(implyingKey, impliedSuper, Arrays.asList(0)));
242 }
243
244 // direct Java superInterfaces
245 for (Class<?> superInterface : instanceClass.getInterfaces()) {
246 if (superInterface != null) {
247 JavaTransitiveInstancesKey impliedInterface = new JavaTransitiveInstancesKey(superInterface);
248 result.add(new InputKeyImplication(implyingKey, impliedInterface, Arrays.asList(0)));
249 }
250 }
251 }
252
253 } else if (implyingKey instanceof EStructuralFeatureInstancesKey) {
254 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) implyingKey).getEmfKey();
255
256 // source and target type
257 final EClass sourceType = featureSourceType(feature);
258 final EClassTransitiveInstancesKey impliedSource = new EClassTransitiveInstancesKey(sourceType);
259 final EClassifier targetType = featureTargetType(feature);
260 final IInputKey impliedTarget;
261 if (feature instanceof EReference) {
262 EReference reference = (EReference) feature;
263
264 if (!canLeadOutOfScope(reference)) {
265 impliedTarget = new EClassTransitiveInstancesKey((EClass) targetType);
266 } else {
267 impliedTarget = (UnscopedTypeSupport.EMIT_NEVER != emitUnscopedEClassTypes) ?
268 new EClassUnscopedTransitiveInstancesKey((EClass) targetType)
269 : null;
270 }
271 } else { // EDatatype
272 impliedTarget = new EDataTypeInSlotsKey((EDataType) targetType);
273 }
274
275 result.add(new InputKeyImplication(implyingKey, impliedSource, Arrays.asList(0)));
276 if (impliedTarget != null)
277 result.add(new InputKeyImplication(implyingKey, impliedTarget, Arrays.asList(1)));
278
279 // opposite
280 EReference opposite = featureOpposite(feature);
281 if (opposite != null && !canLeadOutOfScope((EReference) feature)) {
282 EStructuralFeatureInstancesKey impliedOpposite = new EStructuralFeatureInstancesKey(opposite);
283 result.add(new InputKeyImplication(implyingKey, impliedOpposite, Arrays.asList(1, 0)));
284 }
285
286 // containment
287 // TODO
288 } else if (implyingKey instanceof EDataTypeInSlotsKey) {
289 EDataType dataType = ((EDataTypeInSlotsKey) implyingKey).getEmfKey();
290
291 // instance class of datatype
292 // TODO this can have a generation gap! (could be some dynamic EMF impl or whatever)
293 Class<?> instanceClass = dataType.getInstanceClass();
294 if (instanceClass != null) {
295 JavaTransitiveInstancesKey implied = new JavaTransitiveInstancesKey(instanceClass);
296 result.add(new InputKeyImplication(implyingKey, implied, Arrays.asList(0)));
297 }
298 } else {
299 illegalInputKey(implyingKey);
300 }
301
302 return result;
303 }
304
305 @Override
306 public Map<InputKeyImplication, Set<InputKeyImplication>> getConditionalImplications(IInputKey implyingKey) {
307 ensureValidKey(implyingKey);
308 if (implyingKey instanceof EClassUnscopedTransitiveInstancesKey) {
309 EClass emfKey = ((EClassUnscopedTransitiveInstancesKey) implyingKey).getEmfKey();
310
311 Map<InputKeyImplication, Set<InputKeyImplication>> result = new HashMap<>();
312 result.put(
313 new InputKeyImplication(implyingKey, EOBJECT_SCOPED_KEY, Arrays.asList(0)),
314 new HashSet<>(Arrays.asList(new InputKeyImplication(implyingKey, new EClassTransitiveInstancesKey(emfKey), Arrays.asList(0))))
315 );
316 return result;
317 } else return super.getConditionalImplications(implyingKey);
318 }
319
320 @Override
321 public Collection<InputKeyImplication> getWeakenedAlternatives(IInputKey implyingKey) {
322 ensureValidKey(implyingKey);
323 if (UnscopedTypeSupport.EMIT_ALWAYS == emitUnscopedEClassTypes && implyingKey instanceof EClassTransitiveInstancesKey) {
324 EClass emfKey = ((EClassTransitiveInstancesKey) implyingKey).getEmfKey();
325
326 Collection<InputKeyImplication> result = new HashSet<InputKeyImplication>();
327 result.add(
328 // in some cases, filtering by the the unscoped key may be sufficient
329 new InputKeyImplication(implyingKey, new EClassUnscopedTransitiveInstancesKey(emfKey), Arrays.asList(0))
330 );
331 return result;
332 } else return super.getWeakenedAlternatives(implyingKey);
333 }
334
335 public void ensureValidKey(IInputKey key) {
336 if (! (key instanceof BaseEMFTypeKey<?>) && ! (key instanceof JavaTransitiveInstancesKey))
337 illegalInputKey(key);
338 }
339
340 public void illegalInputKey(IInputKey key) {
341 throw new IllegalArgumentException("The input key " + key + " is not a valid EMF input key.");
342 }
343
344 public boolean isFeatureMultiplicityToOne(EStructuralFeature feature) {
345 return !feature.isMany();
346 }
347
348 public boolean isFeatureMultiplicityOneTo(EStructuralFeature typeObject) {
349 if (typeObject instanceof EReference) {
350 final EReference feature = (EReference)typeObject;
351 final EReference eOpposite = feature.getEOpposite();
352 return feature.isContainment() || (eOpposite != null && !eOpposite.isMany());
353 } else return false;
354 }
355
356 public EClass featureSourceType(EStructuralFeature feature) {
357 return feature.getEContainingClass();
358 }
359 public EClassifier featureTargetType(EStructuralFeature typeObject) {
360 if (typeObject instanceof EAttribute) {
361 EAttribute attribute = (EAttribute) typeObject;
362 return attribute.getEAttributeType();
363 } else if (typeObject instanceof EReference) {
364 EReference reference = (EReference) typeObject;
365 return reference.getEReferenceType();
366 } else
367 throw new IllegalArgumentException("typeObject has invalid type " + typeObject.getClass().getName());
368 }
369 public EReference featureOpposite(EStructuralFeature typeObject) {
370 if (typeObject instanceof EReference) {
371 EReference reference = (EReference) typeObject;
372 return reference.getEOpposite();
373 } else return null;
374 }
375
376 @Override
377 public Comparator<IInputKey> getSuggestedEliminationOrdering() {
378 return SUGGESTED_ELIMINATION_ORDERING;
379 }
380
381 private static final Comparator<IInputKey> SUGGESTED_ELIMINATION_ORDERING = new Comparator<IInputKey>() {
382 @Override
383 public int compare(IInputKey o1, IInputKey o2) {
384 if (o1 instanceof EClassTransitiveInstancesKey && o2 instanceof EClassTransitiveInstancesKey) {
385 // common EClass types with many instances should be eliminated before rare types
386 return getRarity((EClassTransitiveInstancesKey)o1) - getRarity((EClassTransitiveInstancesKey)o2);
387 } else {
388 return getKeyTypeEliminationSequence(o1) - getKeyTypeEliminationSequence(o2);
389 }
390 }
391
392 // The more supertypes there are, the more specialized the type
393 // the more specialized the type, the rarer instances are expected to be found
394 private int getRarity(EClassTransitiveInstancesKey key) {
395 return key.getEmfKey().getEAllSuperTypes().size() + (EOBJECT_SCOPED_KEY.equals(key) ? 0 : 1);
396 }
397
398 // Scoped EClass transitive instance keys are attempted to be eliminated before all else
399 // so that e.g. their unscoped version can eliminate them is variable is known to be scoped
400 private int getKeyTypeEliminationSequence(IInputKey o1) {
401 return (o1 instanceof EClassTransitiveInstancesKey) ? -1 : 0;
402 }
403 };
404
405}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFQueryRuntimeContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFQueryRuntimeContext.java
deleted file mode 100644
index 7809cd24..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFQueryRuntimeContext.java
+++ /dev/null
@@ -1,839 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf;
10
11import java.lang.reflect.InvocationTargetException;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.EnumSet;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.Map;
18import java.util.Optional;
19import java.util.Set;
20import java.util.concurrent.Callable;
21import java.util.function.Function;
22import java.util.stream.Collectors;
23
24import org.apache.log4j.Logger;
25import org.eclipse.emf.ecore.EClass;
26import org.eclipse.emf.ecore.EDataType;
27import org.eclipse.emf.ecore.EObject;
28import org.eclipse.emf.ecore.EStructuralFeature;
29import tools.refinery.viatra.runtime.base.api.DataTypeListener;
30import tools.refinery.viatra.runtime.base.api.FeatureListener;
31import tools.refinery.viatra.runtime.base.api.IndexingLevel;
32import tools.refinery.viatra.runtime.base.api.InstanceListener;
33import tools.refinery.viatra.runtime.base.api.NavigationHelper;
34import tools.refinery.viatra.runtime.emf.types.EClassTransitiveInstancesKey;
35import tools.refinery.viatra.runtime.emf.types.EClassUnscopedTransitiveInstancesKey;
36import tools.refinery.viatra.runtime.emf.types.EDataTypeInSlotsKey;
37import tools.refinery.viatra.runtime.emf.types.EStructuralFeatureInstancesKey;
38import tools.refinery.viatra.runtime.matchers.context.AbstractQueryRuntimeContext;
39import tools.refinery.viatra.runtime.matchers.context.IInputKey;
40import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
41import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
42import tools.refinery.viatra.runtime.matchers.context.IndexingService;
43import tools.refinery.viatra.runtime.matchers.context.common.JavaTransitiveInstancesKey;
44import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
45import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
46import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
47import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
48import tools.refinery.viatra.runtime.matchers.util.Accuracy;
49
50/**
51 * The EMF-based runtime query context, backed by an IQBase NavigationHelper.
52 *
53 * @author Bergmann Gabor
54 *
55 * <p> TODO: {@link #ensureIndexed(EClass)} may be inefficient if supertype already cached.
56 * @since 1.4
57 */
58public class EMFQueryRuntimeContext extends AbstractQueryRuntimeContext {
59 protected final NavigationHelper baseIndex;
60 //private BaseIndexListener listener;
61
62 protected final Map<EClass, EnumSet<IndexingService>> indexedClasses = new HashMap<>();
63 protected final Map<EDataType, EnumSet<IndexingService>> indexedDataTypes = new HashMap<>();
64 protected final Map<EStructuralFeature, EnumSet<IndexingService>> indexedFeatures = new HashMap<>();
65
66 protected final EMFQueryMetaContext metaContext;
67
68 protected Logger logger;
69
70 private EMFScope emfScope;
71
72 public EMFQueryRuntimeContext(NavigationHelper baseIndex, Logger logger, EMFScope emfScope) {
73 this.baseIndex = baseIndex;
74 this.logger = logger;
75 this.metaContext = new EMFQueryMetaContext(emfScope);
76 this.emfScope = emfScope;
77 }
78
79 public EMFScope getEmfScope() {
80 return emfScope;
81 }
82
83 /**
84 * Utility method to add an indexing service to a given key. Returns true if the requested service was
85 * not present before this call.
86 * @param map
87 * @param key
88 * @param service
89 * @return
90 */
91 private static <K> boolean addIndexingService(Map<K, EnumSet<IndexingService>> map, K key, IndexingService service){
92 EnumSet<IndexingService> current = map.get(key);
93 if (current == null){
94 current = EnumSet.of(service);
95 map.put(key, current);
96 return true;
97 }else{
98 return current.add(service);
99 }
100 }
101
102 public void dispose() {
103 //baseIndex.removeFeatureListener(indexedFeatures, listener);
104 indexedFeatures.clear();
105 //baseIndex.removeInstanceListener(indexedClasses, listener);
106 indexedClasses.clear();
107 //baseIndex.removeDataTypeListener(indexedDataTypes, listener);
108 indexedDataTypes.clear();
109
110 // No need to remove listeners, as NavHelper will be disposed imminently.
111 }
112
113 @Override
114 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
115 return baseIndex.coalesceTraversals(callable);
116 }
117
118 @Override
119 public boolean isCoalescing() {
120 return baseIndex.isCoalescing();
121 }
122
123 @Override
124 public IQueryMetaContext getMetaContext() {
125 return metaContext;
126 }
127
128 @Override
129 public void ensureIndexed(IInputKey key, IndexingService service) {
130 ensureEnumerableKey(key);
131 if (key instanceof EClassTransitiveInstancesKey) {
132 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
133 ensureIndexed(eClass, service);
134 } else if (key instanceof EDataTypeInSlotsKey) {
135 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
136 ensureIndexed(dataType, service);
137 } else if (key instanceof EStructuralFeatureInstancesKey) {
138 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
139 ensureIndexed(feature, service);
140 } else {
141 illegalInputKey(key);
142 }
143 }
144
145 /**
146 * Retrieve the current registered indexing services for the given key. May not return null,
147 * returns an empty set if no indexing is registered.
148 *
149 * @since 1.4
150 */
151 protected EnumSet<IndexingService> getCurrentIndexingServiceFor(IInputKey key){
152 ensureEnumerableKey(key);
153 if (key instanceof EClassTransitiveInstancesKey) {
154 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
155 EnumSet<IndexingService> is = indexedClasses.get(eClass);
156 return is == null ? EnumSet.noneOf(IndexingService.class) : is;
157 } else if (key instanceof EDataTypeInSlotsKey) {
158 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
159 EnumSet<IndexingService> is = indexedDataTypes.get(dataType);
160 return is == null ? EnumSet.noneOf(IndexingService.class) : is;
161 } else if (key instanceof EStructuralFeatureInstancesKey) {
162 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
163 EnumSet<IndexingService> is = indexedFeatures.get(feature);
164 return is == null ? EnumSet.noneOf(IndexingService.class) : is;
165 } else {
166 illegalInputKey(key);
167 return EnumSet.noneOf(IndexingService.class);
168 }
169 }
170
171 @Override
172 public boolean isIndexed(IInputKey key, IndexingService service) {
173 return getCurrentIndexingServiceFor(key).contains(service);
174 }
175
176 @Override
177 public boolean containsTuple(IInputKey key, ITuple seed) {
178 ensureValidKey(key);
179 if (key instanceof JavaTransitiveInstancesKey) {
180 Class<?> instanceClass = forceGetWrapperInstanceClass((JavaTransitiveInstancesKey) key);
181 return instanceClass != null && instanceClass.isInstance(seed.get(0));
182 } else if (key instanceof EClassUnscopedTransitiveInstancesKey) {
183 EClass emfKey = ((EClassUnscopedTransitiveInstancesKey) key).getEmfKey();
184 Object candidateInstance = seed.get(0);
185 return candidateInstance instanceof EObject
186 && baseIndex.isInstanceOfUnscoped((EObject) candidateInstance, emfKey);
187 } else {
188 ensureIndexed(key, IndexingService.INSTANCES);
189 if (key instanceof EClassTransitiveInstancesKey) {
190 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
191 // instance check not enough to satisfy scoping, must lookup from index
192 Object candidateInstance = seed.get(0);
193 return candidateInstance instanceof EObject
194 && baseIndex.isInstanceOfScoped((EObject) candidateInstance, eClass);
195 } else if (key instanceof EDataTypeInSlotsKey) {
196 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
197 return baseIndex.isInstanceOfDatatype(seed.get(0), dataType);
198 } else if (key instanceof EStructuralFeatureInstancesKey) {
199 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
200 Object sourceCandidate = seed.get(0);
201 return sourceCandidate instanceof EObject
202 && baseIndex.isFeatureInstance((EObject) sourceCandidate, seed.get(1), feature);
203 } else {
204 illegalInputKey(key);
205 return false;
206 }
207 }
208 }
209
210 private Class<?> forceGetWrapperInstanceClass(JavaTransitiveInstancesKey key) {
211 Class<?> instanceClass;
212 try {
213 instanceClass = key.forceGetWrapperInstanceClass();
214 } catch (ClassNotFoundException e) {
215 logger.error("Could not load instance class for type constraint " + key.getWrappedKey(), e);
216 instanceClass = null;
217 }
218 return instanceClass;
219 }
220
221 @Override
222 public Iterable<Tuple> enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
223 ensureIndexed(key, IndexingService.INSTANCES);
224 final Collection<Tuple> result = new HashSet<Tuple>();
225
226 if (key instanceof EClassTransitiveInstancesKey) {
227 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
228
229 if (seedMask.indices.length == 0) { // unseeded
230 return baseIndex.getAllInstances(eClass).stream().map(wrapUnary).collect(Collectors.toSet());
231 } else { // fully seeded
232 Object seedInstance = seedMask.getValue(seed, 0);
233 if (containsTuple(key, seed))
234 result.add(Tuples.staticArityFlatTupleOf(seedInstance));
235 }
236 } else if (key instanceof EDataTypeInSlotsKey) {
237 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
238
239 if (seedMask.indices.length == 0) { // unseeded
240 return baseIndex.getDataTypeInstances(dataType).stream().map(wrapUnary).collect(Collectors.toSet());
241 } else { // fully seeded
242 Object seedInstance = seedMask.getValue(seed, 0);
243 if (containsTuple(key, seed))
244 result.add(Tuples.staticArityFlatTupleOf(seedInstance));
245 }
246 } else if (key instanceof EStructuralFeatureInstancesKey) {
247 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
248
249 boolean isSourceBound = false;
250 int sourceIndex = -1;
251 boolean isTargetBound = false;
252 int targetIndex = -1;
253 for (int i = 0; i < seedMask.getSize(); i++) {
254 int index = seedMask.indices[i];
255 if (index == 0) {
256 isSourceBound = true;
257 sourceIndex = i;
258 } else if (index == 1) {
259 isTargetBound = true;
260 targetIndex = i;
261 }
262 }
263
264 if (!isSourceBound && isTargetBound) {
265 final Object seedTarget = seed.get(targetIndex);
266 final Set<EObject> results = baseIndex.findByFeatureValue(seedTarget, feature);
267 return results.stream().map(obj -> Tuples.staticArityFlatTupleOf(obj, seedTarget)).collect(Collectors.toSet());
268 } else if (isSourceBound && isTargetBound) { // fully seeded
269 final Object seedSource = seed.get(sourceIndex);
270 final Object seedTarget = seed.get(targetIndex);
271 if (containsTuple(key, seed))
272 result.add(Tuples.staticArityFlatTupleOf(seedSource, seedTarget));
273 } else if (!isSourceBound && !isTargetBound) { // fully unseeded
274 baseIndex.processAllFeatureInstances(feature, (source, target) -> result.add(Tuples.staticArityFlatTupleOf(source, target)));
275 } else if (isSourceBound && !isTargetBound) {
276 final Object seedSource = seed.get(sourceIndex);
277 final Set<Object> results = baseIndex.getFeatureTargets((EObject) seedSource, feature);
278 return results.stream().map(obj -> Tuples.staticArityFlatTupleOf(seedSource, obj)).collect(Collectors.toSet());
279 }
280 } else {
281 illegalInputKey(key);
282 }
283
284
285 return result;
286 }
287
288 private static Function<Object, Tuple> wrapUnary = Tuples::staticArityFlatTupleOf;
289
290 @Override
291 public Iterable<? extends Object> enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) {
292 ensureIndexed(key, IndexingService.INSTANCES);
293
294 if (key instanceof EClassTransitiveInstancesKey) {
295 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
296
297 if (seedMask.indices.length == 0) { // unseeded
298 return baseIndex.getAllInstances(eClass);
299 } else {
300 // must be unseeded, this is enumerateValues after all!
301 illegalEnumerateValues(seed.toImmutable());
302 }
303 } else if (key instanceof EDataTypeInSlotsKey) {
304 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
305
306 if (seedMask.indices.length == 0) { // unseeded
307 return baseIndex.getDataTypeInstances(dataType);
308 } else {
309 // must be unseeded, this is enumerateValues after all!
310 illegalEnumerateValues(seed.toImmutable());
311 }
312 } else if (key instanceof EStructuralFeatureInstancesKey) {
313 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
314
315 boolean isSourceBound = false;
316 int sourceIndex = -1;
317 boolean isTargetBound = false;
318 int targetIndex = -1;
319 for (int i = 0; i < seedMask.getSize(); i++) {
320 int index = seedMask.indices[i];
321 if (index == 0) {
322 isSourceBound = true;
323 sourceIndex = i;
324 } else if (index == 1) {
325 isTargetBound = true;
326 targetIndex = i;
327 }
328 }
329
330 if (!isSourceBound && isTargetBound) {
331 Object seedTarget = seed.get(targetIndex);
332 return baseIndex.findByFeatureValue(seedTarget, feature);
333 } else if (isSourceBound && !isTargetBound) {
334 Object seedSource = seed.get(sourceIndex);
335 return baseIndex.getFeatureTargets((EObject) seedSource, feature);
336 } else {
337 // must be singly unseeded, this is enumerateValues after all!
338 illegalEnumerateValues(seed.toImmutable());
339 }
340 } else {
341 illegalInputKey(key);
342 }
343 return null;
344 }
345
346 @Override
347 public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
348 ensureIndexed(key, IndexingService.STATISTICS);
349
350 if (key instanceof EClassTransitiveInstancesKey) {
351 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
352
353 if (seedMask.indices.length == 0) { // unseeded
354 return baseIndex.countAllInstances(eClass);
355 } else { // fully seeded
356 return (containsTuple(key, seed)) ? 1 : 0;
357 }
358 } else if (key instanceof EDataTypeInSlotsKey) {
359 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
360
361 if (seedMask.indices.length == 0) { // unseeded
362 return baseIndex.countDataTypeInstances(dataType);
363 } else { // fully seeded
364 return (containsTuple(key, seed)) ? 1 : 0;
365 }
366 } else if (key instanceof EStructuralFeatureInstancesKey) {
367 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
368
369 boolean isSourceBound = false;
370 int sourceIndex = -1;
371 boolean isTargetBound = false;
372 int targetIndex = -1;
373 for (int i = 0; i < seedMask.getSize(); i++) {
374 int index = seedMask.indices[i];
375 if (index == 0) {
376 isSourceBound = true;
377 sourceIndex = i;
378 } else if (index == 1) {
379 isTargetBound = true;
380 targetIndex = i;
381 }
382 }
383
384 if (!isSourceBound && isTargetBound) {
385 final Object seedTarget = seed.get(targetIndex);
386 return baseIndex.findByFeatureValue(seedTarget, feature).size();
387 } else if (isSourceBound && isTargetBound) { // fully seeded
388 return (containsTuple(key, seed)) ? 1 : 0;
389 } else if (!isSourceBound && !isTargetBound) { // fully unseeded
390 return baseIndex.countFeatures(feature);
391 } else if (isSourceBound && !isTargetBound) {
392 final Object seedSource = seed.get(sourceIndex);
393 return baseIndex.countFeatureTargets((EObject) seedSource, feature);
394 }
395 } else {
396 illegalInputKey(key);
397 }
398 return 0;
399 }
400
401
402 /**
403 * @since 2.1
404 */
405 @Override
406 public Optional<Long> estimateCardinality(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) {
407
408 if (key instanceof EClassTransitiveInstancesKey) {
409 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
410
411 if (isIndexed(key, IndexingService.STATISTICS)) { // exact answer known
412 if (groupMask.indices.length == 0) { // empty projection
413 return (0 != baseIndex.countAllInstances(eClass)) ? Optional.of(1L) : Optional.of(0L);
414 } else { // unprojected
415 return Optional.of((long)baseIndex.countAllInstances(eClass));
416 }
417 } else return Optional.empty(); // TODO use known supertype counts as upper, subtypes as lower bounds
418
419 } else if (key instanceof EClassUnscopedTransitiveInstancesKey) {
420 EClass eClass = ((EClassUnscopedTransitiveInstancesKey) key).getEmfKey();
421
422 // can give only lower bound based on the scoped key
423 if (Accuracy.BEST_LOWER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) {
424 return estimateCardinality(new EClassTransitiveInstancesKey(eClass), groupMask, requiredAccuracy);
425 } else return Optional.empty();
426
427 } else if (key instanceof EDataTypeInSlotsKey) {
428 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
429
430 if (isIndexed(key, IndexingService.STATISTICS)) {
431 if (groupMask.indices.length == 0) { // empty projection
432 return (0 != baseIndex.countDataTypeInstances(dataType)) ? Optional.of(1L) : Optional.of(0L);
433 } else { // unprojected
434 return Optional.of((long)baseIndex.countDataTypeInstances(dataType));
435 }
436 } else return Optional.empty();
437
438 } else if (key instanceof EStructuralFeatureInstancesKey) {
439 EStructuralFeatureInstancesKey featureKey = (EStructuralFeatureInstancesKey) key;
440 EStructuralFeature feature = featureKey.getEmfKey();
441
442
443 boolean isSourceSelected = false;
444 boolean isTargetSelected = false;
445 for (int i = 0; i < groupMask.getSize(); i++) {
446 int index = groupMask.indices[i];
447 if (index == 0) {
448 isSourceSelected = true;
449 } else if (index == 1) {
450 isTargetSelected = true;
451 }
452 }
453
454 Optional<Long> sourceTypeUpperEstimate =
455 estimateCardinality(metaContext.getSourceTypeKey(featureKey),
456 TupleMask.identity(1), Accuracy.BEST_UPPER_BOUND);
457 Optional<Long> targetTypeUpperEstimate =
458 estimateCardinality(metaContext.getTargetTypeKey(featureKey),
459 TupleMask.identity(1), Accuracy.BEST_UPPER_BOUND);
460
461 if (!isSourceSelected && !isTargetSelected) { // empty projection
462 if (isIndexed(key, IndexingService.STATISTICS)) { // we have exact node counts
463 return (0 == baseIndex.countFeatures(feature)) ? Optional.of(0L) : Optional.of(1L);
464 } else { // we can still say 0 in a few cases
465 if (0 == sourceTypeUpperEstimate.orElse(-1L))
466 return Optional.of(0L);
467
468 if (0 == targetTypeUpperEstimate.orElse(-1L))
469 return Optional.of(0L);
470
471 return Optional.empty();
472 }
473
474 } else if (isSourceSelected && !isTargetSelected) { // count sources
475 if (isIndexed(key, IndexingService.INSTANCES)) { // we have instances, therefore feature end counts
476 return Optional.of((long)(baseIndex.getHoldersOfFeature(feature).size()));
477 } else if (metaContext.isFeatureMultiplicityToOne(feature) &&
478 isIndexed(key, IndexingService.STATISTICS)) { // count of edges = count of sources due to func. dep.
479 return Optional.of((long)(baseIndex.countFeatures(feature)));
480 } else if (Accuracy.BEST_UPPER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) {
481 // upper bound by source type
482 Optional<Long> estimate = sourceTypeUpperEstimate;
483 // total edge counts are another upper bound (even if instances are unindexed)
484 if (isIndexed(key, IndexingService.STATISTICS)) {
485 estimate = Optional.of(Math.min(
486 baseIndex.countFeatures(feature),
487 estimate.orElse(Long.MAX_VALUE)));
488 }
489 return estimate;
490 } else return Optional.empty();
491
492 } else if (!isSourceSelected /*&& isTargetSelected*/) { // count targets
493 if (isIndexed(key, IndexingService.INSTANCES)) { // we have instances, therefore feature end counts
494 return Optional.of((long)(baseIndex.getValuesOfFeature(feature).size()));
495 } else if (metaContext.isFeatureMultiplicityOneTo(feature) &&
496 isIndexed(key, IndexingService.STATISTICS)) { // count of edges = count of targets due to func. dep.
497 return Optional.of((long)(baseIndex.countFeatures(feature)));
498 } else if (Accuracy.BEST_UPPER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) { // upper bound by target type
499 // upper bound by target type
500 Optional<Long> estimate = targetTypeUpperEstimate;
501 // total edge counts are another upper bound (even if instances are unindexed)
502 if (isIndexed(key, IndexingService.STATISTICS)) {
503 estimate = Optional.of(Math.min(
504 baseIndex.countFeatures(feature),
505 estimate.orElse(Long.MAX_VALUE)));
506 }
507 return estimate;
508 } else return Optional.empty();
509
510 } else { // (isSourceSelected && isTargetSelected) // count edges
511 if (isIndexed(key, IndexingService.STATISTICS)) { // we have exact edge counts
512 return Optional.of((long)baseIndex.countFeatures(feature));
513 } else if (Accuracy.BEST_UPPER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) { // overestimates may still be available
514 Optional<Long> estimate = // trivial upper bound: product of source & target type sizes (if available)
515 (sourceTypeUpperEstimate.isPresent() && targetTypeUpperEstimate.isPresent()) ?
516 Optional.of(
517 ((long)sourceTypeUpperEstimate.get()) * targetTypeUpperEstimate.get()
518 ) : Optional.empty();
519
520 if (metaContext.isFeatureMultiplicityToOne(feature) && sourceTypeUpperEstimate.isPresent()) {
521 // upper bounded by source type due to func. dep.
522 estimate = Optional.of(Math.min(
523 sourceTypeUpperEstimate.get(),
524 estimate.orElse(Long.MAX_VALUE)));
525 }
526 if (metaContext.isFeatureMultiplicityOneTo(feature) && targetTypeUpperEstimate.isPresent()) {
527 // upper bounded by target type due to func. dep.
528 estimate = Optional.of(Math.min(
529 targetTypeUpperEstimate.get(),
530 estimate.orElse(Long.MAX_VALUE)));
531 }
532
533 return estimate;
534 } else return Optional.empty();
535 }
536
537 } else {
538 return Optional.empty();
539 }
540 }
541
542 /**
543 * @since 2.1
544 */
545 @Override
546 public Optional<Double> estimateAverageBucketSize(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) {
547 // smart handling of special cases
548 if (key instanceof EStructuralFeatureInstancesKey) {
549 EStructuralFeatureInstancesKey featureKey = (EStructuralFeatureInstancesKey) key;
550 EStructuralFeature feature = featureKey.getEmfKey();
551
552 // special treatment for edge navigation
553 if (1 == groupMask.getSize()) {
554 if (0 == groupMask.indices[0] && metaContext.isFeatureMultiplicityToOne(feature)) { // count targets per source
555 return Optional.of(1.0);
556 } else if (1 == groupMask.indices[0] && metaContext.isFeatureMultiplicityOneTo(feature)) { // count sources per target
557 return Optional.of(1.0);
558 }
559 }
560 }
561
562 // keep the default behaviour
563 return super.estimateAverageBucketSize(key, groupMask, requiredAccuracy);
564 }
565
566
567 public void ensureEnumerableKey(IInputKey key) {
568 ensureValidKey(key);
569 if (! metaContext.isEnumerable(key))
570 throw new IllegalArgumentException("Key is not enumerable: " + key);
571
572 }
573
574 public void ensureValidKey(IInputKey key) {
575 metaContext.ensureValidKey(key);
576 }
577 public void illegalInputKey(IInputKey key) {
578 metaContext.illegalInputKey(key);
579 }
580 public void illegalEnumerateValues(Tuple seed) {
581 throw new IllegalArgumentException("Must have exactly one unseeded element in enumerateValues() invocation, received instead: " + seed);
582 }
583
584 /**
585 * @since 1.4
586 */
587 public void ensureIndexed(EClass eClass, IndexingService service) {
588 if (addIndexingService(indexedClasses, eClass, service)) {
589 final Set<EClass> newClasses = Collections.singleton(eClass);
590 IndexingLevel level = IndexingLevel.toLevel(service);
591 if (!baseIndex.getIndexingLevel(eClass).providesLevel(level)) {
592 baseIndex.registerEClasses(newClasses, level);
593 }
594 //baseIndex.addInstanceListener(newClasses, listener);
595 }
596 }
597
598 /**
599 * @since 1.4
600 */
601 public void ensureIndexed(EDataType eDataType, IndexingService service) {
602 if (addIndexingService(indexedDataTypes, eDataType, service)) {
603 final Set<EDataType> newDataTypes = Collections.singleton(eDataType);
604 IndexingLevel level = IndexingLevel.toLevel(service);
605 if (!baseIndex.getIndexingLevel(eDataType).providesLevel(level)) {
606 baseIndex.registerEDataTypes(newDataTypes, level);
607 }
608 //baseIndex.addDataTypeListener(newDataTypes, listener);
609 }
610 }
611
612 /**
613 * @since 1.4
614 */
615 public void ensureIndexed(EStructuralFeature feature, IndexingService service) {
616 if (addIndexingService(indexedFeatures, feature, service)) {
617 final Set<EStructuralFeature> newFeatures = Collections.singleton(feature);
618 IndexingLevel level = IndexingLevel.toLevel(service);
619 if (!baseIndex.getIndexingLevel(feature).providesLevel(level)) {
620 baseIndex.registerEStructuralFeatures(newFeatures, level);
621 }
622 //baseIndex.addFeatureListener(newFeatures, listener);
623 }
624 }
625
626
627
628 // UPDATE HANDLING SECTION
629
630 /**
631 * Abstract internal listener wrapper for a {@link IQueryRuntimeContextListener}.
632 * Due to the overridden equals/hashCode(), it is safe to create a new instance for the same listener.
633 *
634 * @author Bergmann Gabor
635 */
636 private abstract static class ListenerAdapter {
637 IQueryRuntimeContextListener listener;
638 Tuple seed;
639 /**
640 * @param listener
641 * @param seed must be non-null
642 */
643 public ListenerAdapter(IQueryRuntimeContextListener listener, Object... seed) {
644 this.listener = listener;
645 this.seed = Tuples.flatTupleOf(seed);
646 }
647
648 @Override
649 public int hashCode() {
650 final int prime = 31;
651 int result = 1;
652 result = prime * result
653 + ((listener == null) ? 0 : listener.hashCode());
654 result = prime * result + ((seed == null) ? 0 : seed.hashCode());
655 return result;
656 }
657
658 @Override
659 public boolean equals(Object obj) {
660 if (this == obj)
661 return true;
662 if (obj == null)
663 return false;
664 if (!(obj.getClass().equals(this.getClass())))
665 return false;
666 ListenerAdapter other = (ListenerAdapter) obj;
667 if (listener == null) {
668 if (other.listener != null)
669 return false;
670 } else if (!listener.equals(other.listener))
671 return false;
672 if (seed == null) {
673 if (other.seed != null)
674 return false;
675 } else if (!seed.equals(other.seed))
676 return false;
677 return true;
678 }
679
680
681 @Override
682 public String toString() {
683 return "Wrapped<Seed:" + seed + ">#" + listener;
684 }
685
686
687 }
688 private static class EClassTransitiveInstancesAdapter extends ListenerAdapter implements InstanceListener {
689 private Object seedInstance;
690 public EClassTransitiveInstancesAdapter(IQueryRuntimeContextListener listener, Object seedInstance) {
691 super(listener, seedInstance);
692 this.seedInstance = seedInstance;
693 }
694 @Override
695 public void instanceInserted(EClass clazz, EObject instance) {
696 if (seedInstance != null && !seedInstance.equals(instance)) return;
697 listener.update(new EClassTransitiveInstancesKey(clazz),
698 Tuples.staticArityFlatTupleOf(instance), true);
699 }
700 @Override
701 public void instanceDeleted(EClass clazz, EObject instance) {
702 if (seedInstance != null && !seedInstance.equals(instance)) return;
703 listener.update(new EClassTransitiveInstancesKey(clazz),
704 Tuples.staticArityFlatTupleOf(instance), false);
705 }
706 }
707 private static class EDataTypeInSlotsAdapter extends ListenerAdapter implements DataTypeListener {
708 private Object seedValue;
709 public EDataTypeInSlotsAdapter(IQueryRuntimeContextListener listener, Object seedValue) {
710 super(listener, seedValue);
711 this.seedValue = seedValue;
712 }
713 @Override
714 public void dataTypeInstanceInserted(EDataType type, Object instance,
715 boolean firstOccurrence) {
716 if (firstOccurrence) {
717 if (seedValue != null && !seedValue.equals(instance)) return;
718 listener.update(new EDataTypeInSlotsKey(type),
719 Tuples.staticArityFlatTupleOf(instance), true);
720 }
721 }
722 @Override
723 public void dataTypeInstanceDeleted(EDataType type, Object instance,
724 boolean lastOccurrence) {
725 if (lastOccurrence) {
726 if (seedValue != null && !seedValue.equals(instance)) return;
727 listener.update(new EDataTypeInSlotsKey(type),
728 Tuples.staticArityFlatTupleOf(instance), false);
729 }
730 }
731 }
732 private static class EStructuralFeatureInstancesKeyAdapter extends ListenerAdapter implements FeatureListener {
733 private Object seedHost;
734 private Object seedValue;
735 public EStructuralFeatureInstancesKeyAdapter(IQueryRuntimeContextListener listener, Object seedHost, Object seedValue) {
736 super(listener, seedHost, seedValue);
737 this.seedHost = seedHost;
738 this.seedValue = seedValue;
739 }
740 @Override
741 public void featureInserted(EObject host, EStructuralFeature feature,
742 Object value) {
743 if (seedHost != null && !seedHost.equals(host)) return;
744 if (seedValue != null && !seedValue.equals(value)) return;
745 listener.update(new EStructuralFeatureInstancesKey(feature),
746 Tuples.staticArityFlatTupleOf(host, value), true);
747 }
748 @Override
749 public void featureDeleted(EObject host, EStructuralFeature feature,
750 Object value) {
751 if (seedHost != null && !seedHost.equals(host)) return;
752 if (seedValue != null && !seedValue.equals(value)) return;
753 listener.update(new EStructuralFeatureInstancesKey(feature),
754 Tuples.staticArityFlatTupleOf(host, value), false);
755 }
756 }
757
758 @Override
759 public void addUpdateListener(IInputKey key, Tuple seed /* TODO ignored */, IQueryRuntimeContextListener listener) {
760 // stateless, so NOP
761 if (key instanceof JavaTransitiveInstancesKey) return;
762
763 ensureIndexed(key, IndexingService.INSTANCES);
764 if (key instanceof EClassTransitiveInstancesKey) {
765 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
766 baseIndex.addInstanceListener(Collections.singleton(eClass),
767 new EClassTransitiveInstancesAdapter(listener, seed.get(0)));
768 } else if (key instanceof EDataTypeInSlotsKey) {
769 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
770 baseIndex.addDataTypeListener(Collections.singleton(dataType),
771 new EDataTypeInSlotsAdapter(listener, seed.get(0)));
772 } else if (key instanceof EStructuralFeatureInstancesKey) {
773 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
774 baseIndex.addFeatureListener(Collections.singleton(feature),
775 new EStructuralFeatureInstancesKeyAdapter(listener, seed.get(0), seed.get(1)));
776 } else {
777 illegalInputKey(key);
778 }
779 }
780 @Override
781 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
782 // stateless, so NOP
783 if (key instanceof JavaTransitiveInstancesKey) return;
784
785 ensureIndexed(key, IndexingService.INSTANCES);
786 if (key instanceof EClassTransitiveInstancesKey) {
787 EClass eClass = ((EClassTransitiveInstancesKey) key).getEmfKey();
788 baseIndex.removeInstanceListener(Collections.singleton(eClass),
789 new EClassTransitiveInstancesAdapter(listener, seed.get(0)));
790 } else if (key instanceof EDataTypeInSlotsKey) {
791 EDataType dataType = ((EDataTypeInSlotsKey) key).getEmfKey();
792 baseIndex.removeDataTypeListener(Collections.singleton(dataType),
793 new EDataTypeInSlotsAdapter(listener, seed.get(0)));
794 } else if (key instanceof EStructuralFeatureInstancesKey) {
795 EStructuralFeature feature = ((EStructuralFeatureInstancesKey) key).getEmfKey();
796 baseIndex.removeFeatureListener(Collections.singleton(feature),
797 new EStructuralFeatureInstancesKeyAdapter(listener, seed.get(0), seed.get(1)));
798 } else {
799 illegalInputKey(key);
800 }
801 }
802
803 // TODO wrap / unwrap enum literals
804 // TODO use this in all other public methods (maybe wrap & delegate?)
805
806 @Override
807 public Object unwrapElement(Object internalElement) {
808 return internalElement;
809 }
810 @Override
811 public Tuple unwrapTuple(Tuple internalElements) {
812 return internalElements;
813 }
814 @Override
815 public Object wrapElement(Object externalElement) {
816 return externalElement;
817 }
818 @Override
819 public Tuple wrapTuple(Tuple externalElements) {
820 return externalElements;
821 }
822
823 /**
824 * @since 1.4
825 */
826 @Override
827 public void ensureWildcardIndexing(IndexingService service) {
828 baseIndex.setWildcardLevel(IndexingLevel.toLevel(service));
829 }
830
831 /**
832 * @since 1.4
833 */
834 @Override
835 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException {
836 baseIndex.executeAfterTraversal(runnable);
837 }
838}
839
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFScope.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFScope.java
deleted file mode 100644
index dead9716..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/EMFScope.java
+++ /dev/null
@@ -1,199 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Denes Harmath, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf;
10
11import java.util.Arrays;
12import java.util.Collections;
13import java.util.HashSet;
14import java.util.Set;
15import java.util.function.Predicate;
16import java.util.stream.Collectors;
17
18import org.apache.log4j.Logger;
19import org.eclipse.emf.common.notify.Notifier;
20import org.eclipse.emf.common.util.URI;
21import org.eclipse.emf.ecore.EObject;
22import org.eclipse.emf.ecore.resource.Resource;
23import org.eclipse.emf.ecore.resource.ResourceSet;
24import tools.refinery.viatra.runtime.api.AdvancedViatraQueryEngine;
25import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
26import tools.refinery.viatra.runtime.api.scope.IEngineContext;
27import tools.refinery.viatra.runtime.api.scope.IIndexingErrorListener;
28import tools.refinery.viatra.runtime.api.scope.QueryScope;
29import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
30import tools.refinery.viatra.runtime.base.api.NavigationHelper;
31import tools.refinery.viatra.runtime.exception.ViatraQueryException;
32
33/**
34 * An {@link QueryScope} consisting of EMF objects contained in multiple {@link ResourceSet}s, a single {@link ResourceSet}, {@link Resource} or a containment subtree below a given {@link EObject}.
35 *
36 * <p> The scope is characterized by a root and some options (see {@link BaseIndexOptions}) such as dynamic EMF mode, subtree filtering etc.
37 * <p>
38 * The scope of pattern matching will be the given EMF model root(s) and below (see FAQ for more precise definition).
39 *
40 * <p> Note on <i>cross-resource containment</i>: in case of {@link EObject} scopes, cross-resource containments will be considered part of the scope.
41 * The same goes for {@link ResourceSet} scopes, provided that the resource of the contained element is successfully loaded into the resource set.
42 * In case of a {@link Resource} scope, containments pointing out from the resource will be excluded from the scope.
43 * Thus the boundaries of {@link EObject} scopes conform to the notion of EMF logical containment, while {@link Resource} and {@link ResourceSet} scopes adhere to persistence boundaries.
44 *
45 * @author Bergmann Gabor
46 *
47 */
48public class EMFScope extends QueryScope {
49
50 private Set<? extends Notifier> scopeRoots;
51 private BaseIndexOptions options;
52
53 /**
54 * Creates an EMF scope at the given root, with default options (recommended for most users).
55 * @param scopeRoot the root of the EMF scope
56 * @throws ViatraQueryRuntimeException- if scopeRoot is not an EMF ResourceSet, Resource or EObject
57 */
58 public EMFScope(Notifier scopeRoot) {
59 this(Collections.singleton(scopeRoot), new BaseIndexOptions());
60 }
61
62 /**
63 * Creates an EMF scope at the given root, with customizable options.
64 * <p> Most users should consider {@link #EMFScope(Notifier)} instead.
65 * @param scopeRoot the root of the EMF scope
66 * @param options the base index building settings
67 * @throws ViatraQueryRuntimeException if scopeRoot is not an EMF ResourceSet, Resource or EObject
68 */
69 public EMFScope(Notifier scopeRoot, BaseIndexOptions options) {
70 this(Collections.singleton(scopeRoot), options);
71 }
72
73 /**
74 * Creates an EMF scope at the given roots, with default options (recommended for most users).
75 * @param scopeRoots the roots of the EMF scope, must be {@link ResourceSet}s
76 * @throws ViatraQueryRuntimeException if not all scopeRoots are {@link ResourceSet}s
77 */
78 public EMFScope(Set<? extends ResourceSet> scopeRoots) {
79 this(scopeRoots, new BaseIndexOptions());
80 }
81
82 /**
83 * Creates an EMF scope at the given roots, with customizable options.
84 * <p> Most users should consider {@link #EMFScope(Set)} instead.
85 * @param scopeRoots the roots of the EMF scope, must be {@link ResourceSet}s
86 * @param options the base index building settings
87 * @throws ViatraQueryRuntimeException if not all scopeRoots are {@link ResourceSet}s
88 */
89 public EMFScope(Set<? extends Notifier> scopeRoots, BaseIndexOptions options) {
90 super();
91 if (scopeRoots.isEmpty()) {
92 throw new IllegalArgumentException("No scope roots given");
93 } else if (scopeRoots.size() == 1) {
94 checkScopeRoots(scopeRoots, EObject.class::isInstance, Resource.class::isInstance, ResourceSet.class::isInstance);
95 } else {
96 checkScopeRoots(scopeRoots, ResourceSet.class::isInstance);
97 }
98 this.scopeRoots = new HashSet<>(scopeRoots);
99 this.options = options.copy();
100 }
101
102 @SafeVarargs
103 private final void checkScopeRoots(Set<? extends Notifier> scopeRoots, Predicate<Notifier>... predicates) {
104 for (Notifier scopeRoot : scopeRoots) {
105 // Creating compound predicate that checks the various branches of disjunction together
106 Predicate<Notifier> compoundPredicate = Arrays.stream(predicates).collect(Collectors.reducing(a -> true, a -> a, (a, b) -> a.or(b)));
107 if (!compoundPredicate.test(scopeRoot))
108 throw new ViatraQueryException(ViatraQueryException.INVALID_EMFROOT
109 + (scopeRoot == null ? "(null)" : scopeRoot.getClass().getName()),
110 ViatraQueryException.INVALID_EMFROOT_SHORT);
111 }
112 }
113
114 /**
115 * @return the scope roots ({@link ResourceSet}s) containing the model
116 */
117 public Set<? extends Notifier> getScopeRoots() {
118 return scopeRoots;
119 }
120
121 /**
122 * @return the options
123 */
124 public BaseIndexOptions getOptions() {
125 return options.copy();
126 }
127
128 @Override
129 public int hashCode() {
130 final int prime = 31;
131 int result = 1;
132 result = prime * result + ((options == null) ? 0 : options.hashCode());
133 result = prime * result
134 + ((scopeRoots == null) ? 0 : scopeRoots.hashCode());
135 return result;
136 }
137 @Override
138 public boolean equals(Object obj) {
139 if (this == obj)
140 return true;
141 if (obj == null)
142 return false;
143 if (!(obj instanceof EMFScope))
144 return false;
145 EMFScope other = (EMFScope) obj;
146 if (options == null) {
147 if (other.options != null)
148 return false;
149 } else if (!options.equals(other.options))
150 return false;
151 if (scopeRoots == null) {
152 if (other.scopeRoots != null)
153 return false;
154 } else if (!scopeRoots.equals(other.scopeRoots))
155 return false;
156 return true;
157 }
158
159
160 @Override
161 public String toString() {
162 return String.format("EMFScope(%s):%s", options, scopeRoots.stream().map(this::scopeRootString).collect(Collectors.joining(",")));
163 }
164
165 private String scopeRootString(Notifier notifier) {
166 if (notifier instanceof Resource) {
167 Resource resource = (Resource) notifier;
168 return String.format("%s(%s)", resource.getClass(), resource.getURI());
169 } else if (notifier instanceof ResourceSet) {
170 ResourceSet resourceSet = (ResourceSet) notifier;
171 return resourceSet.getResources().stream()
172 .map(Resource::getURI)
173 .map(URI::toString)
174 .collect(Collectors.joining(", ", resourceSet.getClass() + "(", ")"));
175 } else {
176 return notifier.toString();
177 }
178 }
179
180 @Override
181 protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener, Logger logger) {
182 return new EMFEngineContext(this, engine, errorListener, logger);
183 }
184
185 /**
186 * Provides access to the underlying EMF model index ({@link NavigationHelper}) from a VIATRA Query engine instantiated on an EMFScope
187 *
188 * @param engine an already existing VIATRA Query engine instantiated on an EMFScope
189 * @return the underlying EMF base index that indexes the contents of the EMF model
190 * @throws ViatraQueryRuntimeException if base index initialization fails
191 */
192 public static NavigationHelper extractUnderlyingEMFIndex(ViatraQueryEngine engine) {
193 final QueryScope scope = engine.getScope();
194 if (scope instanceof EMFScope)
195 return ((EMFBaseIndexWrapper)AdvancedViatraQueryEngine.from(engine).getBaseIndex()).getNavigationHelper();
196 else throw new IllegalArgumentException("Cannot extract EMF base index from VIATRA Query engine instantiated on non-EMF scope " + scope);
197 }
198
199}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/helper/ViatraQueryRuntimeHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/helper/ViatraQueryRuntimeHelper.java
deleted file mode 100644
index 93ac97f2..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/helper/ViatraQueryRuntimeHelper.java
+++ /dev/null
@@ -1,161 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf.helper;
10
11import java.util.function.Function;
12
13import org.eclipse.emf.ecore.EClassifier;
14import org.eclipse.emf.ecore.EObject;
15import org.eclipse.emf.ecore.EPackage;
16import org.eclipse.emf.ecore.EStructuralFeature;
17import tools.refinery.viatra.runtime.api.IPatternMatch;
18
19/**
20 * Helper functions for dealing with the EMF objects with VIATRA Queries.
21 *
22 * @author Abel Hegedus
23 * @since 0.9
24 *
25 */
26public class ViatraQueryRuntimeHelper {
27
28 private ViatraQueryRuntimeHelper() {/*Utility class constructor*/}
29
30 private static final Function<Object, String> STRING_VALUE_TRANSFORMER = input -> (input == null) ? "(null)" : input.toString();
31
32 /**
33 * Gives a human-readable name of an EMF type.
34 */
35 public static String prettyPrintEMFType(Object typeObject) {
36 if (typeObject == null) {
37 return "(null)";
38 } else if (typeObject instanceof EClassifier) {
39 final EClassifier eClassifier = (EClassifier) typeObject;
40 final EPackage ePackage = eClassifier.getEPackage();
41 final String nsURI = ePackage == null ? null : ePackage.getNsURI();
42 final String typeName = eClassifier.getName();
43 return "" + nsURI + "/" + typeName;
44 } else if (typeObject instanceof EStructuralFeature) {
45 final EStructuralFeature feature = (EStructuralFeature) typeObject;
46 return prettyPrintEMFType(feature.getEContainingClass()) + "." + feature.getName();
47 } else
48 return typeObject.toString();
49 }
50
51
52 /**
53 * Get the structural feature with the given name of the given object.
54 *
55 * @param o
56 * the object (must be an EObject)
57 * @param featureName
58 * the name of the feature
59 * @return the EStructuralFeature of the object or null if it can not be found
60 */
61 public static EStructuralFeature getFeature(Object o, String featureName) {
62 if (o instanceof EObject) {
63 EStructuralFeature feature = ((EObject) o).eClass().getEStructuralFeature(featureName);
64 return feature;
65 }
66 return null;
67 }
68
69 /**
70 * Returns the message for the given match using the given format. The format string can refer to the value of
71 * parameter A of the match with $A$ and even access features of A (if it's an EObject), e.g. $A.id$.
72 *
73 * <p/>
74 * If the selected parameter does not exist, the string "[no such parameter]" is added
75 *
76 * <p/>
77 * If no feature is defined, but A has a feature called "name", then its value is used.
78 *
79 * <p/>
80 * If the selected feature does not exist, A.toString() is added.
81 *
82 * <p/>
83 * If the selected feature is null, the string "null" is added.
84 *
85 * @param match
86 * cannot be null!
87 * @param messageFormat
88 * cannot be null!
89 */
90 public static String getMessage(IPatternMatch match, String messageFormat) {
91 return getMessage(match, messageFormat, STRING_VALUE_TRANSFORMER);
92 }
93
94 /**
95 * Returns the message for the given match using the given format while transforming values with the given function.
96 * The format string can refer to the value of parameter A of the match with $A$ and even access features of A (if
97 * it's an EObject), e.g. $A.id$. The function will be called to compute the final string representation of the
98 * values selected by the message format.
99 *
100 * <p/>
101 * If the selected parameter does not exist, the string "[no such parameter]" is added
102 *
103 * <p/>
104 * If no feature is defined, but A has a feature called "name", then its value is passed to the function.
105 *
106 * <p/>
107 * If the selected feature does not exist, A is passed to the function.
108 *
109 * <p/>
110 * If the selected feature is null, the string "null" is added.
111 *
112 * @param match
113 * cannot be null!
114 * @param messageFormat
115 * cannot be null!
116 * @param parameterValueTransformer
117 * cannot be null!
118 * @since 2.0
119 */
120 public static String getMessage(IPatternMatch match, String messageFormat, Function<Object,String> parameterValueTransformer) {
121 String[] tokens = messageFormat.split("\\$");
122 StringBuilder newText = new StringBuilder();
123
124 for (int i = 0; i < tokens.length; i++) {
125 if (i % 2 == 0) {
126 newText.append(tokens[i]);
127 } else {
128 String[] objectTokens = tokens[i].split("\\.");
129 if (objectTokens.length > 0) {
130 Object o = null;
131 EStructuralFeature feature = null;
132
133 if (objectTokens.length == 1) {
134 o = match.get(objectTokens[0]);
135 feature = getFeature(o, "name");
136 }
137 if (objectTokens.length == 2) {
138 o = match.get(objectTokens[0]);
139 feature = getFeature(o, objectTokens[1]);
140 }
141
142 if (o != null && feature != null) {
143 Object value = ((EObject) o).eGet(feature);
144 if (value != null) {
145 newText.append(parameterValueTransformer.apply(value));
146 } else {
147 newText.append("null");
148 }
149 } else if (o != null) {
150 newText.append(parameterValueTransformer.apply(o));
151 }
152 } else {
153 newText.append("[no such parameter]");
154 }
155 }
156 }
157
158 return newText.toString();
159 }
160
161}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/BaseEMFTypeKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/BaseEMFTypeKey.java
deleted file mode 100644
index c5dfa966..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/BaseEMFTypeKey.java
+++ /dev/null
@@ -1,34 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf.types;
10
11import tools.refinery.viatra.runtime.matchers.context.common.BaseInputKeyWrapper;
12
13/**
14 * Base class for EMF Type keys.
15 * @author Bergmann Gabor
16 *
17 */
18public abstract class BaseEMFTypeKey<EMFKey> extends BaseInputKeyWrapper<EMFKey> {
19
20 public BaseEMFTypeKey(EMFKey emfKey) {
21 super(emfKey);
22 }
23
24 public EMFKey getEmfKey() {
25 return getWrappedKey();
26 }
27
28 @Override
29 public String toString() {
30 return this.getPrettyPrintableName();
31 }
32
33
34}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassExactInstancesKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassExactInstancesKey.java
deleted file mode 100644
index dd10502d..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassExactInstancesKey.java
+++ /dev/null
@@ -1,51 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.emf.types;
11
12import org.eclipse.emf.ecore.EClass;
13import tools.refinery.viatra.runtime.emf.EMFScope;
14import tools.refinery.viatra.runtime.emf.helper.ViatraQueryRuntimeHelper;
15
16/**
17 * Instance tuples are of form (x), where x is an eObject instance of the given eClass, but <b>not</b> one of its subclasses, <b>within the scope</b>.
18 * <p> This input key has the strict semantics that instances must be within the scope.
19 *
20 * @noreference This class is not intended to be referenced by clients. Not currently supported by {@link EMFScope}, for internal use only at the time
21 *
22 * @author Bergmann Gabor
23 * @since 2.1
24 */
25public class EClassExactInstancesKey extends BaseEMFTypeKey<EClass> {
26
27 public EClassExactInstancesKey(EClass emfKey) {
28 super(emfKey);
29 }
30
31 @Override
32 public String getPrettyPrintableName() {
33 return "(scoped,exact) "+ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey);
34 }
35
36 @Override
37 public String getStringID() {
38 return "eClass(scoped,exact)#"+ ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey);
39 }
40
41 @Override
42 public int getArity() {
43 return 1;
44 }
45
46 @Override
47 public boolean isEnumerable() {
48 return true;
49 }
50
51}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassTransitiveInstancesKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassTransitiveInstancesKey.java
deleted file mode 100644
index 4ca6b220..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassTransitiveInstancesKey.java
+++ /dev/null
@@ -1,47 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf.types;
10
11import org.eclipse.emf.ecore.EClass;
12import tools.refinery.viatra.runtime.emf.EMFScope;
13import tools.refinery.viatra.runtime.emf.helper.ViatraQueryRuntimeHelper;
14
15/**
16 * Instance tuples are of form (x), where x is an eObject instance of the given eClass or one of its subclasses <b>within the scope</b>.
17 * <p> As of version 1.6, this input key has the strict semantics that instances must be within the {@link EMFScope}.
18 * @author Bergmann Gabor
19 *
20 */
21public class EClassTransitiveInstancesKey extends BaseEMFTypeKey<EClass> {
22
23 public EClassTransitiveInstancesKey(EClass emfKey) {
24 super(emfKey);
25 }
26
27 @Override
28 public String getPrettyPrintableName() {
29 return "(scoped) "+ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey);
30 }
31
32 @Override
33 public String getStringID() {
34 return "eClass(scoped)#"+ ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey);
35 }
36
37 @Override
38 public int getArity() {
39 return 1;
40 }
41
42 @Override
43 public boolean isEnumerable() {
44 return true;
45 }
46
47}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassUnscopedTransitiveInstancesKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassUnscopedTransitiveInstancesKey.java
deleted file mode 100644
index 11c5b235..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EClassUnscopedTransitiveInstancesKey.java
+++ /dev/null
@@ -1,46 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf.types;
10
11import org.eclipse.emf.ecore.EClass;
12import tools.refinery.viatra.runtime.emf.helper.ViatraQueryRuntimeHelper;
13
14/**
15 * Instance tuples are of form (x), where x is an eObject instance of the given eClass or one of its subclasses <b>regardless whether it is within the scope</b>.
16 *
17 * @author Bergmann Gabor
18 * @since 1.6
19 */
20public class EClassUnscopedTransitiveInstancesKey extends BaseEMFTypeKey<EClass> {
21
22 public EClassUnscopedTransitiveInstancesKey(EClass emfKey) {
23 super(emfKey);
24 }
25
26 @Override
27 public String getPrettyPrintableName() {
28 return "(unscoped) "+ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey);
29 }
30
31 @Override
32 public String getStringID() {
33 return "eClass(unscoped)#"+ ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey);
34 }
35
36 @Override
37 public int getArity() {
38 return 1;
39 }
40
41 @Override
42 public boolean isEnumerable() {
43 return false;
44 }
45
46}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EDataTypeInSlotsKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EDataTypeInSlotsKey.java
deleted file mode 100644
index a1cc4863..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EDataTypeInSlotsKey.java
+++ /dev/null
@@ -1,48 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf.types;
10
11import org.eclipse.emf.ecore.EDataType;
12import tools.refinery.viatra.runtime.emf.helper.ViatraQueryRuntimeHelper;
13
14/**
15 * Instance tuples are of form (x), where x is an instance of the given eDataType residing at an attribute slot of an eObject in the model.
16 * @author Bergmann Gabor
17 *
18 */
19public class EDataTypeInSlotsKey extends BaseEMFTypeKey<EDataType> {
20
21 /**
22 * @param emfKey
23 */
24 public EDataTypeInSlotsKey(EDataType emfKey) {
25 super(emfKey);
26 }
27
28 @Override
29 public String getPrettyPrintableName() {
30 return "(Attribute Slot Values: " + ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey) + ")";
31 }
32
33 @Override
34 public String getStringID() {
35 return "slotValue#" + ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey);
36 }
37
38 @Override
39 public int getArity() {
40 return 1;
41 }
42
43 @Override
44 public boolean isEnumerable() {
45 return true;
46 }
47
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EStructuralFeatureInstancesKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EStructuralFeatureInstancesKey.java
deleted file mode 100644
index 357f5e7e..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/emf/types/EStructuralFeatureInstancesKey.java
+++ /dev/null
@@ -1,48 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.emf.types;
10
11import org.eclipse.emf.ecore.EStructuralFeature;
12import tools.refinery.viatra.runtime.emf.EMFScope;
13import tools.refinery.viatra.runtime.emf.helper.ViatraQueryRuntimeHelper;
14
15/**
16 * Instance tuples are of form (x, y), where x is an eObject that has y as the value of the given feature (or one of the values in case of multi-valued).
17 *
18 * <p> As of version 1.6, this input key has the strict semantics that x must be within the {@link EMFScope}, scoping is <b>not</b> implied for y.
19 * @author Bergmann Gabor
20 *
21 */
22public class EStructuralFeatureInstancesKey extends BaseEMFTypeKey<EStructuralFeature> {
23
24 public EStructuralFeatureInstancesKey(EStructuralFeature emfKey) {
25 super(emfKey);
26 }
27
28 @Override
29 public String getPrettyPrintableName() {
30 return ViatraQueryRuntimeHelper.prettyPrintEMFType(wrappedKey);
31 }
32
33 @Override
34 public String getStringID() {
35 return "feature#"+ getPrettyPrintableName();
36 }
37
38 @Override
39 public int getArity() {
40 return 2;
41 }
42
43 @Override
44 public boolean isEnumerable() {
45 return true;
46 }
47
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/IQueryGroupProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/IQueryGroupProvider.java
deleted file mode 100644
index 45594b5b..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/IQueryGroupProvider.java
+++ /dev/null
@@ -1,40 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.extensibility;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.api.IQueryGroup;
14import tools.refinery.viatra.runtime.matchers.util.IProvider;
15
16/**
17 * Provider interface for {@link IQueryGroup} instances with added method for
18 * requesting the set of FQNs for the query specifications in the group.
19 *
20 * @author Abel Hegedus
21 * @since 1.3
22 *
23 */
24public interface IQueryGroupProvider extends IProvider<IQueryGroup> {
25
26 /**
27 * Note that the provider should load the query group class only if the FQNs can not be computed in other ways.
28 *
29 * @return the set of query specification FQNs in the group
30 */
31 Set<String> getQuerySpecificationFQNs();
32
33 /**
34 * Note that the provider should load the query group class only if the FQNs can not be computed in other ways.
35 *
36 * @return a set of providers for query specifications in the group
37 */
38 Set<IQuerySpecificationProvider> getQuerySpecificationProviders();
39
40}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/IQuerySpecificationProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/IQuerySpecificationProvider.java
deleted file mode 100644
index 3c9c235d..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/IQuerySpecificationProvider.java
+++ /dev/null
@@ -1,36 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.extensibility;
10
11import tools.refinery.viatra.runtime.api.IQuerySpecification;
12import tools.refinery.viatra.runtime.matchers.util.IProvider;
13
14/**
15 * Provider interface for {@link IQuerySpecification} instances with added method for
16 * requesting the FQN for the query specification.
17 *
18 * @author Abel Hegedus
19 * @since 1.3
20 *
21 */
22public interface IQuerySpecificationProvider extends IProvider<IQuerySpecification<?>> {
23
24 /**
25 * Note that the provider will usually not load the query specification class to return the FQN.
26 *
27 * @return the fully qualified name of the provided query specification
28 */
29 String getFullyQualifiedName();
30
31 /**
32 * Returns the name of project providing the specification (or null if not calculable)
33 */
34 String getSourceProjectName();
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/PQueryExtensionFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/PQueryExtensionFactory.java
deleted file mode 100644
index 91e087d7..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/PQueryExtensionFactory.java
+++ /dev/null
@@ -1,33 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.extensibility;
10
11import org.eclipse.core.runtime.CoreException;
12import org.eclipse.core.runtime.IStatus;
13import org.eclipse.core.runtime.Status;
14import tools.refinery.viatra.runtime.api.IQuerySpecification;
15
16/**
17 * An extension factory to access PQuery instances from Query Specifications.
18 *
19 * @author Zoltan Ujhelyi
20 *
21 */
22public class PQueryExtensionFactory extends SingletonExtensionFactory {
23
24 @Override
25 public Object create() throws CoreException {
26 final Object _spec = super.create();
27 if (_spec instanceof IQuerySpecification<?>) {
28 return ((IQuerySpecification<?>) _spec).getInternalQueryRepresentation();
29 }
30 throw new CoreException(new Status(IStatus.ERROR, getBundle().getSymbolicName(), "Cannot instantiate PQuery instance."));
31 }
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonExtensionFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonExtensionFactory.java
deleted file mode 100644
index 29705968..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonExtensionFactory.java
+++ /dev/null
@@ -1,62 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.extensibility;
10
11import java.lang.reflect.Method;
12
13import org.eclipse.core.runtime.CoreException;
14import org.eclipse.core.runtime.IConfigurationElement;
15import org.eclipse.core.runtime.IExecutableExtension;
16import org.eclipse.core.runtime.IExecutableExtensionFactory;
17import org.eclipse.core.runtime.IStatus;
18import org.eclipse.core.runtime.Platform;
19import org.eclipse.core.runtime.Status;
20import org.osgi.framework.Bundle;
21
22/**
23 * Factory to register a static singleton instance in an extension point.
24 *
25 * @author Zoltan Ujhelyi
26 *
27 */
28public class SingletonExtensionFactory implements IExecutableExtension, IExecutableExtensionFactory {
29
30 private String clazzName;
31 private Bundle bundle;
32
33 protected Bundle getBundle() {
34 return bundle;
35 }
36
37 @Override
38 public Object create() throws CoreException {
39 try {
40 final Class<?> clazz = bundle.loadClass(clazzName);
41 Method method = clazz.getMethod("instance");
42 return method.invoke(null);
43 } catch (Exception e) {
44 throw new CoreException(new Status(IStatus.ERROR, bundle.getSymbolicName(), "Error loading group "
45 + clazzName, e));
46 }
47 }
48
49 @Override
50 public void setInitializationData(IConfigurationElement config, String propertyName, Object data)
51 throws CoreException {
52 String id = config.getContributor().getName();
53 bundle = Platform.getBundle(id);
54 if (data instanceof String) {
55 clazzName = (String) data;
56 } else {
57 throw new CoreException(new Status(IStatus.ERROR, bundle.getSymbolicName(),
58 "Unsupported extension initialization data: " + data));
59 }
60 }
61
62}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonQueryGroupProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonQueryGroupProvider.java
deleted file mode 100644
index 758b51dd..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonQueryGroupProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.extensibility;
10
11import java.util.Set;
12import java.util.stream.Collectors;
13
14import tools.refinery.viatra.runtime.api.IQueryGroup;
15import tools.refinery.viatra.runtime.api.IQuerySpecification;
16import tools.refinery.viatra.runtime.matchers.util.SingletonInstanceProvider;
17
18/**
19 * Provider implementation for storing an existing query group instance.
20 *
21 * @author Abel Hegedus
22 * @since 1.3
23 *
24 */
25public class SingletonQueryGroupProvider extends SingletonInstanceProvider<IQueryGroup> implements IQueryGroupProvider {
26
27 /**
28 * @param instance the instance to wrap
29 */
30 public SingletonQueryGroupProvider(IQueryGroup instance) {
31 super(instance);
32 }
33
34 @Override
35 public Set<String> getQuerySpecificationFQNs() {
36 return get().getSpecifications().stream().map(IQuerySpecification::getFullyQualifiedName)
37 .collect(Collectors.toSet());
38 }
39
40 @Override
41 public Set<IQuerySpecificationProvider> getQuerySpecificationProviders() {
42 return get().getSpecifications().stream().map(SingletonQuerySpecificationProvider::new)
43 .collect(Collectors.toSet());
44 }
45
46}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonQuerySpecificationProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonQuerySpecificationProvider.java
deleted file mode 100644
index f8f3a741..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/SingletonQuerySpecificationProvider.java
+++ /dev/null
@@ -1,42 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.extensibility;
10
11import tools.refinery.viatra.runtime.api.IQuerySpecification;
12import tools.refinery.viatra.runtime.matchers.util.SingletonInstanceProvider;
13
14/**
15 * Provider implementation for storing an existing query specification instance.
16 *
17 * @author Abel Hegedus
18 * @since 1.3
19 *
20 */
21public class SingletonQuerySpecificationProvider extends SingletonInstanceProvider<IQuerySpecification<?>>
22 implements IQuerySpecificationProvider {
23
24 /**
25 *
26 * @param instance the instance to wrap
27 */
28 public SingletonQuerySpecificationProvider(IQuerySpecification<?> instance) {
29 super(instance);
30 }
31
32 @Override
33 public String getFullyQualifiedName() {
34 return get().getFullyQualifiedName();
35 }
36
37 @Override
38 public String getSourceProjectName() {
39 return null;
40 }
41
42}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/ViatraQueryRuntimeConstants.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/ViatraQueryRuntimeConstants.java
deleted file mode 100644
index 9b0850e4..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/extensibility/ViatraQueryRuntimeConstants.java
+++ /dev/null
@@ -1,27 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.extensibility;
10
11/**
12 * Utility class for Viatra Query runtime constants, such as extension point identifiers.
13 *
14 * @author Abel Hegedus
15 *
16 */
17public final class ViatraQueryRuntimeConstants {
18
19 private ViatraQueryRuntimeConstants() {/* Constructor hidden for utility class */}
20
21 // Surrogate query extension
22
23 public static final String SURROGATE_QUERY_EXTENSIONID = "tools.refinery.viatra.runtime.surrogatequeryemf";
24
25
26
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/ExtensionBasedSurrogateQueryLoader.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/ExtensionBasedSurrogateQueryLoader.java
deleted file mode 100644
index af7cdaf1..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/ExtensionBasedSurrogateQueryLoader.java
+++ /dev/null
@@ -1,148 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Abel Hegedus, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.internal;
10
11import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkState;
12
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.HashMap;
16import java.util.Map;
17import java.util.Map.Entry;
18
19import org.apache.log4j.Logger;
20import org.eclipse.core.runtime.CoreException;
21import org.eclipse.core.runtime.IConfigurationElement;
22import org.eclipse.core.runtime.Platform;
23import org.eclipse.emf.ecore.EClass;
24import org.eclipse.emf.ecore.EClassifier;
25import org.eclipse.emf.ecore.EPackage;
26import org.eclipse.emf.ecore.EStructuralFeature;
27import tools.refinery.viatra.runtime.emf.types.EStructuralFeatureInstancesKey;
28import tools.refinery.viatra.runtime.extensibility.ViatraQueryRuntimeConstants;
29import tools.refinery.viatra.runtime.matchers.context.IInputKey;
30import tools.refinery.viatra.runtime.matchers.context.surrogate.SurrogateQueryRegistry;
31import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
32import tools.refinery.viatra.runtime.matchers.util.IProvider;
33
34/**
35 * @author Abel Hegedus
36 *
37 */
38public class ExtensionBasedSurrogateQueryLoader {
39
40 private static final String DUPLICATE_SURROGATE_QUERY = "Duplicate surrogate query definition %s for feature %s of EClass %s in package %s (FQN in map %s, contributing plug-ins %s, plug-in %s)";
41
42 private Map<String, String> contributingPluginOfFeatureMap = new HashMap<>();
43 private Map<EStructuralFeature, PQueryProvider> contributedSurrogateQueries;
44
45 private static final ExtensionBasedSurrogateQueryLoader INSTANCE = new ExtensionBasedSurrogateQueryLoader();
46
47 /**
48 * A provider implementation for PQuery instances based on extension elements. It is expected that the getter will only
49 * @author Zoltan Ujhelyi
50 *
51 */
52 private static final class PQueryProvider implements IProvider<PQuery> {
53
54 private final IConfigurationElement element;
55 private PQuery query;
56
57 public PQueryProvider(IConfigurationElement element) {
58 this.element = element;
59 this.query = null;
60 }
61
62 @Override
63 public PQuery get() {
64 try {
65 if (query == null) {
66 query = (PQuery) element.createExecutableExtension("surrogate-query");
67 }
68 return query;
69 } catch (CoreException e) {
70 throw new IllegalArgumentException("Error initializing surrogate query", e);
71 }
72 }
73 }
74
75 public static ExtensionBasedSurrogateQueryLoader instance() {
76 return INSTANCE;
77 }
78
79 public void loadKnownSurrogateQueriesIntoRegistry() {
80 Map<EStructuralFeature, PQueryProvider> knownSurrogateQueryFQNs = getSurrogateQueryProviders();
81 for (Entry<EStructuralFeature, PQueryProvider> entry : knownSurrogateQueryFQNs.entrySet()) {
82 final IInputKey inputKey = new EStructuralFeatureInstancesKey(entry.getKey());
83 SurrogateQueryRegistry.instance().registerSurrogateQueryForFeature(inputKey, entry.getValue());
84 }
85 }
86
87 private Map<EStructuralFeature, PQueryProvider> getSurrogateQueryProviders() {
88 if(contributedSurrogateQueries != null) {
89 return contributedSurrogateQueries;
90 }
91 contributedSurrogateQueries = new HashMap<>();
92 if (Platform.isRunning()) {
93 for (IConfigurationElement e : Platform.getExtensionRegistry().getConfigurationElementsFor(ViatraQueryRuntimeConstants.SURROGATE_QUERY_EXTENSIONID)) {
94 if (e.isValid()) {
95 processExtension(e);
96 }
97 }
98 }
99 return contributedSurrogateQueries;
100 }
101
102 private void processExtension(IConfigurationElement el) {
103
104 try {
105 String packageUri = el.getAttribute("package-nsUri");
106 String className = el.getAttribute("class-name");
107 String featureName = el.getAttribute("feature-name");
108 String queryFqn = el.getAttribute("query-fqn");
109 if (queryFqn == null) {
110 queryFqn = "";
111 }
112 PQueryProvider surrogateQueryProvider = new PQueryProvider(el);
113
114 String contributorName = el.getContributor().getName();
115 StringBuilder featureIdBuilder = new StringBuilder();
116 checkState(packageUri != null, "Package NsURI cannot be null in extension");
117 checkState(className != null, "Class name cannot be null in extension");
118 checkState(featureName != null, "Feature name cannot be null in extension");
119
120 EPackage pckg = EPackage.Registry.INSTANCE.getEPackage(packageUri);
121 featureIdBuilder.append(packageUri);
122 checkState(pckg != null, "Package %s not found! (plug-in %s)", packageUri, contributorName);
123
124 EClassifier clsr = pckg.getEClassifier(className);
125 featureIdBuilder.append("##").append(className);
126 checkState(clsr instanceof EClass, "EClassifier %s does not exist in package %s! (plug-in %s)", className, packageUri, contributorName);
127
128 EClass cls = (EClass) clsr;
129 EStructuralFeature feature = cls.getEStructuralFeature(featureName);
130 featureIdBuilder.append("##").append(featureName);
131 checkState(feature != null, "Feature %s of EClass %s in package %s not found! (plug-in %s)", featureName, className, packageUri, contributorName);
132
133 PQueryProvider fqnInMap = contributedSurrogateQueries.get(feature);
134 if(fqnInMap != null) {
135 String duplicateSurrogateFormatString = DUPLICATE_SURROGATE_QUERY;
136 Collection<String> contributorPlugins = Arrays.asList(contributorName, contributingPluginOfFeatureMap.get(featureIdBuilder.toString()));
137 String duplicateSurrogateMessage = String.format(duplicateSurrogateFormatString, queryFqn, featureName,
138 className, packageUri, fqnInMap, contributorPlugins, contributorName);
139 throw new IllegalStateException(duplicateSurrogateMessage);
140 }
141 contributedSurrogateQueries.put(feature, surrogateQueryProvider);
142 contributingPluginOfFeatureMap.put(featureIdBuilder.toString(), contributorName);
143 } catch (Exception e) {
144 final Logger logger = Logger.getLogger(SurrogateQueryRegistry.class);
145 logger.error("Surrogate query registration failed", e);
146 }
147 }
148}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/ExtensionBasedSystemDefaultBackendLoader.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/ExtensionBasedSystemDefaultBackendLoader.java
deleted file mode 100644
index 4339b70c..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/ExtensionBasedSystemDefaultBackendLoader.java
+++ /dev/null
@@ -1,60 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.internal;
10
11import org.eclipse.core.runtime.CoreException;
12import org.eclipse.core.runtime.IConfigurationElement;
13import org.eclipse.core.runtime.Platform;
14import tools.refinery.viatra.runtime.api.ViatraQueryEngineOptions;
15import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
16import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactoryProvider;
17import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
18
19/**
20 * @since 2.0
21 */
22public class ExtensionBasedSystemDefaultBackendLoader {
23
24 private static final String EXTENSION_ID = "tools.refinery.viatra.runtime.querybackend";
25 private static final ExtensionBasedSystemDefaultBackendLoader INSTANCE = new ExtensionBasedSystemDefaultBackendLoader();
26
27 public static ExtensionBasedSystemDefaultBackendLoader instance() {
28 return INSTANCE;
29 }
30
31 public void loadKnownBackends() {
32 IQueryBackendFactory defaultBackend = null;
33 IQueryBackendFactory defaultCachingBackend = null;
34 IQueryBackendFactory defaultSearchBackend = null;
35 final IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_ID);
36 for (IConfigurationElement e : config) {
37 try {
38 IQueryBackendFactoryProvider provider = (IQueryBackendFactoryProvider) e
39 .createExecutableExtension("provider");
40 if (provider.isSystemDefaultEngine()) {
41 defaultBackend = provider.getFactory();
42 }
43 if (provider.isSystemDefaultCachingBackend()) {
44 defaultCachingBackend = provider.getFactory();
45 }
46 if (provider.isSystemDefaultSearchBackend()) {
47 defaultSearchBackend = provider.getFactory();
48 }
49
50 } catch (CoreException ex) {
51 // In case errors try to continue with the next one
52 ViatraQueryLoggingUtil.getLogger(getClass()).error(
53 String.format("Error while initializing backend %s from plugin %s.",
54 e.getAttribute("backend"), e.getContributor().getName()), ex);
55 }
56 }
57 ViatraQueryEngineOptions.setSystemDefaultBackends(defaultBackend, defaultCachingBackend, defaultSearchBackend);
58 }
59
60}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java
index c2341273..a3a9d073 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java
@@ -34,9 +34,6 @@ import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
34import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType; 34import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
35import tools.refinery.viatra.runtime.matchers.util.IMultiLookup; 35import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
36import tools.refinery.viatra.runtime.matchers.util.Preconditions; 36import tools.refinery.viatra.runtime.matchers.util.Preconditions;
37import tools.refinery.viatra.runtime.registry.IDefaultRegistryView;
38import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistry;
39import tools.refinery.viatra.runtime.registry.QuerySpecificationRegistry;
40import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil; 37import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
41 38
42import java.lang.ref.WeakReference; 39import java.lang.ref.WeakReference;
@@ -227,17 +224,7 @@ public final class ViatraQueryEngineImpl extends AdvancedViatraQueryEngine
227 224
228 @Override 225 @Override
229 public ViatraQueryMatcher<? extends IPatternMatch> getMatcher(String patternFQN) { 226 public ViatraQueryMatcher<? extends IPatternMatch> getMatcher(String patternFQN) {
230 IQuerySpecificationRegistry registry = QuerySpecificationRegistry.getInstance(); 227 throw new UnsupportedOperationException("Query specification registry is not available");
231 IDefaultRegistryView view = registry.getDefaultView();
232 IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> querySpecification = view
233 .getEntry(patternFQN).get();
234 if (querySpecification != null) {
235 return getMatcher(querySpecification);
236 } else {
237 throw new ViatraQueryException(String.format(
238 "No matcher could be constructed for the pattern with FQN %s; if the generated matcher class is not available, please access for the first time using getMatcher(IQuerySpecification)",
239 patternFQN), "No matcher could be constructed for given pattern FQN.");
240 }
241 } 228 }
242 229
243 @Override 230 @Override
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/ExtensionBasedQuerySpecificationLoader.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/ExtensionBasedQuerySpecificationLoader.java
deleted file mode 100644
index 40bf3e67..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/ExtensionBasedQuerySpecificationLoader.java
+++ /dev/null
@@ -1,303 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.Map;
14import java.util.Objects;
15import java.util.Set;
16
17import org.eclipse.core.runtime.CoreException;
18import org.eclipse.core.runtime.IConfigurationElement;
19import org.eclipse.core.runtime.Platform;
20import tools.refinery.viatra.runtime.IExtensions;
21import tools.refinery.viatra.runtime.api.IQueryGroup;
22import tools.refinery.viatra.runtime.api.IQuerySpecification;
23import tools.refinery.viatra.runtime.extensibility.IQueryGroupProvider;
24import tools.refinery.viatra.runtime.extensibility.IQuerySpecificationProvider;
25import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
26import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
27import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
28import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
29import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
30
31/**
32 * Loader for the {@link QuerySpecificationRegistry} based on the query group extensions generated by the VIATRA Query
33 * builder. The loader has a single instance that processes the extensions on demand if the platform is running, caches
34 * the results and updates the {@link QuerySpecificationRegistry}. Note that the loader does not perform class loading
35 * on the query group if possible.
36 *
37 * <p>
38 * The class has a single instance accessible with {@link #getInstance()}.
39 *
40 * @author Abel Hegedus
41 * @since 1.3
42 *
43 */
44public class ExtensionBasedQuerySpecificationLoader {
45
46 public static final String CONNECTOR_ID = "tools.refinery.viatra.runtime.querygroup.extension.based.connector";
47
48 private static final String DUPLICATE_QUERY_GROUP_MESSAGE = "Duplicate query group identifier %s for plugin %s (already contributed by %s)";
49 private static final ExtensionBasedQuerySpecificationLoader INSTANCE = new ExtensionBasedQuerySpecificationLoader();
50
51 private IMultiLookup<String, String> contributingPluginOfGroupMap =
52 CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
53 private Map<String, QueryGroupProvider> contributedQueryGroups;
54
55 private ExtensionBasedSourceConnector sourceConnector;
56
57
58 /**
59 * @return the single instance of the loader.
60 */
61 public static ExtensionBasedQuerySpecificationLoader getInstance() {
62 return INSTANCE;
63 }
64
65 /**
66 * Loads the query specifications that are registered through extension points into the
67 * {@link QuerySpecificationRegistry}.
68 */
69 public void loadRegisteredQuerySpecificationsIntoRegistry() {
70 ((QuerySpecificationRegistry) QuerySpecificationRegistry.getInstance()).addDelayedSourceConnector(getSourceConnector());
71 }
72
73 /**
74 * Return a source connector that can be used to load query specifications contributed through
75 * extensions into a {@link IQuerySpecificationRegistry}.
76 *
77 * @return the source connector
78 */
79 public IRegistrySourceConnector getSourceConnector() {
80 if (this.sourceConnector == null) {
81 this.sourceConnector = new ExtensionBasedSourceConnector();
82 }
83 return sourceConnector;
84 }
85
86 private Map<String, QueryGroupProvider> getRegisteredQueryGroups() {
87 if(contributedQueryGroups != null) {
88 return contributedQueryGroups;
89 }
90 contributedQueryGroups = new HashMap<>();
91 if (Platform.isRunning()) {
92 for (IConfigurationElement e : Platform.getExtensionRegistry().getConfigurationElementsFor(IExtensions.QUERY_SPECIFICATION_EXTENSION_POINT_ID)) {
93 if (e.isValid()) {
94 processExtension(e);
95 }
96 }
97 }
98 return contributedQueryGroups;
99 }
100
101 private void processExtension(IConfigurationElement el) {
102 String id = null;
103 try {
104 String contributorName = el.getContributor().getName();
105 id = el.getAttribute("id");
106 if(id == null) {
107 throw new IllegalStateException(String.format("Query group extension identifier is required (plug-in: %s)!", contributorName));
108 }
109
110 QueryGroupProvider provider = new QueryGroupProvider(el);
111
112 QueryGroupProvider queryGroupInMap = contributedQueryGroups.get(id);
113 if(queryGroupInMap != null) {
114 IMemoryView<String> contributorPlugins = contributingPluginOfGroupMap.lookupOrEmpty(id);
115 throw new IllegalStateException(String.format(DUPLICATE_QUERY_GROUP_MESSAGE, id, contributorName, contributorPlugins.distinctValues()));
116 }
117
118 contributedQueryGroups.put(id, provider);
119 contributingPluginOfGroupMap.addPair(id, contributorName);
120 } catch (Exception e) {
121 // If there are serious compilation errors in the file loaded by the query registry, an error is thrown
122 if (id == null) {
123 id = "undefined in plugin.xml";
124 }
125 ViatraQueryLoggingUtil.getLogger(ExtensionBasedQuerySpecificationLoader.class).error(
126 "[ExtensionBasedQuerySpecificationLoader] Exception during query specification registry initialization when preparing group: "
127 + id + "! " + e.getMessage(), e);
128 }
129 }
130
131 /**
132 * @author Abel Hegedus
133 *
134 */
135 private final class ExtensionBasedSourceConnector implements IRegistrySourceConnector {
136
137 private Set<IConnectorListener> listeners;
138
139 public ExtensionBasedSourceConnector() {
140 this.listeners = new HashSet<>();
141 }
142
143 @Override
144 public String getIdentifier() {
145 return ExtensionBasedQuerySpecificationLoader.CONNECTOR_ID;
146 }
147
148 @Override
149 public void addListener(IConnectorListener listener) {
150 Objects.requireNonNull(listener, "Listener must not be null!");
151 boolean added = listeners.add(listener);
152 if(added) {
153 for (QueryGroupProvider queryGroupProvider : getRegisteredQueryGroups().values()) {
154 for (IQuerySpecificationProvider specificationProvider : queryGroupProvider.getQuerySpecificationProviders()) {
155 listener.querySpecificationAdded(this, specificationProvider);
156 }
157 }
158 }
159 }
160
161 @Override
162 public void removeListener(IConnectorListener listener) {
163 Objects.requireNonNull(listener, "Listener must not be null!");
164 listeners.remove(listener);
165 }
166
167 @Override
168 public boolean includeSpecificationsInDefaultViews() {
169 return true;
170 }
171 }
172
173 /**
174 * Provider implementation that uses the group extension to load the query group on-demand.
175 * It also provides the set of query FQNs that are part of the group without class loading.
176 * Once loaded, the query group is cached for future use.
177 *
178 * @author Abel Hegedus
179 */
180 private static final class QueryGroupProvider implements IQueryGroupProvider {
181
182 private static final String DUPLICATE_FQN_MESSAGE = "Duplicate FQN %s in query group extension point (plug-in %s)";
183 private final IConfigurationElement element;
184 private IQueryGroup queryGroup;
185 private Set<String> querySpecificationFQNs;
186 private Map<String, IQuerySpecificationProvider> querySpecificationMap;
187
188 public QueryGroupProvider(IConfigurationElement element) {
189 this.element = element;
190 this.queryGroup = null;
191 this.querySpecificationFQNs = null;
192 this.querySpecificationMap = null;
193 }
194
195 @Override
196 public IQueryGroup get() {
197 try{
198 if(queryGroup == null) {
199 queryGroup = (IQueryGroup) element.createExecutableExtension("group");
200 }
201 return queryGroup;
202 } catch (CoreException e) {
203 throw new IllegalStateException(e.getMessage(), e);
204 }
205 }
206
207 @Override
208 public Set<String> getQuerySpecificationFQNs() {
209 if(querySpecificationFQNs == null) {
210 Set<String> fqns = new HashSet<>();
211 for (IConfigurationElement e : element.getChildren("query-specification")) {
212 if (e.isValid()) {
213 String fqn = e.getAttribute("fqn");
214 boolean added = fqns.add(fqn);
215 if(!added) {
216 String contributorName = e.getContributor().getName();
217 throw new IllegalArgumentException(String.format(DUPLICATE_FQN_MESSAGE,fqn, contributorName));
218 }
219 }
220 }
221 if(fqns.isEmpty()) {
222 // we must load the class and get the specifications
223 IQueryGroup loadedQueryGroup = get();
224 for (IQuerySpecification<?> specification : loadedQueryGroup.getSpecifications()) {
225 String fullyQualifiedName = specification.getFullyQualifiedName();
226 boolean added = fqns.add(fullyQualifiedName);
227 if(!added) {
228 String contributorName = element.getContributor().getName();
229 throw new IllegalArgumentException(String.format(DUPLICATE_FQN_MESSAGE, fullyQualifiedName, contributorName));
230 }
231 }
232 }
233 // we will never change the set after initialization
234 querySpecificationFQNs = new HashSet<>(fqns);
235 }
236 return querySpecificationFQNs;
237 }
238
239 @Override
240 public Set<IQuerySpecificationProvider> getQuerySpecificationProviders() {
241 return new HashSet<>(getQuerySpecificationMap().values());
242 }
243
244 private Map<String, IQuerySpecificationProvider> getQuerySpecificationMap() {
245 if(querySpecificationMap == null){
246 querySpecificationMap = new HashMap<>();
247 Set<String> fqns = getQuerySpecificationFQNs();
248 for (String fqn : fqns) {
249 querySpecificationMap.put(fqn, new GroupBasedQuerySpecificationProvider(fqn, this));
250 }
251 }
252 return querySpecificationMap;
253 }
254
255 }
256
257 /**
258 * Provider implementation that uses the query group extension to load a query specification by its FQN. Note that
259 * the FQN of the provided query specification is set with the constructor and can be requested without loading the
260 * class. Once loaded, the query specification is cached for future use.
261 *
262 * @author Abel Hegedus
263 *
264 */
265 private static final class GroupBasedQuerySpecificationProvider implements IQuerySpecificationProvider {
266
267 private String queryFQN;
268 private QueryGroupProvider queryGroupProvider;
269 private IQuerySpecification<?> specification;
270
271 public GroupBasedQuerySpecificationProvider(String queryFQN, QueryGroupProvider queryGroupProvider) {
272 this.queryFQN = queryFQN;
273 this.queryGroupProvider = queryGroupProvider;
274 this.specification = null;
275 }
276
277 @Override
278 public IQuerySpecification<?> get() {
279 if(specification == null) {
280 if(queryGroupProvider.getQuerySpecificationFQNs().contains(queryFQN)) {
281 for (IQuerySpecification<?> spec : queryGroupProvider.get().getSpecifications()) {
282 if(spec.getFullyQualifiedName().equals(queryFQN)){
283 this.specification = spec;
284 }
285 }
286 } else {
287 throw new IllegalStateException(String.format("Could not find query specifition %s in group (plug-in %s)", queryFQN, queryGroupProvider.element.getContributor().getName()));
288 }
289 }
290 return specification;
291 }
292
293 @Override
294 public String getFullyQualifiedName() {
295 return queryFQN;
296 }
297
298 @Override
299 public String getSourceProjectName() {
300 return queryGroupProvider.element.getContributor().getName();
301 }
302 }
303}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IConnectorListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IConnectorListener.java
deleted file mode 100644
index 318415cc..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IConnectorListener.java
+++ /dev/null
@@ -1,40 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11import tools.refinery.viatra.runtime.extensibility.IQuerySpecificationProvider;
12
13/**
14 * Connector listeners are used to receive notifications on addition and removal of query specifications.
15 * The connector itself is also passed in the methods to allow the usage of the same listener on multiple connectors.
16 *
17 * @author Abel Hegedus
18 * @since 1.3
19 *
20 */
21public interface IConnectorListener {
22
23 /**
24 * Called when a new query specification is added to the given connector.
25 * The provider interface is used to avoid class loading as long as possible.
26 *
27 * @param connector that has a new specification
28 * @param specificationProvider that wraps the new specification
29 */
30 void querySpecificationAdded(IRegistrySourceConnector connector, IQuerySpecificationProvider specificationProvider);
31
32 /**
33 * Called when a query specification is removed from the given connector.
34 * The provider interface is used to avoid class loading as long as possible.
35 *
36 * @param connector that has a removed specification
37 * @param specificationProvider that wraps the removed specification
38 */
39 void querySpecificationRemoved(IRegistrySourceConnector connector, IQuerySpecificationProvider specificationProvider);
40}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IDefaultRegistryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IDefaultRegistryView.java
deleted file mode 100644
index 9e3e0394..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IDefaultRegistryView.java
+++ /dev/null
@@ -1,37 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11import java.util.NoSuchElementException;
12
13import tools.refinery.viatra.runtime.api.IQueryGroup;
14
15/**
16 * The default registry view ensures that the fully qualified name of entries are unique and provides an additional
17 * method for retrieving the query group of entries for easy initialization.
18 *
19 * @author Abel Hegedus
20 * @since 1.3
21 *
22 */
23public interface IDefaultRegistryView extends IRegistryView {
24
25 /**
26 * @return a query group containing all query specifications
27 */
28 IQueryGroup getQueryGroup();
29
30 /**
31 * @param fullyQualifiedName
32 * of the entry that is requested
33 * @return the entry with the given FQN
34 * @throws NoSuchElementException if there is no such entry in the default view
35 */
36 IQuerySpecificationRegistryEntry getEntry(String fullyQualifiedName);
37}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistry.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistry.java
deleted file mode 100644
index 97a17f0e..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistry.java
+++ /dev/null
@@ -1,74 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11/**
12 * The query specification registry is used to manage query specifications provided by multiple connectors which can
13 * dynamically add and remove specifications. Users can read the contents of the registry through views that are also
14 * dynamically updated when the registry is changed by the connectors.
15 *
16 * @author Abel Hegedus
17 * @since 1.3
18 *
19 */
20public interface IQuerySpecificationRegistry {
21
22 /**
23 * Cannot register connectors with the same identifier twice. No change occurs if the identifier is already used.
24 *
25 * @param connector
26 * cannot be null
27 * @return false if a connector with the given identifier has already been added, true otherwise
28 */
29 boolean addSource(IRegistrySourceConnector connector);
30
31 /**
32 * Removes the connector if it was registered. No change occurs if the identifier of the connector was not used
33 * before.
34 *
35 * @param connector
36 * cannot be null
37 * @return false if a registered connector with the given identifier was not found, true if it was successfully
38 * removed
39 */
40 boolean removeSource(IRegistrySourceConnector connector);
41
42 /**
43 * Returns a default view instance that contains query specification entries that indicate their inclusion in
44 * default views. If there are entries with the same FQN, only the last added will be included in the view to avoid
45 * duplicate FQNs.
46 *
47 * @return the default view instance
48 */
49 IDefaultRegistryView getDefaultView();
50
51 /**
52 * Creates a view which contains query specification entries that indicate their inclusion in default views. This
53 * view will also be incrementally updated on registry changes and accepts listeners to notify on changes.
54 *
55 * @return a new view instance
56 */
57 IRegistryView createView();
58
59 /**
60 * Creates a view which contains registered query specifications that are considered relevant by the passed filter.
61 * This view will also be incrementally updated on registry changes and accepts listeners to notify on changes.
62 *
63 * @return a new filtered view instance
64 */
65 IRegistryView createView(IRegistryViewFilter filter);
66
67 /**
68 * Creates a view which is instantiated by the factory and is connected to the registry. This
69 * view will also be incrementally updated on registry changes and accepts listeners to notify on changes.
70 *
71 * @return a new view instance
72 */
73 IRegistryView createView(IRegistryViewFactory factory);
74}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistryChangeListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistryChangeListener.java
deleted file mode 100644
index defdd2ab..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistryChangeListener.java
+++ /dev/null
@@ -1,35 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11/**
12 * Listener interface for providing update notifications of views to users. It is used for propagating changes from the
13 * query specification registry to the views and from the views to users.
14 *
15 * @author Abel Hegedus
16 * @since 1.3
17 *
18 */
19public interface IQuerySpecificationRegistryChangeListener {
20
21 /**
22 * Called when a new entry is added to the registry.
23 *
24 * @param entry that is added
25 */
26 void entryAdded(IQuerySpecificationRegistryEntry entry);
27
28 /**
29 * Called when an existing entry is removed from the registry.
30 *
31 * @param entry that is removed
32 */
33 void entryRemoved(IQuerySpecificationRegistryEntry entry);
34
35}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistryEntry.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistryEntry.java
deleted file mode 100644
index 5009d74b..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IQuerySpecificationRegistryEntry.java
+++ /dev/null
@@ -1,48 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11import tools.refinery.viatra.runtime.extensibility.IQuerySpecificationProvider;
12
13/**
14 * The query specification registry entry interface can return the identifier of the source that added it to the
15 * registry. It is provider based and can delay class loading of the wrapped {@link IQuerySpecification} until needed.
16 *
17 * @author Abel Hegedus
18 * @since 1.3
19 *
20 */
21public interface IQuerySpecificationRegistryEntry extends IQuerySpecificationProvider {
22
23 /**
24 * @return the identifier of the registry source that contributed the specification
25 */
26 String getSourceIdentifier();
27
28 /**
29 * Returns whether the query specification was provided by an identifiable project.
30 */
31 boolean isFromProject();
32
33 /**
34 * Collects the name of the project that is registered this specification to the registry.
35 * If {@link #getSourceIdentifier()} is false, it returns null.
36 */
37 String getSourceProjectName();
38
39 /**
40 * @return true if the entry should be included in default views (created without any filters)
41 */
42 boolean includeInDefaultViews();
43
44 /**
45 * @return the wrapped {@link IQuerySpecificationProvider} or itself
46 */
47 IQuerySpecificationProvider getProvider();
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistrySourceConnector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistrySourceConnector.java
deleted file mode 100644
index 94c68d1b..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistrySourceConnector.java
+++ /dev/null
@@ -1,50 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11/**
12 * A registry source connector can provide query specifications to listeners (e.g. {@link IQuerySpecificationRegistry}).
13 * The connector interface does not support direct access to query specifications, instead it sends existing specifications
14 * to listeners on addition and sends notifications to listeners when a change occurs in the set of specifications.
15 *
16 * @author Abel Hegedus
17 * @since 1.3
18 *
19 */
20public interface IRegistrySourceConnector {
21
22 /**
23 * The connector must return the same identifier every time it is invoked!
24 *
25 * @return unique identifier of the connector
26 */
27 String getIdentifier();
28
29 /**
30 *
31 * @return true if the specifications of the connector should be included in default views
32 */
33 boolean includeSpecificationsInDefaultViews();
34
35 /**
36 * Add a listener to get updates on changes in the query specifications available from the connector. When the
37 * listener is added, the connector is expected to call the listener with each existing query specification.
38 *
39 * @param listener that should be added
40 */
41 void addListener(IConnectorListener listener);
42
43 /**
44 * Removes an already registered listener and stops sending updates. The connector is not required to send any
45 * updates before returning from this method, but should not send any events after this method returns.
46 *
47 * @param listener that should be removed
48 */
49 void removeListener(IConnectorListener listener);
50}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryView.java
deleted file mode 100644
index acf49b76..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryView.java
+++ /dev/null
@@ -1,72 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11import java.util.Set;
12
13/**
14 * The registry view is the primary interface for users to interact with the query specifications in an
15 * {@link IQuerySpecificationRegistry}. Views are created using the createView methods of registry and their content is
16 * also dynamically updated by the registry.
17 *
18 * The view contains a set of {@link IQuerySpecificationRegistryEntry} objects that can be used to access the query
19 * specifications themselves through the get() method.
20 *
21 * Users can check the contents of the view and add listeners to get notifications on view changes (added or removed
22 * entries).
23 *
24 * @author Abel Hegedus
25 * @since 1.3
26 *
27 */
28public interface IRegistryView extends IQuerySpecificationRegistryChangeListener {
29
30 /**
31 * @return an immutable copy of all entries found in the view
32 */
33 Iterable<IQuerySpecificationRegistryEntry> getEntries();
34
35 /**
36 * @return the set of FQNs for the query specifications in the view
37 */
38 Set<String> getQuerySpecificationFQNs();
39
40 /**
41 * @param fullyQualifiedName
42 * that is looked up in the view
43 * @return true if the view contains an entry with given FQN, false otherwise
44 */
45 boolean hasQuerySpecificationFQN(String fullyQualifiedName);
46
47 /**
48 * @param fullyQualifiedName
49 * of the entries that are requested
50 * @return the possible empty set of entries with the given FQN
51 */
52 Set<IQuerySpecificationRegistryEntry> getEntries(String fullyQualifiedName);
53
54 /**
55 * Adds a listener to the view that will be notified when an entry is added to or removed from the view.
56 *
57 * @param listener that is added
58 */
59 void addViewListener(IQuerySpecificationRegistryChangeListener listener);
60
61 /**
62 * Removes a listener that was previously added to the view.
63 *
64 * @param listener that is removed
65 */
66 void removeViewListener(IQuerySpecificationRegistryChangeListener listener);
67
68 /**
69 * @return the registry underlying the view
70 */
71 IQuerySpecificationRegistry getRegistry();
72}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryViewFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryViewFactory.java
deleted file mode 100644
index 990902d3..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryViewFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11/**
12 * This interface can be used to ask the registry to construct specific view instances. The factory is responsible for
13 * instantiating the view, but the registry is responsible for establishing the connection with the internal data store
14 * and to fill up the view with entries. Instances of the factory are intended to be passed to
15 * {@link IQuerySpecificationRegistry#createView(IRegistryViewFactory)} and only the view instance returned by that
16 * method can be considered initialized.
17 *
18 * @author Abel Hegedus
19 * @since 1.3
20 *
21 */
22public interface IRegistryViewFactory {
23
24 /**
25 * Instantiate a new view object and store the reference to the registry.
26 * This method should only be called by an {@link IQuerySpecificationRegistry}.
27 *
28 * @param registry that will be connected to the view
29 * @return the new instance of the view
30 * @noreference This method is not intended to be referenced by clients.
31 */
32 IRegistryView createView(IQuerySpecificationRegistry registry);
33
34}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryViewFilter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryViewFilter.java
deleted file mode 100644
index fa13327f..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/IRegistryViewFilter.java
+++ /dev/null
@@ -1,33 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11/**
12 * The registry view filter can control which entries are added and removed from an {@link IRegistryView}.
13 *
14 * @author Abel Hegedus
15 * @since 1.3
16 *
17 */
18public interface IRegistryViewFilter {
19
20 /**
21 * This method controls whether a registry entry is added to the view or not. The filtering is called before
22 * checking the uniqueness of fully qualified names, and relevant entries can overwrite existing entries with the
23 * same FQN.
24 *
25 * Note that filters should usually return the same value for the same entry on multiple invocations.
26 *
27 * @param entry
28 * that is checked
29 * @return true, if the entry is relevant for the view, false otherwise
30 */
31 boolean isEntryRelevant(IQuerySpecificationRegistryEntry entry);
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/QuerySpecificationRegistry.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/QuerySpecificationRegistry.java
deleted file mode 100644
index 139dde1c..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/QuerySpecificationRegistry.java
+++ /dev/null
@@ -1,112 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry;
10
11import java.util.HashSet;
12import java.util.Iterator;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.registry.impl.QuerySpecificationRegistryImpl;
16
17/**
18 * Registry for query specifications that can be accessed using fully qualified names through views.
19 * Additional query specifications can be added using {@link IRegistrySourceConnector}s.
20 *
21 * <p>
22 * When running as an OSGi plug-in, the generated query specifications registered through extensions are automatically loaded
23 * into the registry by the {@link ExtensionBasedQuerySpecificationLoader} class.
24 *
25 * @author Abel Hegedus
26 * @since 1.3
27 *
28 */
29public class QuerySpecificationRegistry implements IQuerySpecificationRegistry {
30
31 private static final QuerySpecificationRegistry INSTANCE = new QuerySpecificationRegistry();
32
33 /**
34 * @return the singleton query specification registry instance
35 */
36 public static IQuerySpecificationRegistry getInstance() {
37 return INSTANCE;
38 }
39
40 private final QuerySpecificationRegistryImpl internalRegistry;
41 /**
42 * Connectors that should not be immediately loaded into the registry.
43 */
44 private final Set<IRegistrySourceConnector> delayedConnectors;
45
46 /**
47 * Hidden constructor for singleton instance
48 */
49 protected QuerySpecificationRegistry() {
50 this.internalRegistry = new QuerySpecificationRegistryImpl();
51 this.delayedConnectors = new HashSet<>();
52
53 }
54
55 /**
56 * @return the internal registry after adding delayed source connectors
57 */
58 protected IQuerySpecificationRegistry getInternalRegistry() {
59 if(!delayedConnectors.isEmpty()) {
60 final Iterator<IRegistrySourceConnector> it = delayedConnectors.iterator();
61 while (it.hasNext()) {
62 final IRegistrySourceConnector connector = it.next();
63 internalRegistry.addSource(connector);
64 it.remove();
65 }
66 }
67 return internalRegistry;
68 }
69
70 /**
71 * When the registry adds itself as a listener to connectors, it must send all specification providers
72 * to the registry. However, when {@link ExtensionBasedQuerySpecificationLoader} is triggered during the
73 * activation of the plugin, the individual query specification classes cannot be loaded yet. To avoid this,
74 * the connector of the loader is delayed until needed.
75 *
76 * @param connector that should be delayed before adding to the registry
77 */
78 protected void addDelayedSourceConnector(IRegistrySourceConnector connector) {
79 delayedConnectors.add(connector);
80 }
81
82 @Override
83 public boolean addSource(IRegistrySourceConnector connector) {
84 return getInternalRegistry().addSource(connector);
85 }
86
87 @Override
88 public boolean removeSource(IRegistrySourceConnector connector) {
89 return getInternalRegistry().removeSource(connector);
90 }
91
92 @Override
93 public IDefaultRegistryView getDefaultView() {
94 return getInternalRegistry().getDefaultView();
95 }
96
97 @Override
98 public IRegistryView createView() {
99 return getInternalRegistry().createView();
100 }
101
102 @Override
103 public IRegistryView createView(IRegistryViewFilter filter) {
104 return getInternalRegistry().createView(filter);
105 }
106
107 @Override
108 public IRegistryView createView(IRegistryViewFactory factory) {
109 return getInternalRegistry().createView(factory);
110 }
111
112}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/AbstractRegistrySourceConnector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/AbstractRegistrySourceConnector.java
deleted file mode 100644
index 0e2ef273..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/AbstractRegistrySourceConnector.java
+++ /dev/null
@@ -1,81 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.connector;
10
11import java.util.HashSet;
12import java.util.Objects;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.registry.IConnectorListener;
16import tools.refinery.viatra.runtime.registry.IRegistrySourceConnector;
17
18/**
19 * Abstract registry source connector implementation that stores the identifier and listener set.
20 *
21 *
22 * @author Abel Hegedus
23 * @since 1.3
24 *
25 */
26public abstract class AbstractRegistrySourceConnector implements IRegistrySourceConnector {
27
28 protected Set<IConnectorListener> listeners;
29 private String identifier;
30 private boolean includeInDefaultViews;
31
32 /**
33 * Creates an instance of the connector with the given identifier. The identifier should be unique if you want to
34 * add it to a registry as a source.
35 *
36 * @param identifier
37 * of the newly created connector
38 * @param includeInDefaultViews
39 * true if the specifications in the connector should be included in default views
40 */
41 public AbstractRegistrySourceConnector(String identifier, boolean includeInDefaultViews) {
42 super();
43 Objects.requireNonNull(identifier, "Identifier must not be null!");
44 this.identifier = identifier;
45 this.includeInDefaultViews = includeInDefaultViews;
46 this.listeners = new HashSet<>();
47 }
48
49 @Override
50 public String getIdentifier() {
51 return identifier;
52 }
53
54 @Override
55 public boolean includeSpecificationsInDefaultViews() {
56 return includeInDefaultViews;
57 }
58
59 @Override
60 public void addListener(IConnectorListener listener) {
61 Objects.requireNonNull(listener, "Listener must not be null!");
62 boolean added = listeners.add(listener);
63 if (added) {
64 sendQuerySpecificationsToListener(listener);
65 }
66 }
67
68 @Override
69 public void removeListener(IConnectorListener listener) {
70 Objects.requireNonNull(listener, "Listener must not be null!");
71 listeners.remove(listener);
72 }
73
74 /**
75 * Subclasses should send add notifications for each specification in the connector to the given listener.
76 *
77 * @param listener that should receive the notifications
78 */
79 protected abstract void sendQuerySpecificationsToListener(IConnectorListener listener);
80
81} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/QueryGroupProviderSourceConnector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/QueryGroupProviderSourceConnector.java
deleted file mode 100644
index e6f0adf0..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/QueryGroupProviderSourceConnector.java
+++ /dev/null
@@ -1,80 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.connector;
10
11import java.util.Objects;
12
13import tools.refinery.viatra.runtime.extensibility.IQueryGroupProvider;
14import tools.refinery.viatra.runtime.extensibility.IQuerySpecificationProvider;
15import tools.refinery.viatra.runtime.registry.IConnectorListener;
16
17/**
18 * Source connector implementation that uses a {@link IQueryGroupProvider} to provide a query specifications into the
19 * registry. The query group can be later updated which triggers the removal of all specifications of the old group and
20 * the addition of all specifications from the new group.
21 *
22 * @author Abel Hegedus
23 * @since 1.3
24 *
25 */
26public class QueryGroupProviderSourceConnector extends AbstractRegistrySourceConnector {
27
28 IQueryGroupProvider queryGroupProvider;
29
30 /**
31 * Creates an instance of the connector with the given identifier and the query group provider. The identifier
32 * should be unique if you want to add it to a registry as a source.
33 *
34 * @param identifier
35 * of the newly created connector
36 * @param provider
37 * that contains the query specifications handled by the connector
38 * @param includeInDefaultViews
39 * true if the specifications in the connector should be included in default views
40 */
41 public QueryGroupProviderSourceConnector(String identifier, IQueryGroupProvider provider, boolean includeInDefaultViews) {
42 super(identifier, includeInDefaultViews);
43 this.queryGroupProvider = provider;
44 }
45
46 /**
47 * Update the query group of the connector, which triggers the removal of all specifications on the old group and
48 * addition of all specifications in the given group.
49 *
50 * @param queryGroupProvider
51 * the queryGroupProvider to set
52 * @param includeInDefaultViews
53 * true if the specifications in the connector should be included in default views
54 */
55 public void setQueryGroupProvider(IQueryGroupProvider queryGroupProvider) {
56 Objects.requireNonNull(queryGroupProvider, "Query group provider must not be null!");
57 IQueryGroupProvider oldProvider = this.queryGroupProvider;
58
59 for (IQuerySpecificationProvider specificationProvider : oldProvider.getQuerySpecificationProviders()) {
60 for (IConnectorListener iConnectorListener : listeners) {
61 iConnectorListener.querySpecificationRemoved(this, specificationProvider);
62 }
63 }
64 for (IQuerySpecificationProvider specificationProvider : queryGroupProvider.getQuerySpecificationProviders()) {
65 for (IConnectorListener iConnectorListener : listeners) {
66 iConnectorListener.querySpecificationAdded(this, specificationProvider);
67 }
68 }
69
70 this.queryGroupProvider = queryGroupProvider;
71 }
72
73 @Override
74 protected void sendQuerySpecificationsToListener(IConnectorListener listener) {
75 for (IQuerySpecificationProvider specificationProvider : queryGroupProvider.getQuerySpecificationProviders()) {
76 listener.querySpecificationAdded(this, specificationProvider);
77 }
78 }
79
80}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/SpecificationMapSourceConnector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/SpecificationMapSourceConnector.java
deleted file mode 100644
index e5778950..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/connector/SpecificationMapSourceConnector.java
+++ /dev/null
@@ -1,147 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.connector;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.NoSuchElementException;
16import java.util.Objects;
17import java.util.Set;
18
19import tools.refinery.viatra.runtime.extensibility.IQuerySpecificationProvider;
20import tools.refinery.viatra.runtime.extensibility.SingletonQuerySpecificationProvider;
21import tools.refinery.viatra.runtime.registry.IConnectorListener;
22
23/**
24 * A simple connector implementation that allows users to simply add and remove specifications. These changes are
25 * propagated to listeners (e.g. the registry). Note that duplicate FQNs are not allowed in a given connector.
26 *
27 * @author Abel Hegedus
28 * @since 1.3
29 *
30 */
31public class SpecificationMapSourceConnector extends AbstractRegistrySourceConnector {
32
33 private static final String DUPLICATE_MESSAGE = "Duplicate FQN %s cannot be added to connector";
34 private Map<String, IQuerySpecificationProvider> specificationProviderMap;
35
36 /**
37 * Creates an instance of the connector with the given identifier. The identifier should be unique if you want to
38 * add it to a registry as a source.
39 *
40 * @param identifier
41 * of the newly created connector
42 * @param includeInDefaultViews
43 * true if the specifications in the connector should be included in default views
44 */
45 public SpecificationMapSourceConnector(String identifier, boolean includeInDefaultViews) {
46 super(identifier, includeInDefaultViews);
47 this.specificationProviderMap = new HashMap<>();
48 }
49
50 /**
51 * Creates an instance of the connector with the given identifier and fills it up with the given specification
52 * providers. The identifier should be unique if you want to add it to a registry as a source.
53 *
54 * @param identifier
55 * of the newly created connector
56 * @param specificationProviders
57 * the initial set of specifications in the connector
58 * @param includeInDefaultViews
59 * true if the specifications in the connector should be included in default views
60 */
61 public SpecificationMapSourceConnector(String identifier, Set<IQuerySpecificationProvider> specificationProviders, boolean includeInDefaultViews) {
62 this(identifier, includeInDefaultViews);
63 for (IQuerySpecificationProvider provider : specificationProviders) {
64 addQuerySpecificationProvider(provider);
65 }
66 }
67
68 /**
69 * Creates an instance of the connector with the given identifier and fills it up with the specification providers
70 * from the given {@link SpecificationMapSourceConnector}. The identifier should be unique if you want to add it to
71 * a registry as a source.
72 *
73 * @param identifier
74 * of the newly created connector
75 * @param connector
76 * that contains the specifications to copy into the new instance
77 * @param includeInDefaultViews
78 * true if the specifications in the connector should be included in default views
79 */
80 public SpecificationMapSourceConnector(String identifier, SpecificationMapSourceConnector connector, boolean includeInDefaultViews) {
81 this(identifier, includeInDefaultViews);
82 this.specificationProviderMap.putAll(connector.specificationProviderMap);
83 }
84
85 /**
86 * Adds a query specification to the connector.
87 * If you have an {@link IQuerySpecification} object, use {@link SingletonQuerySpecificationProvider}.
88 *
89 * @param provider to add to the connector
90 * @throws IllegalArgumentException if the connector already contains a specification with the same FQN
91 */
92 public void addQuerySpecificationProvider(IQuerySpecificationProvider provider) {
93 Objects.requireNonNull(provider, "Provider must not be null!");
94 String fullyQualifiedName = provider.getFullyQualifiedName();
95 if (!specificationProviderMap.containsKey(fullyQualifiedName)) {
96 specificationProviderMap.put(fullyQualifiedName, provider);
97 for (IConnectorListener listener : listeners) {
98 listener.querySpecificationAdded(this, provider);
99 }
100 } else {
101 throw new IllegalArgumentException(String.format(DUPLICATE_MESSAGE, fullyQualifiedName));
102 }
103 }
104
105 /**
106 * Remove a specification that has been added with the given FQN.
107 *
108 * @param fullyQualifiedName
109 * @throws NoSuchElementException if the connector does not contain a specification with the given FQN
110 */
111 public void removeQuerySpecificationProvider(String fullyQualifiedName) {
112 Objects.requireNonNull(fullyQualifiedName, "Fully qualified name must not be null!");
113 IQuerySpecificationProvider provider = specificationProviderMap.remove(fullyQualifiedName);
114 if (provider == null) {
115 throw new NoSuchElementException(
116 String.format("Connector does not contain specification with FQN %s", fullyQualifiedName));
117 }
118 for (IConnectorListener listener : listeners) {
119 listener.querySpecificationRemoved(this, provider);
120 }
121 }
122
123 /**
124 * @return the immutable copy of the set of FQNs for the added query specifications
125 */
126 public Set<String> getQuerySpecificationFQNs() {
127 return Collections.unmodifiableSet(new HashSet<>(specificationProviderMap.keySet()));
128 }
129
130 /**
131 *
132 * @param fullyQualifiedName that is checked
133 * @return true if a specification with the given FQN exists in the connector, false otherwise
134 */
135 public boolean hasQuerySpecificationFQN(String fullyQualifiedName) {
136 Objects.requireNonNull(fullyQualifiedName, "FQN must not be null!");
137 return specificationProviderMap.containsKey(fullyQualifiedName);
138 }
139
140 @Override
141 protected void sendQuerySpecificationsToListener(IConnectorListener listener) {
142 for (IQuerySpecificationProvider provider : specificationProviderMap.values()) {
143 listener.querySpecificationAdded(this, provider);
144 }
145 }
146
147}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/QuerySpecificationStore.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/QuerySpecificationStore.java
deleted file mode 100644
index 649527b6..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/QuerySpecificationStore.java
+++ /dev/null
@@ -1,38 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.data;
10
11import java.util.Map;
12import java.util.TreeMap;
13
14/**
15 * Internal data storage object that represents a query specification registry with a set of sources driven by
16 * connectors. The sources must have unique identifiers.
17 *
18 * @author Abel Hegedus
19 *
20 */
21public class QuerySpecificationStore {
22
23 private Map<String, RegistrySourceImpl> sources;
24
25 /**
26 * Creates a new instance with an empty identifier to source map.
27 */
28 public QuerySpecificationStore() {
29 this.sources = new TreeMap<>();
30 }
31
32 /**
33 * @return the live, modifiable identifier to source map
34 */
35 public Map<String, RegistrySourceImpl> getSources() {
36 return sources;
37 }
38}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/RegistryEntryImpl.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/RegistryEntryImpl.java
deleted file mode 100644
index 758885e2..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/RegistryEntryImpl.java
+++ /dev/null
@@ -1,81 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.data;
10
11import tools.refinery.viatra.runtime.api.IQuerySpecification;
12import tools.refinery.viatra.runtime.extensibility.IQuerySpecificationProvider;
13import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryEntry;
14
15/**
16 * Internal data storage object that represents a query specification entry. The entry contains an
17 * {@link IQuerySpecificationProvider} and has a reference to the source that contains it.
18 *
19 * @author Abel Hegedus
20 *
21 */
22public class RegistryEntryImpl implements IQuerySpecificationRegistryEntry {
23
24 private IQuerySpecificationProvider provider;
25 private RegistrySourceImpl source;
26
27 /**
28 * Creates a new instance with the given source and the given provider.
29 *
30 * @param source
31 * that contains the new entry
32 * @param provider
33 * that wraps the specification represented by the entry
34 */
35 public RegistryEntryImpl(RegistrySourceImpl source, IQuerySpecificationProvider provider) {
36 this.source = source;
37 this.provider = provider;
38 }
39
40 /**
41 * @return the source that contains this entry
42 */
43 public RegistrySourceImpl getSource() {
44 return source;
45 }
46
47 @Override
48 public String getSourceIdentifier() {
49 return source.getIdentifier();
50 }
51
52 @Override
53 public boolean includeInDefaultViews() {
54 return getSource().includeEntriesInDefaultViews();
55 }
56
57 @Override
58 public String getFullyQualifiedName() {
59 return provider.getFullyQualifiedName();
60 }
61
62 @Override
63 public IQuerySpecification<?> get() {
64 return provider.get();
65 }
66
67 @Override
68 public IQuerySpecificationProvider getProvider() {
69 return provider;
70 }
71
72 @Override
73 public boolean isFromProject() {
74 return provider.getSourceProjectName() != null;
75 }
76
77 @Override
78 public String getSourceProjectName() {
79 return provider.getSourceProjectName();
80 }
81}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/RegistrySourceImpl.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/RegistrySourceImpl.java
deleted file mode 100644
index 83c3b920..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/data/RegistrySourceImpl.java
+++ /dev/null
@@ -1,73 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.data;
10
11import java.util.Map;
12import java.util.TreeMap;
13
14/**
15 * Internal data storage object that represents a query specification source driven by a connector. The source must have
16 * unique identifier that is copied from the connector. The source uses a FQN to entry map to manage registry entries.
17 *
18 * @author Abel Hegedus
19 *
20 */
21public class RegistrySourceImpl {
22
23 private String identifier;
24 private boolean includeInDefaultViews;
25 private QuerySpecificationStore querySpecificationStore;
26 private Map<String, RegistryEntryImpl> fqnToEntryMap;
27
28 /**
29 * Creates a new source with the given identifier and an empty entry map.
30 *
31 * @param identifier
32 * for the source
33 * @param querySpecificationStore
34 * that contains this source
35 * @param includeInDefaultViews
36 * true if the entries of the source should be included in default views
37 */
38 public RegistrySourceImpl(String identifier, QuerySpecificationStore querySpecificationStore, boolean includeInDefaultViews) {
39 this.identifier = identifier;
40 this.includeInDefaultViews = includeInDefaultViews;
41 this.querySpecificationStore = querySpecificationStore;
42 this.fqnToEntryMap = new TreeMap<>();
43 }
44
45 /**
46 * @return the identifier of the source
47 */
48 public String getIdentifier() {
49 return identifier;
50 }
51
52 /**
53 * @return true if the entries in the source should be included in default views
54 */
55 public boolean includeEntriesInDefaultViews() {
56 return includeInDefaultViews;
57 }
58
59 /**
60 * @return the store that contains the source
61 */
62 public QuerySpecificationStore getStore() {
63 return querySpecificationStore;
64 }
65
66 /**
67 * @return the live, modifiable FQN to entry map
68 */
69 public Map<String, RegistryEntryImpl> getFqnToEntryMap() {
70 return fqnToEntryMap;
71 }
72
73}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/FilteringRegistryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/FilteringRegistryView.java
deleted file mode 100644
index 164a30d3..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/FilteringRegistryView.java
+++ /dev/null
@@ -1,43 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.impl;
10
11import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistry;
12import tools.refinery.viatra.runtime.registry.IRegistryViewFilter;
13import tools.refinery.viatra.runtime.registry.view.AbstractRegistryView;
14import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryEntry;
15
16/**
17 * Registry view implementation that uses a filter to delegate the decision on whether
18 * a given specification is relevant to the view.
19 *
20 * @author Abel Hegedus
21 *
22 */
23public class FilteringRegistryView extends AbstractRegistryView {
24
25 private IRegistryViewFilter filter;
26
27 /**
28 * Creates a new filtering view instance.
29 *
30 * @param registry that defines the view
31 * @param filter that is used for deciding relevancy
32 */
33 public FilteringRegistryView(IQuerySpecificationRegistry registry, IRegistryViewFilter filter, boolean allowDuplicateFQNs) {
34 super(registry, allowDuplicateFQNs);
35 this.filter = filter;
36 }
37
38 @Override
39 protected boolean isEntryRelevant(IQuerySpecificationRegistryEntry entry) {
40 return filter.isEntryRelevant(entry);
41 }
42
43}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/GlobalRegistryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/GlobalRegistryView.java
deleted file mode 100644
index 75d730b6..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/GlobalRegistryView.java
+++ /dev/null
@@ -1,65 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.impl;
10
11import java.util.NoSuchElementException;
12import java.util.Set;
13import java.util.stream.Collectors;
14
15import tools.refinery.viatra.runtime.api.IQueryGroup;
16import tools.refinery.viatra.runtime.api.LazyLoadingQueryGroup;
17import tools.refinery.viatra.runtime.registry.IDefaultRegistryView;
18import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistry;
19import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryEntry;
20import tools.refinery.viatra.runtime.registry.view.AbstractRegistryView;
21
22/**
23 * Registry view implementation that considers specifications relevant if they are included in default views.
24 *
25 * @author Abel Hegedus
26 *
27 */
28public class GlobalRegistryView extends AbstractRegistryView implements IDefaultRegistryView {
29
30 /**
31 * Creates a new instance of the global view.
32 *
33 * @param registry that defines the view
34 */
35 public GlobalRegistryView(IQuerySpecificationRegistry registry) {
36 super(registry, false);
37 }
38
39 @Override
40 protected boolean isEntryRelevant(IQuerySpecificationRegistryEntry entry) {
41 return entry.includeInDefaultViews();
42 }
43
44 @Override
45 public IQueryGroup getQueryGroup() {
46 Set<IQuerySpecificationRegistryEntry> allQueries =
47 fqnToEntryMap.distinctValuesStream().collect(Collectors.toSet());
48 IQueryGroup queryGroup = LazyLoadingQueryGroup.of(allQueries);
49 return queryGroup;
50 }
51
52 @Override
53 public IQuerySpecificationRegistryEntry getEntry(String fullyQualifiedName) {
54 Set<IQuerySpecificationRegistryEntry> entries = getEntries(fullyQualifiedName);
55 if(entries.isEmpty()){
56 throw new NoSuchElementException("Cannot find entry with FQN " + fullyQualifiedName);
57 }
58 if(entries.size() > 1) {
59 throw new IllegalStateException("Global view must never contain duplicated FQNs!");
60 }
61 IQuerySpecificationRegistryEntry entry = entries.iterator().next();
62 return entry;
63 }
64
65}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/QuerySpecificationRegistryImpl.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/QuerySpecificationRegistryImpl.java
deleted file mode 100644
index 63306e93..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/QuerySpecificationRegistryImpl.java
+++ /dev/null
@@ -1,177 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.impl;
10
11import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument;
12
13import java.util.Map;
14
15import org.apache.log4j.Logger;
16import tools.refinery.viatra.runtime.extensibility.IQuerySpecificationProvider;
17import tools.refinery.viatra.runtime.registry.IConnectorListener;
18import tools.refinery.viatra.runtime.registry.IDefaultRegistryView;
19import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistry;
20import tools.refinery.viatra.runtime.registry.IRegistryView;
21import tools.refinery.viatra.runtime.registry.IRegistryViewFactory;
22import tools.refinery.viatra.runtime.registry.IRegistryViewFilter;
23import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryChangeListener;
24import tools.refinery.viatra.runtime.registry.IRegistrySourceConnector;
25import tools.refinery.viatra.runtime.registry.data.QuerySpecificationStore;
26import tools.refinery.viatra.runtime.registry.data.RegistryEntryImpl;
27import tools.refinery.viatra.runtime.registry.data.RegistrySourceImpl;
28import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
29
30/**
31 * This is the default implementation of the {@link IQuerySpecificationRegistry} interface.
32 * It uses a {@link QuerySpecificationStore} to keep track of sources and entries.
33 * It uses a {@link RegistryChangeMultiplexer} to update all views and a single {@link IConnectorListener}
34 * to subscribe to sources added to the registry.
35 *
36 * @author Abel Hegedus
37 *
38 */
39public class QuerySpecificationRegistryImpl implements IQuerySpecificationRegistry {
40
41 private static final String CONNECTOR_NULL_MSG = "Connector cannot be null";
42 private final QuerySpecificationStore querySpecificationStore;
43 private final IConnectorListener connectorListener;
44 private final RegistryChangeMultiplexer multiplexer;
45 private final Logger logger;
46 private IDefaultRegistryView defaultView = null;
47
48 /**
49 * Creates a new instance of the registry
50 */
51 public QuerySpecificationRegistryImpl() {
52 this.querySpecificationStore = new QuerySpecificationStore();
53 this.connectorListener = new RegistryUpdaterConnectorListener();
54 this.multiplexer = new RegistryChangeMultiplexer();
55 this.logger = ViatraQueryLoggingUtil.getLogger(IQuerySpecificationRegistry.class);
56 }
57
58 @Override
59 public boolean addSource(IRegistrySourceConnector connector) {
60 checkArgument(connector != null, CONNECTOR_NULL_MSG);
61 String identifier = connector.getIdentifier();
62 Map<String, RegistrySourceImpl> sources = querySpecificationStore.getSources();
63 if(sources.containsKey(identifier)){
64 return false;
65 }
66 RegistrySourceImpl source = new RegistrySourceImpl(identifier, querySpecificationStore, connector.includeSpecificationsInDefaultViews());
67 sources.put(identifier, source);
68 connector.addListener(connectorListener);
69 logger.debug("Source added: " + source.getIdentifier());
70 return true;
71 }
72
73 @Override
74 public boolean removeSource(IRegistrySourceConnector connector) {
75 checkArgument(connector != null, CONNECTOR_NULL_MSG);
76 String identifier = connector.getIdentifier();
77 Map<String, RegistrySourceImpl> sources = querySpecificationStore.getSources();
78 if(!sources.containsKey(identifier)){
79 return false;
80 }
81 connector.removeListener(connectorListener);
82 RegistrySourceImpl source = sources.remove(identifier);
83 for (RegistryEntryImpl entry : source.getFqnToEntryMap().values()) {
84 multiplexer.entryRemoved(entry);
85 }
86 logger.debug("Source removed: " + source.getIdentifier());
87 return true;
88 }
89
90 /**
91 * @return the internal store of the registry
92 */
93 protected QuerySpecificationStore getStore() {
94 return querySpecificationStore;
95 }
96
97 @Override
98 public IRegistryView createView() {
99 return createGlobalView();
100 }
101
102 private GlobalRegistryView createGlobalView() {
103 GlobalRegistryView registryView = new GlobalRegistryView(this);
104 initializeChangeListener(registryView);
105 return registryView;
106 }
107
108 protected void initializeChangeListener(IQuerySpecificationRegistryChangeListener listener) {
109 // send existing entries to aspect
110 for (RegistrySourceImpl source : querySpecificationStore.getSources().values()) {
111 Map<String, RegistryEntryImpl> entryMap = source.getFqnToEntryMap();
112 for (RegistryEntryImpl entry : entryMap.values()) {
113 listener.entryAdded(entry);
114 }
115 }
116 multiplexer.addListener(listener);
117 }
118
119 @Override
120 public IRegistryView createView(IRegistryViewFilter filter) {
121 checkArgument(filter != null, "Filter cannot be null");
122 FilteringRegistryView registryView = new FilteringRegistryView(this, filter, false);
123 initializeChangeListener(registryView);
124 return registryView;
125 }
126
127 /**
128 * Internal connector listener implementation for updating internal store and propagating changes to views.
129 *
130 * @author Abel Hegedus
131 *
132 */
133 private final class RegistryUpdaterConnectorListener implements IConnectorListener {
134 @Override
135 public void querySpecificationAdded(IRegistrySourceConnector connector, IQuerySpecificationProvider specification) {
136 String identifier = connector.getIdentifier();
137 RegistrySourceImpl source = querySpecificationStore.getSources().get(identifier);
138 String fullyQualifiedName = specification.getFullyQualifiedName();
139 RegistryEntryImpl registryEntry = new RegistryEntryImpl(source, specification);
140 RegistryEntryImpl oldEntry = source.getFqnToEntryMap().put(fullyQualifiedName, registryEntry);
141 if(oldEntry != null) {
142 logger.warn(String.format("Specification added with existing FQN %s in source %s", fullyQualifiedName, identifier));
143 multiplexer.entryRemoved(oldEntry);
144 }
145 multiplexer.entryAdded(registryEntry);
146
147 }
148
149 @Override
150 public void querySpecificationRemoved(IRegistrySourceConnector connector, IQuerySpecificationProvider specification) {
151 String identifier = connector.getIdentifier();
152 RegistrySourceImpl source = querySpecificationStore.getSources().get(identifier);
153 String fullyQualifiedName = specification.getFullyQualifiedName();
154 RegistryEntryImpl registryEntry = source.getFqnToEntryMap().remove(fullyQualifiedName);
155 if(registryEntry != null) {
156 multiplexer.entryRemoved(registryEntry);
157 }
158 }
159 }
160
161 @Override
162 public IDefaultRegistryView getDefaultView() {
163 if(this.defaultView == null){
164 this.defaultView = createGlobalView();
165 }
166 return this.defaultView;
167 }
168
169 @Override
170 public IRegistryView createView(IRegistryViewFactory factory) {
171 IRegistryView registryView = factory.createView(this);
172 initializeChangeListener(registryView);
173 return registryView;
174 }
175
176
177}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/RegistryChangeMultiplexer.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/RegistryChangeMultiplexer.java
deleted file mode 100644
index 450f36b8..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/impl/RegistryChangeMultiplexer.java
+++ /dev/null
@@ -1,58 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.impl;
10
11import java.util.Collections;
12import java.util.Set;
13import java.util.WeakHashMap;
14
15import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryChangeListener;
16import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryEntry;
17
18/**
19 * Listener implementation that propagates all changes to a set of listeners.
20 * The listeners are stored with weak references to avoid a need for disposal.
21 *
22 * @author Abel Hegedus
23 *
24 */
25public class RegistryChangeMultiplexer implements IQuerySpecificationRegistryChangeListener {
26
27 private Set<IQuerySpecificationRegistryChangeListener> listeners;
28
29 /**
30 * Creates a new instance of the multiplexer.
31 */
32 public RegistryChangeMultiplexer() {
33 this.listeners = Collections.newSetFromMap(new WeakHashMap<IQuerySpecificationRegistryChangeListener, Boolean>());
34 }
35
36 /**
37 * Adds a weak reference on the listener to the multiplexer. The listener will receive all further notifications and
38 * does not have to be removed, since the multiplexer will not keep it in memory when it can be collected.
39 */
40 public boolean addListener(IQuerySpecificationRegistryChangeListener listener) {
41 return listeners.add(listener);
42 }
43
44 @Override
45 public void entryAdded(IQuerySpecificationRegistryEntry entry) {
46 for (IQuerySpecificationRegistryChangeListener listener : listeners) {
47 listener.entryAdded(entry);
48 }
49 }
50
51 @Override
52 public void entryRemoved(IQuerySpecificationRegistryEntry entry) {
53 for (IQuerySpecificationRegistryChangeListener listener : listeners) {
54 listener.entryRemoved(entry);
55 }
56 }
57
58}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/view/AbstractRegistryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/view/AbstractRegistryView.java
deleted file mode 100644
index 7b3c34ba..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/registry/view/AbstractRegistryView.java
+++ /dev/null
@@ -1,150 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.registry.view;
10
11import java.util.Collections;
12import java.util.HashSet;
13import java.util.Set;
14import java.util.stream.Collectors;
15
16import org.apache.log4j.Logger;
17import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
19import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
20import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
21import tools.refinery.viatra.runtime.matchers.util.Preconditions;
22import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistry;
23import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryChangeListener;
24import tools.refinery.viatra.runtime.registry.IQuerySpecificationRegistryEntry;
25import tools.refinery.viatra.runtime.registry.IRegistryView;
26import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
27
28/**
29 * An abstract {@link IRegistryView} implementation that stores the registry, the set of listeners added to the view and
30 * the FQN to entry map of the view itself. The only responsibility of subclasses is to decide whether an entry received
31 * as an addition or removal notification is relevant to the view.
32 *
33 * @author Abel Hegedus
34 * @since 1.3
35 */
36public abstract class AbstractRegistryView implements IRegistryView {
37
38 private static final String LISTENER_EXCEPTION_REMOVE = "Exception occurred while notifying view listener %s about entry removal";
39 private static final String LISTENER_EXCEPTION_ADD = "Exception occurred while notifying view listener %s about entry addition";
40 protected final IQuerySpecificationRegistry registry;
41 protected final IMultiLookup<String, IQuerySpecificationRegistryEntry> fqnToEntryMap;
42 protected final Set<IQuerySpecificationRegistryChangeListener> listeners;
43 protected final boolean allowDuplicateFQNs;
44
45 /**
46 * This method is called both when an addition or removal notification is received from the registry. Subclasses can
47 * implement view filtering by returning false for those specifications that are not relevant for this view.
48 *
49 * @param entry
50 * that is added or removed in the registry
51 * @return true if the entry should be added to or removed from the view, false otherwise
52 */
53 protected abstract boolean isEntryRelevant(IQuerySpecificationRegistryEntry entry);
54
55 /**
56 * Creates a new view instance for the given registry. Note that views are created by the registry and the view
57 * update mechanisms are also set up by the registry.
58 *
59 * @param registry
60 */
61 public AbstractRegistryView(IQuerySpecificationRegistry registry, boolean allowDuplicateFQNs) {
62 this.registry = registry;
63 this.allowDuplicateFQNs = allowDuplicateFQNs;
64 this.fqnToEntryMap = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
65 this.listeners = new HashSet<>();
66 }
67
68 @Override
69 public IQuerySpecificationRegistry getRegistry() {
70 return registry;
71 }
72
73 @Override
74 public Iterable<IQuerySpecificationRegistryEntry> getEntries() {
75 return fqnToEntryMap.distinctValuesStream().collect(Collectors.toSet());
76 }
77
78 @Override
79 public Set<String> getQuerySpecificationFQNs() {
80 return fqnToEntryMap.distinctKeysStream().collect(Collectors.toSet());
81 }
82
83 @Override
84 public boolean hasQuerySpecificationFQN(String fullyQualifiedName) {
85 Preconditions.checkArgument(fullyQualifiedName != null, "FQN must not be null!");
86 return fqnToEntryMap.lookupExists(fullyQualifiedName);
87 }
88
89 @Override
90 public Set<IQuerySpecificationRegistryEntry> getEntries(String fullyQualifiedName) {
91 Preconditions.checkArgument(fullyQualifiedName != null, "FQN must not be null!");
92 IMemoryView<IQuerySpecificationRegistryEntry> entries = fqnToEntryMap.lookupOrEmpty(fullyQualifiedName);
93 return Collections.unmodifiableSet(entries.distinctValues());
94 }
95
96 @Override
97 public void addViewListener(IQuerySpecificationRegistryChangeListener listener) {
98 Preconditions.checkArgument(listener != null, "Null listener not supported");
99 listeners.add(listener);
100 }
101
102 @Override
103 public void removeViewListener(IQuerySpecificationRegistryChangeListener listener) {
104 Preconditions.checkArgument(listener != null, "Null listener not supported");
105 listeners.remove(listener);
106 }
107
108 @Override
109 public void entryAdded(IQuerySpecificationRegistryEntry entry) {
110 if (isEntryRelevant(entry)) {
111 String fullyQualifiedName = entry.getFullyQualifiedName();
112 IMemoryView<IQuerySpecificationRegistryEntry> duplicates = fqnToEntryMap.lookup(fullyQualifiedName);
113 if(!allowDuplicateFQNs && duplicates != null) {
114 Set<IQuerySpecificationRegistryEntry> removed = new HashSet<>(duplicates.distinctValues());
115 for (IQuerySpecificationRegistryEntry e : removed) {
116 fqnToEntryMap.removePair(fullyQualifiedName, e);
117 notifyListeners(e, false);
118 }
119 }
120 fqnToEntryMap.addPair(fullyQualifiedName, entry);
121 notifyListeners(entry, true);
122 }
123 }
124
125 @Override
126 public void entryRemoved(IQuerySpecificationRegistryEntry entry) {
127 if (isEntryRelevant(entry)) {
128 String fullyQualifiedName = entry.getFullyQualifiedName();
129 fqnToEntryMap.removePair(fullyQualifiedName, entry);
130 notifyListeners(entry, false);
131 }
132 }
133
134 private void notifyListeners(IQuerySpecificationRegistryEntry entry, boolean addition) {
135 for (IQuerySpecificationRegistryChangeListener listener : listeners) {
136 try {
137 if(addition){
138 listener.entryAdded(entry);
139 } else {
140 listener.entryRemoved(entry);
141 }
142 } catch (Exception ex) {
143 Logger logger = ViatraQueryLoggingUtil.getLogger(AbstractRegistryView.class);
144 String formatString = addition ? LISTENER_EXCEPTION_ADD : LISTENER_EXCEPTION_REMOVE;
145 logger.error(String.format(formatString, listener), ex);
146 }
147 }
148 }
149
150} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/EcoreIndexHost.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/EcoreIndexHost.java
deleted file mode 100644
index e87a726a..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/EcoreIndexHost.java
+++ /dev/null
@@ -1,166 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.tabular;
11
12import java.util.Collections;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Set;
16
17import org.eclipse.emf.ecore.EClass;
18import org.eclipse.emf.ecore.EClassifier;
19import org.eclipse.emf.ecore.EDataType;
20import org.eclipse.emf.ecore.EPackage;
21import org.eclipse.emf.ecore.EStructuralFeature;
22import org.eclipse.emf.ecore.EcorePackage;
23import tools.refinery.viatra.runtime.api.scope.QueryScope;
24import tools.refinery.viatra.runtime.emf.EMFQueryMetaContext;
25import tools.refinery.viatra.runtime.emf.EMFScope;
26import tools.refinery.viatra.runtime.emf.types.EClassExactInstancesKey;
27import tools.refinery.viatra.runtime.emf.types.EClassTransitiveInstancesKey;
28import tools.refinery.viatra.runtime.emf.types.EDataTypeInSlotsKey;
29import tools.refinery.viatra.runtime.emf.types.EStructuralFeatureInstancesKey;
30import tools.refinery.viatra.runtime.matchers.context.IInputKey;
31import tools.refinery.viatra.runtime.matchers.scopes.IStorageBackend;
32import tools.refinery.viatra.runtime.matchers.scopes.SimpleRuntimeContext;
33import tools.refinery.viatra.runtime.matchers.scopes.tables.DisjointUnionTable;
34import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterBinary;
35import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterUnary;
36import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
37
38/**
39 * Simple EMF-specific demo tabular index host.
40 *
41 * <p> Usage: <ul>
42 * <li> First, instantiate index host with given Ecore metamodel packages
43 * <li> To emulate an EMF instance model, write arbitrary content into the tables using {@link #getTableDirectInstances(EClassifier)} and {@link #getTableFeatureSlots(EStructuralFeature)}.
44 * <li> Initialize and evaluate regular EMF-based Viatra queries on the scope provided by {@link #getScope()}, as you would on an {@link EMFScope}.
45 * <ul>
46 *
47 * <p>
48 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
49 * part of a work in progress. There is no guarantee that this API will
50 * work or that it will remain the same.
51 *
52 * @author Gabor Bergmann
53 * @since 2.1
54 */
55public class EcoreIndexHost extends TabularIndexHost {
56
57 public EcoreIndexHost(IStorageBackend storage, EPackage... packages) {
58 super(storage, new SimpleRuntimeContext(EMFQueryMetaContext.DEFAULT_SURROGATE));
59
60 initTables(packages);
61 }
62
63 @Override
64 protected boolean isQueryScopeEmulated(Class<? extends QueryScope> queryScopeClass) {
65 return EMFScope.class.equals(queryScopeClass);
66 }
67
68
69 private Map<EClassifier, ITableWriterUnary.Table<Object>> tableDirectInstances = CollectionsFactory.createMap();
70 private Map<EClass, DisjointUnionTable> tableTransitiveInstances = CollectionsFactory.createMap();
71 private Map<EStructuralFeature, ITableWriterBinary.Table<Object, Object>> tableFeatures = CollectionsFactory.createMap();
72
73 private void initTables(EPackage[] packages) {
74
75 // create instance tables first
76 for (EPackage ePackage : packages) {
77 for (EClassifier eClassifier : ePackage.getEClassifiers()) {
78 boolean unique;
79 IInputKey classifierKey;
80 if (eClassifier instanceof EClass) {
81 EClass eClass = (EClass) eClassifier;
82
83 // create transitive instances table
84 IInputKey transitiveKey = new EClassTransitiveInstancesKey(eClass);
85 DisjointUnionTable transitiveTable = registerNewTable(new DisjointUnionTable(transitiveKey, runtimeContext));
86 tableTransitiveInstances.put(eClass, transitiveTable);
87
88 // process feature tables
89 for (EStructuralFeature feature : eClass.getEStructuralFeatures()) {
90 IInputKey featureKey = new EStructuralFeatureInstancesKey(feature);
91 ITableWriterBinary.Table<Object, Object> featureTable = newBinaryInputTable(featureKey, feature.isUnique());
92 tableFeatures.put(feature, featureTable);
93 }
94
95 // direct instance table
96 unique = true;
97 classifierKey = new EClassExactInstancesKey(eClass);
98 } else { // datatype
99 unique = false;
100 classifierKey = new EDataTypeInSlotsKey((EDataType) eClassifier);
101 }
102 ITableWriterUnary.Table<Object> directTable = newUnaryInputTable(classifierKey, unique);
103 tableDirectInstances.put(eClassifier, directTable);
104 }
105 }
106
107 // global implicit supertype EObject is always available as a transitive table
108 EClass eObjectClass = EcorePackage.eINSTANCE.getEObject();
109 DisjointUnionTable eObjectAllInstancesTable = tableTransitiveInstances.get(eObjectClass);
110 if (eObjectAllInstancesTable == null) { // is it already added?
111 IInputKey transitiveKey = new EClassTransitiveInstancesKey(eObjectClass);
112 eObjectAllInstancesTable = registerNewTable(new DisjointUnionTable(transitiveKey, runtimeContext));
113 tableTransitiveInstances.put(eObjectClass, eObjectAllInstancesTable);
114
115 boolean unique = true;
116 IInputKey classifierKey = new EClassExactInstancesKey(eObjectClass);
117 ITableWriterUnary.Table<Object> directTable = newUnaryInputTable(classifierKey, unique);
118 tableDirectInstances.put(eObjectClass, directTable);
119 }
120
121 // set up disjoint unoin tables
122 for (Entry<EClass, DisjointUnionTable> entry : tableTransitiveInstances.entrySet()) {
123 EClass eClass = entry.getKey();
124 ITableWriterUnary.Table<Object> directTable = tableDirectInstances.get(eClass);
125
126 // the direct type itself is a child
127 entry.getValue().addChildTable(directTable);
128
129 // connect supertypes
130 for (EClass superClass : eClass.getEAllSuperTypes()) {
131 DisjointUnionTable transitiveTable = tableTransitiveInstances.get(superClass);
132 if (transitiveTable == null) {
133 throw new IllegalStateException(
134 String.format("No index table found for EClass %s, supertype of %s",
135 superClass.getName(), eClass.getName())
136 );
137 }
138 transitiveTable.addChildTable(directTable);
139 }
140 // global implicit supertype
141 if (!eClass.equals(eObjectClass)) {
142 eObjectAllInstancesTable.addChildTable(directTable);
143 }
144
145 }
146
147 }
148
149 public ITableWriterUnary.Table<Object> getTableDirectInstances(EClassifier classifier) {
150 return tableDirectInstances.get(classifier);
151 }
152 public ITableWriterBinary.Table<Object, Object> getTableFeatureSlots(EStructuralFeature feature) {
153 return tableFeatures.get(feature);
154 }
155
156
157
158 public Set<Entry<EClassifier, ITableWriterUnary.Table<Object>>> getAllCurrentTablesDirectInstances() {
159 return Collections.unmodifiableSet(tableDirectInstances.entrySet());
160 }
161 public Set<Entry<EStructuralFeature, ITableWriterBinary.Table<Object, Object>>> getAllCurrentTablesFeatures() {
162 return Collections.unmodifiableSet(tableFeatures.entrySet());
163 }
164
165
166}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/TabularEngineContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/TabularEngineContext.java
deleted file mode 100644
index ee33d3bc..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/TabularEngineContext.java
+++ /dev/null
@@ -1,107 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.tabular;
11
12import org.apache.log4j.Logger;
13import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
14import tools.refinery.viatra.runtime.api.scope.*;
15import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
16import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
17
18import java.lang.reflect.InvocationTargetException;
19import java.util.List;
20import java.util.concurrent.Callable;
21
22/**
23 * @author Gabor Bergmann
24 *
25 * @since 2.1
26 */
27class TabularEngineContext implements IEngineContext, IBaseIndex {
28
29 private TabularIndexHost indexHost;
30 private ViatraQueryEngine engine;
31 private Logger logger;
32
33 private List<IIndexingErrorListener> errorListeners = CollectionsFactory.createObserverList();
34
35 public TabularEngineContext(TabularIndexHost server, ViatraQueryEngine engine,
36 IIndexingErrorListener errorListener, Logger logger) {
37 this.indexHost = server;
38 this.engine = engine;
39 this.logger = logger;
40
41 this.addIndexingErrorListener(errorListener);
42 }
43
44 @Override
45 public IBaseIndex getBaseIndex() {
46 return this;
47 }
48
49 @Override
50 public void dispose() {
51 // NOP, server lifecycle not controlled by engine
52 }
53
54 @Override
55 public IQueryRuntimeContext getQueryRuntimeContext() {
56 return indexHost.getRuntimeContext();
57 }
58
59 @Override
60 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
61 try {
62 return callable.call();
63 } catch (Exception e) {
64 throw new InvocationTargetException(e);
65 }
66 }
67
68 @Override
69 public void addBaseIndexChangeListener(ViatraBaseIndexChangeListener listener) {
70 // TODO no notifications yet
71 }
72
73 @Override
74 public void removeBaseIndexChangeListener(ViatraBaseIndexChangeListener listener) {
75 // TODO no notifications yet
76 }
77
78 @Override
79 public boolean addInstanceObserver(IInstanceObserver observer, Object observedObject) {
80 // TODO no notifications yet
81 return true;
82 }
83
84 @Override
85 public boolean removeInstanceObserver(IInstanceObserver observer, Object observedObject) {
86 // TODO no notifications yet
87 return true;
88 }
89
90 @Override
91 public void resampleDerivedFeatures() {
92 throw new UnsupportedOperationException();
93 }
94
95 @Override
96 public boolean addIndexingErrorListener(IIndexingErrorListener listener) {
97 return errorListeners.add(listener);
98 }
99
100 @Override
101 public boolean removeIndexingErrorListener(IIndexingErrorListener listener) {
102 return errorListeners.remove(listener);
103 }
104
105
106
107}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/TabularIndexHost.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/TabularIndexHost.java
deleted file mode 100644
index 6f2a1f5f..00000000
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/tabular/TabularIndexHost.java
+++ /dev/null
@@ -1,145 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.tabular;
10
11import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
12import tools.refinery.viatra.runtime.api.scope.IEngineContext;
13import tools.refinery.viatra.runtime.api.scope.IIndexingErrorListener;
14import tools.refinery.viatra.runtime.api.scope.QueryScope;
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.scopes.IStorageBackend;
17import tools.refinery.viatra.runtime.matchers.scopes.TabularRuntimeContext;
18import tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable;
19import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterBinary;
20import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterUnary;
21
22/**
23 * Simple tabular index host.
24 *
25 * Unlike traditional Viatra instances initialized on a model,
26 * this index host can be initialized and then queried,
27 * while its queriable "contents" (base relations) can be separately written using table writer API.
28 *
29 * <p> Deriving classes are responsible for setting up the tables of this index and providing the writer API to clients.
30 * For the former, use {@link #newUnaryInputTable(IInputKey, boolean)},
31 * {@link #newBinaryInputTable(IInputKey, boolean)} to create input tables,
32 * or {@link #registerNewTable(IIndexTable)} to register manually created derived tables.
33 * Instantiate such tables with {@link #runtimeContext} as their table context.
34 *
35 *
36 * <p>
37 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
38 * part of a work in progress. There is no guarantee that this API will
39 * work or that it will remain the same.
40 *
41 * @see EcoreIndexHost EcoreIndexHost for EMF-specific example usage.
42 *
43 * @author Gabor Bergmann
44 * @since 2.1
45 */
46public abstract class TabularIndexHost {
47
48 private final IStorageBackend storage;
49 protected final TabularRuntimeContext runtimeContext;
50 protected final TabularIndexScope scope = new TabularIndexScope();
51
52 public TabularIndexHost(IStorageBackend storage, TabularRuntimeContext runtimeContext) {
53 this.storage = storage;
54 this.runtimeContext = runtimeContext;
55 }
56
57
58 public TabularRuntimeContext getRuntimeContext() {
59 return runtimeContext;
60 }
61
62 public TabularIndexScope getScope() {
63 return scope;
64 }
65
66 /**
67 * @return true if this index host aims to serve queries that have a scope of the given type
68 */
69 protected abstract boolean isQueryScopeEmulated(Class<? extends QueryScope> queryScopeClass);
70
71
72
73 /**
74 * Marks the beginning of an update transaction.
75 * In transaction mode, index table updates may be temporarily delayed for better performance.
76 * Stateful query backends will not update their results during the index update transaction. (TODO actually achieve this)
77 */
78 public void startUpdateTransaction() {
79 storage.startTransaction();
80 }
81 /**
82 * Marks the end of an update transaction.
83 * Any updates to index tables that were delayed during the transaction must now be flushed.
84 * Afterwards, stateful query backends will update their results. (TODO actually achieve this)
85 */
86 public void finishUpdateTransaction() {
87 storage.finishTransaction();
88 }
89
90 /**
91 * To be called by deriving class. Creates and registers a new unary input table.
92 */
93 protected ITableWriterUnary.Table<Object> newUnaryInputTable(IInputKey key, boolean unique) {
94 return registerNewTable(storage.createUnaryTable(key, runtimeContext, unique));
95 }
96 /**
97 * To be called by deriving class. Creates and registers a new binary input table.
98 */
99 protected ITableWriterBinary.Table<Object,Object> newBinaryInputTable(IInputKey key, boolean unique) {
100 return registerNewTable(storage.createBinaryTable(key, runtimeContext, unique));
101 }
102 /**
103 * To be called by deriving class. Registers the given freshly created table and also returns it for convenience.
104 */
105 protected <Table extends IIndexTable> Table registerNewTable(Table newTable) {
106 runtimeContext.registerIndexTable(newTable);
107 return newTable;
108 }
109
110
111 /**
112 * A scope describing queries evaluated against tzhis index host.
113 * @author Gabor Bergmann
114 *
115 */
116 public class TabularIndexScope extends QueryScope {
117
118 public TabularIndexHost getIndexHost() {
119 return TabularIndexHost.this;
120 }
121
122 @Override
123 public int hashCode() {
124 return getIndexHost().hashCode();
125 }
126
127 @Override
128 public boolean equals(Object obj) {
129 if (obj instanceof TabularIndexScope)
130 return getIndexHost().equals(((TabularIndexScope) obj).getIndexHost());
131 return false;
132 }
133
134 @Override
135 public boolean isCompatibleWithQueryScope(Class<? extends QueryScope> queryScopeClass) {
136 return isQueryScopeEmulated(queryScopeClass) || super.isCompatibleWithQueryScope(queryScopeClass);
137 }
138
139 @Override
140 protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener, org.apache.log4j.Logger logger) {
141 return new TabularEngineContext(getIndexHost(), engine, errorListener, logger);
142 }
143
144 }
145}