aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects
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
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')
-rw-r--r--subprojects/viatra-runtime-base/about.html26
-rw-r--r--subprojects/viatra-runtime-base/build.gradle.kts19
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/ViatraBasePlugin.java46
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/BaseIndexOptions.java395
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/DataTypeListener.java44
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/EMFBaseIndexChangeListener.java33
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/FeatureListener.java48
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IEClassifierProcessor.java25
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IEMFIndexingErrorListener.java22
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IQueryResultSetter.java63
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IQueryResultUpdateListener.java45
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IStructuralFeatureInstanceProcessor.java19
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IndexingLevel.java113
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/InstanceListener.java41
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/LightweightEObjectObserver.java32
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/LightweightEObjectObserverAdapter.java74
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/NavigationHelper.java885
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/QueryResultAssociativeStore.java322
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/QueryResultMap.java210
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/TransitiveClosureHelper.java26
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/ViatraBaseFactory.java180
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexFeatureFilter.java38
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexObjectFilter.java30
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexResourceFilter.java27
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/SimpleBaseIndexFilter.java46
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/profiler/BaseIndexProfiler.java79
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/profiler/ProfilerMode.java22
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/EMFModelComprehension.java356
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/EMFVisitor.java145
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/WellbehavingDerivedFeatureRegistry.java154
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/AbstractBaseIndexStore.java28
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexInstanceStore.java451
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexMetaStore.java380
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexStatisticsStore.java71
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFDataSource.java137
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperContentAdapter.java750
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperImpl.java1702
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperSetting.java73
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperType.java14
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperVisitor.java441
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/TransitiveClosureHelperImpl.java153
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/profiler/ProfilingNavigationHelperContentAdapter.java155
-rw-r--r--subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/exception/ViatraBaseException.java25
-rw-r--r--subprojects/viatra-runtime-localsearch/build.gradle.kts1
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java26
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java32
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java61
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchBackendFactoryProvider.java29
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchEMFBackendFactory.java65
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java157
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchResultProvider.java56
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ContainmentCheck.java85
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfClassCheck.java75
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfDataTypeCheck.java71
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfJavaClassCheck.java71
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/StructuralFeatureCheck.java91
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/nobase/ScopeCheck.java91
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendToEStructuralFeatureSource.java112
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendToEStructuralFeatureTarget.java102
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverChildren.java90
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverContainers.java126
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEClassInstances.java97
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEDatatypeInstances.java96
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEStructuralFeatureInstances.java115
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/AbstractIteratingExtendOperationExecutor.java54
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/ExtendToEStructuralFeatureSource.java118
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/IterateOverEClassInstances.java93
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/IterateOverEDatatypeInstances.java123
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java158
-rw-r--r--subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/EMFOperationCompiler.java198
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java53
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java51
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java132
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java119
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java266
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java143
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java192
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java212
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java29
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java53
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java320
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java140
-rw-r--r--subprojects/viatra-runtime/build.gradle.kts6
-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
149 files changed, 298 insertions, 17827 deletions
diff --git a/subprojects/viatra-runtime-base/about.html b/subprojects/viatra-runtime-base/about.html
deleted file mode 100644
index d1d5593a..00000000
--- a/subprojects/viatra-runtime-base/about.html
+++ /dev/null
@@ -1,26 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
2<html>
3<!--
4 Copyright (c) 2017, Eclipse.org Foundation, Inc.
5
6 SPDX-License-Identifier: LicenseRef-EPL-Steward
7-->
8<head>
9<title>About</title>
10<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
11</head>
12<body lang="EN-US">
13<h2>About This Content</h2>
14
15<p>March 18, 2019</p>
16<h3>License</h3>
17
18<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
19Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is available at <a href="http://www.eclipse.org/org/documents/epl-v20.php">http://www.eclipse.org/legal/epl-v20.html</a>.
20For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
21
22<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
23apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
24indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
25</body>
26</html>
diff --git a/subprojects/viatra-runtime-base/build.gradle.kts b/subprojects/viatra-runtime-base/build.gradle.kts
deleted file mode 100644
index 55c6acb8..00000000
--- a/subprojects/viatra-runtime-base/build.gradle.kts
+++ /dev/null
@@ -1,19 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9}
10
11dependencies {
12 api(project(":refinery-viatra-runtime-base-itc"))
13 api(project(":refinery-viatra-runtime-matchers"))
14 implementation(libs.eclipse)
15 implementation(libs.ecore)
16 implementation(libs.emf)
17 implementation(libs.osgi)
18 implementation(libs.slf4j.log4j)
19}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/ViatraBasePlugin.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/ViatraBasePlugin.java
deleted file mode 100644
index 96b40825..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/ViatraBasePlugin.java
+++ /dev/null
@@ -1,46 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base;
11
12import org.eclipse.core.runtime.Plugin;
13import tools.refinery.viatra.runtime.base.comprehension.WellbehavingDerivedFeatureRegistry;
14import org.osgi.framework.BundleContext;
15
16public class ViatraBasePlugin extends Plugin {
17
18 // The shared instance
19 private static ViatraBasePlugin plugin;
20
21 public static final String PLUGIN_ID = "tools.refinery.viatra.runtime.base";
22 public static final String WELLBEHAVING_DERIVED_FEATURE_EXTENSION_POINT_ID = "tools.refinery.viatra.runtime.base.wellbehaving.derived.features";
23
24 @Override
25 public void start(BundleContext context) throws Exception {
26 super.start(context);
27 plugin = this;
28 WellbehavingDerivedFeatureRegistry.initRegistry();
29 }
30
31 @Override
32 public void stop(BundleContext context) throws Exception {
33 plugin = null;
34 super.stop(context);
35 }
36
37 /**
38 * Returns the shared instance
39 *
40 * @return the shared instance
41 */
42 public static ViatraBasePlugin getDefault() {
43 return plugin;
44 }
45
46}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/BaseIndexOptions.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/BaseIndexOptions.java
deleted file mode 100644
index 92663400..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/BaseIndexOptions.java
+++ /dev/null
@@ -1,395 +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.base.api;
10
11import java.util.Objects;
12
13import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexFeatureFilter;
14import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexObjectFilter;
15import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexResourceFilter;
16import tools.refinery.viatra.runtime.base.api.profiler.ProfilerMode;
17
18/**
19 * The base index options indicate how the indices are built.
20 *
21 * <p>
22 * One of the options is to build indices in <em>wildcard mode</em>, meaning that all EClasses, EDataTypes, EReferences
23 * and EAttributes are indexed. This is convenient, but comes at a high memory cost. To save memory, one can disable
24 * <em>wildcard mode</em> and manually register those EClasses, EDataTypes, EReferences and EAttributes that should be
25 * indexed.
26 * </p>
27 *
28 * <p>
29 * Another choice is whether to build indices in <em>dynamic EMF mode</em>, meaning that types are identified by the
30 * String IDs that are ultimately derived from the nsURI of the EPackage. Multiple types with the same ID are treated as
31 * the same. This is useful if dynamic EMF is used, where there can be multiple copies (instantiations) of the same
32 * EPackage, representing essentially the same metamodel. If one disables <em>dynamic EMF mode</em>, an error is logged
33 * if duplicate EPackages with the same nsURI are encountered.
34 * </p>
35 *
36 * @author Abel Hegedus
37 * @noimplement This class is not intended to be subclasses outside of VIATRA runtime
38 *
39 */
40public class BaseIndexOptions {
41
42 /**
43 *
44 * By default, base indices will be constructed with wildcard mode set as false.
45 */
46 protected static final IndexingLevel WILDCARD_MODE_DEFAULT = IndexingLevel.NONE;
47 /**
48 *
49 * By default, base indices will be constructed with only well-behaving features traversed.
50 */
51 private static final boolean TRAVERSE_ONLY_WELLBEHAVING_DERIVED_FEATURES_DEFAULT = true;
52 /**
53 *
54 * By default, base indices will be constructed with dynamic EMF mode set as false.
55 */
56 protected static final boolean DYNAMIC_EMF_MODE_DEFAULT = false;
57
58 /**
59 *
60 * By default, the scope will make the assumption that it is free from dangling edges.
61 * @since 1.6
62 */
63 protected static final boolean DANGLING_FREE_ASSUMPTION_DEFAULT = true;
64
65 /**
66 * By default, duplicate notifications are only logged.
67 *
68 * @since 1.6
69 */
70 protected static final boolean STRICT_NOTIFICATION_MODE_DEFAULT = true;
71
72 /**
73 * @since 2.3
74 */
75 protected static final ProfilerMode INDEX_PROFILER_MODE_DEFAULT = ProfilerMode.OFF;
76
77 /**
78 * @since 1.6
79 */
80 protected boolean danglingFreeAssumption = DANGLING_FREE_ASSUMPTION_DEFAULT;
81 protected boolean dynamicEMFMode = DYNAMIC_EMF_MODE_DEFAULT;
82 protected boolean traverseOnlyWellBehavingDerivedFeatures = TRAVERSE_ONLY_WELLBEHAVING_DERIVED_FEATURES_DEFAULT;
83 protected IndexingLevel wildcardMode = WILDCARD_MODE_DEFAULT;
84 protected IBaseIndexObjectFilter notifierFilterConfiguration;
85 protected IBaseIndexResourceFilter resourceFilterConfiguration;
86 /**
87 * @since 1.5
88 */
89 protected IBaseIndexFeatureFilter featureFilterConfiguration;
90
91 /**
92 * If strict notification mode is turned on, errors related to inconsistent notifications, e.g. duplicate deletions
93 * cause the entire Base index to be considered invalid, e.g. the query engine on top of the index should become
94 * tainted.
95 *
96 * @since 1.6
97 */
98 protected boolean strictNotificationMode = STRICT_NOTIFICATION_MODE_DEFAULT;
99
100 /**
101 * Returns whether base index profiling should be turned on.
102 *
103 * @since 2.3
104 */
105 protected ProfilerMode indexerProfilerMode = INDEX_PROFILER_MODE_DEFAULT;
106
107 /**
108 * Creates a base index options with the default values.
109 */
110 public BaseIndexOptions() {
111 }
112
113 /**
114 * Creates a base index options using the provided values for dynamic EMF mode and wildcard mode.
115 * @since 1.4
116 */
117 public BaseIndexOptions(boolean dynamicEMFMode, IndexingLevel wildcardMode) {
118 this.dynamicEMFMode = dynamicEMFMode;
119 this.wildcardMode = wildcardMode;
120 }
121
122 /**
123 *
124 * @param dynamicEMFMode
125 * @since 0.9
126 */
127 public BaseIndexOptions withDynamicEMFMode(boolean dynamicEMFMode) {
128 BaseIndexOptions result = copy();
129 result.dynamicEMFMode = dynamicEMFMode;
130 return result;
131 }
132
133 /**
134 * Sets the dangling edge handling property of the index option. If not set explicitly, it is considered as `true`.
135 * @param danglingFreeAssumption if true,
136 * the base index will assume that there are no dangling references
137 * (pointing out of scope or to proxies)
138 * @since 1.6
139 */
140 public BaseIndexOptions withDanglingFreeAssumption(boolean danglingFreeAssumption) {
141 BaseIndexOptions result = copy();
142 result.danglingFreeAssumption = danglingFreeAssumption;
143 return result;
144 }
145
146 /**
147 * Adds an object-level filter to the indexer configuration. Warning - object-level indexing can increase indexing time
148 * noticeably. If possibly, use {@link #withResourceFilterConfiguration(IBaseIndexResourceFilter)} instead.
149 *
150 * @param filter
151 * @since 0.9
152 */
153 public BaseIndexOptions withObjectFilterConfiguration(IBaseIndexObjectFilter filter) {
154 BaseIndexOptions result = copy();
155 result.notifierFilterConfiguration = filter;
156 return result;
157 }
158
159 /**
160 * @return the selected object filter configuration, or null if not set
161 */
162 public IBaseIndexObjectFilter getObjectFilterConfiguration() {
163 return notifierFilterConfiguration;
164 }
165
166 /**
167 * Returns a copy of the configuration with a specified resource filter
168 *
169 * @param filter
170 * @since 0.9
171 */
172 public BaseIndexOptions withResourceFilterConfiguration(IBaseIndexResourceFilter filter) {
173 BaseIndexOptions result = copy();
174 result.resourceFilterConfiguration = filter;
175 return result;
176 }
177
178 /**
179 * @return the selected resource filter, or null if not set
180 */
181 public IBaseIndexResourceFilter getResourceFilterConfiguration() {
182 return resourceFilterConfiguration;
183 }
184
185
186 /**
187 * Returns a copy of the configuration with a specified feature filter
188 *
189 * @param filter
190 * @since 1.5
191 */
192 public BaseIndexOptions withFeatureFilterConfiguration(IBaseIndexFeatureFilter filter) {
193 BaseIndexOptions result = copy();
194 result.featureFilterConfiguration = filter;
195 return result;
196 }
197
198 /**
199 * @return the selected feature filter, or null if not set
200 * @since 1.5
201 */
202 public IBaseIndexFeatureFilter getFeatureFilterConfiguration() {
203 return featureFilterConfiguration;
204 }
205
206
207 /**
208 * @return whether the base index option has dynamic EMF mode set
209 */
210 public boolean isDynamicEMFMode() {
211 return dynamicEMFMode;
212 }
213
214 /**
215 * @return whether the base index makes the assumption that there can be no dangling edges
216 * @since 1.6
217 */
218 public boolean isDanglingFreeAssumption() {
219 return danglingFreeAssumption;
220 }
221
222 /**
223 * @return whether the base index option has traverse only well-behaving derived features set
224 */
225 public boolean isTraverseOnlyWellBehavingDerivedFeatures() {
226 return traverseOnlyWellBehavingDerivedFeatures;
227 }
228
229 /**
230 *
231 * @param wildcardMode
232 * @since 1.4
233 */
234 public BaseIndexOptions withWildcardLevel(IndexingLevel wildcardLevel) {
235 BaseIndexOptions result = copy();
236 result.wildcardMode = wildcardLevel;
237 return result;
238 }
239
240 /**
241 * @since 1.6
242 */
243 public BaseIndexOptions withStrictNotificationMode(boolean strictNotificationMode) {
244 BaseIndexOptions result = copy();
245 result.strictNotificationMode = strictNotificationMode;
246 return result;
247 }
248
249 /**
250 * @since 2.3
251 */
252 public BaseIndexOptions withIndexProfilerMode(ProfilerMode indexerProfilerMode) {
253 BaseIndexOptions result = copy();
254 result.indexerProfilerMode = indexerProfilerMode;
255 return result;
256 }
257
258 /**
259 * @return whether the base index option has wildcard mode set
260 */
261 public boolean isWildcardMode() {
262 return wildcardMode == IndexingLevel.FULL;
263 }
264
265 /**
266 * @return the wildcardMode level
267 * @since 1.4
268 */
269 public IndexingLevel getWildcardLevel() {
270 return wildcardMode;
271 }
272
273 /**
274 * If strict notification mode is turned on, errors related to inconsistent notifications, e.g. duplicate deletions
275 * cause the entire Base index to be considered invalid, e.g. the query engine on top of the index should become
276 * tainted.
277 *
278 * @since 1.6
279 */
280 public boolean isStrictNotificationMode() {
281 return strictNotificationMode;
282 }
283
284 /**
285 * Returns whether base indexer profiling is enabled. The profiling causes some slowdown, but provides information
286 * about how much time the base indexer takes for initialization and updates.
287 *
288 * @since 2.3
289 */
290 public ProfilerMode getIndexerProfilerMode() {
291 return indexerProfilerMode;
292 }
293
294 /**
295 * Creates an independent copy of itself. The values of each option will be the same as this options. This method is
296 * used when a provided option must be copied to avoid external option changes afterward.
297 *
298 * @return the copy of this options
299 */
300 public BaseIndexOptions copy() {
301 BaseIndexOptions baseIndexOptions = new BaseIndexOptions(this.dynamicEMFMode, this.wildcardMode);
302 baseIndexOptions.danglingFreeAssumption = this.danglingFreeAssumption;
303 baseIndexOptions.traverseOnlyWellBehavingDerivedFeatures = this.traverseOnlyWellBehavingDerivedFeatures;
304 baseIndexOptions.notifierFilterConfiguration = this.notifierFilterConfiguration;
305 baseIndexOptions.resourceFilterConfiguration = this.resourceFilterConfiguration;
306 baseIndexOptions.featureFilterConfiguration = this.featureFilterConfiguration;
307 baseIndexOptions.strictNotificationMode = this.strictNotificationMode;
308 baseIndexOptions.indexerProfilerMode = this.indexerProfilerMode;
309 return baseIndexOptions;
310 }
311
312 @Override
313 public int hashCode() {
314 return Objects.hash(dynamicEMFMode, notifierFilterConfiguration, resourceFilterConfiguration,
315 featureFilterConfiguration, traverseOnlyWellBehavingDerivedFeatures, wildcardMode, strictNotificationMode,
316 danglingFreeAssumption, indexerProfilerMode);
317 }
318
319 @Override
320 public boolean equals(Object obj) {
321 if (this == obj)
322 return true;
323 if (obj == null)
324 return false;
325 if (!(obj instanceof BaseIndexOptions))
326 return false;
327 BaseIndexOptions other = (BaseIndexOptions) obj;
328 if (dynamicEMFMode != other.dynamicEMFMode)
329 return false;
330 if (danglingFreeAssumption != other.danglingFreeAssumption)
331 return false;
332 if (notifierFilterConfiguration == null) {
333 if (other.notifierFilterConfiguration != null)
334 return false;
335 } else if (!notifierFilterConfiguration
336 .equals(other.notifierFilterConfiguration))
337 return false;
338 if (resourceFilterConfiguration == null) {
339 if (other.resourceFilterConfiguration != null)
340 return false;
341 } else if (!resourceFilterConfiguration
342 .equals(other.resourceFilterConfiguration)){
343 return false;
344 }
345
346 if (featureFilterConfiguration == null) {
347 if (other.featureFilterConfiguration != null)
348 return false;
349 } else if (!featureFilterConfiguration
350 .equals(other.featureFilterConfiguration)){
351 return false;
352 }
353
354 if (traverseOnlyWellBehavingDerivedFeatures != other.traverseOnlyWellBehavingDerivedFeatures)
355 return false;
356 if (wildcardMode != other.wildcardMode)
357 return false;
358 if (strictNotificationMode != other.strictNotificationMode) {
359 return false;
360 }
361 if (indexerProfilerMode != other.indexerProfilerMode) {
362 return false;
363 }
364 return true;
365 }
366
367
368 @Override
369 public String toString() {
370 StringBuilder sb = new StringBuilder();
371 appendModifier(sb, dynamicEMFMode, DYNAMIC_EMF_MODE_DEFAULT, "dynamicEMF");
372 appendModifier(sb, wildcardMode, WILDCARD_MODE_DEFAULT, "wildcard");
373 appendModifier(sb, danglingFreeAssumption, DANGLING_FREE_ASSUMPTION_DEFAULT, "danglingFreeAssumption");
374 appendModifier(sb, traverseOnlyWellBehavingDerivedFeatures, TRAVERSE_ONLY_WELLBEHAVING_DERIVED_FEATURES_DEFAULT, "wellBehavingOnly");
375 appendModifier(sb, strictNotificationMode, STRICT_NOTIFICATION_MODE_DEFAULT, "strictNotificationMode");
376 appendModifier(sb, indexerProfilerMode, INDEX_PROFILER_MODE_DEFAULT, "indexerProfilerMode");
377 appendModifier(sb, notifierFilterConfiguration, null, "notifierFilter=");
378 appendModifier(sb, resourceFilterConfiguration, null, "resourceFilter=");
379 appendModifier(sb, featureFilterConfiguration, null, "featureFilterConfiguration=");
380 final String result = sb.toString();
381 return result.isEmpty() ? "defaults" : result;
382 }
383
384 private static void appendModifier(StringBuilder sb, Object actualValue, Object expectedValue, String switchName) {
385 if (Objects.equals(expectedValue, actualValue)) {
386 // silent
387 } else {
388 sb.append(Boolean.FALSE.equals(actualValue) ? '-' : '+');
389 sb.append(switchName);
390 if (! (actualValue instanceof Boolean))
391 sb.append(actualValue);
392 }
393 }
394
395}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/DataTypeListener.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/DataTypeListener.java
deleted file mode 100644
index 3d30df5e..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/DataTypeListener.java
+++ /dev/null
@@ -1,44 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.api;
10
11import org.eclipse.emf.ecore.EDataType;
12
13/**
14 * Interface for observing insertion and deletion of instances of data types.
15 *
16 * @author Tamas Szabo
17 *
18 */
19public interface DataTypeListener {
20
21 /**
22 * Called when an instance of the given type is inserted.
23 *
24 * @param type
25 * the {@link EDataType}
26 * @param instance
27 * the instance of the data type
28 * @param firstOccurrence
29 * true if this value was not previously present in the model
30 */
31 public void dataTypeInstanceInserted(EDataType type, Object instance, boolean firstOccurrence);
32
33 /**
34 * Called when an instance of the given type is deleted.
35 *
36 * @param type
37 * the {@link EDataType}
38 * @param instance
39 * the instance of the data type
40 * @param lastOccurrence
41 * true if this value is no longer present in the model
42 */
43 public void dataTypeInstanceDeleted(EDataType type, Object instance, boolean lastOccurrence);
44}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/EMFBaseIndexChangeListener.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/EMFBaseIndexChangeListener.java
deleted file mode 100644
index 5a2486f9..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/EMFBaseIndexChangeListener.java
+++ /dev/null
@@ -1,33 +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.base.api;
10
11/**
12 * Listener interface for change notifications from the VIATRA Base index.
13 *
14 * @author Abel Hegedus
15 *
16 */
17public interface EMFBaseIndexChangeListener {
18
19 /**
20 * NOTE: it is possible that this method is called only ONCE! Consider returning a constant value that is set in the constructor.
21 *
22 * @return true, if the listener should be notified only after index changes, false if notification is needed after each model change
23 */
24 public boolean onlyOnIndexChange();
25
26 /**
27 * Called after a model change is handled by the VIATRA Base index and if <code>indexChanged == onlyOnIndexChange()</code>.
28 *
29 * @param indexChanged true, if the model change also affected the contents of the base index
30 */
31 public void notifyChanged(boolean indexChanged);
32
33}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/FeatureListener.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/FeatureListener.java
deleted file mode 100644
index fa2d679e..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/FeatureListener.java
+++ /dev/null
@@ -1,48 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.api;
10
11import org.eclipse.emf.ecore.EAttribute;
12import org.eclipse.emf.ecore.EObject;
13import org.eclipse.emf.ecore.EReference;
14import org.eclipse.emf.ecore.EStructuralFeature;
15
16/**
17 * Interface for observing insertion and deletion of structural feature values ("settings"). (Works both for
18 * single-valued and many-valued features.)
19 *
20 * @author Tamas Szabo
21 *
22 */
23public interface FeatureListener {
24
25 /**
26 * Called when the given value is inserted into the given feature of the given host EObject.
27 *
28 * @param host
29 * the host (holder) of the feature
30 * @param feature
31 * the {@link EAttribute} or {@link EReference} instance
32 * @param value
33 * the target of the feature
34 */
35 public void featureInserted(EObject host, EStructuralFeature feature, Object value);
36
37 /**
38 * Called when the given value is removed from the given feature of the given host EObject.
39 *
40 * @param host
41 * the host (holder) of the feature
42 * @param feature
43 * the {@link EAttribute} or {@link EReference} instance
44 * @param value
45 * the target of the feature
46 */
47 public void featureDeleted(EObject host, EStructuralFeature feature, Object value);
48}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IEClassifierProcessor.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IEClassifierProcessor.java
deleted file mode 100644
index aaa98918..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IEClassifierProcessor.java
+++ /dev/null
@@ -1,25 +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.base.api;
10
11import org.eclipse.emf.ecore.EClass;
12import org.eclipse.emf.ecore.EDataType;
13import org.eclipse.emf.ecore.EObject;
14
15/**
16 * @author Abel Hegedus
17 *
18 */
19public interface IEClassifierProcessor<ClassType, InstanceType> {
20
21 void process(ClassType type, InstanceType instance);
22
23 public interface IEClassProcessor extends IEClassifierProcessor<EClass, EObject>{}
24 public interface IEDataTypeProcessor extends IEClassifierProcessor<EDataType, Object>{}
25}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IEMFIndexingErrorListener.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IEMFIndexingErrorListener.java
deleted file mode 100644
index 1dc3291b..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IEMFIndexingErrorListener.java
+++ /dev/null
@@ -1,22 +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.base.api;
10
11/**
12 *
13 * This interface contains callbacks for various internal errors from the {@link NavigationHelper base index}.
14 *
15 * @author Zoltan Ujhelyi
16 *
17 */
18public interface IEMFIndexingErrorListener {
19
20 void error(String description, Throwable t);
21 void fatal(String description, Throwable t);
22}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IQueryResultSetter.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IQueryResultSetter.java
deleted file mode 100644
index 717bad4b..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IQueryResultSetter.java
+++ /dev/null
@@ -1,63 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, 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.base.api;
10
11/**
12 * Setter interface for query result multimaps that allow modifications of the model through the multimap.
13 *
14 * <p>
15 * The model modifications should ensure that the multimap changes exactly as required (i.e. a put results in only one
16 * new key-value pair and remove results in only one removed pair).
17 *
18 * <p>
19 * The input parameters of both put and remove can be validated by implementing the {@link #validate(Object, Object)}
20 * method.
21 *
22 * @author Abel Hegedus
23 *
24 * @param <KeyType>
25 * @param <ValueType>
26 */
27public interface IQueryResultSetter<KeyType, ValueType> {
28 /**
29 * Modify the underlying model of the query in order to have the given key-value pair as a new result of the query.
30 *
31 * @param key
32 * the key for which a new value is added to the query results
33 * @param value
34 * the new value that should be added to the query results for the given key
35 * @return true, if the query result changed
36 */
37 boolean put(KeyType key, ValueType value);
38
39 /**
40 * Modify the underlying model of the query in order to remove the given key-value pair from the results of the
41 * query.
42 *
43 * @param key
44 * the key for which the value is removed from the query results
45 * @param value
46 * the value that should be removed from the query results for the given key
47 * @return true, if the query result changed
48 */
49 boolean remove(KeyType key, ValueType value);
50
51 /**
52 * Validates a given key-value pair for the query result. The validation has to ensure that (1) if the pair does not
53 * exist in the result, it can be added safely (2) if the pair already exists in the result, it can be removed
54 * safely
55 *
56 * @param key
57 * the key of the pair that is validated
58 * @param value
59 * the value of the pair that is validated
60 * @return true, if the pair does not exists but can be added or the pair exists and can be removed
61 */
62 boolean validate(KeyType key, ValueType value);
63} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IQueryResultUpdateListener.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IQueryResultUpdateListener.java
deleted file mode 100644
index 5addfd78..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IQueryResultUpdateListener.java
+++ /dev/null
@@ -1,45 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, 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.base.api;
10
11/**
12 * Listener interface for receiving notification from {@link QueryResultMultimap}
13 *
14 * @author Abel Hegedus
15 *
16 * @param <KeyType>
17 * @param <ValueType>
18 */
19public interface IQueryResultUpdateListener<KeyType, ValueType> {
20 /**
21 * This method is called by the query result multimap when a new key-value pair is put into the multimap
22 *
23 * <p>
24 * Only invoked if the contents of the multimap changed!
25 *
26 * @param key
27 * the key of the newly inserted pair
28 * @param value
29 * the value of the newly inserted pair
30 */
31 void notifyPut(KeyType key, ValueType value);
32
33 /**
34 * This method is called by the query result multimap when key-value pair is removed from the multimap
35 *
36 * <p>
37 * Only invoked if the contents of the multimap changed!
38 *
39 * @param key
40 * the key of the removed pair
41 * @param value
42 * the value of the removed pair
43 */
44 void notifyRemove(KeyType key, ValueType value);
45} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IStructuralFeatureInstanceProcessor.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IStructuralFeatureInstanceProcessor.java
deleted file mode 100644
index 208ad761..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IStructuralFeatureInstanceProcessor.java
+++ /dev/null
@@ -1,19 +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.base.api;
10
11import org.eclipse.emf.ecore.EObject;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public interface IStructuralFeatureInstanceProcessor {
18 void process(EObject source, Object target);
19}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IndexingLevel.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IndexingLevel.java
deleted file mode 100644
index df5c59f5..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/IndexingLevel.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
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.base.api;
10
11import tools.refinery.viatra.runtime.matchers.context.IndexingService;
12
13import java.util.Set;
14
15/**
16 * The values of this enum denotes the level of indexing the base indexer is capable of.
17 *
18 * @author Grill Balázs
19 * @since 1.4
20 *
21 */
22public enum IndexingLevel {
23
24 /**
25 * No indexing is performed
26 */
27 NONE,
28
29 /**
30 * Only cardinality information is stored. This indexing level makes possible to calculate
31 * results of {@link NavigationHelper#countAllInstances(org.eclipse.emf.ecore.EClass)}, {@link NavigationHelper#countFeatures(org.eclipse.emf.ecore.EStructuralFeature)}
32 * and {@link NavigationHelper#countDataTypeInstances(org.eclipse.emf.ecore.EDataType)} with minimal memory footprint.
33 */
34 STATISTICS,
35
36 /**
37 * Notifications are dispatched about the changes
38 */
39 NOTIFICATIONS,
40
41 /**
42 * Cardinality information is stored and live notifications are dispatched
43 */
44 BOTH,
45
46 /**
47 * Full indexing is performed, set of instances is available
48 */
49 FULL
50
51 ;
52
53 private static final IndexingLevel[][] mergeTable = {
54 /* NONE STATISTICS NOTIFICATIONS BOTH FULL*/
55 /* NONE */{ NONE, STATISTICS, NOTIFICATIONS, BOTH, FULL},
56 /* STATISTICS */{ STATISTICS, STATISTICS, BOTH, BOTH, FULL},
57 /* NOTIFICATIONS */{ NOTIFICATIONS, BOTH, NOTIFICATIONS, BOTH, FULL},
58 /* BOTH */{ BOTH, BOTH, BOTH, BOTH, FULL},
59 /* FULL */{ FULL, FULL, FULL, FULL, FULL}
60 };
61
62 public static IndexingLevel toLevel(IndexingService service){
63 switch(service){
64 case INSTANCES:
65 return IndexingLevel.FULL;
66 case NOTIFICATIONS:
67 return IndexingLevel.NOTIFICATIONS;
68 case STATISTICS:
69 return IndexingLevel.STATISTICS;
70 default:
71 return IndexingLevel.NONE;
72 }
73 }
74
75 public static IndexingLevel toLevel(Set<IndexingService> services){
76 IndexingLevel result = NONE;
77 for(IndexingService service : services){
78 result = result.merge(toLevel(service));
79 }
80 return result;
81 }
82
83 /**
84 * Merge this level with the given other level, The resulting indexing level will provide the
85 * functionality which conforms to both given levels.
86 */
87 public IndexingLevel merge(IndexingLevel other){
88 if (other == null) return this;
89 return mergeTable[this.ordinal()][other.ordinal()];
90 }
91
92 /**
93 * Tells whether the indexer shall perform separate statistics calculation for this level
94 */
95 public boolean hasStatistics() {
96 return this == IndexingLevel.BOTH || this == IndexingLevel.STATISTICS || this == IndexingLevel.FULL;
97 }
98
99 /**
100 * Tells whether the indexer shall perform instance indexing
101 */
102 public boolean hasInstances(){
103 return this == IndexingLevel.FULL;
104 }
105
106 /**
107 * Returns whether the current indexing level includes all features from the parameter level
108 * @since 1.5
109 */
110 public boolean providesLevel(IndexingLevel level) {
111 return this.merge(level) == this;
112 }
113}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/InstanceListener.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/InstanceListener.java
deleted file mode 100644
index 6339545d..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/InstanceListener.java
+++ /dev/null
@@ -1,41 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.api;
10
11import org.eclipse.emf.ecore.EClass;
12import org.eclipse.emf.ecore.EObject;
13
14/**
15 * Interface for observing insertion / deletion of instances of EClass.
16 *
17 * @author Tamas Szabo
18 *
19 */
20public interface InstanceListener {
21
22 /**
23 * Called when the given instance was added to the model.
24 *
25 * @param clazz
26 * an EClass registered for this listener, for which a new instance (possibly an instance of a subclass) was inserted into the model
27 * @param instance
28 * an EObject instance that was inserted into the model
29 */
30 public void instanceInserted(EClass clazz, EObject instance);
31
32 /**
33 * Called when the given instance was removed from the model.
34 *
35 * @param clazz
36 * an EClass registered for this listener, for which an instance (possibly an instance of a subclass) was removed from the model
37 * @param instance
38 * an EObject instance that was removed from the model
39 */
40 public void instanceDeleted(EClass clazz, EObject instance);
41}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/LightweightEObjectObserver.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/LightweightEObjectObserver.java
deleted file mode 100644
index f0245b5d..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/LightweightEObjectObserver.java
+++ /dev/null
@@ -1,32 +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.base.api;
10
11import org.eclipse.emf.common.notify.Notification;
12import org.eclipse.emf.ecore.EObject;
13import org.eclipse.emf.ecore.EStructuralFeature;
14
15
16/**
17 * Listener interface for lightweight observation on EObject feature value changes.
18 *
19 * @author Abel Hegedus
20 *
21 */
22public interface LightweightEObjectObserver {
23
24 /**
25 *
26 * @param host
27 * @param feature
28 * @param notification
29 */
30 void notifyFeatureChanged(EObject host, EStructuralFeature feature, Notification notification);
31
32}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/LightweightEObjectObserverAdapter.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/LightweightEObjectObserverAdapter.java
deleted file mode 100644
index bcdb8ff4..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/LightweightEObjectObserverAdapter.java
+++ /dev/null
@@ -1,74 +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.base.api;
10
11import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument;
12
13import java.util.Collection;
14import java.util.HashSet;
15
16import org.eclipse.emf.common.notify.Notification;
17import org.eclipse.emf.ecore.EObject;
18import org.eclipse.emf.ecore.EStructuralFeature;
19
20/**
21 * Adapter class for lightweight observer which filters feature updates to a selected set of features.
22 *
23 * @author Abel Hegedus
24 *
25 */
26public abstract class LightweightEObjectObserverAdapter implements LightweightEObjectObserver {
27
28 private Collection<EStructuralFeature> observedFeatures;
29
30 /**
31 * Creates a new adapter with the given set of observed features.
32 */
33 public LightweightEObjectObserverAdapter(Collection<EStructuralFeature> observedFeatures) {
34 checkArgument(observedFeatures != null, "List of observed features must not be null!");
35 this.observedFeatures = new HashSet<>(observedFeatures);
36 }
37
38 public void observeAdditionalFeature(EStructuralFeature observedFeature) {
39 checkArgument(observedFeature != null, "Cannot observe null feature!");
40 this.observedFeatures.add(observedFeature);
41 }
42
43 public void observeAdditionalFeatures(Collection<EStructuralFeature> observedFeatures) {
44 checkArgument(observedFeatures != null, "List of additional observed features must not be null!");
45 this.observedFeatures.addAll(observedFeatures);
46 }
47
48 public void removeObservedFeature(EStructuralFeature observedFeature) {
49 checkArgument(observedFeature != null, "Cannot remove null observed feature!");
50 this.observedFeatures.remove(observedFeature);
51 }
52
53 public void removeObservedFeatures(Collection<EStructuralFeature> observedFeatures) {
54 checkArgument(observedFeatures != null, "List of observed features to remove must not be null!");
55 this.observedFeatures.removeAll(observedFeatures);
56 }
57
58 @Override
59 public void notifyFeatureChanged(EObject host, EStructuralFeature feature, Notification notification) {
60 if(this.observedFeatures.contains(feature)) {
61 observedFeatureUpdate(host, feature, notification);
62 }
63 }
64
65 /**
66 * This method is called when the feature that changed is among the observed features of the adapter.
67 *
68 * @param host
69 * @param feature
70 * @param notification
71 */
72 public abstract void observedFeatureUpdate(EObject host, EStructuralFeature feature, Notification notification);
73
74}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/NavigationHelper.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/NavigationHelper.java
deleted file mode 100644
index 6a9f704b..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/NavigationHelper.java
+++ /dev/null
@@ -1,885 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base.api;
11
12import org.eclipse.emf.common.notify.Notifier;
13import org.eclipse.emf.common.util.EList;
14import org.eclipse.emf.common.util.Enumerator;
15import org.eclipse.emf.ecore.*;
16import org.eclipse.emf.ecore.EStructuralFeature.Setting;
17import org.eclipse.emf.ecore.resource.Resource;
18import org.eclipse.emf.ecore.resource.ResourceSet;
19import tools.refinery.viatra.runtime.base.api.IEClassifierProcessor.IEClassProcessor;
20import tools.refinery.viatra.runtime.base.api.IEClassifierProcessor.IEDataTypeProcessor;
21import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
22
23import java.lang.reflect.InvocationTargetException;
24import java.util.Collection;
25import java.util.ConcurrentModificationException;
26import java.util.Set;
27import java.util.concurrent.Callable;
28
29/**
30 *
31 * Using an index of the EMF model, this interface exposes useful query functionality, such as:
32 * <ul>
33 * <li>
34 * Getting all the (direct or descendant) instances of a given {@link EClass}
35 * <li>
36 * Inverse navigation along arbitrary {@link EReference} instances (heterogenous paths too)
37 * <li>
38 * Finding model elements by attribute value (i.e. inverse navigation along {@link EAttribute})
39 * <li>
40 * Querying instances of given data types, or structural features.
41 * </ul>
42 * As queries are served from an index, results are always instantaneous.
43 *
44 * <p>
45 * Such indices will be built on an EMF model rooted at an {@link EObject}, {@link Resource} or {@link ResourceSet}.
46 * The boundaries of the model are defined by the containment (sub)tree.
47 * The indices will be <strong>maintained incrementally</strong> on changes to the model; these updates can also be
48 * observed by registering listeners.
49 * </p>
50 *
51 * <p>
52 * One of the options is to build indices in <em>wildcard mode</em>, meaning that all EClasses, EDataTypes, EReferences
53 * and EAttributes are indexed. This is convenient, but comes at a high memory cost. To save memory, one can disable
54 * <em>wildcard mode</em> and manually register those EClasses, EDataTypes, EReferences and EAttributes that should be
55 * indexed.
56 * </p>
57 *
58 * <p>
59 * Another choice is whether to build indices in <em>dynamic EMF mode</em>, meaning that types are identified by the String IDs
60 * that are ultimately derived from the nsURI of the EPackage. Multiple types with the same ID are treated as the same.
61 * This is useful if dynamic EMF is used, where there can be multiple copies (instantiations) of the same EPackage,
62 * representing essentially the same metamodel. If one disables <em>dynamic EMF mode</em>, an error is logged if
63 * duplicate EPackages with the same nsURI are encountered.
64 * </p>
65 *
66 * <p>
67 * Note that none of the defined query methods return null upon empty result sets. All query methods return either a copy of
68 * the result sets (where {@link Setting} is instantiated) or an unmodifiable collection of the result view.
69 *
70 * <p>
71 * Instantiate using {@link ViatraBaseFactory}
72 *
73 * @author Tamas Szabo
74 * @noimplement This interface is not intended to be implemented by clients.
75 *
76 */
77public interface NavigationHelper {
78
79 /**
80 * Indicates whether indexing is performed in <em>wildcard mode</em>, where every aspect of the EMF model is
81 * automatically indexed.
82 *
83 * @return true if everything is indexed, false if manual registration of interesting EClassifiers and
84 * EStructuralFeatures is required.
85 */
86 public boolean isInWildcardMode();
87
88 /**
89 * Indicates whether indexing is performed in <em>wildcard mode</em> for a selected indexing level
90 *
91 * @return true if everything is indexed, false if manual registration of interesting EClassifiers and
92 * EStructuralFeatures is required.
93 * @since 1.5
94 */
95 public boolean isInWildcardMode(IndexingLevel level);
96
97 /**
98 * Returns the current {@link IndexingLevel} applied to all model elements. For specific types it is possible to request a higher indexing levels, but cannot be lowered.
99 * @return the current level of index specified
100 * @since 1.4
101 */
102 public IndexingLevel getWildcardLevel();
103
104 /**
105 * Starts wildcard indexing at the given level. After this call, no registration is required for this {@link IndexingLevel}.
106 * a previously set wildcard level cannot be lowered, only extended.
107 *
108 * @since 1.4
109 */
110 public void setWildcardLevel(IndexingLevel level);
111
112 /**
113 * Indicates whether indexing is performed in <em>dynamic EMF mode</em>, i.e. EPackage nsURI collisions are
114 * tolerated and EPackages with the same URI are automatically considered as equal.
115 *
116 * @return true if multiple EPackages with the same nsURI are treated as the same,
117 * false if an error is logged instead in this case.
118 */
119 public boolean isInDynamicEMFMode();
120
121 /**
122 * For a given attribute value <code>value</code>, find each {@link EAttribute} and host {@link EObject}
123 * such that this attribute of the the host object takes the given value. The method will
124 * return a set of {@link Setting}s, one for each such host object - EAttribute - value triplet.
125 *
126 * <p>
127 * <strong>Precondition:</strong> Unset / null attribute values are not indexed, so <code>value!=null</code>
128 *
129 * <p>
130 * <strong>Precondition:</strong> Will only find those EAttributes that have already been registered using
131 * {@link #registerEStructuralFeatures(Set)}, unless running in <em>wildcard mode</em> (see
132 * {@link #isInWildcardMode()}).
133 *
134 * @param value
135 * the value of the attribute
136 * @return a set of {@link Setting}s, one for each EObject and EAttribute that have the given value
137 * @see #findByAttributeValue(Object)
138 */
139 public Set<Setting> findByAttributeValue(Object value);
140
141 /**
142 * For given <code>attributes</code> and an attribute value <code>value</code>, find each host {@link EObject}
143 * such that any of these attributes of the the host object takes the given value. The method will
144 * return a set of {@link Setting}s, one for each such host object - EAttribute - value triplet.
145 *
146 * <p>
147 * <strong>Precondition:</strong> Unset / null attribute values are not indexed, so <code>value!=null</code>
148 *
149 * <p>
150 * <strong>Precondition:</strong> Will only find those EAttributes that have already been registered using
151 * {@link #registerEStructuralFeatures(Set)}, unless running in <em>wildcard mode</em> (see
152 * {@link #isInWildcardMode()}).
153 *
154 * @param value
155 * the value of the attribute
156 * @param attributes
157 * the collection of attributes that should take the given value
158 * @return a set of {@link Setting}s, one for each EObject and attribute that have the given value
159 */
160 public Set<Setting> findByAttributeValue(Object value, Collection<EAttribute> attributes);
161
162 /**
163 * Find all {@link EObject}s for which the given <code>attribute</code> takes the given <code>value</code>.
164 *
165 * <p>
166 * <strong>Precondition:</strong> Unset / null attribute values are not indexed, so <code>value!=null</code>
167 *
168 * <p>
169 * <strong>Precondition:</strong> Results will be returned only if either (a) the EAttribute has already been
170 * registered using {@link #registerEStructuralFeatures(Set)}, or (b) running in <em>wildcard mode</em> (see
171 * {@link #isInWildcardMode()}).
172 *
173 * @param value
174 * the value of the attribute
175 * @param attribute
176 * the EAttribute that should take the given value
177 * @return the set of {@link EObject}s for which the given attribute has the given value
178 */
179 public Set<EObject> findByAttributeValue(Object value, EAttribute attribute);
180
181 /**
182 * Returns the set of instances for the given {@link EDataType} that can be found in the model.
183 *
184 * <p>
185 * <strong>Precondition:</strong> Results will be returned only if either (a) the EDataType has already been
186 * registered using {@link #registerEDataTypes(Set)}, or (b) running in <em>wildcard mode</em> (see
187 * {@link #isInWildcardMode()}).
188 *
189 * @param type
190 * the data type
191 * @return the set of all attribute values found in the model that are of the given data type
192 */
193 public Set<Object> getDataTypeInstances(EDataType type);
194
195 /**
196 * Returns whether an object is an instance for the given {@link EDataType} that can be found in the current scope.
197 * <p>
198 * <strong>Precondition:</strong> Result will be true only if either (a) the EDataType has already been registered
199 * using {@link #registerEDataTypes(Set)}, or (b) running in <em>wildcard mode</em> (see
200 * {@link #isInWildcardMode()}).
201 *
202 * @param value a non-null value to decide whether it is available as an EDataType instance
203 * @param type a non-null EDataType
204 * @return true, if a corresponding instance was found
205 * @since 1.7
206 */
207 public boolean isInstanceOfDatatype(Object value, EDataType type);
208
209 /**
210 * Find all {@link EObject}s that are the target of the EReference <code>reference</code> from the given
211 * <code>source</code> {@link EObject}.
212 *
213 * <p>
214 * Unset / null-valued references are not indexed, and will not be included in the results.
215 *
216 * <p>
217 * <strong>Precondition:</strong> Results will be returned only if either (a) the reference has already been
218 * registered using {@link #registerEStructuralFeatures(Set)}, or (b) running in <em>wildcard mode</em> (see
219 * {@link #isInWildcardMode()}).
220 *
221 * @param source the host object
222 * @param reference an EReference of the host object
223 * @return the set of {@link EObject}s that the given reference points to, from the given source object
224 */
225 public Set<EObject> getReferenceValues(EObject source, EReference reference);
226
227 /**
228 * Find all {@link Object}s that are the target of the EStructuralFeature <code>feature</code> from the given
229 * <code>source</code> {@link EObject}.
230 *
231 * <p>
232 * Unset / null-valued features are not indexed, and will not be included in the results.
233 *
234 * <p>
235 * <strong>Precondition:</strong> Results will be returned only if either (a) the feature has already been
236 * registered, or (b) running in <em>wildcard mode</em> (see
237 * {@link #isInWildcardMode()}).
238 *
239 * @param source the host object
240 * @param feature an EStructuralFeature of the host object
241 * @return the set of values that the given feature takes at the given source object
242 *
243 * @see #getReferenceValues(EObject, EReference)
244 */
245 public Set<Object> getFeatureTargets(EObject source, EStructuralFeature feature);
246
247 /**
248 * Decides whether the given non-null source and target objects are connected via a specific, indexed EStructuralFeature instance.
249 *
250 * <p>
251 * Unset / null-valued features are not indexed, and will not be included in the results.
252 *
253 * <p>
254 * <strong>Precondition:</strong> Result will be true only if either (a) the feature has already been
255 * registered, or (b) running in <em>wildcard mode</em> (see
256 * {@link #isInWildcardMode()}).
257 * @since 1.7
258 */
259 public boolean isFeatureInstance(EObject source, Object target, EStructuralFeature feature);
260
261 /**
262 * For a given {@link EObject} <code>target</code>, find each {@link EReference} and source {@link EObject}
263 * such that this reference (list) of the the host object points to the given target object. The method will
264 * return a set of {@link Setting}s, one for each such source object - EReference - target triplet.
265 *
266 * <p>
267 * <strong>Precondition:</strong> Unset / null reference values are not indexed, so <code>target!=null</code>
268 *
269 * <p>
270 * <strong>Precondition:</strong> Results will be returned only for those references that have already been
271 * registered using {@link #registerEStructuralFeatures(Set)}, or all references if running in
272 * <em>wildcard mode</em> (see {@link #isInWildcardMode()}).
273 *
274 * @param target
275 * the EObject pointed to by the references
276 * @return a set of {@link Setting}s, one for each source EObject and reference that point to the given target
277 */
278 public Set<Setting> getInverseReferences(EObject target);
279
280 /**
281 * For given <code>references</code> and an {@link EObject} <code>target</code>, find each source {@link EObject}
282 * such that any of these references of the the source object points to the given target object. The method will
283 * return a set of {@link Setting}s, one for each such source object - EReference - target triplet.
284 *
285 * <p>
286 * <strong>Precondition:</strong> Unset / null reference values are not indexed, so <code>target!=null</code>
287 *
288 * <p>
289 * <strong>Precondition:</strong> Will only find those EReferences that have already been registered using
290 * {@link #registerEStructuralFeatures(Set)}, unless running in <em>wildcard mode</em> (see
291 * {@link #isInWildcardMode()}).
292 *
293 * @param target
294 * the EObject pointed to by the references
295 * @param references a set of EReferences pointing to the target
296 * @return a set of {@link Setting}s, one for each source EObject and reference that point to the given target
297 */
298 public Set<Setting> getInverseReferences(EObject target, Collection<EReference> references);
299
300 /**
301 * Find all source {@link EObject}s for which the given <code>reference</code> points to the given <code>target</code> object.
302 *
303 * <p>
304 * <strong>Precondition:</strong> Unset / null reference values are not indexed, so <code>target!=null</code>
305 *
306 * <p>
307 * <strong>Precondition:</strong> Results will be returned only if either (a) the reference has already been
308 * registered using {@link #registerEStructuralFeatures(Set)}, or (b) running in <em>wildcard mode</em> (see
309 * {@link #isInWildcardMode()}).
310 *
311 * @param target
312 * the EObject pointed to by the references
313 * @param reference
314 * an EReference pointing to the target
315 * @return the collection of {@link EObject}s for which the given reference points to the given target object
316 */
317 public Set<EObject> getInverseReferences(EObject target, EReference reference);
318
319 /**
320 * Get the direct {@link EObject} instances of the given {@link EClass}. Instances of subclasses will be excluded.
321 *
322 * <p>
323 * <strong>Precondition:</strong> Results will be returned only if either (a) the EClass (or any superclass) has
324 * already been registered using {@link #registerEClasses(Set)}, or (b) running in <em>wildcard mode</em> (see
325 * {@link #isInWildcardMode()}).
326 *
327 * @param clazz
328 * an EClass
329 * @return the collection of {@link EObject} direct instances of the given EClass (not of subclasses)
330 *
331 * @see #getAllInstances(EClass)
332 */
333 public Set<EObject> getDirectInstances(EClass clazz);
334
335 /**
336 * Get the all {@link EObject} instances of the given {@link EClass}.
337 * This includes instances of subclasses.
338 *
339 * <p>
340 * <strong>Precondition:</strong> Results will be returned only if either (a) the EClass (or any superclass) has
341 * already been registered using {@link #registerEClasses(Set)}, or (b) running in <em>wildcard mode</em> (see
342 * {@link #isInWildcardMode()}).
343 *
344 * @param clazz
345 * an EClass
346 * @return the collection of {@link EObject} instances of the given EClass and any of its subclasses
347 *
348 * @see #getDirectInstances(EClass)
349 */
350 public Set<EObject> getAllInstances(EClass clazz);
351
352 /**
353 * Checks whether the given {@link EObject} is an instance of the given {@link EClass}.
354 * This includes instances of subclasses.
355 * <p> Special note: this method does not check whether the object is indexed in the scope,
356 * and will return true for out-of-scope objects as well (as long as they are instances of the class).
357 * <p> The given class does not have to be indexed.
358 * <p> The difference between this method and {@link EClassifier#isInstance(Object)} is that in dynamic EMF mode, EPackage equivalence is taken into account.
359 * @since 1.6
360 */
361 public boolean isInstanceOfUnscoped(EObject object, EClass clazz);
362
363 /**
364 * Checks whether the given {@link EObject} is an instance of the given {@link EClass}.
365 * This includes instances of subclasses.
366 * <p> Special note: this method does check whether the object is indexed in the scope,
367 * and will return false for out-of-scope objects as well (as long as they are instances of the class).
368 * <p> The given class does have to be indexed.
369 * @since 1.7
370 */
371 public boolean isInstanceOfScoped(EObject object, EClass clazz);
372
373 /**
374 * Get the total number of instances of the given {@link EClass} and all of its subclasses.
375 *
376 * @since 1.4
377 */
378 public int countAllInstances(EClass clazz);
379
380 /**
381 * Find all source {@link EObject}s for which the given <code>feature</code> points to / takes the given <code>value</code>.
382 *
383 * <p>
384 * <strong>Precondition:</strong> Unset / null-valued features are not indexed, so <code>value!=null</code>
385 *
386 * <p>
387 * <strong>Precondition:</strong> Results will be returned only if either (a) the feature has already been
388 * registered using {@link #registerEStructuralFeatures(Set)}, or (b) running in <em>wildcard mode</em> (see
389 * {@link #isInWildcardMode()}).
390 *
391 * @param value
392 * the value of the feature
393 * @param feature
394 * the feature instance
395 * @return the collection of {@link EObject} instances
396 */
397 public Set<EObject> findByFeatureValue(Object value, EStructuralFeature feature);
398
399 /**
400 * Returns those host {@link EObject}s that have a non-null value for the given feature
401 * (at least one, in case of multi-valued references).
402 *
403 * <p>
404 * Unset / null-valued features are not indexed, and will not be included in the results.
405 *
406 * <p>
407 * <strong>Precondition:</strong> Results will be returned only if either (a) the feature has already been
408 * registered using {@link #registerEStructuralFeatures(Set)}, or (b) running in <em>wildcard mode</em> (see
409 * {@link #isInWildcardMode()}).
410 *
411 * @param feature
412 * a structural feature
413 * @return the collection of {@link EObject}s that have some value for the given structural feature
414 */
415 public Set<EObject> getHoldersOfFeature(EStructuralFeature feature);
416 /**
417 * Returns all non-null values that the given feature takes at least once for any {@link EObject} in the scope
418 *
419 * <p>
420 * Unset / null-valued features are not indexed, and will not be included in the results.
421 *
422 * <p>
423 * <strong>Precondition:</strong> Results will be returned only if either (a) the feature has already been
424 * registered using {@link #registerEStructuralFeatures(Set)}, or (b) running in <em>wildcard mode</em> (see
425 * {@link #isInWildcardMode()}).
426 *
427 * @param feature
428 * a structural feature
429 * @return the collection of values that the given structural feature takes
430 * @since 2.1
431 */
432 public Set<Object> getValuesOfFeature(EStructuralFeature feature);
433
434 /**
435 * Call this method to dispose the NavigationHelper.
436 *
437 * <p>After its disposal, the NavigationHelper will no longer listen to EMF change notifications,
438 * and it will be possible to GC it even if the model is retained in memory.
439 *
440 * <dt><b>Precondition:</b><dd> no listeners can be registered at all.
441 * @throws IllegalStateException if there are any active listeners
442 *
443 */
444 public void dispose();
445
446 /**
447 * The given <code>listener</code> will be notified from now on whenever instances the given {@link EClass}es
448 * (and any of their subtypes) are added to or removed from the model.
449 *
450 * <br/>
451 * <b>Important</b>: Do not call this method from {@link InstanceListener} methods as it may cause a
452 * {@link ConcurrentModificationException}, if you want to add a listener
453 * at that point, wrap the call with {@link #executeAfterTraversal(Runnable)}.
454 *
455 * @param classes
456 * the collection of classes whose instances the listener should be notified of
457 * @param listener
458 * the listener instance
459 */
460 public void addInstanceListener(Collection<EClass> classes, InstanceListener listener);
461
462 /**
463 * Unregisters an instance listener for the given classes.
464 *
465 * <br/>
466 * <b>Important</b>: Do not call this method from {@link InstanceListener} methods as it may cause a
467 * {@link ConcurrentModificationException}, if you want to remove a listener at that point, wrap the call with
468 * {@link #executeAfterTraversal(Runnable)}.
469 *
470 * @param classes
471 * the collection of classes
472 * @param listener
473 * the listener instance
474 */
475 public void removeInstanceListener(Collection<EClass> classes, InstanceListener listener);
476
477 /**
478 * The given <code>listener</code> will be notified from now on whenever instances the given {@link EDataType}s are
479 * added to or removed from the model.
480 *
481 * <br/>
482 * <b>Important</b>: Do not call this method from {@link DataTypeListener} methods as it may cause a
483 * {@link ConcurrentModificationException}, if you want to add a listener at that point, wrap the call with
484 * {@link #executeAfterTraversal(Runnable)}.
485 *
486 * @param types
487 * the collection of types associated to the listener
488 * @param listener
489 * the listener instance
490 */
491 public void addDataTypeListener(Collection<EDataType> types, DataTypeListener listener);
492
493 /**
494 * Unregisters a data type listener for the given types.
495 *
496 * <br/>
497 * <b>Important</b>: Do not call this method from {@link DataTypeListener} methods as it may cause a
498 * {@link ConcurrentModificationException}, if you want to remove a listener at that point, wrap the call with
499 * {@link #executeAfterTraversal(Runnable)}.
500 *
501 * @param types
502 * the collection of data types
503 * @param listener
504 * the listener instance
505 */
506 public void removeDataTypeListener(Collection<EDataType> types, DataTypeListener listener);
507
508 /**
509 * The given <code>listener</code> will be notified from now on whenever instances the given
510 * {@link EStructuralFeature}s are added to or removed from the model.
511 *
512 * <br/>
513 * <b>Important</b>: Do not call this method from {@link FeatureListener} methods as it may cause a
514 * {@link ConcurrentModificationException}, if you want to add a listener at that point, wrap the call with
515 * {@link #executeAfterTraversal(Runnable)}.
516 *
517 * @param features
518 * the collection of features associated to the listener
519 * @param listener
520 * the listener instance
521 */
522 public void addFeatureListener(Collection<? extends EStructuralFeature> features, FeatureListener listener);
523
524 /**
525 * Unregisters a feature listener for the given features.
526 *
527 * <br/>
528 * <b>Important</b>: Do not call this method from {@link FeatureListener} methods as it may cause a
529 * {@link ConcurrentModificationException}, if you want to remove a listener at that point, wrap the call with
530 * {@link #executeAfterTraversal(Runnable)}.
531 *
532 * @param listener
533 * the listener instance
534 * @param features
535 * the collection of features
536 */
537 public void removeFeatureListener(Collection<? extends EStructuralFeature> features, FeatureListener listener);
538
539 /**
540 * Register a lightweight observer that is notified if the value of any feature of the given EObject changes.
541 *
542 * <br/>
543 * <b>Important</b>: Do not call this method from {@link LightweightEObjectObserver} methods as it may cause a
544 * {@link ConcurrentModificationException}, if you want to add an observer at that point, wrap the call with
545 * {@link #executeAfterTraversal(Runnable)}.
546 *
547 * @param observer
548 * the listener instance
549 * @param observedObject
550 * the observed EObject
551 * @return false if the observer was already attached to the object (call has no effect), true otherwise
552 */
553 public boolean addLightweightEObjectObserver(LightweightEObjectObserver observer, EObject observedObject);
554
555 /**
556 * Unregisters a lightweight observer for the given EObject.
557 *
558 * <br/>
559 * <b>Important</b>: Do not call this method from {@link LightweightEObjectObserver} methods as it may cause a
560 * {@link ConcurrentModificationException}, if you want to remove an observer at that point, wrap the call with
561 * {@link #executeAfterTraversal(Runnable)}.
562 *
563 * @param observer
564 * the listener instance
565 * @param observedObject
566 * the observed EObject
567 * @return false if the observer has not been previously attached to the object (call has no effect), true otherwise
568 */
569 public boolean removeLightweightEObjectObserver(LightweightEObjectObserver observer, EObject observedObject);
570
571 /**
572 * Manually turns on indexing for the given types (indexing of others are unaffected). Note that
573 * registering new types will result in a single iteration through the whole attached model.
574 * <b> Not usable in <em>wildcard mode</em>.</b>
575 *
576 * @param classes
577 * the set of classes to observe (null okay)
578 * @param dataTypes
579 * the set of data types to observe (null okay)
580 * @param features
581 * the set of features to observe (null okay)
582 * @throws IllegalStateException if in wildcard mode
583 * @since 1.4
584 */
585 public void registerObservedTypes(Set<EClass> classes, Set<EDataType> dataTypes, Set<? extends EStructuralFeature> features, IndexingLevel level);
586
587 /**
588 * Manually turns off indexing for the given types (indexing of others are unaffected). Note that if the
589 * unregistered types are re-registered later, the whole attached model needs to be visited again.
590 * <b> Not usable in <em>wildcard mode</em>.</b>
591 *
592 * <dt><b>Precondition:</b><dd> no listeners can be registered for the given types.
593 * @param classes
594 * the set of classes that will be ignored again from now on (null okay)
595 * @param dataTypes
596 * the set of data types that will be ignored again from now on (null okay)
597 * @param features
598 * the set of features that will be ignored again from now on (null okay)
599 * @throws IllegalStateException if in wildcard mode, or if there are listeners registered for the given types
600 */
601 public void unregisterObservedTypes(Set<EClass> classes, Set<EDataType> dataTypes, Set<? extends EStructuralFeature> features);
602
603 /**
604 * Manually turns on indexing for the given features (indexing of other features are unaffected). Note that
605 * registering new features will result in a single iteration through the whole attached model.
606 * <b> Not usable in <em>wildcard mode</em>.</b>
607 *
608 * @param features
609 * the set of features to observe
610 * @throws IllegalStateException if in wildcard mode
611 * @since 1.4
612 */
613 public void registerEStructuralFeatures(Set<? extends EStructuralFeature> features, IndexingLevel level);
614
615 /**
616 * Manually turns off indexing for the given features (indexing of other features are unaffected). Note that if the
617 * unregistered features are re-registered later, the whole attached model needs to be visited again.
618 * <b> Not usable in <em>wildcard mode</em>.</b>
619 *
620 * <dt><b>Precondition:</b><dd> no listeners can be registered for the given features.
621 *
622 * @param features
623 * the set of features that will be ignored again from now on
624 * @throws IllegalStateException if in wildcard mode, or if there are listeners registered for the given types
625 */
626 public void unregisterEStructuralFeatures(Set<? extends EStructuralFeature> features);
627
628 /**
629 * Manually turns on indexing for the given classes (indexing of other classes are unaffected). Instances of
630 * subclasses will also be indexed. Note that registering new classes will result in a single iteration through the whole
631 * attached model.
632 * <b> Not usable in <em>wildcard mode</em>.</b>
633 *
634 * @param classes
635 * the set of classes to observe
636 * @throws IllegalStateException if in wildcard mode
637 * @since 1.4
638 */
639 public void registerEClasses(Set<EClass> classes, IndexingLevel level);
640
641 /**
642 * Manually turns off indexing for the given classes (indexing of other classes are unaffected). Note that if the
643 * unregistered classes are re-registered later, the whole attached model needs to be visited again.
644 * <b> Not usable in <em>wildcard mode</em>.</b>
645 *
646 * <dt><b>Precondition:</b><dd> no listeners can be registered for the given classes.
647 * @param classes
648 * the set of classes that will be ignored again from now on
649 * @throws IllegalStateException if in wildcard mode, or if there are listeners registered for the given types
650 */
651 public void unregisterEClasses(Set<EClass> classes);
652
653 /**
654 * Manually turns on indexing for the given data types (indexing of other features are unaffected). Note that
655 * registering new data types will result in a single iteration through the whole attached model.
656 * <b> Not usable in <em>wildcard mode</em>.</b>
657 *
658 * @param dataTypes
659 * the set of data types to observe
660 * @throws IllegalStateException if in wildcard mode
661 * @since 1.4
662 */
663 public void registerEDataTypes(Set<EDataType> dataTypes, IndexingLevel level);
664
665 /**
666 * Manually turns off indexing for the given data types (indexing of other data types are unaffected). Note that if
667 * the unregistered data types are re-registered later, the whole attached model needs to be visited again.
668 * <b> Not usable in <em>wildcard mode</em>.</b>
669 *
670 * <dt><b>Precondition:</b><dd> no listeners can be registered for the given datatypes.
671 *
672 * @param dataTypes
673 * the set of data types that will be ignored again from now on
674 * @throws IllegalStateException if in wildcard mode, or if there are listeners registered for the given types
675 */
676 public void unregisterEDataTypes(Set<EDataType> dataTypes);
677
678 /**
679 * The given callback will be executed, and all model traversals and index registrations will be delayed until the
680 * execution is done. If there are any outstanding feature, class or datatype registrations, a single coalesced model
681 * traversal will initialize the caches and deliver the notifications.
682 *
683 * @param callable
684 */
685 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException;
686
687 /**
688 * Execute the given runnable after traversal. It is guaranteed that the runnable is executed as soon as
689 * the indexing is finished. The callback is executed only once, then is removed from the callback queue.
690 * @param traversalCallback
691 * @throws InvocationTargetException
692 * @since 1.4
693 */
694 public void executeAfterTraversal(Runnable traversalCallback) throws InvocationTargetException;
695
696 /**
697 * Examines whether execution is currently in the callable
698 * block of an invocation of {#link {@link #coalesceTraversals(Callable)}}.
699 */
700 public boolean isCoalescing();
701
702 /**
703 * Adds a coarse-grained listener that will be invoked after the NavigationHelper index or the underlying model is changed. Can be used
704 * e.g. to check model contents. Not intended for general use.
705 *
706 * <p/> See {@link #removeBaseIndexChangeListener(EMFBaseIndexChangeListener)}
707 * @param listener
708 */
709 public void addBaseIndexChangeListener(EMFBaseIndexChangeListener listener);
710
711 /**
712 * Removes a registered listener.
713 *
714 * <p/> See {@link #addBaseIndexChangeListener(EMFBaseIndexChangeListener)}
715 *
716 * @param listener
717 */
718 public void removeBaseIndexChangeListener(EMFBaseIndexChangeListener listener);
719
720 /**
721 * Adds an additional EMF model root.
722 *
723 * @param emfRoot
724 * @throws ViatraQueryRuntimeException
725 */
726 public void addRoot(Notifier emfRoot);
727
728 /**
729 * Moves an EObject (along with its entire containment subtree) within the containment hierarchy of the EMF model.
730 * The object will be relocated from the original parent object to a different parent, or a different containment
731 * list of the same parent.
732 *
733 * <p> When indexing is enabled, such a relocation is costly if performed through normal getters/setters, as the index
734 * for the entire subtree is pruned at the old location and reconstructed at the new one.
735 * This method provides a workaround to keep the operation cheap.
736 *
737 * <p> This method is experimental. Re-entrancy not supported.
738 *
739 * @param element the eObject to be moved
740 * @param targetContainmentReferenceList containment list of the new parent object into which the element has to be moved
741 *
742 */
743 public <T extends EObject> void cheapMoveTo(T element, EList<T> targetContainmentReferenceList);
744
745 /**
746 * Moves an EObject (along with its entire containment subtree) within the containment hierarchy of the EMF model.
747 * The object will be relocated from the original parent object to a different parent, or a different containment
748 * list of the same parent.
749 *
750 * <p> When indexing is enabled, such a relocation is costly if performed through normal getters/setters, as the index
751 * for the entire subtree is pruned at the old location and reconstructed at the new one.
752 * This method provides a workaround to keep the operation cheap.
753 *
754 * <p> This method is experimental. Re-entrancy not supported.
755 *
756 * @param element the eObject to be moved
757 * @param parent the new parent object under which the element has to be moved
758 * @param containmentFeature the kind of containment reference that should be established between the new parent and the element
759 *
760 */
761 public void cheapMoveTo(EObject element, EObject parent, EReference containmentFeature);
762
763
764 /**
765 * Traverses all instances of a selected data type stored in the base index, and allows executing a custom function on
766 * it. There is no guaranteed order in which the processor will be called with the selected features.
767 *
768 * @param type
769 * @param processor
770 * @since 0.8
771 */
772 void processDataTypeInstances(EDataType type, IEDataTypeProcessor processor);
773
774 /**
775 * Traverses all direct instances of a selected class stored in the base index, and allows executing a custom function on
776 * it. There is no guaranteed order in which the processor will be called with the selected features.
777 *
778 * @param type
779 * @param processor
780 * @since 0.8
781 */
782 void processAllInstances(EClass type, IEClassProcessor processor);
783
784 /**
785 * Traverses all direct instances of a selected class stored in the base index, and allows executing a custom function on
786 * it. There is no guaranteed order in which the processor will be called with the selected features.
787 *
788 * @param type
789 * @param processor
790 * @since 0.8
791 */
792 void processDirectInstances(EClass type, IEClassProcessor processor);
793
794 /**
795 * Traverses all instances of a selected feature stored in the base index, and allows executing a custom function on
796 * it. There is no guaranteed order in which the processor will be called with the selected features.
797 *
798 * <p>
799 * <strong>Precondition:</strong> Will only find those {@link EStructuralFeature}s that have already been registered using
800 * {@link #registerEStructuralFeatures(Set)}, unless running in <em>wildcard mode</em> (see
801 * {@link #isInWildcardMode()}).
802 *
803 * @since 1.7
804 */
805 void processAllFeatureInstances(EStructuralFeature feature, IStructuralFeatureInstanceProcessor processor);
806 /**
807 * Returns all EClasses that currently have direct instances cached by the index. <ul>
808 * <li> Supertypes will not be returned, unless they have direct instances in the model as well.
809 * <li> If not in <em>wildcard mode</em>, only registered EClasses and their subtypes will be considered.
810 * <li> Note for advanced users: if a type is represented by multiple EClass objects, one of them is chosen as representative and returned.
811 * </ul>
812 */
813 public Set<EClass> getAllCurrentClasses();
814
815 /**
816 * Updates the value of indexed derived features that are not well-behaving.
817 */
818 void resampleDerivedFeatures();
819
820 /**
821 * Adds a listener for internal errors in the index. A listener can only be added once.
822 *
823 * @param listener
824 * @returns true if the listener was not already added
825 * @since 0.8
826 */
827 boolean addIndexingErrorListener(IEMFIndexingErrorListener listener);
828
829 /**
830 * Removes a listener for internal errors in the index.
831 *
832 * @param listener
833 * @returns true if the listener was successfully removed (e.g. it did exist)
834 * @since 0.8
835 */
836 boolean removeIndexingErrorListener(IEMFIndexingErrorListener listener);
837
838 /**
839 * Returns the internal, canonicalized implementation of an attribute value.
840 *
841 * <p> Behaviour: when in dynamic EMF mode, substitutes enum literals with a canonical version of the enum literal.
842 * Otherwise, returns the input.
843 *
844 * <p> The canonical enum literal will be guaranteed to be a valid EMF enum literal ({@link Enumerator}),
845 * and the best effort is made to ensure that it will be the same for all versions of the {@link EEnum},
846 * including {@link EEnumLiteral}s in different versions of ecore packages, as well as Java enums generated from them..
847 *
848 * <p> Usage is not required when simply querying the indexed model through the {@link NavigationHelper} API,
849 * as both method inputs and the results returned are automatically canonicalized in dynamic EMF mode.
850 * Using this method is required only if the client wants to do querying/filtering on the results returned, and wants to know what to look for.
851 */
852 Object toCanonicalValueRepresentation(Object value);
853
854 /**
855 * @since 1.4
856 */
857 IndexingLevel getIndexingLevel(EClass type);
858
859 /**
860 * @since 1.4
861 */
862 IndexingLevel getIndexingLevel(EDataType type);
863
864 /**
865 * @since 1.4
866 */
867 IndexingLevel getIndexingLevel(EStructuralFeature feature);
868
869 /**
870 * @since 1.4
871 */
872 public int countDataTypeInstances(EDataType dataType);
873
874 /**
875 * @since 1.4
876 */
877 public int countFeatureTargets(EObject seedSource, EStructuralFeature feature);
878
879 /**
880 * @since 1.4
881 */
882 public int countFeatures(EStructuralFeature feature);
883
884
885}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/QueryResultAssociativeStore.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/QueryResultAssociativeStore.java
deleted file mode 100644
index 27d08506..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/QueryResultAssociativeStore.java
+++ /dev/null
@@ -1,322 +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.base.api;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.Iterator;
15import java.util.Map.Entry;
16
17import org.apache.log4j.Logger;
18import tools.refinery.viatra.runtime.matchers.util.Direction;
19
20/**
21 * @author Abel Hegedus
22 *
23 */
24public abstract class QueryResultAssociativeStore<KeyType, ValueType> {
25 /**
26 * Error literal returned when associative store modification is attempted without a setter available
27 */
28 protected static final String NOT_ALLOW_MODIFICATIONS = "Query result associative store does not allow modifications";
29
30 /**
31 * Logger that can be used for reporting errors during runtime
32 */
33 private Logger logger;
34 /**
35 * The collection of listeners registered for this result associative store
36 */
37 private Collection<IQueryResultUpdateListener<KeyType, ValueType>> listeners;
38
39 /**
40 * The setter registered for changing the contents of the associative store
41 */
42 private IQueryResultSetter<KeyType, ValueType> setter;
43
44 /**
45 * @return the listeners
46 */
47 protected Collection<IQueryResultUpdateListener<KeyType, ValueType>> getListeners() {
48 return listeners;
49 }
50
51 /**
52 * @param listeners the listeners to set
53 */
54 protected void setListeners(Collection<IQueryResultUpdateListener<KeyType, ValueType>> listeners) {
55 this.listeners = listeners;
56 }
57
58 /**
59 * @return the setter
60 */
61 protected IQueryResultSetter<KeyType, ValueType> getSetter() {
62 return setter;
63 }
64
65 /**
66 * @param setter the setter to set
67 */
68 protected void setSetter(IQueryResultSetter<KeyType, ValueType> setter) {
69 this.setter = setter;
70 }
71
72 /**
73 * @param logger the logger to set
74 */
75 protected void setLogger(Logger logger) {
76 this.logger = logger;
77 }
78
79 /**
80 * Returns the entries in the cache as a collection.
81 * @return the entries
82 */
83 protected abstract Collection<Entry<KeyType, ValueType>> getCacheEntries();
84
85 /**
86 * Registers a listener for this query result associative store that is invoked every time when a key-value pair is inserted
87 * or removed from the associative store.
88 *
89 * <p>
90 * The listener can be unregistered via {@link #removeCallbackOnQueryResultUpdate(IQueryResultUpdateListener)}.
91 *
92 * @param listener
93 * the listener that will be notified of each key-value pair that is inserted or removed, starting from
94 * now.
95 * @param fireNow
96 * if true, notifyPut will be immediately invoked on all current key-values as a one-time effect.
97 */
98 public void addCallbackOnQueryResultUpdate(IQueryResultUpdateListener<KeyType, ValueType> listener, boolean fireNow) {
99 if (listeners == null) {
100 listeners = new HashSet<IQueryResultUpdateListener<KeyType, ValueType>>();
101 }
102 listeners.add(listener);
103 if(fireNow) {
104 for (Entry<KeyType, ValueType> entry : getCacheEntries()) {
105 sendNotificationToListener(Direction.INSERT, entry.getKey(), entry.getValue(), listener);
106 }
107 }
108 }
109
110 /**
111 * Unregisters a callback registered by {@link #addCallbackOnQueryResultUpdate(IQueryResultUpdateListener, boolean)}
112 * .
113 *
114 * @param listener
115 * the listener that will no longer be notified.
116 */
117 public void removeCallbackOnQueryResultUpdate(IQueryResultUpdateListener<KeyType, ValueType> listener) {
118 if (listeners != null) {
119 listeners.remove(listener);
120 }
121 }
122
123 /**
124 * This method notifies the listeners that the query result associative store has changed.
125 *
126 * @param direction
127 * the type of the change (insert or delete)
128 * @param key
129 * the key of the pair that changed
130 * @param value
131 * the value of the pair that changed
132 */
133 protected void notifyListeners(Direction direction, KeyType key, ValueType value) {
134 if(listeners != null) {
135 for (IQueryResultUpdateListener<KeyType, ValueType> listener : listeners) {
136 sendNotificationToListener(direction, key, value, listener);
137 }
138 }
139 }
140
141 private void sendNotificationToListener(Direction direction, KeyType key, ValueType value,
142 IQueryResultUpdateListener<KeyType, ValueType> listener) {
143 try {
144 if (direction == Direction.INSERT) {
145 listener.notifyPut(key, value);
146 } else {
147 listener.notifyRemove(key, value);
148 }
149 } catch (Exception e) { // NOPMD
150 logger.warn(
151 String.format(
152 "The query result associative store encountered an error during executing a callback on %s of key %s and value %s. Error message: %s. (Developer note: %s in %s called from QueryResultMultimap)",
153 direction == Direction.INSERT ? "insertion" : "removal", key, value, e.getMessage(), e
154 .getClass().getSimpleName(), listener), e);
155 throw new IllegalStateException("The query result associative store encountered an error during invoking setter",e);
156 }
157 }
158
159 /**
160 * Implementations of QueryResultAssociativeStore can put a new key-value pair into the associative store with this method. If the
161 * insertion of the key-value pair results in a change, the listeners are notified.
162 *
163 * <p>
164 * No validation or null-checking is performed during the method!
165 *
166 * @param key
167 * the key which identifies where the new value is put
168 * @param value
169 * the value that is put into the collection of the key
170 * @return true, if the insertion resulted in a change (the key-value pair was not yet in the associative store)
171 */
172 protected boolean internalPut(KeyType key, ValueType value){
173 boolean putResult = internalCachePut(key, value);
174 if (putResult) {
175 notifyListeners(Direction.INSERT, key, value);
176 }
177 return putResult;
178 }
179 /**
180 * Implementations of QueryResultAssociativeStore can remove a key-value pair from the associative store with this method. If the
181 * removal of the key-value pair results in a change, the listeners are notified.
182 *
183 * <p>
184 * No validation or null-checking is performed during the method!
185 *
186 * @param key
187 * the key which identifies where the value is removed from
188 * @param value
189 * the value that is removed from the collection of the key
190 * @return true, if the removal resulted in a change (the key-value pair was in the associative store)
191 */
192 protected boolean internalRemove(KeyType key, ValueType value){
193 boolean removeResult = internalCacheRemove(key, value);
194 if (removeResult) {
195 notifyListeners(Direction.DELETE, key, value);
196 }
197 return removeResult;
198 }
199
200
201 protected abstract boolean internalCachePut(KeyType key, ValueType value);
202 protected abstract boolean internalCacheRemove(KeyType key, ValueType value);
203 protected abstract int internalCacheSize();
204 protected abstract boolean internalCacheContainsEntry(KeyType key, ValueType value);
205
206 /**
207 * @param setter
208 * the setter to set
209 */
210 public void setQueryResultSetter(IQueryResultSetter<KeyType, ValueType> setter) {
211 this.setter = setter;
212 }
213
214 /**
215 * @return the logger
216 */
217 protected Logger getLogger() {
218 return logger;
219 }
220
221 protected void internalClear() {
222 if (setter == null) {
223 throw new UnsupportedOperationException(NOT_ALLOW_MODIFICATIONS);
224 }
225 Collection<Entry<KeyType, ValueType>> entries = new ArrayList<>(getCacheEntries());
226 Iterator<Entry<KeyType, ValueType>> iterator = entries.iterator();
227 while (iterator.hasNext()) {
228 Entry<KeyType, ValueType> entry = iterator.next();
229 modifyThroughQueryResultSetter(entry.getKey(), entry.getValue(), Direction.DELETE);
230 }
231 if (internalCacheSize() != 0) {
232 StringBuilder sb = new StringBuilder();
233 for (Entry<KeyType, ValueType> entry : getCacheEntries()) {
234 if (sb.length() > 0) {
235 sb.append(", ");
236 }
237 sb.append(entry.toString());
238 }
239 logger.warn(String
240 .format("The query result associative store is not empty after clear, remaining entries: %s. (Developer note: %s called from QueryResultMultimap)",
241 sb.toString(), setter));
242 }
243 }
244
245 /**
246 * This method is used for calling the query result setter to put or remove a value by modifying the model.
247 *
248 * <p>
249 * The given key-value pair is first validated (see {@link IQueryResultSetter#validate(Object, Object)}, then the
250 * put or remove method is called (see {@link IQueryResultSetter#put(Object, Object)} and
251 * {@link IQueryResultSetter#remove(Object, Object)}). If the setter reported that the model has been changed, the
252 * change is checked.
253 *
254 * <p>
255 * If the model modification did not change the result set in the desired way, a warning is logged.
256 *
257 * <p>
258 * If the setter throws any {@link Throwable}, it is either rethrown in case of {@link Error} and logged otherwise.
259 *
260 *
261 * @param key
262 * the key of the pair to be inserted or removed
263 * @param value
264 * the value of the pair to be inserted or removed
265 * @param direction
266 * specifies whether a put or a remove is performed
267 * @return true, if the associative store changed according to the direction
268 */
269 protected boolean modifyThroughQueryResultSetter(KeyType key, ValueType value, Direction direction) {
270 try {
271 if (setter.validate(key, value)) {
272 final int size = internalCacheSize();
273 final int expectedChange = (direction == Direction.INSERT) ? 1 : -1;
274 boolean changed = false;
275 if (direction == Direction.INSERT) {
276 changed = setter.put(key, value);
277 } else {
278 changed = setter.remove(key, value);
279 }
280 if (changed) {
281 return checkModificationThroughQueryResultSetter(key, value, direction, expectedChange, size);
282 } else {
283 logger.warn(String
284 .format("The query result associative store %s of key %s and value %s resulted in %s. (Developer note: %s called from QueryResultMultimap)",
285 direction == Direction.INSERT ? "insertion" : "removal", key, value,
286 Math.abs(internalCacheSize() - size) > 1 ? "more than one changed result"
287 : "no changed results", setter));
288 }
289 }
290 } catch (Exception e) { // NOPMD
291 logger.warn(
292 String.format(
293 "The query result associative store encountered an error during invoking setter on %s of key %s and value %s. Error message: %s. (Developer note: %s in %s called from QueryResultMultimap)",
294 direction == Direction.INSERT ? "insertion" : "removal", key, value, e.getMessage(), e
295 .getClass().getSimpleName(), setter), e);
296 throw new IllegalStateException("The query result associative store encountered an error during invoking setter",e);
297 }
298
299 return false;
300 }
301
302 /**
303 * Checks whether the model modification performed by the {@link IQueryResultSetter} resulted in the insertion or
304 * removal of exactly the required key-value pair.
305 *
306 * @param key
307 * the key for the pair that was inserted or removed
308 * @param value
309 * the value for the pair that was inserted or removed
310 * @param direction
311 * the direction of the change
312 * @param size
313 * the size of the cache before the change
314 * @return true, if the changes made by the query result setter were correct
315 */
316 protected boolean checkModificationThroughQueryResultSetter(KeyType key, ValueType value, Direction direction,
317 final int expectedChange, final int size) {
318 boolean isInsertion = direction == Direction.INSERT;
319 return (isInsertion == internalCacheContainsEntry(key, value)
320 && (internalCacheSize() - expectedChange) == size);
321 }
322}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/QueryResultMap.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/QueryResultMap.java
deleted file mode 100644
index a106ea71..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/QueryResultMap.java
+++ /dev/null
@@ -1,210 +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.base.api;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Set;
16
17import org.apache.log4j.Logger;
18import tools.refinery.viatra.runtime.matchers.util.Direction;
19
20/**
21 * @author Abel Hegedus
22 *
23 */
24public abstract class QueryResultMap<KeyType,ValueType> extends QueryResultAssociativeStore<KeyType, ValueType> implements Map<KeyType, ValueType> {
25
26 /**
27 * This map contains the current key-values. Implementing classes should not modify it directly
28 */
29 private Map<KeyType, ValueType> cache;
30
31 /**
32 * Constructor only visible to subclasses.
33 *
34 * @param logger
35 * a logger that can be used for error reporting
36 */
37 protected QueryResultMap(Logger logger) {
38 cache = new HashMap<KeyType, ValueType>();
39 setLogger(logger);
40 }
41
42 @Override
43 protected Collection<java.util.Map.Entry<KeyType, ValueType>> getCacheEntries() {
44 return cache.entrySet();
45 }
46
47 @Override
48 protected boolean internalCachePut(KeyType key, ValueType value) {
49 ValueType put = cache.put(key, value);
50 if(put == null) {
51 return value != null;
52 } else {
53 return !put.equals(value);
54 }
55 }
56
57 @Override
58 protected boolean internalCacheRemove(KeyType key, ValueType value) {
59 ValueType remove = cache.remove(key);
60 return remove != null;
61 }
62
63 @Override
64 protected int internalCacheSize() {
65 return cache.size();
66 }
67
68 @Override
69 protected boolean internalCacheContainsEntry(KeyType key, ValueType value) {
70 return cache.containsKey(key) && cache.get(key).equals(value);
71 }
72
73 /**
74 * @return the cache
75 */
76 protected Map<KeyType, ValueType> getCache() {
77 return cache;
78 }
79
80 /**
81 * @param cache
82 * the cache to set
83 */
84 protected void setCache(Map<KeyType, ValueType> cache) {
85 this.cache = cache;
86 }
87
88 // ======================= implemented Map methods ======================
89
90 @Override
91 public void clear() {
92 internalClear();
93 }
94
95 @Override
96 public boolean containsKey(Object key) {
97 return cache.containsKey(key);
98 }
99
100 @Override
101 public boolean containsValue(Object value) {
102 return cache.containsValue(value);
103 }
104
105 /**
106 * {@inheritDoc}
107 *
108 * <p>
109 * The returned set is immutable.
110 *
111 */
112 @Override
113 public Set<Entry<KeyType, ValueType>> entrySet() {
114 return Collections.unmodifiableSet((Set<Entry<KeyType, ValueType>>) getCacheEntries());
115 }
116
117 @Override
118 public ValueType get(Object key) {
119 return cache.get(key);
120 }
121
122 @Override
123 public boolean isEmpty() {
124 return cache.isEmpty();
125 }
126
127 /**
128 * {@inheritDoc}
129 *
130 * <p>
131 * The returned set is immutable.
132 *
133 */
134 @Override
135 public Set<KeyType> keySet() {
136 return Collections.unmodifiableSet(cache.keySet());
137 }
138
139 /**
140 * {@inheritDoc}
141 *
142 * <p>
143 * Throws {@link UnsupportedOperationException} if there is no {@link IQueryResultSetter}
144 */
145 @Override
146 public ValueType put(KeyType key, ValueType value) {
147 if (getSetter() == null) {
148 throw new UnsupportedOperationException(NOT_ALLOW_MODIFICATIONS);
149 }
150 ValueType oldValue = cache.get(key);
151 boolean modified = modifyThroughQueryResultSetter(key, value, Direction.INSERT);
152 return modified ? oldValue : null;
153 }
154
155 /**
156 * {@inheritDoc}
157 *
158 * <p>
159 * Throws {@link UnsupportedOperationException} if there is no {@link IQueryResultSetter}
160 */
161 @Override
162 public void putAll(Map<? extends KeyType, ? extends ValueType> map) {
163 if (getSetter() == null) {
164 throw new UnsupportedOperationException(NOT_ALLOW_MODIFICATIONS);
165 }
166 for (Entry<? extends KeyType, ? extends ValueType> entry : map.entrySet()) {
167 modifyThroughQueryResultSetter(entry.getKey(), entry.getValue(), Direction.INSERT);
168 }
169 return;
170 }
171
172 /**
173 * {@inheritDoc}
174 *
175 * <p>
176 * Throws {@link UnsupportedOperationException} if there is no {@link IQueryResultSetter}
177 */
178 @SuppressWarnings("unchecked")
179 @Override
180 public ValueType remove(Object key) {
181 if (getSetter() == null) {
182 throw new UnsupportedOperationException(NOT_ALLOW_MODIFICATIONS);
183 }
184 // if it contains the entry, the types MUST be correct
185 if (cache.containsKey(key)) {
186 ValueType value = cache.get(key);
187 modifyThroughQueryResultSetter((KeyType) key, value, Direction.DELETE);
188 return value;
189 }
190 return null;
191 }
192
193 @Override
194 public int size() {
195 return internalCacheSize();
196 }
197
198 /**
199 * {@inheritDoc}
200 *
201 * <p>
202 * The returned collection is immutable.
203 *
204 */
205 @Override
206 public Collection<ValueType> values() {
207 return Collections.unmodifiableCollection(cache.values());
208 }
209
210}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/TransitiveClosureHelper.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/TransitiveClosureHelper.java
deleted file mode 100644
index fc92fef3..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/TransitiveClosureHelper.java
+++ /dev/null
@@ -1,26 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base.api;
11
12import org.eclipse.emf.ecore.EObject;
13import tools.refinery.viatra.runtime.base.itc.igraph.ITcDataSource;
14
15/**
16 * The class can be used to compute the transitive closure of a given emf model, where the nodes will be the objects in
17 * the model and the edges will be represented by the references between them. One must provide the set of references
18 * that the helper should treat as edges when creating an instance with the factory: only the notifications about these
19 * references will be handled.
20 *
21 * @author Tamas Szabo
22 *
23 */
24public interface TransitiveClosureHelper extends ITcDataSource<EObject> {
25
26}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/ViatraBaseFactory.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/ViatraBaseFactory.java
deleted file mode 100644
index 81bd4f35..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/ViatraBaseFactory.java
+++ /dev/null
@@ -1,180 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base.api;
11
12import java.util.Set;
13
14import org.apache.log4j.Logger;
15import org.eclipse.emf.common.notify.Notifier;
16import org.eclipse.emf.ecore.EClass;
17import org.eclipse.emf.ecore.EDataType;
18import org.eclipse.emf.ecore.EReference;
19import org.eclipse.emf.ecore.EStructuralFeature;
20import tools.refinery.viatra.runtime.base.core.NavigationHelperImpl;
21import tools.refinery.viatra.runtime.base.core.TransitiveClosureHelperImpl;
22
23/**
24 * Factory class for the utils in the library: <ul>
25 * <li>NavigationHelper (automatic and manual)
26 * <li>TransitiveClosureUtil
27 * </ul>
28 *
29 * @author Tamas Szabo
30 *
31 */
32public class ViatraBaseFactory {
33
34 private static ViatraBaseFactory instance;
35
36 /**
37 * Get the singleton instance of ViatraBaseFactory.
38 *
39 * @return the singleton instance
40 */
41 public static synchronized ViatraBaseFactory getInstance() {
42 if (instance == null) {
43 instance = new ViatraBaseFactory();
44 }
45
46 return instance;
47 }
48
49 protected ViatraBaseFactory() {
50 super();
51 }
52
53 /**
54 * The method creates a {@link NavigationHelper} index for the given EMF model root.
55 * A new instance will be created on every call.
56 * <p>
57 * A NavigationHelper in wildcard mode will process and index all EStructuralFeatures, EClasses and EDatatypes. If
58 * wildcard mode is off, the client will have to manually register the interesting aspects of the model.
59 * <p>
60 * The NavigationHelper will be created without dynamic EMF support by default.
61 * See {@link #createNavigationHelper(Notifier, boolean, boolean, Logger)} for more options.
62 *
63 * @see NavigationHelper
64 *
65 * @param emfRoot
66 * the root of the EMF tree to be indexed. Recommended: Resource or ResourceSet. Can be null - you can
67 * add a root later using {@link NavigationHelper#addRoot(Notifier)}
68 * @param wildcardMode
69 * true if all aspects of the EMF model should be indexed automatically, false if manual registration of
70 * interesting aspects is desirable
71 * @param logger
72 * the log output where errors will be logged if encountered during the operation of the
73 * NavigationHelper; if null, the default logger for {@link NavigationHelper} is used.
74 * @return the NavigationHelper instance
75 * @throws ViatraQueryRuntimeException
76 */
77 public NavigationHelper createNavigationHelper(Notifier emfRoot, boolean wildcardMode, Logger logger) {
78 BaseIndexOptions options = new BaseIndexOptions(false, wildcardMode ? IndexingLevel.FULL : IndexingLevel.NONE);
79 return createNavigationHelper(emfRoot, options, logger);
80 }
81
82 /**
83 * The method creates a {@link NavigationHelper} index for the given EMF model root.
84 * A new instance will be created on every call.
85 * <p>
86 * A NavigationHelper in wildcard mode will process and index all EStructuralFeatures, EClasses and EDatatypes. If
87 * wildcard mode is off, the client will have to manually register the interesting aspects of the model.
88 * <p>
89 * If the dynamic model flag is set to true, the index will use String ids to distinguish between the various
90 * {@link EStructuralFeature}, {@link EClass} and {@link EDataType} instances. This way the index is able to
91 * handle dynamic EMF instance models too.
92 *
93 * @see NavigationHelper
94 *
95 * @param emfRoot
96 * the root of the EMF tree to be indexed. Recommended: Resource or ResourceSet. Can be null - you can
97 * add a root later using {@link NavigationHelper#addRoot(Notifier)}
98 * @param wildcardMode
99 * true if all aspects of the EMF model should be indexed automatically, false if manual registration of
100 * interesting aspects is desirable
101 * @param dynamicModel
102 * true if the index should use String ids (nsURIs) for the various EMF types and features, and treat
103 * multiple EPackages sharing an nsURI as the same. false if dynamic model support is not required
104 * @param logger
105 * the log output where errors will be logged if encountered during the operation of the
106 * NavigationHelper; if null, the default logger for {@link NavigationHelper} is used.
107 * @return the NavigationHelper instance
108 * @throws ViatraQueryRuntimeException
109 */
110 public NavigationHelper createNavigationHelper(Notifier emfRoot, boolean wildcardMode, boolean dynamicModel, Logger logger) {
111 BaseIndexOptions options = new BaseIndexOptions(dynamicModel, wildcardMode ? IndexingLevel.FULL : IndexingLevel.NONE);
112 return createNavigationHelper(emfRoot, options, logger);
113 }
114
115 /**
116 * The method creates a {@link NavigationHelper} index for the given EMF model root.
117 * A new instance will be created on every call.
118 * <p>
119 * For details of base index options including wildcard and dynamic EMF mode, see {@link BaseIndexOptions}.
120 *
121 * @see NavigationHelper
122 *
123 * @param emfRoot
124 * the root of the EMF tree to be indexed. Recommended: Resource or ResourceSet. Can be null - you can
125 * add a root later using {@link NavigationHelper#addRoot(Notifier)}
126 * @param options the options used by the index
127 * @param logger
128 * the log output where errors will be logged if encountered during the operation of the
129 * NavigationHelper; if null, the default logger for {@link NavigationHelper} is used.
130 * @return the NavigationHelper instance
131 * @throws ViatraQueryRuntimeException
132 */
133 public NavigationHelper createNavigationHelper(Notifier emfRoot, BaseIndexOptions options, Logger logger) {
134 Logger l = logger;
135 if (l == null)
136 l = Logger.getLogger(NavigationHelper.class);
137 return new NavigationHelperImpl(emfRoot, options, l);
138 }
139
140
141
142 /**
143 * The method creates a TransitiveClosureHelper instance for the given EMF model root.
144 * A new instance will be created on every call.
145 *
146 * <p>
147 * One must specify the set of EReferences that will be considered as edges. The set can contain multiple elements;
148 * this way one can query forward and backward reachability information along heterogenous paths.
149 *
150 * @param emfRoot
151 * the root of the EMF tree to be processed. Recommended: Resource or ResourceSet.
152 * @param referencesToObserve
153 * the set of references to observe
154 * @return the TransitiveClosureHelper instance
155 * @throws ViatraQueryRuntimeException if the creation of the internal NavigationHelper failed
156 */
157 public TransitiveClosureHelper createTransitiveClosureHelper(Notifier emfRoot, Set<EReference> referencesToObserve) {
158 return new TransitiveClosureHelperImpl(getInstance().createNavigationHelper(emfRoot, false, null), true, referencesToObserve);
159 }
160
161 /**
162 * The method creates a TransitiveClosureHelper instance built on an existing NavigationHelper.
163 * A new instance will be created on every call.
164 *
165 * <p>
166 * One must specify the set of EReferences that will be considered as edges. The set can contain multiple elements;
167 * this way one can query forward and backward reachability information along heterogenous paths.
168 *
169 * @param baseIndex
170 * the already existing NavigationHelper index on the model
171 * @param referencesToObserve
172 * the set of references to observe
173 * @return the TransitiveClosureHelper instance
174 */
175 public TransitiveClosureHelper createTransitiveClosureHelper(NavigationHelper baseIndex, Set<EReference> referencesToObserve) {
176 return new TransitiveClosureHelperImpl(baseIndex, false, referencesToObserve);
177 }
178
179
180}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexFeatureFilter.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexFeatureFilter.java
deleted file mode 100644
index 8929b2ab..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexFeatureFilter.java
+++ /dev/null
@@ -1,38 +0,0 @@
1/**
2 * Copyright (c) 2010-2016, Peter Lunk, 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.base.api.filters;
10
11import org.eclipse.emf.ecore.EStructuralFeature;
12
13/**
14 *
15 * Defines if an {@link EStructuralFeature} should not be indexed by VIATRA Base. This filtering
16 * method should only be used if the input metamodel has certain features, that the base indexer
17 * cannot handle. If the filtered feature is a containment feature, the whole sub-tree accessible
18 * through the said feature will be filtered.
19 *
20 * Note: This API feature is for advanced users only. Usage of this feature is not encouraged,
21 * unless the filtering task is impossible via using the more straightforward
22 * {@link IBaseIndexResourceFilter} or {@link IBaseIndexObjectFilter}.
23 *
24 * @author Peter Lunk
25 * @since 1.5
26 *
27 */
28public interface IBaseIndexFeatureFilter {
29
30 /**
31 * Decides whether the selected {@link EStructuralFeature} is filtered.
32 *
33 * @param feature
34 * @return true, if the feature should not be indexed
35 */
36 boolean isFiltered(EStructuralFeature feature);
37
38} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexObjectFilter.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexObjectFilter.java
deleted file mode 100644
index e1e46bbd..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexObjectFilter.java
+++ /dev/null
@@ -1,30 +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.base.api.filters;
10
11import org.eclipse.emf.common.notify.Notifier;
12
13/**
14 *
15 * Stores a collection of {@link Notifier} instances that need not to be indexed by VIATRA Base.
16 *
17 * @author Zoltan Ujhelyi
18 *
19 */
20public interface IBaseIndexObjectFilter {
21
22 /**
23 * Decides whether the selected notifier is filtered.
24 *
25 * @param notifier
26 * @return true, if the notifier should not be indexed
27 */
28 boolean isFiltered(Notifier notifier);
29
30} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexResourceFilter.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexResourceFilter.java
deleted file mode 100644
index 73d3e961..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/IBaseIndexResourceFilter.java
+++ /dev/null
@@ -1,27 +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.base.api.filters;
10
11import org.eclipse.emf.ecore.resource.Resource;
12
13/**
14 * Defines a filter for indexing resources
15 * @author Zoltan Ujhelyi
16 *
17 */
18public interface IBaseIndexResourceFilter {
19
20 /**
21 * Decides whether a selected resource needs to be indexed
22 * @param resource
23 * @return true, if the selected resource is filtered
24 */
25 boolean isResourceFiltered(Resource resource);
26
27} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/SimpleBaseIndexFilter.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/SimpleBaseIndexFilter.java
deleted file mode 100644
index 9ae88a1a..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/filters/SimpleBaseIndexFilter.java
+++ /dev/null
@@ -1,46 +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.base.api.filters;
10
11import org.eclipse.emf.common.notify.Notifier;
12
13import java.util.Collection;
14import java.util.HashSet;
15import java.util.Set;
16
17/**
18 * An index filter that is based on a collection of {@link Notifier} instances.
19 *
20 * @author Zoltan Ujhelyi
21 *
22 */
23public class SimpleBaseIndexFilter implements IBaseIndexObjectFilter {
24
25 Set<Notifier> filters;
26
27 /**
28 * Creates a filter using a collection of (Resource and) Notifier instances. Every containment subtree, selected by
29 * the given Notifiers are filtered out.
30 *
31 * @param filterConfiguration
32 */
33 public SimpleBaseIndexFilter(Collection<Notifier> filterConfiguration) {
34 filters = new HashSet<>(filterConfiguration);
35 }
36
37 public SimpleBaseIndexFilter(SimpleBaseIndexFilter other) {
38 this(other.filters);
39 }
40
41 @Override
42 public boolean isFiltered(Notifier notifier) {
43 return filters.contains(notifier);
44 }
45
46}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/profiler/BaseIndexProfiler.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/profiler/BaseIndexProfiler.java
deleted file mode 100644
index d3cc152e..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/profiler/BaseIndexProfiler.java
+++ /dev/null
@@ -1,79 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, 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.base.api.profiler;
10
11import tools.refinery.viatra.runtime.base.api.NavigationHelper;
12import tools.refinery.viatra.runtime.base.core.NavigationHelperContentAdapter;
13import tools.refinery.viatra.runtime.base.core.NavigationHelperImpl;
14import tools.refinery.viatra.runtime.base.core.profiler.ProfilingNavigationHelperContentAdapter;
15import tools.refinery.viatra.runtime.matchers.util.Preconditions;
16
17/**
18 * An index profiler can be attached to an existing navigation helper instance to access the profiling data and control
19 * the profiler itself. If the NavigationHelper was not started in profiling mode, the profiler cannot be initialized.
20 *
21 * @since 2.3
22 */
23public class BaseIndexProfiler {
24
25 ProfilingNavigationHelperContentAdapter adapter;
26
27 /**
28 *
29 * @throws IllegalArgumentException if the profiler cannot be attached to the base index instance
30 */
31 public BaseIndexProfiler(NavigationHelper navigationHelper) {
32 if (navigationHelper instanceof NavigationHelperImpl) {
33 final NavigationHelperContentAdapter contentAdapter = ((NavigationHelperImpl) navigationHelper).getContentAdapter();
34 if (contentAdapter instanceof ProfilingNavigationHelperContentAdapter) {
35 adapter = (ProfilingNavigationHelperContentAdapter)contentAdapter;
36 }
37 }
38 Preconditions.checkArgument(adapter != null, "Cannot attach profiler to Base Index");
39 }
40
41 /**
42 * Returns the number of external request (e.g. model changes) the profiler recorded.
43 */
44 public long getNotificationCount() {
45 return adapter.getNotificationCount();
46 }
47
48 /**
49 * Return the total time base index profiler recorded for reacting to model operations.
50 */
51 public long getTotalMeasuredTimeInMS() {
52 return adapter.getTotalMeasuredTimeInMS();
53 }
54
55 /**
56 * Returns whether the profiler is turned on (e.g. measured values are increased).
57 */
58 public boolean isEnabled() {
59 return adapter.isEnabled();
60 }
61
62 /**
63 * Enables the base index profiling (e.g. measured values are increased)
64 */
65 public void setEnabled(boolean isEnabled) {
66 adapter.setEnabled(isEnabled);
67 }
68
69 /**
70 * Resets all measurements to 0, regardless whether the profiler is enabled or not.
71 * </p>
72 *
73 * <strong>Note</strong>: The behavior of the profiler is undefined when the measurements are reset while an EMF
74 * notification is being processed and the profiler is enabled.
75 */
76 public void resetMeasurement() {
77 adapter.resetMeasurement();
78 }
79}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/profiler/ProfilerMode.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/profiler/ProfilerMode.java
deleted file mode 100644
index 74901263..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/api/profiler/ProfilerMode.java
+++ /dev/null
@@ -1,22 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, 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.base.api.profiler;
10
11/**
12 * @since 2.3
13 */
14public enum ProfilerMode {
15
16 /** The base index profiler is not available */
17 OFF,
18 /** The profiler is initialized but not started until necessary */
19 START_DISABLED,
20 /** The profiler is initialized and started by default */
21 START_ENABLED
22}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/EMFModelComprehension.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/EMFModelComprehension.java
deleted file mode 100644
index bde93367..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/EMFModelComprehension.java
+++ /dev/null
@@ -1,356 +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.base.comprehension;
11
12import java.util.ArrayList;
13import java.util.Iterator;
14import java.util.List;
15
16import org.eclipse.emf.common.notify.Notifier;
17import org.eclipse.emf.common.util.EList;
18import org.eclipse.emf.ecore.EAttribute;
19import org.eclipse.emf.ecore.EObject;
20import org.eclipse.emf.ecore.EReference;
21import org.eclipse.emf.ecore.EStructuralFeature;
22import org.eclipse.emf.ecore.EcorePackage;
23import org.eclipse.emf.ecore.InternalEObject;
24import org.eclipse.emf.ecore.resource.Resource;
25import org.eclipse.emf.ecore.resource.ResourceSet;
26import org.eclipse.emf.ecore.util.EcoreUtil;
27import org.eclipse.emf.ecore.util.ExtendedMetaData;
28import org.eclipse.emf.ecore.util.FeatureMap;
29import org.eclipse.emf.ecore.util.FeatureMap.Entry;
30import org.eclipse.emf.ecore.util.InternalEList;
31import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
32import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexFeatureFilter;
33import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexObjectFilter;
34import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexResourceFilter;
35
36/**
37 * @author Bergmann Gábor
38 *
39 * Does not directly visit derived links, unless marked as a WellBehavingFeature. Derived edges are
40 * automatically interpreted correctly in these cases: - EFeatureMaps - eOpposites of containments
41 *
42 * @noextend This class is not intended to be subclassed by clients.
43 */
44public class EMFModelComprehension {
45
46 /**
47 * @since 2.3
48 */
49 protected BaseIndexOptions options;
50
51 /**
52 * Creates a model comprehension with the specified options. The options are copied, therefore subsequent changes
53 * will not affect the comprehension.
54 */
55 public EMFModelComprehension(BaseIndexOptions options) {
56 this.options = options.copy();
57 }
58
59 /**
60 * Should not traverse this feature directly. It is still possible that it can be represented in IQBase if
61 * {@link #representable(EStructuralFeature)} is true.
62 */
63 public boolean untraversableDirectly(EStructuralFeature feature) {
64
65 if((feature instanceof EReference && ((EReference)feature).isContainer())) {
66 // container features are always represented through their opposite
67 return true;
68 }
69
70 //If the feature is filtered by the feature filter specified in the BaseIndexOptions, return true
71 final IBaseIndexFeatureFilter featureFilter = options.getFeatureFilterConfiguration();
72 if(featureFilter != null && featureFilter.isFiltered(feature)){
73 return true;
74 }
75
76 boolean suspect = onlySamplingFeature(feature);
77 if(suspect) {
78 // even if the feature can only be sampled, it may be used if the proper base index option is set
79 suspect = options.isTraverseOnlyWellBehavingDerivedFeatures();
80 }
81 return suspect;
82 }
83
84 /**
85 * Decides whether a feature can only be sampled as there is no guarantee that proper notifications will be
86 * delivered by their implementation.
87 *
88 * <p/> Such features are derived (and/or volatile) features that are not well-behaving.
89 */
90 public boolean onlySamplingFeature(EStructuralFeature feature) {
91 boolean suspect =
92 feature.isDerived() ||
93 feature.isVolatile();
94 if (suspect) {
95 // override support here
96 // (e.g. if manual notifications available, or no changes expected afterwards)
97 suspect = !WellbehavingDerivedFeatureRegistry.isWellbehavingFeature(feature);
98 // TODO verbose flag somewhere to ease debugging (for such warnings)
99 // TODO add warning about not visited subtree (containment, FeatureMap and annotation didn't define
100 // otherwise)
101 }
102 return suspect;
103 }
104
105 /**
106 * This feature can be represented in IQBase.
107 */
108 public boolean representable(EStructuralFeature feature) {
109 if (!untraversableDirectly(feature))
110 return true;
111
112 if (feature instanceof EReference) {
113 final EReference reference = (EReference) feature;
114 if (reference.isContainer() && representable(reference.getEOpposite()))
115 return true;
116 }
117
118 boolean isMixed = "mixed".equals(EcoreUtil.getAnnotation(feature.getEContainingClass(),
119 ExtendedMetaData.ANNOTATION_URI, "kind"));
120 if (isMixed)
121 return true; // TODO maybe check the "name"=":mixed" or ":group" feature for representability?
122
123 // Group features are alternative features that are used when the ecore is derived from an xsd schema containing
124 // choices; in that case instead of the asked feature we should index the corresponding group feature
125 final EStructuralFeature groupFeature = ExtendedMetaData.INSTANCE.getGroup(feature);
126 if (groupFeature != null) {
127 return representable(groupFeature);
128 }
129
130 return false;
131 }
132
133 /**
134 * Resource filters not consulted here (for performance), because model roots are assumed to be pre-filtered.
135 */
136 public void traverseModel(EMFVisitor visitor, Notifier source) {
137 if (source == null)
138 return;
139 if (source instanceof EObject) {
140 final EObject sourceObject = (EObject) source;
141 if (sourceObject.eIsProxy())
142 throw new IllegalArgumentException("Proxy EObject cannot act as model roots for VIATRA: " + source);
143 traverseObject(visitor, sourceObject);
144 } else if (source instanceof Resource) {
145 traverseResource(visitor, (Resource) source);
146 } else if (source instanceof ResourceSet) {
147 traverseResourceSet(visitor, (ResourceSet) source);
148 }
149 }
150
151 public void traverseResourceSet(EMFVisitor visitor, ResourceSet source) {
152 if (source == null)
153 return;
154 final List<Resource> resources = new ArrayList<Resource>(source.getResources());
155 for (Resource resource : resources) {
156 traverseResourceIfUnfiltered(visitor, resource);
157 }
158 }
159
160 public void traverseResourceIfUnfiltered(EMFVisitor visitor, Resource resource) {
161 final IBaseIndexResourceFilter resourceFilter = options.getResourceFilterConfiguration();
162 if (resourceFilter != null && resourceFilter.isResourceFiltered(resource))
163 return;
164 final IBaseIndexObjectFilter objectFilter = options.getObjectFilterConfiguration();
165 if (objectFilter != null && objectFilter.isFiltered(resource))
166 return;
167
168 traverseResource(visitor, resource);
169 }
170
171 public void traverseResource(EMFVisitor visitor, Resource source) {
172 if (source == null)
173 return;
174 if (visitor.pruneSubtrees(source))
175 return;
176 final EList<EObject> contents = source.getContents();
177 for (EObject eObject : contents) {
178 traverseObjectIfUnfiltered(visitor, eObject);
179 }
180 }
181
182
183 public void traverseObjectIfUnfiltered(EMFVisitor visitor, EObject targetObject) {
184 final IBaseIndexObjectFilter objectFilter = options.getObjectFilterConfiguration();
185 if (objectFilter != null && objectFilter.isFiltered(targetObject))
186 return;
187
188 traverseObject(visitor, targetObject);
189 }
190
191 public void traverseObject(EMFVisitor visitor, EObject source) {
192 if (source == null)
193 return;
194
195 if (visitor.preOrder()) visitor.visitElement(source);
196 for (EStructuralFeature feature : source.eClass().getEAllStructuralFeatures()) {
197 if (untraversableDirectly(feature))
198 continue;
199 final boolean visitorPrunes = visitor.pruneFeature(feature);
200 if (visitorPrunes && !unprunableFeature(visitor, source, feature))
201 continue;
202
203 traverseFeatureTargets(visitor, source, feature, visitorPrunes);
204 }
205 if (!visitor.preOrder()) visitor.visitElement(source);
206 }
207
208 protected void traverseFeatureTargets(EMFVisitor visitor, EObject source, EStructuralFeature feature,
209 final boolean visitorPrunes) {
210 boolean attemptResolve = (feature instanceof EAttribute) || visitor.attemptProxyResolutions(source, (EReference)feature);
211 if (feature.isMany()) {
212 EList<?> targets = (EList<?>) source.eGet(feature);
213 int position = 0;
214 Iterator<?> iterator = attemptResolve ? targets.iterator() : ((InternalEList<?>)targets).basicIterator();
215 while (iterator.hasNext()) {
216 Object target = iterator.next();
217 traverseFeatureInternal(visitor, source, feature, target, visitorPrunes, position++);
218 }
219 } else {
220 Object target = source.eGet(feature, attemptResolve);
221 if (target != null)
222 traverseFeatureInternal(visitor, source, feature, target, visitorPrunes, null);
223 }
224 }
225 /**
226 * @since 2.3
227 */
228 protected boolean unprunableFeature(EMFVisitor visitor, EObject source, EStructuralFeature feature) {
229 return (feature instanceof EAttribute && EcorePackage.eINSTANCE.getEFeatureMapEntry().equals(
230 ((EAttribute) feature).getEAttributeType()))
231 || (feature instanceof EReference && ((EReference) feature).isContainment() && (!visitor
232 .pruneSubtrees(source) || ((EReference) feature).getEOpposite() != null));
233 }
234
235 /**
236 * @param position optional: known position in multivalued collection (for more efficient proxy resolution)
237 */
238 public void traverseFeature(EMFVisitor visitor, EObject source, EStructuralFeature feature, Object target, Integer position) {
239 if (target == null)
240 return;
241 if (untraversableDirectly(feature))
242 return;
243 traverseFeatureInternalSimple(visitor, source, feature, target, position);
244 }
245
246 /**
247 * @param position optional: known position in multivalued collection (for more efficient proxy resolution)
248 * @since 2.3
249 */
250 protected void traverseFeatureInternalSimple(EMFVisitor visitor, EObject source, EStructuralFeature feature,
251 Object target, Integer position) {
252 final boolean visitorPrunes = visitor.pruneFeature(feature);
253 if (visitorPrunes && !unprunableFeature(visitor, source, feature))
254 return;
255
256 traverseFeatureInternal(visitor, source, feature, target, visitorPrunes, position);
257 }
258
259 /**
260 * @pre target != null
261 * @param position optional: known position in multivalued collection (for more efficient proxy resolution)
262 * @since 2.3
263 */
264 protected void traverseFeatureInternal(EMFVisitor visitor, EObject source, EStructuralFeature feature,
265 Object target, boolean visitorPrunes, Integer position) {
266 if (feature instanceof EAttribute) {
267 if (!visitorPrunes)
268 visitor.visitAttribute(source, (EAttribute) feature, target);
269 if (target instanceof FeatureMap.Entry) { // emulated derived edge based on FeatureMap
270 Entry entry = (FeatureMap.Entry) target;
271 final EStructuralFeature emulated = entry.getEStructuralFeature();
272 final Object emulatedTarget = entry.getValue();
273
274 emulateUntraversableFeature(visitor, source, emulated, emulatedTarget);
275 }
276 } else if (feature instanceof EReference) {
277 EReference reference = (EReference) feature;
278 EObject targetObject = (EObject) target;
279 if (reference.isContainment()) {
280 if (!visitor.avoidTransientContainmentLink(source, reference, targetObject)) {
281 if (!visitorPrunes)
282 visitor.visitInternalContainment(source, reference, targetObject);
283 if (!visitor.pruneSubtrees(source)) {
284 // Recursively follow containment...
285 // unless cross-resource containment (in which case we may skip)
286 Resource targetResource = (targetObject instanceof InternalEObject)?
287 ((InternalEObject)targetObject).eDirectResource() : null;
288 boolean crossResourceContainment = targetResource != null;
289 if (!crossResourceContainment || visitor.descendAlongCrossResourceContainments()) {
290 // in-resource containment shall be followed
291 // as well as cross-resource containment for an object scope
292 traverseObjectIfUnfiltered(visitor, targetObject);
293 } else {
294 // do not follow
295 // target will be traversed separately from its resource (resourceSet scope)
296 // or left out of scope (resource scope)
297 }
298 }
299
300 final EReference opposite = reference.getEOpposite();
301 if (opposite != null) { // emulated derived edge based on container opposite
302 emulateUntraversableFeature(visitor, targetObject, opposite, source);
303 }
304 }
305 } else {
306 // if (containedElements.contains(target))
307 if (!visitorPrunes)
308 visitor.visitNonContainmentReference(source, reference, targetObject);
309 }
310 if (targetObject.eIsProxy()) {
311 if (!reference.isResolveProxies()) {
312 throw new IllegalStateException(String.format(
313 "EReference '%s' of EClass %s is set as proxy-non-resolving (i.e. it should never point to a proxy, and never lead cross-resource), " +
314 "yet VIATRA Base encountered a proxy object %s referenced from %s.",
315 reference.getName(), reference.getEContainingClass().getInstanceTypeName(),
316 targetObject, source));
317 }
318 visitor.visitProxyReference(source, reference, targetObject, position);
319 }
320 }
321
322 }
323
324
325 /**
326 * Emulates a derived edge, if it is not visited otherwise
327 *
328 * @pre target != null
329 * @since 2.3
330 */
331 protected void emulateUntraversableFeature(EMFVisitor visitor, EObject source,
332 final EStructuralFeature emulated, final Object target) {
333 if (untraversableDirectly(emulated))
334 traverseFeatureInternalSimple(visitor, source, emulated, target, null);
335 }
336
337 /**
338 * Can be called to attempt to resolve a reference pointing to one or more proxies, using eGet().
339 */
340 @SuppressWarnings("unchecked")
341 public void tryResolveReference(EObject source, EReference reference) {
342 final Object result = source.eGet(reference, true);
343 if (reference.isMany()) {
344 // no idea which element to get, have to iterate through
345 ((Iterable<EObject>) result).forEach(EObject -> {/*proxy resolution as a side-effect of traversal*/});
346 }
347 }
348
349 /**
350 * Finds out whether the Resource is currently loading
351 */
352 public boolean isLoading(Resource resource) {
353 return !resource.isLoaded() || ((Resource.Internal)resource).isLoading();
354 }
355
356} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/EMFVisitor.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/EMFVisitor.java
deleted file mode 100644
index 6029bb02..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/EMFVisitor.java
+++ /dev/null
@@ -1,145 +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.base.comprehension;
11
12import org.eclipse.emf.ecore.EAttribute;
13import org.eclipse.emf.ecore.EObject;
14import org.eclipse.emf.ecore.EReference;
15import org.eclipse.emf.ecore.EStructuralFeature;
16import org.eclipse.emf.ecore.resource.Resource;
17
18/**
19 * Use EMFModelComprehension to visit an EMF model.
20 *
21 * @author Bergmann Gábor
22 *
23 */
24// FIXME:
25// - handle boundary of active emfRoot subtree
26// - more efficient traversal
27public class EMFVisitor {
28
29 boolean preOrder;
30
31 public EMFVisitor(boolean preOrder) {
32 super();
33 this.preOrder = preOrder;
34 }
35
36 /**
37 * @param resource
38 * @param element
39 */
40 public void visitTopElementInResource(Resource resource, EObject element) {
41 }
42
43 /**
44 * @param resource
45 */
46 public void visitResource(Resource resource) {
47 }
48
49 /**
50 * @param source
51 */
52 public void visitElement(EObject source) {
53 }
54
55 /**
56 * @param source
57 * @param feature
58 * @param target
59 */
60 public void visitNonContainmentReference(EObject source, EReference feature, EObject target) {
61 }
62
63 /**
64 * @param source
65 * @param feature
66 * @param target
67 */
68 public void visitInternalContainment(EObject source, EReference feature, EObject target) {
69 }
70
71 /**
72 * @param source
73 * @param feature
74 * @param target
75 */
76 public void visitAttribute(EObject source, EAttribute feature, Object target) {
77 }
78
79 /**
80 * Returns true if the given feature should not be traversed (interesting esp. if multi-valued)
81 */
82 public boolean pruneFeature(EStructuralFeature feature) {
83 return false;
84 }
85
86 /**
87 * Returns true if the contents of an object should be pruned (and not explored by the visitor)
88 */
89 public boolean pruneSubtrees(EObject source) {
90 return false;
91 }
92
93 /**
94 * Returns true if the contents of a resource should be pruned (and not explored by the visitor)
95 */
96 public boolean pruneSubtrees(Resource source) {
97 return false;
98 }
99
100 /**
101 * An opportunity for the visitor to indicate that the containment link is considered in a transient state, and the
102 * model comprehension should avoid following it.
103 *
104 * A containment is in a transient state from the point of view of the visitor if it connects a subtree that is
105 * being inserted <em>during</em> a full-model traversal, and a separate notification handler will deal with it
106 * later.
107 */
108 public boolean avoidTransientContainmentLink(EObject source, EReference reference, EObject targetObject) {
109 return false;
110 }
111
112 /**
113 * @return if objects should be visited before their outgoing edges
114 */
115 public boolean preOrder() {
116 return preOrder;
117 }
118
119 /**
120 * Called after visiting the reference, if the target is a proxy.
121 *
122 * @param position
123 * optional: known position in multivalued collection (for more efficient proxy resolution)
124 */
125 public void visitProxyReference(EObject source, EReference reference, EObject targetObject, Integer position) {
126 }
127
128 /**
129 * Whether the given reference of the given object should be resolved when it is a proxy
130 */
131 public boolean attemptProxyResolutions(EObject source, EReference feature) {
132 return true;
133 }
134
135 /**
136 * @return true if traversing visitors shall descend along cross-resource containments
137 * (this only makes sense for traversing visitors on an object scope)
138 *
139 * @since 1.7
140 */
141 public boolean descendAlongCrossResourceContainments() {
142 return false;
143 }
144
145} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/WellbehavingDerivedFeatureRegistry.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/WellbehavingDerivedFeatureRegistry.java
deleted file mode 100644
index d696ddd6..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/comprehension/WellbehavingDerivedFeatureRegistry.java
+++ /dev/null
@@ -1,154 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2011 Abel Hegedus 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.base.comprehension;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.WeakHashMap;
14
15import org.apache.log4j.Logger;
16import org.eclipse.core.runtime.IConfigurationElement;
17import org.eclipse.core.runtime.IExtension;
18import org.eclipse.core.runtime.IExtensionPoint;
19import org.eclipse.core.runtime.IExtensionRegistry;
20import org.eclipse.core.runtime.Platform;
21import org.eclipse.emf.ecore.EClass;
22import org.eclipse.emf.ecore.EClassifier;
23import org.eclipse.emf.ecore.EPackage;
24import org.eclipse.emf.ecore.EStructuralFeature;
25import tools.refinery.viatra.runtime.base.ViatraBasePlugin;
26
27/**
28 * @author Abel Hegedus
29 *
30 */
31public class WellbehavingDerivedFeatureRegistry {
32
33
34 private static Collection<EStructuralFeature> contributedWellbehavingDerivedFeatures = Collections.newSetFromMap(new WeakHashMap<EStructuralFeature, Boolean>());
35 private static Collection<EClass> contributedWellbehavingDerivedClasses = Collections.newSetFromMap(new WeakHashMap<EClass, Boolean>());
36 private static Collection<EPackage> contributedWellbehavingDerivedPackages = Collections.newSetFromMap(new WeakHashMap<EPackage, Boolean>());
37
38 private WellbehavingDerivedFeatureRegistry() {
39 }
40
41 /**
42 * Called by ViatraBasePlugin.
43 */
44 public static void initRegistry() {
45 getContributedWellbehavingDerivedFeatures().clear();
46 getContributedWellbehavingDerivedClasses().clear();
47 getContributedWellbehavingDerivedPackages().clear();
48
49 IExtensionRegistry reg = Platform.getExtensionRegistry();
50 IExtensionPoint poi;
51
52 poi = reg.getExtensionPoint(ViatraBasePlugin.WELLBEHAVING_DERIVED_FEATURE_EXTENSION_POINT_ID);
53 if (poi != null) {
54 IExtension[] exts = poi.getExtensions();
55
56 for (IExtension ext : exts) {
57
58 IConfigurationElement[] els = ext.getConfigurationElements();
59 for (IConfigurationElement el : els) {
60 if (el.getName().equals("wellbehaving-derived-feature")) {
61 processWellbehavingExtension(el);
62 } else {
63 throw new UnsupportedOperationException("Unknown configuration element " + el.getName()
64 + " in plugin.xml of " + el.getDeclaringExtension().getUniqueIdentifier());
65 }
66 }
67 }
68 }
69 }
70
71 private static void processWellbehavingExtension(IConfigurationElement el) {
72 try {
73 String packageUri = el.getAttribute("package-nsUri");
74 String featureName = el.getAttribute("feature-name");
75 String classifierName = el.getAttribute("classifier-name");
76 String contributorName = el.getContributor().getName();
77 StringBuilder featureIdBuilder = new StringBuilder();
78 if (packageUri != null) {
79 EPackage pckg = EPackage.Registry.INSTANCE.getEPackage(packageUri);
80 featureIdBuilder.append(packageUri);
81 if (pckg != null) {
82 if (classifierName != null) {
83 EClassifier clsr = pckg.getEClassifier(classifierName);
84 featureIdBuilder.append("##").append(classifierName);
85 if (clsr instanceof EClass) {
86 if (featureName != null) {
87 EClass cls = (EClass) clsr;
88 EStructuralFeature feature = cls.getEStructuralFeature(featureName);
89 featureIdBuilder.append("##").append(featureName);
90 if (feature != null) {
91 registerWellbehavingDerivedFeature(feature);
92 } else {
93 throw new IllegalStateException(String.format("Feature %s of EClass %s in package %s not found! (plug-in %s)", featureName, classifierName, packageUri, contributorName));
94 }
95 } else {
96 registerWellbehavingDerivedClass((EClass) clsr);
97 }
98 } else {
99 throw new IllegalStateException(String.format("EClassifier %s does not exist in package %s! (plug-in %s)", classifierName, packageUri, contributorName));
100 }
101 } else {
102 if(featureName != null){
103 throw new IllegalStateException(String.format("Feature name must be empty if classifier name is not set! (package %s, plug-in %s)", packageUri, contributorName));
104 }
105 registerWellbehavingDerivedPackage(pckg);
106 }
107 }
108 }
109 } catch (Exception e) {
110 final Logger logger = Logger.getLogger(WellbehavingDerivedFeatureRegistry.class);
111 logger.error("Well-behaving feature registration failed", e);
112 }
113 }
114
115 /**
116 *
117 * @param feature
118 * @return true if the feature (or its defining EClass or ) is registered as well-behaving
119 */
120 public static boolean isWellbehavingFeature(EStructuralFeature feature) {
121 if(feature == null){
122 return false;
123 } else if (contributedWellbehavingDerivedFeatures.contains(feature)) {
124 return true;
125 } else if (contributedWellbehavingDerivedClasses.contains(feature.getEContainingClass())) {
126 return true;
127 } else return contributedWellbehavingDerivedPackages.contains(feature.getEContainingClass().getEPackage());
128 }
129
130 public static void registerWellbehavingDerivedFeature(EStructuralFeature feature) {
131 contributedWellbehavingDerivedFeatures.add(feature);
132 }
133
134 public static void registerWellbehavingDerivedClass(EClass cls) {
135 contributedWellbehavingDerivedClasses.add(cls);
136 }
137
138 public static void registerWellbehavingDerivedPackage(EPackage pkg) {
139 contributedWellbehavingDerivedPackages.add(pkg);
140 }
141
142 public static Collection<EStructuralFeature> getContributedWellbehavingDerivedFeatures() {
143 return contributedWellbehavingDerivedFeatures;
144 }
145
146 public static Collection<EClass> getContributedWellbehavingDerivedClasses() {
147 return contributedWellbehavingDerivedClasses;
148 }
149
150 public static Collection<EPackage> getContributedWellbehavingDerivedPackages() {
151 return contributedWellbehavingDerivedPackages;
152 }
153
154}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/AbstractBaseIndexStore.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/AbstractBaseIndexStore.java
deleted file mode 100644
index 3d61b1bf..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/AbstractBaseIndexStore.java
+++ /dev/null
@@ -1,28 +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.base.core;
10
11import org.apache.log4j.Logger;
12import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
13
14/**
15 * @since 1.6
16 */
17public class AbstractBaseIndexStore {
18
19 protected final NavigationHelperImpl navigationHelper;
20 protected final Logger logger;
21 protected final BaseIndexOptions options;
22
23 public AbstractBaseIndexStore(NavigationHelperImpl navigationHelper, Logger logger) {
24 this.navigationHelper = navigationHelper;
25 this.logger = logger;
26 this.options = navigationHelper.getBaseIndexOptions();
27 }
28}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexInstanceStore.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexInstanceStore.java
deleted file mode 100644
index 2094bbbe..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexInstanceStore.java
+++ /dev/null
@@ -1,451 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.core;
10
11import java.util.Collections;
12import java.util.HashSet;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Set;
16
17import org.apache.log4j.Logger;
18import org.eclipse.emf.ecore.EClass;
19import org.eclipse.emf.ecore.EClassifier;
20import org.eclipse.emf.ecore.EObject;
21import tools.refinery.viatra.runtime.base.api.IStructuralFeatureInstanceProcessor;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
23import tools.refinery.viatra.runtime.matchers.util.IMultiset;
24
25/**
26 * Stores the indexed contents of an EMF model
27 * (includes instance model information).
28 *
29 * @author Gabor Bergmann
30 * @noextend This class is not intended to be subclassed by clients.
31 */
32public class EMFBaseIndexInstanceStore extends AbstractBaseIndexStore {
33
34 public EMFBaseIndexInstanceStore(NavigationHelperImpl navigationHelper, Logger logger) {
35 super(navigationHelper, logger);
36 }
37
38 /**
39 * since last run of after-update callbacks
40 */
41 boolean isDirty = false;
42
43 /**
44 * feature (EAttribute or EReference or equivalent String key) -> FeatureData
45 * @since 1.7
46 */
47 private Map<Object, FeatureData> featureDataMap = CollectionsFactory.createMap();
48
49 /**
50 * value -> featureKey(s);
51 * constructed on-demand, null if unused (hopefully most of the time)
52 */
53 private Map<Object, IMultiset<Object>> valueToFeatureMap = null;
54
55
56 /**
57 * key (String id or EClass instance) -> instance(s)
58 */
59 private final Map<Object, Set<EObject>> instanceMap = CollectionsFactory.createMap();
60
61 /**
62 * key (String id or EDataType instance) -> multiset of value(s)
63 */
64 private final Map<Object, IMultiset<Object>> dataTypeMap = CollectionsFactory.createMap();
65
66 /**
67 * Bundles all instance store data specific to a given binary feature.
68 *
69 * <p> TODO: specialize for to-one features and unique to-many features
70 * <p> TODO: on-demand construction of valueToHolderMap
71 *
72 * @author Gabor Bergmann
73 * @since 1.7
74 */
75 class FeatureData {
76 /** value -> holder(s) */
77 private Map<Object, IMultiset<EObject>> valueToHolderMap = CollectionsFactory.createMap();
78 /**
79 * holder -> value(s);
80 * constructed on-demand, null if unused
81 */
82 private Map<EObject, IMultiset<Object>> holderToValueMap;
83
84 /**
85 * feature (EAttribute or EReference) or its string key (in dynamic EMF mode)
86 */
87 private Object featureKey;
88
89 /**
90 * @return feature (EAttribute or EReference) or its string key (in dynamic EMF mode)
91 */
92 public Object getFeatureKey() {
93 return featureKey;
94 }
95
96 @Override
97 public String toString() {
98 return this.getClass().getSimpleName() + ":" + featureKey;
99 }
100
101 /**
102 * @return true if this was the first time the value was added to this feature of this holder (false is only
103 * expected for non-unique features)
104 */
105 boolean insertFeatureTuple(boolean unique, final Object value, final EObject holder) {
106 // TODO we currently assume V2H map exists
107 boolean changed = addToValueToHolderMap(value, holder);
108 if (holderToValueMap != null) {
109 addToHolderToValueMap(value, holder);
110 }
111
112 if (unique && !changed) {
113 navigationHelper.logIncidentFeatureTupleInsertion(value, holder, featureKey);
114 }
115 return changed;
116 }
117
118 /**
119 * @return true if this was the last duplicate of the value added to this feature of this holder (false is only
120 * expected for non-unique features)
121 */
122 boolean removeFeatureTuple(boolean unique, final Object value, final EObject holder) {
123 Object featureKey = getFeatureKey();
124 try {
125 // TODO we currently assume V2H map exists
126 boolean changed = removeFromValueToHolderMap(value, holder);
127 if (holderToValueMap != null) {
128 removeFromHolderToValueMap(value, holder);
129 }
130
131 if (unique && !changed) {
132 navigationHelper.logIncidentFeatureTupleRemoval(value, holder, featureKey);
133 }
134 return changed;
135 } catch (IllegalStateException ex) {
136 navigationHelper.logIncidentFeatureTupleRemoval(value, holder, featureKey);
137 return false;
138 }
139 }
140
141
142 protected boolean addToHolderToValueMap(Object value, EObject holder) {
143 IMultiset<Object> values = holderToValueMap.computeIfAbsent(holder,
144 CollectionsFactory::emptyMultiset);
145 boolean changed = values.addOne(value);
146 return changed;
147 }
148
149 protected boolean addToValueToHolderMap(final Object value, final EObject holder) {
150 IMultiset<EObject> holders = valueToHolderMap.computeIfAbsent(value,
151 CollectionsFactory::emptyMultiset);
152 boolean changed = holders.addOne(holder);
153 return changed;
154 }
155
156 protected boolean removeFromHolderToValueMap(Object value, EObject holder) throws IllegalStateException {
157 IMultiset<Object> values = holderToValueMap.get(holder);
158 if (values == null)
159 throw new IllegalStateException();
160 boolean changed = values.removeOne(value);
161 if (changed && values.isEmpty())
162 holderToValueMap.remove(holder);
163 return changed;
164 }
165 protected boolean removeFromValueToHolderMap(final Object value, final EObject holder) throws IllegalStateException {
166 IMultiset<EObject> holders = valueToHolderMap.get(value);
167 if (holders == null)
168 throw new IllegalStateException();
169 boolean changed = holders.removeOne(holder);
170 if (changed && holders.isEmpty())
171 valueToHolderMap.remove(value);
172 return changed;
173 }
174
175 protected Map<EObject, IMultiset<Object>> getHolderToValueMap() {
176 if (holderToValueMap == null) {
177 holderToValueMap = CollectionsFactory.createMap();
178
179 // TODO we currently assume V2H map exists
180 for (Entry<Object, IMultiset<EObject>> entry : valueToHolderMap.entrySet()) {
181 Object value = entry.getKey();
182 IMultiset<EObject> holders = entry.getValue();
183 for (EObject holder : holders.distinctValues()) {
184 int count = holders.getCount(holder);
185
186 IMultiset<Object> valuesOfHolder = holderToValueMap.computeIfAbsent(holder,
187 CollectionsFactory::emptyMultiset);
188 valuesOfHolder.addPositive(value, count);
189 }
190 }
191 }
192 return holderToValueMap;
193 }
194 protected Map<Object, IMultiset<EObject>> getValueToHolderMap() {
195 // TODO we currently assume V2H map exists
196 return valueToHolderMap;
197 }
198
199 public void forEach(IStructuralFeatureInstanceProcessor processor) {
200 // TODO we currently assume V2H map exists
201 if (valueToHolderMap != null) {
202 for (Entry<Object, IMultiset<EObject>> entry : valueToHolderMap.entrySet()) {
203 Object value = entry.getKey();
204 for (EObject eObject : entry.getValue().distinctValues()) {
205 processor.process(eObject, value);
206 }
207 }
208 } else throw new UnsupportedOperationException("TODO implement");
209 }
210
211 public Set<EObject> getAllDistinctHolders() {
212 return getHolderToValueMap().keySet();
213 }
214
215 public Set<Object> getAllDistinctValues() {
216 return getValueToHolderMap().keySet();
217 }
218
219 public Set<EObject> getDistinctHoldersOfValue(Object value) {
220 IMultiset<EObject> holdersMultiset = getValueToHolderMap().get(value);
221 if (holdersMultiset == null)
222 return Collections.emptySet();
223 else return holdersMultiset.distinctValues();
224 }
225
226
227 public Set<Object> getDistinctValuesOfHolder(EObject holder) {
228 IMultiset<Object> valuesMultiset = getHolderToValueMap().get(holder);
229 if (valuesMultiset == null)
230 return Collections.emptySet();
231 else return valuesMultiset.distinctValues();
232 }
233
234 public boolean isInstance(EObject source, Object target) {
235 // TODO we currently assume V2H map exists
236 if (valueToHolderMap != null) {
237 IMultiset<EObject> holders = valueToHolderMap.get(target);
238 return holders != null && holders.containsNonZero(source);
239 } else throw new UnsupportedOperationException("TODO implement");
240 }
241
242
243 }
244
245
246 FeatureData getFeatureData(Object featureKey) {
247 FeatureData data = featureDataMap.get(featureKey);
248 if (data == null) {
249 data = createFeatureData(featureKey);
250 featureDataMap.put(featureKey, data);
251 }
252 return data;
253 }
254
255 /**
256 * TODO: specialize for to-one features and unique to-many features
257 */
258 protected FeatureData createFeatureData(Object featureKey) {
259 FeatureData data = new FeatureData();
260 data.featureKey = featureKey;
261 return data;
262 }
263
264
265
266
267 protected void insertFeatureTuple(final Object featureKey, boolean unique, final Object value, final EObject holder) {
268 boolean changed = getFeatureData(featureKey).insertFeatureTuple(unique, value, holder);
269 if (changed) { // if not duplicated
270
271 if (valueToFeatureMap != null) {
272 insertIntoValueToFeatureMap(featureKey, value);
273 }
274
275 isDirty = true;
276 navigationHelper.notifyFeatureListeners(holder, featureKey, value, true);
277 }
278 }
279
280 protected void removeFeatureTuple(final Object featureKey, boolean unique, final Object value, final EObject holder) {
281 boolean changed = getFeatureData(featureKey).removeFeatureTuple(unique, value, holder);
282 if (changed) { // if not duplicated
283
284 if (valueToFeatureMap != null) {
285 removeFromValueToFeatureMap(featureKey, value);
286 }
287
288 isDirty = true;
289 navigationHelper.notifyFeatureListeners(holder, featureKey, value, false);
290 }
291 }
292
293
294 public Set<Object> getFeatureKeysPointingTo(Object target) {
295 final IMultiset<Object> sources = getValueToFeatureMap().get(target);
296 return sources == null ? Collections.emptySet() : sources.distinctValues();
297 }
298
299 protected Map<Object, IMultiset<Object>> getValueToFeatureMap() {
300 if (valueToFeatureMap == null) { // must be inverted from feature data
301 valueToFeatureMap = CollectionsFactory.createMap();
302 for (FeatureData featureData : featureDataMap.values()) {
303 final Object featureKey = featureData.getFeatureKey();
304 featureData.forEach((source, target) -> insertIntoValueToFeatureMap(featureKey, target));
305 }
306 }
307 return valueToFeatureMap;
308 }
309
310 protected void insertIntoValueToFeatureMap(final Object featureKey, Object target) {
311 IMultiset<Object> featureKeys = valueToFeatureMap.computeIfAbsent(target, CollectionsFactory::emptyMultiset);
312 featureKeys.addOne(featureKey);
313 }
314 protected void removeFromValueToFeatureMap(final Object featureKey, final Object value) {
315 IMultiset<Object> featureKeys = valueToFeatureMap.get(value);
316 if (featureKeys == null)
317 throw new IllegalStateException();
318 featureKeys.removeOne(featureKey);
319 if (featureKeys.isEmpty())
320 valueToFeatureMap.remove(value);
321 }
322
323 // START ********* InstanceSet *********
324 public Set<EObject> getInstanceSet(final Object keyClass) {
325 return instanceMap.get(keyClass);
326 }
327
328 public void removeInstanceSet(final Object keyClass) {
329 instanceMap.remove(keyClass);
330 }
331
332 public void insertIntoInstanceSet(final Object keyClass, final EObject value) {
333 Set<EObject> set = instanceMap.computeIfAbsent(keyClass, CollectionsFactory::emptySet);
334
335 if (!set.add(value)) {
336 navigationHelper.logIncidentInstanceInsertion(keyClass, value);
337 } else {
338 isDirty = true;
339 navigationHelper.notifyInstanceListeners(keyClass, value, true);
340 }
341 }
342
343 public void removeFromInstanceSet(final Object keyClass, final EObject value) {
344 final Set<EObject> set = instanceMap.get(keyClass);
345 if (set != null) {
346 if(!set.remove(value)) {
347 navigationHelper.logIncidentInstanceRemoval(keyClass, value);
348 } else {
349 if (set.isEmpty()) {
350 instanceMap.remove(keyClass);
351 }
352 isDirty = true;
353 navigationHelper.notifyInstanceListeners(keyClass, value, false);
354 }
355 } else {
356 navigationHelper.logIncidentInstanceRemoval(keyClass, value);
357 }
358
359 }
360
361
362
363 // END ********* InstanceSet *********
364
365 // START ********* DataTypeMap *********
366 public Set<Object> getDistinctDataTypeInstances(final Object keyType) {
367 IMultiset<Object> values = dataTypeMap.get(keyType);
368 return values == null ? Collections.emptySet() : values.distinctValues();
369 }
370
371 public void removeDataTypeMap(final Object keyType) {
372 dataTypeMap.remove(keyType);
373 }
374
375 public void insertIntoDataTypeMap(final Object keyType, final Object value) {
376 IMultiset<Object> valMap = dataTypeMap.computeIfAbsent(keyType, CollectionsFactory::emptyMultiset);
377 final boolean firstOccurrence = valMap.addOne(value);
378
379 isDirty = true;
380 navigationHelper.notifyDataTypeListeners(keyType, value, true, firstOccurrence);
381 }
382
383 public void removeFromDataTypeMap(final Object keyType, final Object value) {
384 final IMultiset<Object> valMap = dataTypeMap.get(keyType);
385 if (valMap != null) {
386 final boolean lastOccurrence = valMap.removeOne(value);
387 if (lastOccurrence && valMap.isEmpty()) {
388 dataTypeMap.remove(keyType);
389 }
390
391 isDirty = true;
392 navigationHelper.notifyDataTypeListeners(keyType, value, false, lastOccurrence);
393 }
394 }
395
396 // END ********* DataTypeMap *********
397
398 protected Set<EObject> getHoldersOfFeature(Object featureKey) {
399 FeatureData featureData = getFeatureData(featureKey);
400 return featureData.getAllDistinctHolders();
401 }
402 protected Set<Object> getValuesOfFeature(Object featureKey) {
403 FeatureData featureData = getFeatureData(featureKey);
404 return featureData.getAllDistinctValues();
405 }
406
407 /**
408 * Returns all EClasses that currently have direct instances cached by the index.
409 * <p>
410 * Supertypes will not be returned, unless they have direct instances in the model as well. If not in
411 * <em>wildcard mode</em>, only registered EClasses and their subtypes will be returned.
412 * <p>
413 * Note for advanced users: if a type is represented by multiple EClass objects, one of them is chosen as
414 * representative and returned.
415 */
416 public Set<EClass> getAllCurrentClasses() {
417 final Set<EClass> result = CollectionsFactory.createSet();
418 final Set<Object> classifierKeys = instanceMap.keySet();
419 for (final Object classifierKey : classifierKeys) {
420 final EClassifier knownClassifier = navigationHelper.metaStore.getKnownClassifierForKey(classifierKey);
421 if (knownClassifier instanceof EClass) {
422 result.add((EClass) knownClassifier);
423 }
424 }
425 return result;
426 }
427
428 Set<Object> getOldValuesForHolderAndFeature(EObject source, Object featureKey) {
429 // while this is slower than using the holderToFeatureToValueMap, we do not want to construct that to avoid
430 // memory overhead
431 Map<Object, IMultiset<EObject>> oldValuesToHolders = getFeatureData(featureKey).valueToHolderMap;
432 Set<Object> oldValues = new HashSet<Object>();
433 for (Entry<Object, IMultiset<EObject>> entry : oldValuesToHolders.entrySet()) {
434 if (entry.getValue().containsNonZero(source)) {
435 oldValues.add(entry.getKey());
436 }
437 }
438 return oldValues;
439 }
440
441 protected void forgetFeature(Object featureKey) {
442 FeatureData removed = featureDataMap.remove(featureKey);
443 if (valueToFeatureMap != null) {
444 for (Object value : removed.getAllDistinctValues()) {
445 removeFromValueToFeatureMap(featureKey, value);
446 }
447 }
448 }
449
450
451}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexMetaStore.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexMetaStore.java
deleted file mode 100644
index 52ca3a53..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexMetaStore.java
+++ /dev/null
@@ -1,380 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.core;
10
11import org.eclipse.emf.common.util.Enumerator;
12import org.eclipse.emf.ecore.*;
13import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
14import tools.refinery.viatra.runtime.base.api.IndexingLevel;
15import tools.refinery.viatra.runtime.base.api.InstanceListener;
16import tools.refinery.viatra.runtime.base.exception.ViatraBaseException;
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;
22
23import java.util.*;
24import java.util.Map.Entry;
25
26/**
27 * Stores the indexed metamodel information.
28 *
29 * @author Gabor Bergmann
30 * @noextend This class is not intended to be subclassed by clients.
31 */
32public class EMFBaseIndexMetaStore {
33
34 private static final EClass EOBJECT_CLASS = EcorePackage.eINSTANCE.getEObject();
35 private final boolean isDynamicModel;
36 private NavigationHelperImpl navigationHelper;
37
38 /**
39 *
40 */
41 public EMFBaseIndexMetaStore(final NavigationHelperImpl navigationHelper) {
42 this.navigationHelper = navigationHelper;
43 final BaseIndexOptions options = navigationHelper.getBaseIndexOptions();
44 this.isDynamicModel = options.isDynamicEMFMode();
45 }
46
47 /**
48 * Supports collision detection and EEnum canonicalization. Used for all EPackages that have types whose instances
49 * were encountered at least once.
50 */
51 private final Set<EPackage> knownPackages = new HashSet<EPackage>();
52
53 /**
54 * Field variable because it is needed for collision detection. Used for all EClasses whose instances were
55 * encountered at least once.
56 */
57 private final Set<EClassifier> knownClassifiers = new HashSet<EClassifier>();
58 /**
59 * Field variable because it is needed for collision detection. Used for all EStructuralFeatures whose instances
60 * were encountered at least once.
61 */
62 private final Set<EStructuralFeature> knownFeatures = new HashSet<EStructuralFeature>();
63
64 /**
65 * (EClass or String ID) -> all subtypes in knownClasses
66 */
67 private final Map<Object, Set<Object>> subTypeMap = new HashMap<Object, Set<Object>>();
68 /**
69 * (EClass or String ID) -> all supertypes in knownClasses
70 */
71 private final Map<Object, Set<Object>> superTypeMap = new HashMap<Object, Set<Object>>();
72
73 /**
74 * EPacakge NsURI -> EPackage instances; this is instance-level to detect collisions
75 */
76 private final IMultiLookup<String, EPackage> uniqueIDToPackage = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
77
78 /**
79 * static maps between metamodel elements and their unique IDs
80 */
81 private final Map<EClassifier, String> uniqueIDFromClassifier = new HashMap<EClassifier, String>();
82 private final Map<ETypedElement, String> uniqueIDFromTypedElement = new HashMap<ETypedElement, String>();
83 private final Map<Enumerator, String> uniqueIDFromEnumerator = new HashMap<Enumerator, String>();
84 private final IMultiLookup<String, EClassifier> uniqueIDToClassifier = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
85 private final IMultiLookup<String, ETypedElement> uniqueIDToTypedElement = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
86 private final IMultiLookup<String, Enumerator> uniqueIDToEnumerator = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
87 private final Map<String, Enumerator> uniqueIDToCanonicalEnumerator = new HashMap<String, Enumerator>();
88
89 /**
90 * Map from enum classes generated for {@link EEnum}s to the actual EEnum.
91 */
92 private Map<Class<?>, EEnum> generatedEENumClasses = new HashMap<Class<?>, EEnum>();
93
94 /**
95 * @return the eObjectClassKey
96 */
97 public Object getEObjectClassKey() {
98 if (eObjectClassKey == null) {
99 eObjectClassKey = toKey(EOBJECT_CLASS);
100 }
101 return eObjectClassKey;
102 }
103 private Object eObjectClassKey = null;
104
105 protected Object toKey(final EClassifier classifier) {
106 if (isDynamicModel) {
107 return toKeyDynamicInternal(classifier);
108 } else {
109 maintainMetamodel(classifier);
110 return classifier;
111 }
112 }
113
114 protected String toKeyDynamicInternal(final EClassifier classifier) {
115 String id = uniqueIDFromClassifier.get(classifier);
116 if (id == null) {
117 Preconditions.checkArgument(!classifier.eIsProxy(),
118 "Classifier %s is an unresolved proxy", classifier);
119 id = classifier.getEPackage().getNsURI() + "##" + classifier.getName();
120 uniqueIDFromClassifier.put(classifier, id);
121 uniqueIDToClassifier.addPair(id, classifier);
122 // metamodel maintenance will call back toKey(), but now the ID maps are already filled
123 maintainMetamodel(classifier);
124 }
125 return id;
126 }
127
128 protected String enumToKeyDynamicInternal(Enumerator enumerator) {
129 String id = uniqueIDFromEnumerator.get(enumerator);
130 if (id == null) {
131 if (enumerator instanceof EEnumLiteral) {
132 EEnumLiteral enumLiteral = (EEnumLiteral) enumerator;
133 final EEnum eEnum = enumLiteral.getEEnum();
134 maintainMetamodel(eEnum);
135
136 id = constructEnumID(eEnum.getEPackage().getNsURI(), eEnum.getName(), enumLiteral.getLiteral());
137
138 // there might be a generated enum for this enum literal!
139 // generated enum should pre-empt the ecore enum literal as canonical enumerator
140 Enumerator instanceEnum = enumLiteral.getInstance();
141 if (instanceEnum != null && !uniqueIDToCanonicalEnumerator.containsKey(id)) {
142 uniqueIDToCanonicalEnumerator.put(id, instanceEnum);
143 }
144 // if generated enum not found... delay selection of canonical enumerator
145 } else { // generated enum
146 final EEnum eEnum = generatedEENumClasses.get(enumerator.getClass());
147 if (eEnum != null)
148 id = constructEnumID(eEnum.getEPackage().getNsURI(), eEnum.getName(), enumerator.getLiteral());
149 else
150 id = constructEnumID("unkownPackage URI", enumerator.getClass().getSimpleName(),
151 enumerator.getLiteral());
152
153 // generated enum should pre-empt the ecore enum literal as canonical enumerator
154 if (!uniqueIDToCanonicalEnumerator.containsKey(id)) {
155 uniqueIDToCanonicalEnumerator.put(id, enumerator);
156 }
157 }
158 uniqueIDFromEnumerator.put(enumerator, id);
159 uniqueIDToEnumerator.addPair(id, enumerator);
160 }
161 return id;
162 }
163
164 protected String constructEnumID(String nsURI, String name, String literal) {
165 return String.format("%s##%s##%s", nsURI, name, literal);
166 }
167
168 protected Object toKey(final EStructuralFeature feature) {
169 if (isDynamicModel) {
170 String id = uniqueIDFromTypedElement.get(feature);
171 if (id == null) {
172 Preconditions.checkArgument(!feature.eIsProxy(),
173 "Element %s is an unresolved proxy", feature);
174 id = toKeyDynamicInternal((EClassifier) feature.eContainer()) + "##" + feature.getEType().getName()
175 + "##" + feature.getName();
176 uniqueIDFromTypedElement.put(feature, id);
177 uniqueIDToTypedElement.addPair(id, feature);
178 // metamodel maintenance will call back toKey(), but now the ID maps are already filled
179 maintainMetamodel(feature);
180 }
181 return id;
182 } else {
183 maintainMetamodel(feature);
184 return feature;
185 }
186 }
187
188 protected Enumerator enumToCanonicalDynamicInternal(final Enumerator value) {
189 final String key = enumToKeyDynamicInternal(value);
190 Enumerator canonicalEnumerator = uniqueIDToCanonicalEnumerator.computeIfAbsent(key,
191 // if no canonical version appointed yet, appoint first version
192 k -> uniqueIDToEnumerator.lookup(k).iterator().next());
193 return canonicalEnumerator;
194 }
195
196 /**
197 * If in dynamic EMF mode, substitutes enum literals with a canonical version of the enum literal.
198 */
199 protected Object toInternalValueRepresentation(final Object value) {
200 if (isDynamicModel) {
201 if (value instanceof Enumerator)
202 return enumToCanonicalDynamicInternal((Enumerator) value);
203 else
204 return value;
205 } else {
206 return value;
207 }
208 }
209
210 /**
211 * Checks the {@link EStructuralFeature}'s source and target {@link EPackage} for NsURI collision. An error message
212 * will be logged if a model element from an other {@link EPackage} instance with the same NsURI has been already
213 * processed. The error message will be logged only for the first time for a given {@link EPackage} instance.
214 *
215 * @param classifier
216 * the classifier instance
217 */
218 protected void maintainMetamodel(final EStructuralFeature feature) {
219 if (!knownFeatures.contains(feature)) {
220 knownFeatures.add(feature);
221 maintainMetamodel(feature.getEContainingClass());
222 maintainMetamodel(feature.getEType());
223 }
224 }
225
226 /**
227 * put subtype information into cache
228 */
229 protected void maintainMetamodel(final EClassifier classifier) {
230 if (!knownClassifiers.contains(classifier)) {
231 checkEPackage(classifier);
232 knownClassifiers.add(classifier);
233
234 if (classifier instanceof EClass) {
235 final EClass clazz = (EClass) classifier;
236 final Object clazzKey = toKey(clazz);
237 for (final EClass superType : clazz.getEAllSuperTypes()) {
238 maintainTypeHierarhyInternal(clazzKey, toKey(superType));
239 }
240 maintainTypeHierarhyInternal(clazzKey, getEObjectClassKey());
241 } else if (classifier instanceof EEnum) {
242 EEnum eEnum = (EEnum) classifier;
243
244 if (isDynamicModel) {
245 // if there is a generated enum class, save this model element for describing that class
246 if (eEnum.getInstanceClass() != null)
247 generatedEENumClasses.put(eEnum.getInstanceClass(), eEnum);
248
249 for (EEnumLiteral eEnumLiteral : eEnum.getELiterals()) {
250 // create string ID; register generated enum values
251 enumToKeyDynamicInternal(eEnumLiteral);
252 }
253 }
254 }
255 }
256 }
257
258 /**
259 * Checks the {@link EClassifier}'s {@link EPackage} for NsURI collision. An error message will be logged if a model
260 * element from an other {@link EPackage} instance with the same NsURI has been already processed. The error message
261 * will be logged only for the first time for a given {@link EPackage} instance.
262 *
263 * @param classifier
264 * the classifier instance
265 */
266 protected void checkEPackage(final EClassifier classifier) {
267 final EPackage ePackage = classifier.getEPackage();
268 if (knownPackages.add(ePackage)) { // this is a new EPackage
269 final String nsURI = ePackage.getNsURI();
270 final IMemoryView<EPackage> packagesOfURI = uniqueIDToPackage.lookupOrEmpty(nsURI);
271 if (!packagesOfURI.containsNonZero(ePackage)) { // this should be true
272 uniqueIDToPackage.addPair(nsURI, ePackage);
273 // collision detection between EPackages (disabled in dynamic model mode)
274 if (!isDynamicModel && packagesOfURI.size() == 2) { // only report the issue if the new EPackage
275 // instance is the second for the same URI
276 navigationHelper.processingError(
277 new ViatraBaseException("NsURI (" + nsURI
278 + ") collision detected between different instances of EPackages. If this is normal, try using dynamic EMF mode."),
279 "process new metamodel elements.");
280 }
281 }
282 }
283 }
284
285 /**
286 * Maintains subtype hierarchy
287 *
288 * @param subClassKey
289 * EClass or String id of subclass
290 * @param superClassKey
291 * EClass or String id of superclass
292 */
293 protected void maintainTypeHierarhyInternal(final Object subClassKey, final Object superClassKey) {
294 // update observed class and instance listener tables according to new subtype information
295 Map<Object, IndexingLevel> allObservedClasses = navigationHelper.getAllObservedClassesInternal();
296 if (allObservedClasses.containsKey(superClassKey)) {
297 // we know that there are no known subtypes of subClassKey at this point, so a single insert should suffice
298 allObservedClasses.put(subClassKey, allObservedClasses.get(superClassKey));
299 }
300 final Map<Object, Map<InstanceListener, Set<EClass>>> instanceListeners = navigationHelper.peekInstanceListeners();
301 if (instanceListeners != null) { // table already constructed
302 for (final Entry<InstanceListener, Set<EClass>> entry : instanceListeners.getOrDefault(superClassKey, Collections.emptyMap()).entrySet()) {
303 final InstanceListener listener = entry.getKey();
304 for (final EClass subscriptionType : entry.getValue()) {
305 navigationHelper.addInstanceListenerInternal(listener, subscriptionType, subClassKey);
306 }
307 }
308 }
309
310 // update subtype maps
311 Set<Object> subTypes = subTypeMap.computeIfAbsent(superClassKey, k -> new HashSet<>());
312 subTypes.add(subClassKey);
313 Set<Object> superTypes = superTypeMap.computeIfAbsent(subClassKey, k -> new HashSet<>());
314 superTypes.add(superClassKey);
315 }
316
317 /**
318 * @return the subTypeMap
319 */
320 protected Map<Object, Set<Object>> getSubTypeMap() {
321 return subTypeMap;
322 }
323
324 protected Map<Object, Set<Object>> getSuperTypeMap() {
325 return superTypeMap;
326 }
327
328 /**
329 * Returns the corresponding {@link EStructuralFeature} instance for the id.
330 *
331 * @param featureId
332 * the id of the feature
333 * @return the {@link EStructuralFeature} instance
334 */
335 public EStructuralFeature getKnownFeature(final String featureId) {
336 final IMemoryView<ETypedElement> features = uniqueIDToTypedElement.lookup(featureId);
337 if (features != null && !features.isEmpty()) {
338 final ETypedElement next = features.iterator().next();
339 if (next instanceof EStructuralFeature) {
340 return (EStructuralFeature) next;
341 }
342 }
343 return null;
344
345 }
346
347 public EStructuralFeature getKnownFeatureForKey(Object featureKey) {
348 EStructuralFeature feature;
349 if (isDynamicModel) {
350 feature = getKnownFeature((String) featureKey);
351 } else {
352 feature = (EStructuralFeature) featureKey;
353 }
354 return feature;
355 }
356
357 /**
358 * Returns the corresponding {@link EClassifier} instance for the id.
359 */
360 public EClassifier getKnownClassifier(final String key) {
361 final IMemoryView<EClassifier> classifiersOfThisID = uniqueIDToClassifier.lookup(key);
362 if (classifiersOfThisID != null && !classifiersOfThisID.isEmpty()) {
363 return classifiersOfThisID.iterator().next();
364 } else {
365 return null;
366 }
367 }
368
369 public EClassifier getKnownClassifierForKey(Object classifierKey) {
370 EClassifier cls;
371 if (isDynamicModel) {
372 cls = getKnownClassifier((String) classifierKey);
373 } else {
374 cls = (EClassifier) classifierKey;
375 }
376 return cls;
377 }
378
379
380}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexStatisticsStore.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexStatisticsStore.java
deleted file mode 100644
index de66de78..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFBaseIndexStatisticsStore.java
+++ /dev/null
@@ -1,71 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.base.core;
10
11import java.util.HashMap;
12import java.util.Map;
13
14import org.apache.log4j.Logger;
15import org.eclipse.emf.ecore.EClassifier;
16import org.eclipse.emf.ecore.EStructuralFeature;
17
18/**
19 * @author Grill Balázs
20 * @noextend This class is not intended to be subclassed by clients.
21 */
22public class EMFBaseIndexStatisticsStore extends AbstractBaseIndexStore {
23
24 /**
25 * A common map is used to store instance/value statistics. The key can be an {@link EClassifier},
26 * {@link EStructuralFeature} or a String ID.
27 */
28 private final Map<Object, Integer> stats = new HashMap<Object, Integer>();
29
30 public EMFBaseIndexStatisticsStore(NavigationHelperImpl navigationHelper, Logger logger) {
31 super(navigationHelper, logger);
32 }
33 public void addFeature(Object element, Object feature){
34 addInstance(feature);
35 }
36
37 public void removeFeature(Object element, Object feature){
38 removeInstance(feature);
39 }
40
41 public void addInstance(Object key){
42 Integer v = stats.get(key);
43 stats.put(key, v == null ? 1 : v+1);
44 }
45
46 public void removeInstance(Object key){
47 Integer v = stats.get(key);
48 if(v == null || v <= 0) {
49 navigationHelper.logIncidentStatRemoval(key);
50 return;
51 }
52 if (v.intValue() == 1){
53 stats.remove(key);
54 }else{
55 stats.put(key, v-1);
56 }
57 }
58 public int countInstances(Object key){
59 Integer v = stats.get(key);
60 return v == null ? 0 : v.intValue();
61 }
62
63 public void removeType(Object key){
64 stats.remove(key);
65 }
66
67 public int countFeatures(Object feature) {
68 return countInstances(feature);
69 }
70
71}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFDataSource.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFDataSource.java
deleted file mode 100644
index 35e590f2..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/EMFDataSource.java
+++ /dev/null
@@ -1,137 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base.core;
11
12import java.util.LinkedList;
13import java.util.List;
14import java.util.Set;
15
16import org.eclipse.emf.ecore.EClass;
17import org.eclipse.emf.ecore.EObject;
18import org.eclipse.emf.ecore.EReference;
19import tools.refinery.viatra.runtime.base.api.NavigationHelper;
20import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
21import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
23import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
24import tools.refinery.viatra.runtime.matchers.util.IMultiset;
25
26// TODO IBiDirectionalGraphDataSource
27public class EMFDataSource implements IGraphDataSource<EObject> {
28
29 private List<IGraphObserver<EObject>> observers;
30 private Set<EReference> references;
31 private Set<EClass> classes;
32 private NavigationHelper navigationHelper;
33 private IMultiset<EObject> allEObjects; // contains objects even if only appearing as sources or targets
34
35 /**
36 * @param navigationHelper
37 * @param references
38 * @param classes
39 * additional classes to treat as nodes. Source and target classes of references need not be added.
40 */
41 public EMFDataSource(NavigationHelper navigationHelper, Set<EReference> references, Set<EClass> classes) {
42 this.references = references;
43 this.classes = classes;
44 this.observers = new LinkedList<IGraphObserver<EObject>>();
45 this.navigationHelper = navigationHelper;
46 }
47
48 @Override
49 public Set<EObject> getAllNodes() {
50 return getAllEObjects().distinctValues();
51 }
52
53 @Override
54 public IMemoryView<EObject> getTargetNodes(EObject source) {
55 IMultiset<EObject> targetNodes = CollectionsFactory.createMultiset();
56
57 for (EReference ref : references) {
58 final Set<EObject> referenceValues = navigationHelper.getReferenceValues(source, ref);
59 for (EObject referenceValue : referenceValues) {
60 targetNodes.addOne(referenceValue);
61 }
62 }
63
64 return targetNodes;
65 }
66
67 @Override
68 public void attachObserver(IGraphObserver<EObject> go) {
69 observers.add(go);
70 }
71
72 @Override
73 public void attachAsFirstObserver(IGraphObserver<EObject> observer) {
74 observers.add(0, observer);
75 }
76
77 @Override
78 public void detachObserver(IGraphObserver<EObject> go) {
79 observers.remove(go);
80 }
81
82 public void notifyEdgeInserted(EObject source, EObject target) {
83 nodeAdditionInternal(source);
84 nodeAdditionInternal(target);
85 for (IGraphObserver<EObject> o : observers) {
86 o.edgeInserted(source, target);
87 }
88 }
89
90 public void notifyEdgeDeleted(EObject source, EObject target) {
91 for (IGraphObserver<EObject> o : observers) {
92 o.edgeDeleted(source, target);
93 }
94 nodeRemovalInternal(source);
95 nodeRemovalInternal(target);
96 }
97
98 public void notifyNodeInserted(EObject node) {
99 nodeAdditionInternal(node);
100 }
101
102 public void notifyNodeDeleted(EObject node) {
103 nodeRemovalInternal(node);
104 }
105
106 private void nodeAdditionInternal(EObject node) {
107 if (allEObjects.addOne(node))
108 for (IGraphObserver<EObject> o : observers) {
109 o.nodeInserted(node);
110 }
111 }
112
113 private void nodeRemovalInternal(EObject node) {
114 if (getAllEObjects().removeOne(node))
115 for (IGraphObserver<EObject> o : observers) {
116 o.nodeDeleted(node);
117 }
118 }
119
120 protected IMultiset<EObject> getAllEObjects() {
121 if (allEObjects == null) {
122 allEObjects = CollectionsFactory.createMultiset();
123 for (EClass clazz : classes) {
124 for (EObject obj : navigationHelper.getAllInstances(clazz)) {
125 allEObjects.addOne(obj);
126 }
127 }
128 for (EReference ref : references) {
129 navigationHelper.processAllFeatureInstances(ref, (source, target) -> {
130 allEObjects.addOne(source);
131 allEObjects.addOne((EObject) target);
132 });
133 }
134 }
135 return allEObjects;
136 }
137}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperContentAdapter.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperContentAdapter.java
deleted file mode 100644
index 39271c5b..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperContentAdapter.java
+++ /dev/null
@@ -1,750 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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 * Note: this file contains methods copied from EContentAdapter.java of the EMF project
10 *******************************************************************************/
11package tools.refinery.viatra.runtime.base.core;
12
13import java.lang.reflect.InvocationTargetException;
14import java.util.Collection;
15import java.util.List;
16import java.util.Objects;
17import java.util.concurrent.Callable;
18
19import org.eclipse.emf.common.notify.Adapter;
20import org.eclipse.emf.common.notify.Notification;
21import org.eclipse.emf.common.notify.Notifier;
22import org.eclipse.emf.common.notify.impl.AdapterImpl;
23import org.eclipse.emf.common.util.EList;
24import org.eclipse.emf.ecore.EObject;
25import org.eclipse.emf.ecore.EReference;
26import org.eclipse.emf.ecore.EStructuralFeature;
27import org.eclipse.emf.ecore.InternalEObject;
28import org.eclipse.emf.ecore.resource.Resource;
29import org.eclipse.emf.ecore.resource.ResourceSet;
30import org.eclipse.emf.ecore.util.EContentAdapter;
31import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
32import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexObjectFilter;
33import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexResourceFilter;
34import tools.refinery.viatra.runtime.base.comprehension.EMFModelComprehension;
35import tools.refinery.viatra.runtime.base.comprehension.EMFVisitor;
36import tools.refinery.viatra.runtime.base.core.NavigationHelperVisitor.ChangeVisitor;
37
38/**
39 * Content Adapter that recursively attaches itself to the containment hierarchy of an EMF model.
40 * The purpose is to gather the contents of the model, and to subscribe to model change notifications.
41 *
42 * <p> Originally, this was implemented as a subclass of {@link EContentAdapter}.
43 * Because of Bug 490105, EContentAdapter is no longer a superclass; its code is copied over with modifications.
44 * See {@link EContentAdapter} header for original authorship and copyright information.
45 *
46 * @author Gabor Bergmann
47 * @see EContentAdapter
48 * @noextend This class is not intended to be subclassed by clients.
49 */
50public class NavigationHelperContentAdapter extends AdapterImpl {
51
52 private final NavigationHelperImpl navigationHelper;
53
54
55
56 // move optimization to avoid removing and re-adding entire subtrees
57 EObject ignoreInsertionAndDeletion;
58 // Set<EObject> ignoreRootInsertion = new HashSet<EObject>();
59 // Set<EObject> ignoreRootDeletion = new HashSet<EObject>();
60
61 private final EMFModelComprehension comprehension;
62
63 private IBaseIndexObjectFilter objectFilterConfiguration;
64 private IBaseIndexResourceFilter resourceFilterConfiguration;
65
66
67
68 private EMFVisitor removalVisitor;
69 private EMFVisitor insertionVisitor;
70
71 public NavigationHelperContentAdapter(final NavigationHelperImpl navigationHelper) {
72 this.navigationHelper = navigationHelper;
73 final BaseIndexOptions options = this.navigationHelper.getBaseIndexOptions();
74 objectFilterConfiguration = options.getObjectFilterConfiguration();
75 resourceFilterConfiguration = options.getResourceFilterConfiguration();
76 this.comprehension = navigationHelper.getComprehension();
77
78 removalVisitor = initChangeVisitor(false);
79 insertionVisitor = initChangeVisitor(true);
80 }
81
82 /**
83 * Point of customization, called by constructor.
84 */
85 protected ChangeVisitor initChangeVisitor(boolean isInsertion) {
86 return new NavigationHelperVisitor.ChangeVisitor(navigationHelper, isInsertion);
87 }
88
89 // key representative of the EObject class
90
91
92 @Override
93 public void notifyChanged(final Notification notification) {
94 try {
95 this.navigationHelper.coalesceTraversals(new Callable<Void>() {
96 @Override
97 public Void call() throws Exception {
98 simpleNotifyChanged(notification);
99
100 final Object oFeature = notification.getFeature();
101 final Object oNotifier = notification.getNotifier();
102 if (oNotifier instanceof EObject && oFeature instanceof EStructuralFeature) {
103 final EObject notifier = (EObject) oNotifier;
104 final EStructuralFeature feature = (EStructuralFeature) oFeature;
105
106 final boolean notifyLightweightObservers = handleNotification(notification, notifier, feature);
107
108 if (notifyLightweightObservers) {
109 navigationHelper.notifyLightweightObservers(notifier, feature, notification);
110 }
111 } else if (oNotifier instanceof Resource) {
112 if (notification.getFeatureID(Resource.class) == Resource.RESOURCE__IS_LOADED) {
113 final Resource resource = (Resource) oNotifier;
114 if (comprehension.isLoading(resource))
115 navigationHelper.resolutionDelayingResources.add(resource);
116 else
117 navigationHelper.resolutionDelayingResources.remove(resource);
118 }
119 }
120 return null;
121 }
122 });
123 } catch (final InvocationTargetException ex) {
124 navigationHelper.processingFatal(ex.getCause(), "handling the following update notification: " + notification);
125 } catch (final Exception ex) {
126 navigationHelper.processingFatal(ex, "handling the following update notification: " + notification);
127 }
128
129 navigationHelper.notifyBaseIndexChangeListeners();
130 }
131
132 @SuppressWarnings("deprecation")
133 protected boolean handleNotification(final Notification notification, final EObject notifier,
134 final EStructuralFeature feature) {
135 final Object oldValue = notification.getOldValue();
136 final Object newValue = notification.getNewValue();
137 final int positionInt = notification.getPosition();
138 final Integer position = positionInt == Notification.NO_INDEX ? null : positionInt;
139 final int eventType = notification.getEventType();
140 boolean notifyLightweightObservers = true;
141 switch (eventType) {
142 case Notification.ADD:
143 featureUpdate(true, notifier, feature, newValue, position);
144 break;
145 case Notification.ADD_MANY:
146 for (final Object newElement : (Collection<?>) newValue) {
147 featureUpdate(true, notifier, feature, newElement, position);
148 }
149 break;
150 case Notification.CREATE:
151 notifyLightweightObservers = false;
152 break;
153 case Notification.MOVE:
154 // lightweight observers should be notified on MOVE
155 break; // currently no support for ordering
156 case Notification.REMOVE:
157 featureUpdate(false, notifier, feature, oldValue, position);
158 break;
159 case Notification.REMOVE_MANY:
160 for (final Object oldElement : (Collection<?>) oldValue) {
161 featureUpdate(false, notifier, feature, oldElement, position);
162 }
163 break;
164 case Notification.REMOVING_ADAPTER:
165 notifyLightweightObservers = false;
166 break;
167 case Notification.RESOLVE: // must be EReference
168 if (navigationHelper.isFeatureResolveIgnored(feature))
169 break; // otherwise same as SET
170 if (!feature.isMany()) { // if single-valued, can be removed from delayed resolutions
171 navigationHelper.delayedProxyResolutions.removePairOrNop(notifier, (EReference) feature);
172 }
173 featureUpdate(false, notifier, feature, oldValue, position);
174 featureUpdate(true, notifier, feature, newValue, position);
175 break;
176 case Notification.UNSET:
177 case Notification.SET:
178 if(feature.isMany() && position == null){
179 // spurious UNSET notification of entire collection
180 notifyLightweightObservers = false;
181 } else {
182 featureUpdate(false, notifier, feature, oldValue, position);
183 featureUpdate(true, notifier, feature, newValue, position);
184 }
185 break;
186 default:
187 notifyLightweightObservers = false;
188 break;
189 }
190 return notifyLightweightObservers;
191 }
192
193 protected void featureUpdate(final boolean isInsertion, final EObject notifier, final EStructuralFeature feature,
194 final Object value, final Integer position) {
195 // this is a safe visitation, no reads will happen, thus no danger of notifications or matcher construction
196 comprehension.traverseFeature(getVisitorForChange(isInsertion), notifier, feature, value, position);
197 }
198
199 // OFFICIAL ENTRY POINT OF BASE INDEX RELATED PARTS
200 protected void addAdapter(final Notifier notifier) {
201 if (notifier == ignoreInsertionAndDeletion) {
202 return;
203 }
204 try {
205 // cross-resource containment workaround, see Bug 483089 and Bug 483086.
206 if (notifier.eAdapters().contains(this))
207 return;
208
209 if (objectFilterConfiguration != null && objectFilterConfiguration.isFiltered(notifier)) {
210 return;
211 }
212 this.navigationHelper.coalesceTraversals(new Callable<Void>() {
213 @Override
214 public Void call() throws Exception {
215 // the object is really traversed BEFORE the notification listener is added,
216 // so that if a proxy is resolved due to the traversal, we do not get notified about it
217 if (notifier instanceof EObject) {
218 comprehension.traverseObject(getVisitorForChange(true), (EObject) notifier);
219 } else if (notifier instanceof Resource) {
220 Resource resource = (Resource) notifier;
221 if (resourceFilterConfiguration != null
222 && resourceFilterConfiguration.isResourceFiltered(resource)) {
223 return null;
224 }
225 if (comprehension.isLoading(resource))
226 navigationHelper.resolutionDelayingResources.add(resource);
227 }
228 // subscribes to the adapter list, will receive setTarget callback that will spread addAdapter to
229 // children
230 simpleAddAdapter(notifier);
231 return null;
232 }
233 });
234 } catch (final InvocationTargetException ex) {
235 navigationHelper.processingFatal(ex.getCause(), "add the object: " + notifier);
236 } catch (final Exception ex) {
237 navigationHelper.processingFatal(ex, "add the object: " + notifier);
238 }
239 }
240
241 // OFFICIAL ENTRY POINT OF BASE INDEX RELATED PARTS
242 protected void removeAdapter(final Notifier notifier) {
243 if (notifier == ignoreInsertionAndDeletion) {
244 return;
245 }
246 try {
247 removeAdapterInternal(notifier);
248 } catch (final InvocationTargetException ex) {
249 navigationHelper.processingFatal(ex.getCause(), "remove the object: " + notifier);
250 } catch (final Exception ex) {
251 navigationHelper.processingFatal(ex, "remove the object: " + notifier);
252 }
253 }
254
255 // The additional boolean options are there to save the cost of extra checks, see Bug 483089 and Bug 483086.
256 protected void removeAdapter(final Notifier notifier, boolean additionalObjectContainerPossible,
257 boolean additionalResourceContainerPossible) {
258 if (notifier == ignoreInsertionAndDeletion) {
259 return;
260 }
261 try {
262
263 // cross-resource containment workaround, see Bug 483089 and Bug 483086.
264 if (notifier instanceof InternalEObject) {
265 InternalEObject internalEObject = (InternalEObject) notifier;
266 if (additionalResourceContainerPossible) {
267 Resource eDirectResource = internalEObject.eDirectResource();
268 if (eDirectResource != null && eDirectResource.eAdapters().contains(this)) {
269 return;
270 }
271 }
272 if (additionalObjectContainerPossible) {
273 InternalEObject eInternalContainer = internalEObject.eInternalContainer();
274 if (eInternalContainer != null && eInternalContainer.eAdapters().contains(this)) {
275 return;
276 }
277 }
278 }
279
280 removeAdapterInternal(notifier);
281 } catch (final InvocationTargetException ex) {
282 navigationHelper.processingFatal(ex.getCause(), "remove the object: " + notifier);
283 } catch (final Exception ex) {
284 navigationHelper.processingFatal(ex, "remove the object: " + notifier);
285 }
286 }
287
288 /**
289 * @throws InvocationTargetException
290 */
291 protected void removeAdapterInternal(final Notifier notifier) throws InvocationTargetException {
292 // some non-standard EMF implementations send these
293 if (!notifier.eAdapters().contains(this)) {
294 // the adapter was not even attached to the notifier
295 navigationHelper.logIncidentAdapterRemoval(notifier);
296
297 // skip the rest of the method, do not traverse contents
298 // as they have either never been added to the index or already removed
299 return;
300 }
301
302 if (objectFilterConfiguration != null && objectFilterConfiguration.isFiltered(notifier)) {
303 return;
304 }
305 this.navigationHelper.coalesceTraversals(new Callable<Void>() {
306 @Override
307 public Void call() throws Exception {
308 if (notifier instanceof EObject) {
309 final EObject eObject = (EObject) notifier;
310 comprehension.traverseObject(getVisitorForChange(false), eObject);
311 navigationHelper.delayedProxyResolutions.lookupAndRemoveAll(eObject);
312 } else if (notifier instanceof Resource) {
313 if (resourceFilterConfiguration != null
314 && resourceFilterConfiguration.isResourceFiltered((Resource) notifier)) {
315 return null;
316 }
317 navigationHelper.resolutionDelayingResources.remove(notifier);
318 }
319 // unsubscribes from the adapter list, will receive unsetTarget callback that will spread
320 // removeAdapter to children
321 simpleRemoveAdapter(notifier);
322 return null;
323 }
324 });
325 }
326
327 protected EMFVisitor getVisitorForChange(final boolean isInsertion) {
328 return isInsertion ? insertionVisitor : removalVisitor;
329 }
330
331
332 // WORKAROUND (TMP) for eContents vs. derived features bug
333 protected void setTarget(final EObject target) {
334 basicSetTarget(target);
335 spreadToChildren(target, true);
336 }
337
338 protected void unsetTarget(final EObject target) {
339 basicUnsetTarget(target);
340 spreadToChildren(target, false);
341 }
342
343 // Spread adapter removal/addition to children of EObject
344 protected void spreadToChildren(final EObject target, final boolean add) {
345 final EList<EReference> features = target.eClass().getEAllReferences();
346 for (final EReference feature : features) {
347 if (!feature.isContainment()) {
348 continue;
349 }
350 if (!comprehension.representable(feature)) {
351 continue;
352 }
353 if (feature.isMany()) {
354 final Collection<?> values = (Collection<?>) target.eGet(feature);
355 for (final Object value : values) {
356 final Notifier notifier = (Notifier) value;
357 if (add) {
358 addAdapter(notifier);
359 } else {
360 removeAdapter(notifier, false, true);
361 }
362 }
363 } else {
364 final Object value = target.eGet(feature);
365 if (value != null) {
366 final Notifier notifier = (Notifier) value;
367 if (add) {
368 addAdapter(notifier);
369 } else {
370 removeAdapter(notifier, false, true);
371 }
372 }
373 }
374 }
375 }
376
377
378 //
379 // ***********************************************************
380 // RENAMED METHODS COPIED OVER FROM EContentAdapter DOWN BELOW
381 // ***********************************************************
382 //
383
384 /**
385 * Handles a notification by calling {@link #selfAdapt selfAdapter}.
386 */
387 public void simpleNotifyChanged(Notification notification)
388 {
389 selfAdapt(notification);
390
391 super.notifyChanged(notification);
392 }
393
394 protected void simpleAddAdapter(Notifier notifier)
395 {
396 EList<Adapter> eAdapters = notifier.eAdapters();
397 if (!eAdapters.contains(this))
398 {
399 eAdapters.add(this);
400 }
401 }
402
403 protected void simpleRemoveAdapter(Notifier notifier)
404 {
405 notifier.eAdapters().remove(this);
406 }
407
408
409 //
410 // *********************************************************
411 // CODE COPIED OVER VERBATIM FROM EContentAdapter DOWN BELOW
412 // *********************************************************
413 //
414
415
416 /**
417 * Handles a notification by calling {@link #handleContainment handleContainment}
418 * for any containment-based notification.
419 */
420 protected void selfAdapt(Notification notification)
421 {
422 Object notifier = notification.getNotifier();
423 if (notifier instanceof ResourceSet)
424 {
425 if (notification.getFeatureID(ResourceSet.class) == ResourceSet.RESOURCE_SET__RESOURCES)
426 {
427 handleContainment(notification);
428 }
429 }
430 else if (notifier instanceof Resource)
431 {
432 if (notification.getFeatureID(Resource.class) == Resource.RESOURCE__CONTENTS)
433 {
434 handleContainment(notification);
435 }
436 }
437 else if (notifier instanceof EObject)
438 {
439 Object feature = notification.getFeature();
440 if (feature instanceof EReference)
441 {
442 EReference eReference = (EReference)feature;
443 if (eReference.isContainment())
444 {
445 handleContainment(notification);
446 }
447 }
448 }
449 }
450
451 /**
452 * Handles a containment change by adding and removing the adapter as appropriate.
453 */
454 protected void handleContainment(Notification notification)
455 {
456 switch (notification.getEventType())
457 {
458 case Notification.RESOLVE:
459 {
460 // We need to be careful that the proxy may be resolved while we are attaching this adapter.
461 // We need to avoid attaching the adapter during the resolve
462 // and also attaching it again as we walk the eContents() later.
463 // Checking here avoids having to check during addAdapter.
464 //
465 Notifier oldValue = (Notifier)notification.getOldValue();
466 if (oldValue.eAdapters().contains(this))
467 {
468 removeAdapter(oldValue);
469 Notifier newValue = (Notifier)notification.getNewValue();
470 addAdapter(newValue);
471 }
472 break;
473 }
474 case Notification.UNSET:
475 {
476 Object oldValue = notification.getOldValue();
477 if (!Objects.equals(oldValue, Boolean.TRUE) && !Objects.equals(oldValue, Boolean.FALSE))
478 {
479 if (oldValue != null)
480 {
481 removeAdapter((Notifier)oldValue, false, true);
482 }
483 Notifier newValue = (Notifier)notification.getNewValue();
484 if (newValue != null)
485 {
486 addAdapter(newValue);
487 }
488 }
489 break;
490 }
491 case Notification.SET:
492 {
493 Notifier oldValue = (Notifier)notification.getOldValue();
494 if (oldValue != null)
495 {
496 removeAdapter(oldValue, false, true);
497 }
498 Notifier newValue = (Notifier)notification.getNewValue();
499 if (newValue != null)
500 {
501 addAdapter(newValue);
502 }
503 break;
504 }
505 case Notification.ADD:
506 {
507 Notifier newValue = (Notifier)notification.getNewValue();
508 if (newValue != null)
509 {
510 addAdapter(newValue);
511 }
512 break;
513 }
514 case Notification.ADD_MANY:
515 {
516 @SuppressWarnings("unchecked") Collection<Notifier> newValues = (Collection<Notifier>)notification.getNewValue();
517 for (Notifier newValue : newValues)
518 {
519 addAdapter(newValue);
520 }
521 break;
522 }
523 case Notification.REMOVE:
524 {
525 Notifier oldValue = (Notifier)notification.getOldValue();
526 if (oldValue != null)
527 {
528 boolean checkContainer = notification.getNotifier() instanceof Resource;
529 boolean checkResource = notification.getFeature() != null;
530 removeAdapter(oldValue, checkContainer, checkResource);
531 }
532 break;
533 }
534 case Notification.REMOVE_MANY:
535 {
536 boolean checkContainer = notification.getNotifier() instanceof Resource;
537 boolean checkResource = notification.getFeature() != null;
538 @SuppressWarnings("unchecked") Collection<Notifier> oldValues = (Collection<Notifier>)notification.getOldValue();
539 for ( Notifier oldContentValue : oldValues)
540 {
541 removeAdapter(oldContentValue, checkContainer, checkResource);
542 }
543 break;
544 }
545 }
546 }
547
548 /**
549 * Handles installation of the adapter
550 * by adding the adapter to each of the directly contained objects.
551 */
552 @Override
553 public void setTarget(Notifier target)
554 {
555 if (target instanceof EObject)
556 {
557 setTarget((EObject)target);
558 }
559 else if (target instanceof Resource)
560 {
561 setTarget((Resource)target);
562 }
563 else if (target instanceof ResourceSet)
564 {
565 setTarget((ResourceSet)target);
566 }
567 else
568 {
569 basicSetTarget(target);
570 }
571 }
572
573 /**
574 * Actually sets the target by calling super.
575 */
576 protected void basicSetTarget(Notifier target)
577 {
578 super.setTarget(target);
579 }
580
581 /**
582 * Handles installation of the adapter on a Resource
583 * by adding the adapter to each of the directly contained objects.
584 */
585 protected void setTarget(Resource target)
586 {
587 basicSetTarget(target);
588 List<EObject> contents = target.getContents();
589 for (int i = 0, size = contents.size(); i < size; ++i)
590 {
591 Notifier notifier = contents.get(i);
592 addAdapter(notifier);
593 }
594 }
595
596 /**
597 * Handles installation of the adapter on a ResourceSet
598 * by adding the adapter to each of the directly contained objects.
599 */
600 protected void setTarget(ResourceSet target)
601 {
602 basicSetTarget(target);
603 List<Resource> resources = target.getResources();
604 for (int i = 0; i < resources.size(); ++i)
605 {
606 Notifier notifier = resources.get(i);
607 addAdapter(notifier);
608 }
609 }
610
611 /**
612 * Handles undoing the installation of the adapter
613 * by removing the adapter from each of the directly contained objects.
614 */
615 @Override
616 public void unsetTarget(Notifier target)
617 {
618 Object target1 = target;
619 if (target1 instanceof EObject)
620 {
621 unsetTarget((EObject)target1);
622 }
623 else if (target1 instanceof Resource)
624 {
625 unsetTarget((Resource)target1);
626 }
627 else if (target1 instanceof ResourceSet)
628 {
629 unsetTarget((ResourceSet)target1);
630 }
631 else
632 {
633 basicUnsetTarget((Notifier)target1);
634 }
635 }
636
637 /**
638 * Actually unsets the target by calling super.
639 */
640 protected void basicUnsetTarget(Notifier target)
641 {
642 super.unsetTarget(target);
643 }
644
645 /**
646 * Handles undoing the installation of the adapter from a Resource
647 * by removing the adapter from each of the directly contained objects.
648 */
649 protected void unsetTarget(Resource target)
650 {
651 basicUnsetTarget(target);
652 List<EObject> contents = target.getContents();
653 for (int i = 0, size = contents.size(); i < size; ++i)
654 {
655 Notifier notifier = contents.get(i);
656 removeAdapter(notifier, true, false);
657 }
658 }
659
660 /**
661 * Handles undoing the installation of the adapter from a ResourceSet
662 * by removing the adapter from each of the directly contained objects.
663 */
664 protected void unsetTarget(ResourceSet target)
665 {
666 basicUnsetTarget(target);
667 List<Resource> resources = target.getResources();
668 for (int i = 0; i < resources.size(); ++i)
669 {
670 Notifier notifier = resources.get(i);
671 removeAdapter(notifier, false, false);
672 }
673 }
674
675 protected boolean resolve()
676 {
677 return true;
678 }
679
680 //
681 // *********************************************************
682 // OBSOLETE CODE COPIED OVER FROM EContentAdapter DOWN BELOW
683 // *********************************************************
684 //
685 // *** Preserved on purpose as comments,
686 // *** in order to more easily follow future changes to EContentAdapter.
687 //
688
689
690// protected void removeAdapter(Notifier notifier, boolean checkContainer, boolean checkResource)
691// {
692// if (checkContainer || checkResource)
693// {
694// InternalEObject internalEObject = (InternalEObject) notifier;
695// if (checkResource)
696// {
697// Resource eDirectResource = internalEObject.eDirectResource();
698// if (eDirectResource != null && eDirectResource.eAdapters().contains(this))
699// {
700// return;
701// }
702// }
703// if (checkContainer)
704// {
705// InternalEObject eInternalContainer = internalEObject.eInternalContainer();
706// if (eInternalContainer != null && eInternalContainer.eAdapters().contains(this))
707// {
708// return;
709// }
710// }
711// }
712//
713// removeAdapter(notifier);
714// }
715
716// /**
717// * Handles undoing the installation of the adapter from an EObject
718// * by removing the adapter from each of the directly contained objects.
719// */
720// protected void unsetTarget(EObject target)
721// {
722// basicUnsetTarget(target);
723// for (Iterator<? extends Notifier> i = resolve() ?
724// target.eContents().iterator() :
725// ((InternalEList<EObject>)target.eContents()).basicIterator();
726// i.hasNext(); )
727// {
728// Notifier notifier = i.next();
729// removeAdapter(notifier, false, true);
730// }
731// }
732
733// /**
734// * Handles installation of the adapter on an EObject
735// * by adding the adapter to each of the directly contained objects.
736// */
737// protected void setTarget(EObject target)
738// {
739// basicSetTarget(target);
740// for (Iterator<? extends Notifier> i = resolve() ?
741// target.eContents().iterator() :
742// ((InternalEList<? extends Notifier>)target.eContents()).basicIterator();
743// i.hasNext(); )
744// {
745// Notifier notifier = i.next();
746// addAdapter(notifier);
747// }
748// }
749
750}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperImpl.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperImpl.java
deleted file mode 100644
index 2b5d74b5..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperImpl.java
+++ /dev/null
@@ -1,1702 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.core;
10
11import org.apache.log4j.Logger;
12import org.eclipse.emf.common.notify.Notification;
13import org.eclipse.emf.common.notify.Notifier;
14import org.eclipse.emf.common.notify.NotifyingList;
15import org.eclipse.emf.common.util.EList;
16import org.eclipse.emf.ecore.*;
17import org.eclipse.emf.ecore.EStructuralFeature.Setting;
18import org.eclipse.emf.ecore.impl.ENotificationImpl;
19import org.eclipse.emf.ecore.resource.Resource;
20import org.eclipse.emf.ecore.resource.ResourceSet;
21import org.eclipse.emf.ecore.util.EcoreUtil;
22import tools.refinery.viatra.runtime.base.api.*;
23import tools.refinery.viatra.runtime.base.api.IEClassifierProcessor.IEClassProcessor;
24import tools.refinery.viatra.runtime.base.api.IEClassifierProcessor.IEDataTypeProcessor;
25import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexObjectFilter;
26import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexResourceFilter;
27import tools.refinery.viatra.runtime.base.comprehension.EMFModelComprehension;
28import tools.refinery.viatra.runtime.base.comprehension.EMFVisitor;
29import tools.refinery.viatra.runtime.base.core.EMFBaseIndexInstanceStore.FeatureData;
30import tools.refinery.viatra.runtime.base.core.NavigationHelperVisitor.TraversingVisitor;
31import tools.refinery.viatra.runtime.base.core.profiler.ProfilingNavigationHelperContentAdapter;
32import tools.refinery.viatra.runtime.base.exception.ViatraBaseException;
33import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
34import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
35import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
36import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
37import tools.refinery.viatra.runtime.matchers.util.Preconditions;
38
39import java.lang.reflect.InvocationTargetException;
40import java.util.*;
41import java.util.Map.Entry;
42import java.util.concurrent.Callable;
43import java.util.function.Function;
44import java.util.function.Supplier;
45import java.util.stream.Collectors;
46import java.util.stream.Stream;
47
48import static java.util.function.Function.identity;
49
50/**
51 * @noextend This class is not intended to be subclassed by clients.
52 * @author Gabor Bergmann and Tamas Szabo
53 */
54public class NavigationHelperImpl implements NavigationHelper {
55
56 /**
57 * This is never null.
58 */
59 protected IndexingLevel wildcardMode;
60
61
62 protected Set<Notifier> modelRoots;
63 private boolean expansionAllowed;
64 private boolean traversalDescendsAlongCrossResourceContainment;
65 // protected NavigationHelperVisitor visitor;
66 protected NavigationHelperContentAdapter contentAdapter;
67
68 protected final Logger logger;
69
70 // type object or String id
71 protected Map<Object, IndexingLevel> directlyObservedClasses = new HashMap<Object, IndexingLevel>();
72 // including subclasses; if null, must be recomputed
73 protected Map<Object, IndexingLevel> allObservedClasses = null;
74 protected Map<Object, IndexingLevel> observedDataTypes;
75 protected Map<Object, IndexingLevel> observedFeatures;
76 // ignore RESOLVE for these features, as they are just starting to be observed - see [428458]
77 protected Set<Object> ignoreResolveNotificationFeatures;
78
79 /**
80 * Feature registration and model traversal is delayed while true
81 */
82 protected boolean delayTraversals = false;
83 /**
84 * Classes (or String ID in dynamic mode) to be registered once the coalescing period is over
85 */
86 protected Map<Object, IndexingLevel> delayedClasses = new HashMap<>();
87 /**
88 * EStructuralFeatures (or String ID in dynamic mode) to be registered once the coalescing period is over
89 */
90 protected Map<Object, IndexingLevel> delayedFeatures = new HashMap<>();
91 /**
92 * EDataTypes (or String ID in dynamic mode) to be registered once the coalescing period is over
93 */
94 protected Map<Object, IndexingLevel> delayedDataTypes = new HashMap<>();
95
96 /**
97 * Features per EObject to be resolved later (towards the end of a coalescing period when no Resources are loading)
98 */
99 protected IMultiLookup<EObject, EReference> delayedProxyResolutions = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
100 /**
101 * Reasources that are currently loading, implying the proxy resolution attempts should be delayed
102 */
103 protected Set<Resource> resolutionDelayingResources = new HashSet<Resource>();
104
105 protected Queue<Runnable> traversalCallbacks = new LinkedList<Runnable>();
106
107 /**
108 * These global listeners will be called after updates.
109 */
110 // private final Set<Runnable> afterUpdateCallbacks;
111 private final Set<EMFBaseIndexChangeListener> baseIndexChangeListeners;
112 private final Map<EObject, Set<LightweightEObjectObserver>> lightweightObservers;
113
114 // These are the user subscriptions to notifications
115 private final Map<InstanceListener, Set<EClass>> subscribedInstanceListeners;
116 private final Map<FeatureListener, Set<EStructuralFeature>> subscribedFeatureListeners;
117 private final Map<DataTypeListener, Set<EDataType>> subscribedDataTypeListeners;
118
119 // these are the internal notification tables
120 // (element Type or String id) -> listener -> (subscription types)
121 // if null, must be recomputed from subscriptions
122 // potentially multiple subscription types for each element type because (a) nsURI collisions, (b) multiple
123 // supertypes
124 private Map<Object, Map<InstanceListener, Set<EClass>>> instanceListeners;
125 private Map<Object, Map<FeatureListener, Set<EStructuralFeature>>> featureListeners;
126 private Map<Object, Map<DataTypeListener, Set<EDataType>>> dataTypeListeners;
127
128 private final Set<IEMFIndexingErrorListener> errorListeners;
129 private final BaseIndexOptions baseIndexOptions;
130
131 private EMFModelComprehension comprehension;
132
133 private boolean loggedRegistrationMessage = false;
134
135 EMFBaseIndexMetaStore metaStore;
136 EMFBaseIndexInstanceStore instanceStore;
137 EMFBaseIndexStatisticsStore statsStore;
138
139 <T> Set<T> setMinus(Collection<? extends T> a, Collection<T> b) {
140 Set<T> result = new HashSet<T>(a);
141 result.removeAll(b);
142 return result;
143 }
144
145 @SuppressWarnings("unchecked")
146 <T extends EObject> Set<T> resolveAllInternal(Set<? extends T> a) {
147 if (a == null)
148 a = Collections.emptySet();
149 Set<T> result = new HashSet<T>();
150 for (T t : a) {
151 if (t.eIsProxy()) {
152 result.add((T) EcoreUtil.resolve(t, (ResourceSet) null));
153 } else {
154 result.add(t);
155 }
156 }
157 return result;
158 }
159
160 Set<Object> resolveClassifiersToKey(Set<? extends EClassifier> classes) {
161 Set<? extends EClassifier> resolveds = resolveAllInternal(classes);
162 Set<Object> result = new HashSet<Object>();
163 for (EClassifier resolved : resolveds) {
164 result.add(toKey(resolved));
165 }
166 return result;
167 }
168
169 Set<Object> resolveFeaturesToKey(Set<? extends EStructuralFeature> features) {
170 Set<EStructuralFeature> resolveds = resolveAllInternal(features);
171 Set<Object> result = new HashSet<Object>();
172 for (EStructuralFeature resolved : resolveds) {
173 result.add(toKey(resolved));
174 }
175 return result;
176 }
177
178 @Override
179 public boolean isInWildcardMode() {
180 return isInWildcardMode(IndexingLevel.FULL);
181 }
182
183 @Override
184 public boolean isInWildcardMode(IndexingLevel level) {
185 return wildcardMode.providesLevel(level);
186 }
187
188 @Override
189 public boolean isInDynamicEMFMode() {
190 return baseIndexOptions.isDynamicEMFMode();
191 }
192
193 /**
194 * @return the baseIndexOptions
195 */
196 public BaseIndexOptions getBaseIndexOptions() {
197 return baseIndexOptions.copy();
198 }
199
200 /**
201 * @return the comprehension
202 */
203 public EMFModelComprehension getComprehension() {
204 return comprehension;
205 }
206
207 /**
208 * @throws ViatraQueryRuntimeException
209 */
210 public NavigationHelperImpl(Notifier emfRoot, BaseIndexOptions options, Logger logger) {
211 this.baseIndexOptions = options.copy();
212 this.logger = logger;
213 assert (logger != null);
214
215 this.comprehension = initModelComprehension();
216 this.wildcardMode = baseIndexOptions.getWildcardLevel();
217 this.subscribedInstanceListeners = new HashMap<InstanceListener, Set<EClass>>();
218 this.subscribedFeatureListeners = new HashMap<FeatureListener, Set<EStructuralFeature>>();
219 this.subscribedDataTypeListeners = new HashMap<DataTypeListener, Set<EDataType>>();
220 this.lightweightObservers = CollectionsFactory.createMap();
221 this.observedFeatures = new HashMap<Object, IndexingLevel>();
222 this.ignoreResolveNotificationFeatures = new HashSet<Object>();
223 this.observedDataTypes = new HashMap<Object, IndexingLevel>();
224
225 metaStore = initMetaStore();
226 instanceStore = initInstanceStore();
227 statsStore = initStatStore();
228
229 this.contentAdapter = initContentAdapter();
230 this.baseIndexChangeListeners = new HashSet<EMFBaseIndexChangeListener>();
231 this.errorListeners = new LinkedHashSet<IEMFIndexingErrorListener>();
232
233 this.modelRoots = new HashSet<Notifier>();
234 this.expansionAllowed = false;
235 this.traversalDescendsAlongCrossResourceContainment = false;
236
237 if (emfRoot != null) {
238 addRootInternal(emfRoot);
239 }
240
241 }
242
243 @Override
244 public IndexingLevel getWildcardLevel() {
245 return wildcardMode;
246 }
247
248 @Override
249 public void setWildcardLevel(final IndexingLevel level) {
250 try{
251 IndexingLevel mergedLevel = NavigationHelperImpl.this.wildcardMode.merge(level);
252 if (mergedLevel != NavigationHelperImpl.this.wildcardMode){
253 NavigationHelperImpl.this.wildcardMode = mergedLevel;
254
255 // force traversal upon change of wildcard level
256 final NavigationHelperVisitor visitor = initTraversingVisitor(
257 Collections.<Object, IndexingLevel>emptyMap(), Collections.<Object, IndexingLevel>emptyMap(), Collections.<Object, IndexingLevel>emptyMap(), Collections.<Object, IndexingLevel>emptyMap());
258 coalesceTraversals(() -> traverse(visitor));
259 }
260 } catch (InvocationTargetException ex) {
261 processingFatal(ex.getCause(), "Setting wildcard level: " + level);
262 } catch (Exception ex) {
263 processingFatal(ex, "Setting wildcard level: " + level);
264 }
265 }
266
267 public NavigationHelperContentAdapter getContentAdapter() {
268 return contentAdapter;
269 }
270
271 public Map<Object, IndexingLevel> getObservedFeaturesInternal() {
272 return observedFeatures;
273 }
274
275 public boolean isFeatureResolveIgnored(EStructuralFeature feature) {
276 return ignoreResolveNotificationFeatures.contains(toKey(feature));
277 }
278
279 @Override
280 public void dispose() {
281 ensureNoListenersForDispose();
282 for (Notifier root : modelRoots) {
283 contentAdapter.removeAdapter(root);
284 }
285 }
286
287 @Override
288 public Set<Object> getDataTypeInstances(EDataType type) {
289 Object typeKey = toKey(type);
290 return Collections.unmodifiableSet(instanceStore.getDistinctDataTypeInstances(typeKey));
291 }
292
293 @Override
294 public boolean isInstanceOfDatatype(Object value, EDataType type) {
295 Object typeKey = toKey(type);
296 Set<Object> valMap = instanceStore.getDistinctDataTypeInstances(typeKey);
297 return valMap.contains(value);
298 }
299
300 protected FeatureData featureData(EStructuralFeature feature) {
301 return instanceStore.getFeatureData(toKey(feature));
302 }
303
304 @Override
305 public Set<Setting> findByAttributeValue(Object value_) {
306 Object value = toCanonicalValueRepresentation(value_);
307 return getSettingsForTarget(value);
308 }
309
310 @Override
311 public Set<Setting> findByAttributeValue(Object value_, Collection<EAttribute> attributes) {
312 Object value = toCanonicalValueRepresentation(value_);
313 Set<Setting> retSet = new HashSet<Setting>();
314
315 for (EAttribute attr : attributes) {
316 for (EObject holder : featureData(attr).getDistinctHoldersOfValue(value)) {
317 retSet.add(new NavigationHelperSetting(attr, holder, value));
318 }
319 }
320
321 return retSet;
322 }
323
324 @Override
325 public Set<EObject> findByAttributeValue(Object value_, EAttribute attribute) {
326 Object value = toCanonicalValueRepresentation(value_);
327 final Set<EObject> holders = featureData(attribute).getDistinctHoldersOfValue(value);
328 return Collections.unmodifiableSet(holders);
329 }
330
331 @Override
332 public void processAllFeatureInstances(EStructuralFeature feature, IStructuralFeatureInstanceProcessor processor) {
333 featureData(feature).forEach(processor);
334 }
335
336 @Override
337 public void processDirectInstances(EClass type, IEClassProcessor processor) {
338 Object typeKey = toKey(type);
339 processDirectInstancesInternal(type, processor, typeKey);
340 }
341
342 @Override
343 public void processAllInstances(EClass type, IEClassProcessor processor) {
344 Object typeKey = toKey(type);
345 Set<Object> subTypes = metaStore.getSubTypeMap().get(typeKey);
346 if (subTypes != null) {
347 for (Object subTypeKey : subTypes) {
348 processDirectInstancesInternal(type, processor, subTypeKey);
349 }
350 }
351 processDirectInstancesInternal(type, processor, typeKey);
352 }
353
354 @Override
355 public void processDataTypeInstances(EDataType type, IEDataTypeProcessor processor) {
356 Object typeKey = toKey(type);
357 for (Object value : instanceStore.getDistinctDataTypeInstances(typeKey)) {
358 processor.process(type, value);
359 }
360 }
361
362 protected void processDirectInstancesInternal(EClass type, IEClassProcessor processor, Object typeKey) {
363 final Set<EObject> instances = instanceStore.getInstanceSet(typeKey);
364 if (instances != null) {
365 for (EObject eObject : instances) {
366 processor.process(type, eObject);
367 }
368 }
369 }
370
371 @Override
372 public Set<Setting> getInverseReferences(EObject target) {
373 return getSettingsForTarget(target);
374 }
375
376 protected Set<Setting> getSettingsForTarget(Object target) {
377 Set<Setting> retSet = new HashSet<Setting>();
378 for (Object featureKey : instanceStore.getFeatureKeysPointingTo(target)) {
379 Set<EObject> holders = instanceStore.getFeatureData(featureKey).getDistinctHoldersOfValue(target);
380 for (EObject holder : holders) {
381 EStructuralFeature feature = metaStore.getKnownFeatureForKey(featureKey);
382 retSet.add(new NavigationHelperSetting(feature, holder, target));
383 }
384 }
385 return retSet;
386 }
387
388 @Override
389 public Set<Setting> getInverseReferences(EObject target, Collection<EReference> references) {
390 Set<Setting> retSet = new HashSet<>();
391 for (EReference ref : references) {
392 final Set<EObject> holders = featureData(ref).getDistinctHoldersOfValue(target);
393 for (EObject source : holders) {
394 retSet .add(new NavigationHelperSetting(ref, source, target));
395 }
396 }
397
398 return retSet;
399 }
400
401 @Override
402 public Set<EObject> getInverseReferences(EObject target, EReference reference) {
403 final Set<EObject> holders = featureData(reference).getDistinctHoldersOfValue(target);
404 return Collections.unmodifiableSet(holders);
405 }
406
407 @Override
408 @SuppressWarnings("unchecked")
409 public Set<EObject> getReferenceValues(EObject source, EReference reference) {
410 Set<Object> targets = getFeatureTargets(source, reference);
411 return (Set<EObject>) (Set<?>) targets; // this is known to be safe, as EReferences can only point to EObjects
412 }
413
414 @Override
415 public Set<Object> getFeatureTargets(EObject source, EStructuralFeature _feature) {
416 return Collections.unmodifiableSet(featureData(_feature).getDistinctValuesOfHolder(source));
417 }
418
419 @Override
420 public boolean isFeatureInstance(EObject source, Object target, EStructuralFeature _feature) {
421 return featureData(_feature).isInstance(source, target);
422 }
423
424 @Override
425 public Set<EObject> getDirectInstances(EClass type) {
426 Object typeKey = toKey(type);
427 Set<EObject> valSet = instanceStore.getInstanceSet(typeKey);
428 if (valSet == null) {
429 return Collections.emptySet();
430 } else {
431 return Collections.unmodifiableSet(valSet);
432 }
433 }
434
435 protected Object toKey(EClassifier eClassifier) {
436 return metaStore.toKey(eClassifier);
437 }
438
439 protected Object toKey(EStructuralFeature feature) {
440 return metaStore.toKey(feature);
441 }
442
443 @Override
444 public Object toCanonicalValueRepresentation(Object value) {
445 return metaStore.toInternalValueRepresentation(value);
446 }
447
448 @Override
449 public Set<EObject> getAllInstances(EClass type) {
450 Set<EObject> retSet = new HashSet<EObject>();
451
452 Object typeKey = toKey(type);
453 Set<Object> subTypes = metaStore.getSubTypeMap().get(typeKey);
454 if (subTypes != null) {
455 for (Object subTypeKey : subTypes) {
456 final Set<EObject> instances = instanceStore.getInstanceSet(subTypeKey);
457 if (instances != null) {
458 retSet.addAll(instances);
459 }
460 }
461 }
462 final Set<EObject> instances = instanceStore.getInstanceSet(typeKey);
463 if (instances != null) {
464 retSet.addAll(instances);
465 }
466
467 return retSet;
468 }
469
470 @Override
471 public boolean isInstanceOfUnscoped(EObject object, EClass clazz) {
472 Object candidateTypeKey = toKey(clazz);
473 Object typeKey = toKey(object.eClass());
474
475 return doCalculateInstanceOf(candidateTypeKey, typeKey);
476 }
477
478 @Override
479 public boolean isInstanceOfScoped(EObject object, EClass clazz) {
480 Object typeKey = toKey(object.eClass());
481 if (!doCalculateInstanceOf(toKey(clazz), typeKey)) {
482 return false;
483 }
484 final Set<EObject> instances = instanceStore.getInstanceSet(typeKey);
485 return instances != null && instances.contains(object);
486 }
487
488 protected boolean doCalculateInstanceOf(Object candidateTypeKey, Object typeKey) {
489 if (candidateTypeKey.equals(typeKey)) return true;
490 if (metaStore.getEObjectClassKey().equals(candidateTypeKey)) return true;
491
492 Set<Object> superTypes = metaStore.getSuperTypeMap().get(typeKey);
493 return superTypes.contains(candidateTypeKey);
494 }
495
496 @Override
497 public Set<EObject> findByFeatureValue(Object value_, EStructuralFeature _feature) {
498 Object value = toCanonicalValueRepresentation(value_);
499 return Collections.unmodifiableSet(featureData(_feature).getDistinctHoldersOfValue(value));
500 }
501
502 @Override
503 public Set<EObject> getHoldersOfFeature(EStructuralFeature _feature) {
504 Object feature = toKey(_feature);
505 return Collections.unmodifiableSet(instanceStore.getHoldersOfFeature(feature));
506 }
507 @Override
508 public Set<Object> getValuesOfFeature(EStructuralFeature _feature) {
509 Object feature = toKey(_feature);
510 return Collections.unmodifiableSet(instanceStore.getValuesOfFeature(feature));
511 }
512
513 @Override
514 public void addInstanceListener(Collection<EClass> classes, InstanceListener listener) {
515 Set<EClass> registered = this.subscribedInstanceListeners.computeIfAbsent(listener, l -> new HashSet<>());
516 Set<EClass> delta = setMinus(classes, registered);
517 if (!delta.isEmpty()) {
518 registered.addAll(delta);
519 if (instanceListeners != null) { // if already computed
520 for (EClass subscriptionType : delta) {
521 final Object superElementTypeKey = toKey(subscriptionType);
522 addInstanceListenerInternal(listener, subscriptionType, superElementTypeKey);
523 final Set<Object> subTypeKeys = metaStore.getSubTypeMap().get(superElementTypeKey);
524 if (subTypeKeys != null)
525 for (Object subTypeKey : subTypeKeys) {
526 addInstanceListenerInternal(listener, subscriptionType, subTypeKey);
527 }
528 }
529 }
530 }
531 }
532
533 @Override
534 public void removeInstanceListener(Collection<EClass> classes, InstanceListener listener) {
535 Set<EClass> restriction = this.subscribedInstanceListeners.get(listener);
536 if (restriction != null) {
537 boolean changed = restriction.removeAll(classes);
538 if (restriction.size() == 0) {
539 this.subscribedInstanceListeners.remove(listener);
540 }
541 if (changed)
542 instanceListeners = null; // recompute later on demand
543 }
544 }
545
546 @Override
547 public void addFeatureListener(Collection<? extends EStructuralFeature> features, FeatureListener listener) {
548 Set<EStructuralFeature> registered = this.subscribedFeatureListeners.computeIfAbsent(listener, l -> new HashSet<>());
549 Set<EStructuralFeature> delta = setMinus(features, registered);
550 if (!delta.isEmpty()) {
551 registered.addAll(delta);
552 if (featureListeners != null) { // if already computed
553 for (EStructuralFeature subscriptionType : delta) {
554 addFeatureListenerInternal(listener, subscriptionType, toKey(subscriptionType));
555 }
556 }
557 }
558 }
559
560 @Override
561 public void removeFeatureListener(Collection<? extends EStructuralFeature> features, FeatureListener listener) {
562 Collection<EStructuralFeature> restriction = this.subscribedFeatureListeners.get(listener);
563 if (restriction != null) {
564 boolean changed = restriction.removeAll(features);
565 if (restriction.size() == 0) {
566 this.subscribedFeatureListeners.remove(listener);
567 }
568 if (changed)
569 featureListeners = null; // recompute later on demand
570 }
571 }
572
573 @Override
574 public void addDataTypeListener(Collection<EDataType> types, DataTypeListener listener) {
575 Set<EDataType> registered = this.subscribedDataTypeListeners.computeIfAbsent(listener, l -> new HashSet<>());
576 Set<EDataType> delta = setMinus(types, registered);
577 if (!delta.isEmpty()) {
578 registered.addAll(delta);
579 if (dataTypeListeners != null) { // if already computed
580 for (EDataType subscriptionType : delta) {
581 addDatatypeListenerInternal(listener, subscriptionType, toKey(subscriptionType));
582 }
583 }
584 }
585 }
586
587 @Override
588 public void removeDataTypeListener(Collection<EDataType> types, DataTypeListener listener) {
589 Collection<EDataType> restriction = this.subscribedDataTypeListeners.get(listener);
590 if (restriction != null) {
591 boolean changed = restriction.removeAll(types);
592 if (restriction.size() == 0) {
593 this.subscribedDataTypeListeners.remove(listener);
594 }
595 if (changed)
596 dataTypeListeners = null; // recompute later on demand
597 }
598 }
599
600 /**
601 * @return the observedDataTypes
602 */
603 public Map<Object, IndexingLevel> getObservedDataTypesInternal() {
604 return observedDataTypes;
605 }
606
607 @Override
608 public boolean addLightweightEObjectObserver(LightweightEObjectObserver observer, EObject observedObject) {
609 Set<LightweightEObjectObserver> observers = lightweightObservers.computeIfAbsent(observedObject, CollectionsFactory::emptySet);
610 return observers.add(observer);
611 }
612
613 @Override
614 public boolean removeLightweightEObjectObserver(LightweightEObjectObserver observer, EObject observedObject) {
615 boolean result = false;
616 Set<LightweightEObjectObserver> observers = lightweightObservers.get(observedObject);
617 if (observers != null) {
618 result = observers.remove(observer);
619 if (observers.isEmpty()) {
620 lightweightObservers.remove(observedObject);
621 }
622 }
623 return result;
624 }
625
626 public void notifyBaseIndexChangeListeners() {
627 notifyBaseIndexChangeListeners(instanceStore.isDirty);
628 if (instanceStore.isDirty) {
629 instanceStore.isDirty = false;
630 }
631 }
632
633 /**
634 * This will run after updates.
635 */
636 protected void notifyBaseIndexChangeListeners(boolean baseIndexChanged) {
637 if (!baseIndexChangeListeners.isEmpty()) {
638 for (EMFBaseIndexChangeListener listener : new ArrayList<>(baseIndexChangeListeners)) {
639 try {
640 if (!listener.onlyOnIndexChange() || baseIndexChanged) {
641 listener.notifyChanged(baseIndexChanged);
642 }
643 } catch (Exception ex) {
644 notifyFatalListener("VIATRA Base encountered an error in delivering notifications about changes. ",
645 ex);
646 }
647 }
648 }
649 }
650
651 void notifyDataTypeListeners(final Object typeKey, final Object value, final boolean isInsertion,
652 final boolean firstOrLastOccurrence) {
653 for (final Entry<DataTypeListener, Set<EDataType>> entry : getDataTypeListeners().getOrDefault(typeKey, Collections.emptyMap()).entrySet()) {
654 final DataTypeListener listener = entry.getKey();
655 for (final EDataType subscriptionType : entry.getValue()) {
656 if (isInsertion) {
657 listener.dataTypeInstanceInserted(subscriptionType, value, firstOrLastOccurrence);
658 } else {
659 listener.dataTypeInstanceDeleted(subscriptionType, value, firstOrLastOccurrence);
660 }
661 }
662 }
663 }
664
665 void notifyFeatureListeners(final EObject host, final Object featureKey, final Object value,
666 final boolean isInsertion) {
667 for (final Entry<FeatureListener, Set<EStructuralFeature>> entry : getFeatureListeners().getOrDefault(featureKey, Collections.emptyMap())
668 .entrySet()) {
669 final FeatureListener listener = entry.getKey();
670 for (final EStructuralFeature subscriptionType : entry.getValue()) {
671 if (isInsertion) {
672 listener.featureInserted(host, subscriptionType, value);
673 } else {
674 listener.featureDeleted(host, subscriptionType, value);
675 }
676 }
677 }
678 }
679
680 void notifyInstanceListeners(final Object clazzKey, final EObject instance, final boolean isInsertion) {
681 for (final Entry<InstanceListener, Set<EClass>> entry : getInstanceListeners().getOrDefault(clazzKey, Collections.emptyMap()).entrySet()) {
682 final InstanceListener listener = entry.getKey();
683 for (final EClass subscriptionType : entry.getValue()) {
684 if (isInsertion) {
685 listener.instanceInserted(subscriptionType, instance);
686 } else {
687 listener.instanceDeleted(subscriptionType, instance);
688 }
689 }
690 }
691 }
692
693 void notifyLightweightObservers(final EObject host, final EStructuralFeature feature,
694 final Notification notification) {
695 if (lightweightObservers.containsKey(host)) {
696 Set<LightweightEObjectObserver> observers = lightweightObservers.get(host);
697 for (final LightweightEObjectObserver observer : observers) {
698 observer.notifyFeatureChanged(host, feature, notification);
699 }
700 }
701 }
702
703 @Override
704 public void addBaseIndexChangeListener(EMFBaseIndexChangeListener listener) {
705 Preconditions.checkArgument(listener != null, "Cannot add null listener!");
706 baseIndexChangeListeners.add(listener);
707 }
708
709 @Override
710 public void removeBaseIndexChangeListener(EMFBaseIndexChangeListener listener) {
711 Preconditions.checkArgument(listener != null, "Cannot remove null listener!");
712 baseIndexChangeListeners.remove(listener);
713 }
714
715 @Override
716 public boolean addIndexingErrorListener(IEMFIndexingErrorListener listener) {
717 return errorListeners.add(listener);
718 }
719
720 @Override
721 public boolean removeIndexingErrorListener(IEMFIndexingErrorListener listener) {
722 return errorListeners.remove(listener);
723 }
724
725 protected void processingFatal(final Throwable ex, final String task) {
726 notifyFatalListener(logTaskFormat(task), ex);
727 }
728
729 protected void processingError(final Throwable ex, final String task) {
730 notifyErrorListener(logTaskFormat(task), ex);
731 }
732
733 public void notifyErrorListener(String message, Throwable t) {
734 logger.error(message, t);
735 for (IEMFIndexingErrorListener listener : new ArrayList<>(errorListeners)) {
736 listener.error(message, t);
737 }
738 }
739
740 public void notifyFatalListener(String message, Throwable t) {
741 logger.fatal(message, t);
742 for (IEMFIndexingErrorListener listener : new ArrayList<>(errorListeners)) {
743 listener.fatal(message, t);
744 }
745 }
746
747 protected String logTaskFormat(final String task) {
748 return "VIATRA Query encountered an error in processing the EMF model. " + "This happened while trying to "
749 + task;
750 }
751
752 protected void considerForExpansion(EObject obj) {
753 if (expansionAllowed) {
754 Resource eResource = obj.eResource();
755 if (eResource != null && eResource.getResourceSet() == null) {
756 expandToAdditionalRoot(eResource);
757 }
758 }
759 }
760
761 protected void expandToAdditionalRoot(Notifier root) {
762 if (modelRoots.contains(root))
763 return;
764
765 if (root instanceof ResourceSet) {
766 expansionAllowed = true;
767 } else if (root instanceof Resource) {
768 IBaseIndexResourceFilter resourceFilter = baseIndexOptions.getResourceFilterConfiguration();
769 if (resourceFilter != null && resourceFilter.isResourceFiltered((Resource) root))
770 return;
771 } else { // root instanceof EObject
772 traversalDescendsAlongCrossResourceContainment = true;
773 }
774 final IBaseIndexObjectFilter objectFilter = baseIndexOptions.getObjectFilterConfiguration();
775 if (objectFilter != null && objectFilter.isFiltered(root))
776 return;
777
778 // no veto by filters
779 modelRoots.add(root);
780 contentAdapter.addAdapter(root);
781 notifyBaseIndexChangeListeners();
782 }
783
784 /**
785 * @return the expansionAllowed
786 */
787 public boolean isExpansionAllowed() {
788 return expansionAllowed;
789 }
790
791 public boolean traversalDescendsAlongCrossResourceContainment() {
792 return traversalDescendsAlongCrossResourceContainment;
793 }
794
795 /**
796 * @return the directlyObservedClasses
797 */
798 public Set<Object> getDirectlyObservedClassesInternal() {
799 return directlyObservedClasses.keySet();
800 }
801
802 boolean isObservedInternal(Object clazzKey) {
803 return isInWildcardMode() || getAllObservedClassesInternal().containsKey(clazzKey);
804 }
805
806 /**
807 * Add the given item the map with the given indexing level if it wasn't already added with a higher level.
808 * @param level non-null
809 * @return whether actually changed
810 */
811 protected static <V> boolean putIntoMapMerged(Map<V, IndexingLevel> map, V key, IndexingLevel level) {
812 IndexingLevel l = map.get(key);
813 IndexingLevel merged = level.merge(l);
814 if (merged != l) {
815 map.put(key, merged);
816 return true;
817 } else {
818 return false;
819 }
820 }
821
822 /**
823 * @return true if actually changed
824 */
825 protected boolean addObservedClassesInternal(Object eClassKey, IndexingLevel level) {
826 boolean changed = putIntoMapMerged(allObservedClasses, eClassKey, level);
827 if (!changed) return false;
828
829 final Set<Object> subTypes = metaStore.getSubTypeMap().get(eClassKey);
830 if (subTypes != null) {
831 for (Object subType : subTypes) {
832 /*
833 * It is necessary to check if the class has already been added with a higher indexing level as in case
834 * of multiple inheritance, a subclass may be registered for statistics only but full indexing may be
835 * required via one of its super classes.
836 */
837 putIntoMapMerged(allObservedClasses, subType, level);
838 }
839 }
840 return true;
841 }
842
843 /**
844 * not just the directly observed classes, but also their known subtypes
845 */
846 public Map<Object, IndexingLevel> getAllObservedClassesInternal() {
847 if (allObservedClasses == null) {
848 allObservedClasses = new HashMap<Object, IndexingLevel>();
849 for (Entry<Object, IndexingLevel> entry : directlyObservedClasses.entrySet()) {
850 Object eClassKey = entry.getKey();
851 IndexingLevel level = entry.getValue();
852 addObservedClassesInternal(eClassKey, level);
853 }
854 }
855 return allObservedClasses;
856 }
857
858 /**
859 * @return the instanceListeners
860 */
861 Map<Object, Map<InstanceListener, Set<EClass>>> getInstanceListeners() {
862 if (instanceListeners == null) {
863 instanceListeners = CollectionsFactory.createMap();
864 for (Entry<InstanceListener, Set<EClass>> subscription : subscribedInstanceListeners.entrySet()) {
865 final InstanceListener listener = subscription.getKey();
866 for (EClass subscriptionType : subscription.getValue()) {
867 final Object superElementTypeKey = toKey(subscriptionType);
868 addInstanceListenerInternal(listener, subscriptionType, superElementTypeKey);
869 final Set<Object> subTypeKeys = metaStore.getSubTypeMap().get(superElementTypeKey);
870 if (subTypeKeys != null)
871 for (Object subTypeKey : subTypeKeys) {
872 addInstanceListenerInternal(listener, subscriptionType, subTypeKey);
873 }
874 }
875 }
876 }
877 return instanceListeners;
878 }
879
880 Map<Object, Map<InstanceListener, Set<EClass>>> peekInstanceListeners() {
881 return instanceListeners;
882 }
883
884 void addInstanceListenerInternal(final InstanceListener listener, EClass subscriptionType,
885 final Object elementTypeKey) {
886 Set<EClass> subscriptionTypes = instanceListeners
887 .computeIfAbsent(elementTypeKey, k -> CollectionsFactory.createMap())
888 .computeIfAbsent(listener, k -> CollectionsFactory.createSet());
889 subscriptionTypes.add(subscriptionType);
890 }
891
892 /**
893 * @return the featureListeners
894 */
895 Map<Object, Map<FeatureListener, Set<EStructuralFeature>>> getFeatureListeners() {
896 if (featureListeners == null) {
897 featureListeners = CollectionsFactory.createMap();
898 for (Entry<FeatureListener, Set<EStructuralFeature>> subscription : subscribedFeatureListeners.entrySet()) {
899 final FeatureListener listener = subscription.getKey();
900 for (EStructuralFeature subscriptionType : subscription.getValue()) {
901 final Object elementTypeKey = toKey(subscriptionType);
902 addFeatureListenerInternal(listener, subscriptionType, elementTypeKey);
903 }
904 }
905 }
906 return featureListeners;
907 }
908
909 void addFeatureListenerInternal(final FeatureListener listener, EStructuralFeature subscriptionType,
910 final Object elementTypeKey) {
911 Set<EStructuralFeature> subscriptionTypes = featureListeners
912 .computeIfAbsent(elementTypeKey, k -> CollectionsFactory.createMap())
913 .computeIfAbsent(listener, k -> CollectionsFactory.createSet());
914 subscriptionTypes.add(subscriptionType);
915 }
916
917 /**
918 * @return the dataTypeListeners
919 */
920 Map<Object, Map<DataTypeListener, Set<EDataType>>> getDataTypeListeners() {
921 if (dataTypeListeners == null) {
922 dataTypeListeners = CollectionsFactory.createMap();
923 for (Entry<DataTypeListener, Set<EDataType>> subscription : subscribedDataTypeListeners.entrySet()) {
924 final DataTypeListener listener = subscription.getKey();
925 for (EDataType subscriptionType : subscription.getValue()) {
926 final Object elementTypeKey = toKey(subscriptionType);
927 addDatatypeListenerInternal(listener, subscriptionType, elementTypeKey);
928 }
929 }
930 }
931 return dataTypeListeners;
932 }
933
934 void addDatatypeListenerInternal(final DataTypeListener listener, EDataType subscriptionType,
935 final Object elementTypeKey) {
936 Set<EDataType> subscriptionTypes = dataTypeListeners
937 .computeIfAbsent(elementTypeKey, k -> CollectionsFactory.createMap())
938 .computeIfAbsent(listener, k -> CollectionsFactory.createSet());
939 subscriptionTypes.add(subscriptionType);
940 }
941
942 public void registerObservedTypes(Set<EClass> classes, Set<EDataType> dataTypes,
943 Set<? extends EStructuralFeature> features) {
944 registerObservedTypes(classes, dataTypes, features, IndexingLevel.FULL);
945 }
946
947 @Override
948 public void registerObservedTypes(Set<EClass> classes, Set<EDataType> dataTypes,
949 Set<? extends EStructuralFeature> features, final IndexingLevel level) {
950 if (isRegistrationNecessary(level) && (classes != null || features != null || dataTypes != null)) {
951 final Set<Object> resolvedFeatures = resolveFeaturesToKey(features);
952 final Set<Object> resolvedClasses = resolveClassifiersToKey(classes);
953 final Set<Object> resolvedDatatypes = resolveClassifiersToKey(dataTypes);
954
955 try {
956 coalesceTraversals(() -> {
957 Function<Object, IndexingLevel> f = input -> level;
958 delayedFeatures.putAll(resolvedFeatures.stream().collect(Collectors.toMap(identity(), f)));
959 delayedDataTypes.putAll(resolvedDatatypes.stream().collect(Collectors.toMap(identity(), f)));
960 delayedClasses.putAll(resolvedClasses.stream().collect(Collectors.toMap(identity(), f)));
961 });
962 } catch (InvocationTargetException ex) {
963 processingFatal(ex.getCause(), "register en masse the observed EClasses " + resolvedClasses
964 + " and EDatatypes " + resolvedDatatypes + " and EStructuralFeatures " + resolvedFeatures);
965 } catch (Exception ex) {
966 processingFatal(ex, "register en masse the observed EClasses " + resolvedClasses + " and EDatatypes "
967 + resolvedDatatypes + " and EStructuralFeatures " + resolvedFeatures);
968 }
969 }
970 }
971
972 @Override
973 public void unregisterObservedTypes(Set<EClass> classes, Set<EDataType> dataTypes,
974 Set<? extends EStructuralFeature> features) {
975 unregisterEClasses(classes);
976 unregisterEDataTypes(dataTypes);
977 unregisterEStructuralFeatures(features);
978 }
979
980 @Override
981 public void registerEStructuralFeatures(Set<? extends EStructuralFeature> features, final IndexingLevel level) {
982 if (isRegistrationNecessary(level) && features != null) {
983 final Set<Object> resolved = resolveFeaturesToKey(features);
984
985 try {
986 coalesceTraversals(() -> resolved.forEach(o -> delayedFeatures.put(o, level)));
987 } catch (InvocationTargetException ex) {
988 processingFatal(ex.getCause(), "register the observed EStructuralFeatures: " + resolved);
989 } catch (Exception ex) {
990 processingFatal(ex, "register the observed EStructuralFeatures: " + resolved);
991 }
992 }
993 }
994
995 @Override
996 public void unregisterEStructuralFeatures(Set<? extends EStructuralFeature> features) {
997 if (isRegistrationNecessary(IndexingLevel.FULL) && features != null) {
998 final Set<Object> resolved = resolveFeaturesToKey(features);
999 ensureNoListeners(resolved, getFeatureListeners());
1000 observedFeatures.keySet().removeAll(resolved);
1001 delayedFeatures.keySet().removeAll(resolved);
1002 for (Object f : resolved) {
1003 instanceStore.forgetFeature(f);
1004 statsStore.removeType(f);
1005 }
1006 }
1007 }
1008
1009 @Override
1010 public void registerEClasses(Set<EClass> classes, final IndexingLevel level) {
1011 if (isRegistrationNecessary(level) && classes != null) {
1012 final Set<Object> resolvedClasses = resolveClassifiersToKey(classes);
1013
1014 try {
1015 coalesceTraversals(() -> resolvedClasses.forEach(o -> delayedClasses.put(o, level)));
1016 } catch (InvocationTargetException ex) {
1017 processingFatal(ex.getCause(), "register the observed EClasses: " + resolvedClasses);
1018 } catch (Exception ex) {
1019 processingFatal(ex, "register the observed EClasses: " + resolvedClasses);
1020 }
1021 }
1022 }
1023
1024 /**
1025 * @return true if there is an actual change in the transitively computed observation levels,
1026 * warranting an actual traversal
1027 */
1028 protected boolean startObservingClasses(Map<Object, IndexingLevel> requestedClassObservations) {
1029 boolean warrantsTraversal = false;
1030 getAllObservedClassesInternal(); // pre-populate
1031 for (Entry<Object, IndexingLevel> request : requestedClassObservations.entrySet()) {
1032 if (putIntoMapMerged(directlyObservedClasses, request.getKey(), request.getValue())) {
1033 // maybe already observed for the sake of a supertype?
1034 if (addObservedClassesInternal(request.getKey(), request.getValue())) {
1035 warrantsTraversal = true;
1036 };
1037 }
1038 }
1039 return warrantsTraversal;
1040 }
1041
1042 @Override
1043 public void unregisterEClasses(Set<EClass> classes) {
1044 if (isRegistrationNecessary(IndexingLevel.FULL) && classes != null) {
1045 final Set<Object> resolved = resolveClassifiersToKey(classes);
1046 ensureNoListeners(resolved, getInstanceListeners());
1047 directlyObservedClasses.keySet().removeAll(resolved);
1048 allObservedClasses = null;
1049 delayedClasses.keySet().removeAll(resolved);
1050 for (Object c : resolved) {
1051 instanceStore.removeInstanceSet(c);
1052 statsStore.removeType(c);
1053 }
1054 }
1055 }
1056
1057 @Override
1058 public void registerEDataTypes(Set<EDataType> dataTypes, final IndexingLevel level) {
1059 if (isRegistrationNecessary(level) && dataTypes != null) {
1060 final Set<Object> resolved = resolveClassifiersToKey(dataTypes);
1061
1062 try {
1063 coalesceTraversals(() -> resolved.forEach(o -> delayedDataTypes.put(o, level)));
1064 } catch (InvocationTargetException ex) {
1065 processingFatal(ex.getCause(), "register the observed EDataTypes: " + resolved);
1066 } catch (Exception ex) {
1067 processingFatal(ex, "register the observed EDataTypes: " + resolved);
1068 }
1069 }
1070 }
1071
1072 @Override
1073 public void unregisterEDataTypes(Set<EDataType> dataTypes) {
1074 if (isRegistrationNecessary(IndexingLevel.FULL) && dataTypes != null) {
1075 final Set<Object> resolved = resolveClassifiersToKey(dataTypes);
1076 ensureNoListeners(resolved, getDataTypeListeners());
1077 observedDataTypes.keySet().removeAll(resolved);
1078 delayedDataTypes.keySet().removeAll(resolved);
1079 for (Object dataType : resolved) {
1080 instanceStore.removeDataTypeMap(dataType);
1081 statsStore.removeType(dataType);
1082 }
1083 }
1084 }
1085
1086 @Override
1087 public boolean isCoalescing() {
1088 return delayTraversals;
1089 }
1090
1091 public void coalesceTraversals(final Runnable runnable) throws InvocationTargetException {
1092 coalesceTraversals(() -> {
1093 runnable.run();
1094 return null;
1095 });
1096 }
1097
1098 @Override
1099 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
1100 V finalResult = null;
1101
1102 if (delayTraversals) { // reentrant case, no special action needed
1103 try {
1104 finalResult = callable.call();
1105 } catch (Exception e) {
1106 throw new InvocationTargetException(e);
1107 }
1108 return finalResult;
1109 }
1110
1111 boolean firstRun = true;
1112 while (callable != null) { // repeat if post-processing needed
1113
1114 try {
1115 delayTraversals = true;
1116
1117 V result = callable.call();
1118 if (firstRun) {
1119 firstRun = false;
1120 finalResult = result;
1121 }
1122
1123 // are there proxies left to be resolved? are we allowed to resolve them now?
1124 while ((!delayedProxyResolutions.isEmpty()) && resolutionDelayingResources.isEmpty()) {
1125 // pop first entry
1126 EObject toResolveObject = delayedProxyResolutions.distinctKeys().iterator().next();
1127 EReference toResolveReference = delayedProxyResolutions.lookup(toResolveObject).iterator().next();
1128 delayedProxyResolutions.removePair(toResolveObject, toResolveReference);
1129
1130 // see if we can resolve proxies
1131 comprehension.tryResolveReference(toResolveObject, toResolveReference);
1132 }
1133
1134 delayTraversals = false;
1135 callable = considerRevisit();
1136 } catch (Exception e) {
1137 // since this is a fatal error, it is OK if delayTraversals remains true,
1138 // hence no need for a try-finally block
1139
1140 notifyFatalListener(
1141 "VIATRA Base encountered an error while traversing the EMF model to gather new information. ",
1142 e);
1143 throw new InvocationTargetException(e);
1144 }
1145 }
1146 executeTraversalCallbacks();
1147 return finalResult;
1148 }
1149
1150 protected <V> Callable<V> considerRevisit() {
1151 // has there been any requests for a retraversal at all?
1152 if (!delayedClasses.isEmpty() || !delayedFeatures.isEmpty() || !delayedDataTypes.isEmpty()) {
1153 // make copies of requested types so that
1154 // (a) original accumulators can be cleaned for the next cycle, also
1155 // (b) to remove entries that are already covered, or
1156 // (c) for the rare case that a coalesced traversal is invoked during visitation,
1157 // e.g. by a derived feature implementation
1158 // initialize the collections empty (but with capacity), fill with new entries
1159 final Map<Object, IndexingLevel> toGatherClasses = new HashMap<Object, IndexingLevel>(delayedClasses.size());
1160 final Map<Object, IndexingLevel> toGatherFeatures = new HashMap<Object, IndexingLevel>(delayedFeatures.size());
1161 final Map<Object, IndexingLevel> toGatherDataTypes = new HashMap<Object, IndexingLevel>(delayedDataTypes.size());
1162
1163 for (Entry<Object, IndexingLevel> requested : delayedFeatures.entrySet()) {
1164 Object typekey = requested.getKey();
1165 IndexingLevel old = observedFeatures.get(typekey);
1166 IndexingLevel merged = requested.getValue().merge(old);
1167 if (merged != old) toGatherFeatures.put(typekey, merged);
1168 }
1169 for (Entry<Object, IndexingLevel> requested : delayedClasses.entrySet()) {
1170 Object typekey = requested.getKey();
1171 IndexingLevel old = directlyObservedClasses.get(typekey);
1172 IndexingLevel merged = requested.getValue().merge(old);
1173 if (merged != old) toGatherClasses.put(typekey, merged);
1174 }
1175 for (Entry<Object, IndexingLevel> requested : delayedDataTypes.entrySet()) {
1176 Object typekey = requested.getKey();
1177 IndexingLevel old = observedDataTypes.get(typekey);
1178 IndexingLevel merged = requested.getValue().merge(old);
1179 if (merged != old) toGatherDataTypes.put(typekey, merged);
1180 }
1181
1182 delayedClasses.clear();
1183 delayedFeatures.clear();
1184 delayedDataTypes.clear();
1185
1186 // check if the filtered request sets are empty
1187 // - could be false alarm if we already observe all of them
1188 if (!toGatherClasses.isEmpty() || !toGatherFeatures.isEmpty() || !toGatherDataTypes.isEmpty()) {
1189 final HashMap<Object, IndexingLevel> oldClasses = new HashMap<Object, IndexingLevel>(
1190 directlyObservedClasses);
1191
1192 /* Instance indexing would add extra entries to the statistics store, so we have to clean the
1193 * appropriate entries. If no re-traversal is required, it is detected earlier; at this point we
1194 * only have to consider the target indexing level. See bug
1195 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=518356 for more details.
1196 *
1197 * This has to be executed before the old observed types are updated to check whether the indexing level increased.
1198 *
1199 * Technically, the statsStore cleanup seems only necessary for EDataTypes; otherwise everything
1200 * works as expected, but it seems a better idea to do the cleanup for all types in the same way */
1201 toGatherClasses.forEach((key, value) -> {
1202 IndexingLevel oldIndexingLevel = getIndexingLevel(metaStore.getKnownClassifierForKey(key));
1203 if (value.hasInstances() && oldIndexingLevel.hasStatistics() && !oldIndexingLevel.hasInstances()) {
1204 statsStore.removeType(key);
1205 }
1206
1207 });
1208 toGatherFeatures.forEach((key, value) -> {
1209 IndexingLevel oldIndexingLevel = getIndexingLevel(metaStore.getKnownFeatureForKey(key));
1210 if (value.hasInstances() && oldIndexingLevel.hasStatistics() && !oldIndexingLevel.hasInstances()) {
1211 statsStore.removeType(key);
1212 }
1213
1214 });
1215 toGatherDataTypes.forEach((key, value) -> {
1216 IndexingLevel oldIndexingLevel = getIndexingLevel(metaStore.getKnownClassifierForKey(key));
1217 if (value.hasInstances() && oldIndexingLevel.hasStatistics() && !oldIndexingLevel.hasInstances()) {
1218 statsStore.removeType(key);
1219 }
1220
1221 });
1222
1223 // Are there new classes to be observed that are not available via superclasses?
1224 // (at sufficient level)
1225 // if yes, model traversal needed
1226 // if not, index can be updated without retraversal
1227 boolean classesWarrantTraversal = startObservingClasses(toGatherClasses);
1228 observedDataTypes.putAll(toGatherDataTypes);
1229 observedFeatures.putAll(toGatherFeatures);
1230
1231
1232 // So, is an actual traversal needed, or are we done?
1233 if (classesWarrantTraversal || !toGatherFeatures.isEmpty() || !toGatherDataTypes.isEmpty()) {
1234 // repeat the cycle with this visit
1235 final NavigationHelperVisitor visitor = initTraversingVisitor(toGatherClasses, toGatherFeatures, toGatherDataTypes, oldClasses);
1236
1237 return new Callable<V>() {
1238 @Override
1239 public V call() throws Exception {
1240 // temporarily ignoring RESOLVE on these features, as they were not observed before
1241 ignoreResolveNotificationFeatures.addAll(toGatherFeatures.keySet());
1242 try {
1243 traverse(visitor);
1244 } finally {
1245 ignoreResolveNotificationFeatures.removeAll(toGatherFeatures.keySet());
1246 }
1247 return null;
1248 }
1249 };
1250
1251 }
1252 }
1253 }
1254
1255 return null; // no callable -> no further action
1256 }
1257
1258 protected void executeTraversalCallbacks() throws InvocationTargetException{
1259 final Runnable[] callbacks = traversalCallbacks.toArray(new Runnable[traversalCallbacks.size()]);
1260 traversalCallbacks.clear();
1261 if (callbacks.length > 0){
1262 coalesceTraversals(() -> Arrays.stream(callbacks).forEach(Runnable::run));
1263 }
1264 }
1265
1266 protected void traverse(final NavigationHelperVisitor visitor) {
1267 // Cloning model roots avoids a concurrent modification exception
1268 for (Notifier root : new HashSet<Notifier>(modelRoots)) {
1269 comprehension.traverseModel(visitor, root);
1270 }
1271 notifyBaseIndexChangeListeners();
1272 }
1273
1274 /**
1275 * Returns a stream of model roots registered to the navigation helper instance
1276 * @since 2.3
1277 */
1278 protected Stream<Notifier> getModelRoots() {
1279 return modelRoots.stream();
1280 }
1281
1282 @Override
1283 public void addRoot(Notifier emfRoot) {
1284 addRootInternal(emfRoot);
1285 }
1286
1287 /**
1288 * Supports removing model roots
1289 * </p>
1290 * Note: for now this API is considered experimental thus it is not added to the {@link NavigationHelper} interface.
1291 * @since 2.3
1292 */
1293 protected void removeRoot(Notifier root) {
1294 if (!((root instanceof EObject) || (root instanceof Resource) || (root instanceof ResourceSet))) {
1295 throw new ViatraBaseException(ViatraBaseException.INVALID_EMFROOT);
1296 }
1297
1298 if (!modelRoots.contains(root))
1299 return;
1300
1301 if (root instanceof Resource) {
1302 IBaseIndexResourceFilter resourceFilter = getBaseIndexOptions().getResourceFilterConfiguration();
1303 if (resourceFilter != null && resourceFilter.isResourceFiltered((Resource) root))
1304 return;
1305 }
1306 final IBaseIndexObjectFilter objectFilter = getBaseIndexOptions().getObjectFilterConfiguration();
1307 if (objectFilter != null && objectFilter.isFiltered(root))
1308 return;
1309
1310 // no veto by filters
1311 modelRoots.remove(root);
1312 contentAdapter.removeAdapter(root);
1313 notifyBaseIndexChangeListeners();
1314 }
1315
1316 @Override
1317 public <T extends EObject> void cheapMoveTo(T element, EList<T> targetContainmentReferenceList) {
1318 if (element.eAdapters().contains(contentAdapter)
1319 && targetContainmentReferenceList instanceof NotifyingList<?>) {
1320 final Object listNotifier = ((NotifyingList<?>) targetContainmentReferenceList).getNotifier();
1321 if (listNotifier instanceof Notifier && ((Notifier) listNotifier).eAdapters().contains(contentAdapter)) {
1322 contentAdapter.ignoreInsertionAndDeletion = element;
1323 try {
1324 targetContainmentReferenceList.add(element);
1325 } finally {
1326 contentAdapter.ignoreInsertionAndDeletion = null;
1327 }
1328 } else {
1329 targetContainmentReferenceList.add(element);
1330 }
1331 } else {
1332 targetContainmentReferenceList.add(element);
1333 }
1334 }
1335
1336 @SuppressWarnings({ "unchecked", "rawtypes" })
1337 @Override
1338 public void cheapMoveTo(EObject element, EObject parent, EReference containmentFeature) {
1339 metaStore.maintainMetamodel(containmentFeature);
1340 if (containmentFeature.isMany())
1341 cheapMoveTo(element, (EList) parent.eGet(containmentFeature));
1342 else if (element.eAdapters().contains(contentAdapter) && parent.eAdapters().contains(contentAdapter)) {
1343 contentAdapter.ignoreInsertionAndDeletion = element;
1344 try {
1345 parent.eSet(containmentFeature, element);
1346 } finally {
1347 contentAdapter.ignoreInsertionAndDeletion = null;
1348 }
1349 } else {
1350 parent.eSet(containmentFeature, element);
1351 }
1352 }
1353
1354 protected void addRootInternal(Notifier emfRoot) {
1355 if (!((emfRoot instanceof EObject) || (emfRoot instanceof Resource) || (emfRoot instanceof ResourceSet))) {
1356 throw new ViatraBaseException(ViatraBaseException.INVALID_EMFROOT);
1357 }
1358 expandToAdditionalRoot(emfRoot);
1359 }
1360
1361 @Override
1362 public Set<EClass> getAllCurrentClasses() {
1363 return instanceStore.getAllCurrentClasses();
1364 }
1365
1366 protected boolean isRegistrationNecessary(IndexingLevel level) {
1367 boolean inWildcardMode = isInWildcardMode(level);
1368 if (inWildcardMode && !loggedRegistrationMessage) {
1369 loggedRegistrationMessage = true;
1370 logger.warn("Type registration/unregistration not required in wildcard mode. This message will not be repeated for future occurences.");
1371 }
1372 return !inWildcardMode;
1373 }
1374
1375 protected <X, Y> void ensureNoListeners(Set<Object> unobservedTypes,
1376 final Map<Object, Map<X, Set<Y>>> listenerRegistry) {
1377 if (!Collections.disjoint(unobservedTypes, listenerRegistry.keySet()))
1378 throw new IllegalStateException("Cannot unregister observed types for which there are active listeners");
1379 }
1380
1381 protected void ensureNoListenersForDispose() {
1382 if (!(baseIndexChangeListeners.isEmpty() && subscribedFeatureListeners.isEmpty()
1383 && subscribedDataTypeListeners.isEmpty() && subscribedInstanceListeners.isEmpty()))
1384 throw new IllegalStateException("Cannot dispose while there are active listeners");
1385 }
1386
1387 /**
1388 * Resamples the values of not well-behaving derived features if those features are also indexed.
1389 */
1390 @Override
1391 public void resampleDerivedFeatures() {
1392 // otherwise notifications are delivered anyway
1393 if (!baseIndexOptions.isTraverseOnlyWellBehavingDerivedFeatures()) {
1394 // get all required classes
1395 Set<EClass> allCurrentClasses = instanceStore.getAllCurrentClasses();
1396 Set<EStructuralFeature> featuresToSample = new HashSet<>();
1397 // collect features to sample
1398 for (EClass cls : allCurrentClasses) {
1399 EList<EStructuralFeature> features = cls.getEAllStructuralFeatures();
1400 for (EStructuralFeature f : features) {
1401 // is feature only sampled?
1402 if (comprehension.onlySamplingFeature(f)) {
1403 featuresToSample.add(f);
1404 }
1405 }
1406 }
1407
1408 final EMFVisitor removalVisitor = contentAdapter.getVisitorForChange(false);
1409 final EMFVisitor insertionVisitor = contentAdapter.getVisitorForChange(true);
1410
1411 // iterate on instances
1412 for (final EStructuralFeature f : featuresToSample) {
1413 EClass containingClass = f.getEContainingClass();
1414 processAllInstances(containingClass, (type, instance) ->
1415 resampleFeatureValueForHolder(instance, f, insertionVisitor, removalVisitor));
1416 }
1417 notifyBaseIndexChangeListeners();
1418 }
1419 }
1420
1421 protected void resampleFeatureValueForHolder(EObject source, EStructuralFeature feature,
1422 EMFVisitor insertionVisitor, EMFVisitor removalVisitor) {
1423 // traverse features and update value
1424 Object newValue = source.eGet(feature);
1425 Set<Object> oldValues = instanceStore.getOldValuesForHolderAndFeature(source, toKey(feature));
1426 if (feature.isMany()) {
1427 resampleManyFeatureValueForHolder(source, feature, newValue, oldValues, insertionVisitor, removalVisitor);
1428 } else {
1429 resampleSingleFeatureValueForHolder(source, feature, newValue, oldValues, insertionVisitor, removalVisitor);
1430 }
1431
1432 }
1433
1434 protected void resampleManyFeatureValueForHolder(EObject source, EStructuralFeature feature, Object newValue,
1435 Set<Object> oldValues, EMFVisitor insertionVisitor, EMFVisitor removalVisitor) {
1436 InternalEObject internalEObject = (InternalEObject) source;
1437 Collection<?> newValues = (Collection<?>) newValue;
1438 // add those that are in new but not in old
1439 Set<Object> newValueSet = new HashSet<Object>(newValues);
1440 newValueSet.removeAll(oldValues);
1441 // remove those that are in old but not in new
1442 oldValues.removeAll(newValues);
1443 if (!oldValues.isEmpty()) {
1444 for (Object ov : oldValues) {
1445 comprehension.traverseFeature(removalVisitor, source, feature, ov, null);
1446 }
1447 ENotificationImpl removeNotification = new ENotificationImpl(internalEObject, Notification.REMOVE_MANY,
1448 feature, oldValues, null);
1449 notifyLightweightObservers(source, feature, removeNotification);
1450 }
1451 if (!newValueSet.isEmpty()) {
1452 for (Object nv : newValueSet) {
1453 comprehension.traverseFeature(insertionVisitor, source, feature, nv, null);
1454 }
1455 ENotificationImpl addNotification = new ENotificationImpl(internalEObject, Notification.ADD_MANY, feature,
1456 null, newValueSet);
1457 notifyLightweightObservers(source, feature, addNotification);
1458 }
1459 }
1460
1461 protected void resampleSingleFeatureValueForHolder(EObject source, EStructuralFeature feature, Object newValue,
1462 Set<Object> oldValues, EMFVisitor insertionVisitor, EMFVisitor removalVisitor) {
1463 InternalEObject internalEObject = (InternalEObject) source;
1464 Object oldValue = oldValues.stream().findFirst().orElse(null);
1465 if (!Objects.equals(oldValue, newValue)) {
1466 // value changed
1467 comprehension.traverseFeature(removalVisitor, source, feature, oldValue, null);
1468 comprehension.traverseFeature(insertionVisitor, source, feature, newValue, null);
1469 ENotificationImpl notification = new ENotificationImpl(internalEObject, Notification.SET, feature, oldValue,
1470 newValue);
1471 notifyLightweightObservers(source, feature, notification);
1472 }
1473 }
1474
1475 @Override
1476 public int countAllInstances(EClass type) {
1477 int result = 0;
1478
1479 Object typeKey = toKey(type);
1480 Set<Object> subTypes = metaStore.getSubTypeMap().get(typeKey);
1481 if (subTypes != null) {
1482 for (Object subTypeKey : subTypes) {
1483 result += statsStore.countInstances(subTypeKey);
1484 }
1485 }
1486 result += statsStore.countInstances(typeKey);
1487
1488 return result;
1489 }
1490
1491 @Override
1492 public int countDataTypeInstances(EDataType dataType) {
1493 return statsStore.countInstances(toKey(dataType));
1494 }
1495
1496 @Override
1497 public int countFeatureTargets(EObject seedSource, EStructuralFeature feature) {
1498 return featureData(feature).getDistinctValuesOfHolder(seedSource).size();
1499 }
1500
1501 @Override
1502 public int countFeatures(EStructuralFeature feature) {
1503 return statsStore.countFeatures(toKey(feature));
1504 }
1505
1506 protected IndexingLevel getIndexingLevel(Object type) {
1507 if (type instanceof EClass) {
1508 return getIndexingLevel((EClass)type);
1509 } else if (type instanceof EDataType) {
1510 return getIndexingLevel((EDataType)type);
1511 } else if (type instanceof EStructuralFeature) {
1512 return getIndexingLevel((EStructuralFeature)type);
1513 } else {
1514 throw new IllegalArgumentException("Unexpected type descriptor " + type.toString());
1515 }
1516 }
1517
1518 @Override
1519 public IndexingLevel getIndexingLevel(EClass type) {
1520 Object key = toKey(type);
1521 IndexingLevel level = directlyObservedClasses.get(key);
1522 if (level == null) {
1523 level = delayedClasses.get(key);
1524 }
1525 // Wildcard mode is never null
1526 return wildcardMode.merge(level);
1527 }
1528
1529 @Override
1530 public IndexingLevel getIndexingLevel(EDataType type) {
1531 Object key = toKey(type);
1532 IndexingLevel level = observedDataTypes.get(key);
1533 if (level == null) {
1534 level = delayedDataTypes.get(key);
1535 }
1536 // Wildcard mode is never null
1537 return wildcardMode.merge(level);
1538 }
1539
1540 @Override
1541 public IndexingLevel getIndexingLevel(EStructuralFeature feature) {
1542 Object key = toKey(feature);
1543 IndexingLevel level = observedFeatures.get(key);
1544 if (level == null) {
1545 level = delayedFeatures.get(key);
1546 }
1547 // Wildcard mode is never null
1548 return wildcardMode.merge(level);
1549 }
1550
1551 @Override
1552 public void executeAfterTraversal(final Runnable traversalCallback) throws InvocationTargetException {
1553 coalesceTraversals(() -> traversalCallbacks.add(traversalCallback));
1554 }
1555
1556 /**
1557 * Records a non-exception incident such as faulty notifications.
1558 * Depending on the strictness setting {@link BaseIndexOptions#isStrictNotificationMode()} and log levels,
1559 * this may be treated as a fatal error, merely logged, or just ignored.
1560 *
1561 * @param msgProvider message supplier that only invoked if the message actually gets logged.
1562 *
1563 * @since 2.3
1564 */
1565 protected void logIncident(Supplier<String> msgProvider) {
1566 if (baseIndexOptions.isStrictNotificationMode()) {
1567 // This will cause e.g. query engine to become tainted
1568 String msg = msgProvider.get();
1569 notifyFatalListener(msg, new IllegalStateException(msg));
1570 } else {
1571 if (notificationErrorReported) {
1572 if (logger.isDebugEnabled()) {
1573 String msg = msgProvider.get();
1574 logger.debug(msg);
1575 }
1576 } else {
1577 notificationErrorReported = true;
1578 String msg = msgProvider.get();
1579 logger.error(msg);
1580 }
1581 }
1582 }
1583 boolean notificationErrorReported = false;
1584
1585
1586// DESIGNATED CUSTOMIZATION POINTS FOR SUBCLASSES
1587
1588 /**
1589 * Point of customization, called by constructor
1590 * @since 2.3
1591 */
1592 protected NavigationHelperContentAdapter initContentAdapter() {
1593 switch (baseIndexOptions.getIndexerProfilerMode()) {
1594 case START_DISABLED:
1595 return new ProfilingNavigationHelperContentAdapter(this, false);
1596 case START_ENABLED:
1597 return new ProfilingNavigationHelperContentAdapter(this, true);
1598 case OFF:
1599 default:
1600 return new NavigationHelperContentAdapter(this);
1601 }
1602 }
1603
1604 /**
1605 * Point of customization, called by constructor
1606 * @since 2.3
1607 */
1608 protected EMFBaseIndexStatisticsStore initStatStore() {
1609 return new EMFBaseIndexStatisticsStore(this, logger);
1610 }
1611
1612 /**
1613 * Point of customization, called by constructor
1614 * @since 2.3
1615 */
1616 protected EMFBaseIndexInstanceStore initInstanceStore() {
1617 return new EMFBaseIndexInstanceStore(this, logger);
1618 }
1619
1620 /**
1621 * Point of customization, called by constructor
1622 * @since 2.3
1623 */
1624 protected EMFBaseIndexMetaStore initMetaStore() {
1625 return new EMFBaseIndexMetaStore(this);
1626 }
1627
1628 /**
1629 * Point of customization, called by constructor
1630 * @since 2.3
1631 */
1632 protected EMFModelComprehension initModelComprehension() {
1633 return new EMFModelComprehension(baseIndexOptions);
1634 }
1635
1636 /**
1637 * Point of customization, called at runtime
1638 * @since 2.3
1639 */
1640 protected TraversingVisitor initTraversingVisitor(final Map<Object, IndexingLevel> toGatherClasses,
1641 final Map<Object, IndexingLevel> toGatherFeatures, final Map<Object, IndexingLevel> toGatherDataTypes,
1642 final Map<Object, IndexingLevel> oldClasses) {
1643 return new NavigationHelperVisitor.TraversingVisitor(this,
1644 toGatherFeatures, toGatherClasses, oldClasses, toGatherDataTypes);
1645 }
1646
1647
1648
1649 /**
1650 * Point of customization, e.g. override to suppress
1651 * @since 2.3
1652 */
1653 protected void logIncidentAdapterRemoval(final Notifier notifier) {
1654 logIncident(() -> String.format("Erroneous removal of unattached notification adapter from notifier %s", notifier));
1655 }
1656
1657 /**
1658 * Point of customization, e.g. override to suppress
1659 * @since 2.3
1660 */
1661 protected void logIncidentFeatureTupleInsertion(final Object value, final EObject holder, Object featureKey) {
1662 logIncident(() -> String.format(
1663 "Error: trying to add duplicate value %s to the unique feature %s of host object %s. This indicates some errors in underlying model representation.",
1664 value, featureKey, holder));
1665 }
1666
1667 /**
1668 * Point of customization, e.g. override to suppress
1669 * @since 2.3
1670 */
1671 protected void logIncidentFeatureTupleRemoval(final Object value, final EObject holder, Object featureKey) {
1672 logIncident(() -> String.format(
1673 "Error: trying to remove duplicate value %s from the unique feature %s of host object %s. This indicates some errors in underlying model representation.",
1674 value, featureKey, holder));
1675 }
1676
1677 /**
1678 * Point of customization, e.g. override to suppress
1679 * @since 2.3
1680 */
1681 protected void logIncidentInstanceInsertion(final Object keyClass, final EObject value) {
1682 logIncident(() -> String.format("Notification received to index %s as a %s, but it already exists in the index. This indicates some errors in underlying model representation.", value, keyClass));
1683 }
1684
1685 /**
1686 * Point of customization, e.g. override to suppress
1687 * @since 2.3
1688 */
1689 protected void logIncidentInstanceRemoval(final Object keyClass, final EObject value) {
1690 logIncident(() -> String.format("Notification received to remove %s as a %s, but it is missing from the index. This indicates some errors in underlying model representation.", value, keyClass));
1691 }
1692
1693 /**
1694 * Point of customization, e.g. override to suppress
1695 * @since 2.3
1696 */
1697 protected void logIncidentStatRemoval(Object key) {
1698 logIncident(() -> String.format("No instances of %s is registered before calling removeInstance method.", key));
1699 }
1700
1701
1702}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperSetting.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperSetting.java
deleted file mode 100644
index 56556ea8..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperSetting.java
+++ /dev/null
@@ -1,73 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base.core;
11
12import org.eclipse.emf.ecore.EObject;
13import org.eclipse.emf.ecore.EStructuralFeature;
14import org.eclipse.emf.ecore.EStructuralFeature.Setting;
15
16/**
17 * EStructuralFeature.Setting implementation for the NavigationHelper.
18 *
19 * @author Tamás Szabó
20 *
21 */
22public class NavigationHelperSetting implements Setting {
23
24 private EStructuralFeature feature;
25 private EObject holder;
26 private Object value;
27
28 public NavigationHelperSetting() {
29 super();
30 }
31
32 public NavigationHelperSetting(EStructuralFeature feature, EObject holder, Object value) {
33 super();
34 this.feature = feature;
35 this.holder = holder;
36 this.value = value;
37 }
38
39 @Override
40 public EObject getEObject() {
41 return holder;
42 }
43
44 @Override
45 public EStructuralFeature getEStructuralFeature() {
46 return feature;
47 }
48
49 @Override
50 public Object get(boolean resolve) {
51 return value;
52 }
53
54 @Override
55 public void set(Object newValue) {
56 this.value = newValue;
57 }
58
59 @Override
60 public boolean isSet() {
61 return (value != null);
62 }
63
64 @Override
65 public void unset() {
66 this.value = null;
67 }
68
69 @Override
70 public String toString() {
71 return "feature = " + feature + " holder = " + holder + " value = " + value;
72 }
73}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperType.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperType.java
deleted file mode 100644
index 2bab4914..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperType.java
+++ /dev/null
@@ -1,14 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base.core;
11
12public enum NavigationHelperType {
13 REGISTER, ALL
14}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperVisitor.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperVisitor.java
deleted file mode 100644
index b5de8d20..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/NavigationHelperVisitor.java
+++ /dev/null
@@ -1,441 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.core;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.Map;
14import java.util.Set;
15
16import org.eclipse.emf.ecore.EAttribute;
17import org.eclipse.emf.ecore.EClass;
18import org.eclipse.emf.ecore.EClassifier;
19import org.eclipse.emf.ecore.EObject;
20import org.eclipse.emf.ecore.EReference;
21import org.eclipse.emf.ecore.EStructuralFeature;
22import org.eclipse.emf.ecore.resource.Resource;
23import org.eclipse.emf.ecore.util.EcoreUtil;
24import tools.refinery.viatra.runtime.base.api.IndexingLevel;
25import tools.refinery.viatra.runtime.base.comprehension.EMFModelComprehension;
26import tools.refinery.viatra.runtime.base.comprehension.EMFVisitor;
27
28public abstract class NavigationHelperVisitor extends EMFVisitor {
29
30 /**
31 * A visitor for processing a single change event. Does not traverse the model. Uses all the observed types.
32 */
33 public static class ChangeVisitor extends NavigationHelperVisitor {
34 // local copies to save actual state, in case visitor has to be saved for later due unresolvable proxies
35 private final IndexingLevel wildcardMode;
36 private final Map<Object, IndexingLevel> allObservedClasses;
37 private final Map<Object, IndexingLevel> observedDataTypes;
38 private final Map<Object, IndexingLevel> observedFeatures;
39 private final Map<Object, Boolean> sampledClasses;
40
41 public ChangeVisitor(NavigationHelperImpl navigationHelper, boolean isInsertion) {
42 super(navigationHelper, isInsertion, false);
43 wildcardMode = navigationHelper.getWildcardLevel();
44 allObservedClasses = navigationHelper.getAllObservedClassesInternal(); // new HashSet<EClass>();
45 observedDataTypes = navigationHelper.getObservedDataTypesInternal(); // new HashSet<EDataType>();
46 observedFeatures = navigationHelper.getObservedFeaturesInternal(); // new HashSet<EStructuralFeature>();
47 sampledClasses = new HashMap<Object, Boolean>();
48 }
49
50 @Override
51 protected boolean observesClass(Object eClass) {
52 return wildcardMode.hasInstances() || (IndexingLevel.FULL == allObservedClasses.get(eClass)) || registerSampledClass(eClass);
53 }
54
55 protected boolean registerSampledClass(Object eClass) {
56 Boolean classAlreadyChecked = sampledClasses.get(eClass);
57 if (classAlreadyChecked != null) {
58 return classAlreadyChecked;
59 }
60 boolean isSampledClass = isSampledClass(eClass);
61 sampledClasses.put(eClass, isSampledClass);
62 // do not modify observation configuration during traversal
63 return false;
64 }
65
66 @Override
67 protected boolean observesDataType(Object type) {
68 return wildcardMode.hasInstances() || (IndexingLevel.FULL == observedDataTypes.get(type));
69 }
70
71 @Override
72 protected boolean observesFeature(Object feature) {
73 return wildcardMode.hasInstances() || (IndexingLevel.FULL == observedFeatures.get(feature));
74 }
75
76 @Override
77 protected boolean countsFeature(Object feature) {
78 return wildcardMode.hasStatistics() || observedFeatures.containsKey(feature) && observedFeatures.get(feature).hasStatistics();
79 }
80
81 @Override
82 protected boolean countsDataType(Object type) {
83 return wildcardMode.hasStatistics() || observedDataTypes.containsKey(type) && observedDataTypes.get(type).hasStatistics();
84 }
85
86 @Override
87 protected boolean countsClass(Object eClass) {
88 return wildcardMode.hasStatistics() || allObservedClasses.containsKey(eClass) && allObservedClasses.get(eClass).hasStatistics();
89 }
90 }
91
92 /**
93 * A visitor for a single-pass traversal of the whole model, processing only the given types and inserting them.
94 */
95 public static class TraversingVisitor extends NavigationHelperVisitor {
96 private final IndexingLevel wildcardMode;
97 Map<Object, IndexingLevel> features;
98 Map<Object, IndexingLevel> newClasses;
99 Map<Object, IndexingLevel> oldClasses; // if decends from an old class, no need to add!
100 Map<Object, IndexingLevel> classObservationMap; // true for a class even if only a supertype is included in classes;
101 Map<Object, IndexingLevel> dataTypes;
102
103 public TraversingVisitor(NavigationHelperImpl navigationHelper, Map<Object, IndexingLevel> features, Map<Object, IndexingLevel> newClasses,
104 Map<Object, IndexingLevel> oldClasses, Map<Object, IndexingLevel> dataTypes) {
105 super(navigationHelper, true, true);
106 wildcardMode = navigationHelper.getWildcardLevel();
107 this.features = features;
108 this.newClasses = newClasses;
109 this.oldClasses = oldClasses;
110 this.classObservationMap = new HashMap<Object, IndexingLevel>();
111 this.dataTypes = dataTypes;
112 }
113
114 protected IndexingLevel getExistingIndexingLevel(Object eClass){
115 IndexingLevel result = IndexingLevel.NONE;
116 result = result.merge(oldClasses.get(eClass));
117 result = result.merge(oldClasses.get(metaStore.getEObjectClassKey()));
118 if (IndexingLevel.FULL == result) return result;
119 Set<Object> superTypes = metaStore.getSuperTypeMap().get(eClass);
120 if (superTypes != null){
121 for(Object superType: superTypes){
122 result = result.merge(oldClasses.get(superType));
123 if (IndexingLevel.FULL == result) return result;
124 }
125 }
126 return result;
127 }
128
129 protected IndexingLevel getRequestedIndexingLevel(Object eClass){
130 IndexingLevel result = IndexingLevel.NONE;
131 result = result.merge(newClasses.get(eClass));
132 result = result.merge(newClasses.get(metaStore.getEObjectClassKey()));
133 if (IndexingLevel.FULL == result) return result;
134 Set<Object> superTypes = metaStore.getSuperTypeMap().get(eClass);
135 if (superTypes != null){
136 for(Object superType: superTypes){
137 result = result.merge(newClasses.get(superType));
138 if (IndexingLevel.FULL == result) return result;
139 }
140 }
141 return result;
142 }
143
144 protected IndexingLevel getTraversalIndexing(Object eClass){
145 IndexingLevel level = classObservationMap.get(eClass);
146 if (level == null){
147 IndexingLevel existing = getExistingIndexingLevel(eClass);
148 IndexingLevel requested = getRequestedIndexingLevel(eClass);
149
150 // Calculate the type of indexing which needs to be executed to reach requested indexing state
151 // Considering indexes which are already available
152 if (existing == requested || existing == IndexingLevel.FULL) return IndexingLevel.NONE;
153 if (requested == IndexingLevel.FULL) return IndexingLevel.FULL;
154 if (requested.hasStatistics() == existing.hasStatistics()) return IndexingLevel.NONE;
155 if (requested.hasStatistics()) return IndexingLevel.STATISTICS;
156 return IndexingLevel.NONE;
157 }
158 return level;
159 }
160
161 @Override
162 protected boolean observesClass(Object eClass) {
163 if (wildcardMode.hasInstances()) {
164 return true;
165 }
166 return IndexingLevel.FULL == getTraversalIndexing(eClass);
167 }
168
169 @Override
170 protected boolean countsClass(Object eClass) {
171 return wildcardMode.hasStatistics() || getTraversalIndexing(eClass).hasStatistics();
172 }
173
174 @Override
175 protected boolean observesDataType(Object type) {
176 return wildcardMode.hasInstances() || (IndexingLevel.FULL == dataTypes.get(type));
177 }
178
179 @Override
180 protected boolean observesFeature(Object feature) {
181 return wildcardMode.hasInstances() || (IndexingLevel.FULL == features.get(feature));
182 }
183
184 @Override
185 protected boolean countsDataType(Object type) {
186 return wildcardMode.hasStatistics() || dataTypes.containsKey(type) && dataTypes.get(type).hasStatistics();
187 }
188
189 @Override
190 protected boolean countsFeature(Object feature) {
191 return wildcardMode.hasStatistics() || features.containsKey(feature) && features.get(feature).hasStatistics();
192 }
193
194 @Override
195 public boolean avoidTransientContainmentLink(EObject source, EReference reference, EObject targetObject) {
196 return !targetObject.eAdapters().contains(navigationHelper.contentAdapter);
197 }
198 }
199
200 protected NavigationHelperImpl navigationHelper;
201 boolean isInsertion;
202 boolean descendHierarchy;
203 boolean traverseOnlyWellBehavingDerivedFeatures;
204 EMFBaseIndexInstanceStore instanceStore;
205 EMFBaseIndexStatisticsStore statsStore;
206 EMFBaseIndexMetaStore metaStore;
207
208 NavigationHelperVisitor(NavigationHelperImpl navigationHelper, boolean isInsertion, boolean descendHierarchy) {
209 super(isInsertion /* preOrder iff insertion */);
210 this.navigationHelper = navigationHelper;
211 instanceStore = navigationHelper.instanceStore;
212 metaStore = navigationHelper.metaStore;
213 statsStore = navigationHelper.statsStore;
214 this.isInsertion = isInsertion;
215 this.descendHierarchy = descendHierarchy;
216 this.traverseOnlyWellBehavingDerivedFeatures = navigationHelper.getBaseIndexOptions()
217 .isTraverseOnlyWellBehavingDerivedFeatures();
218 }
219
220 @Override
221 public boolean pruneSubtrees(EObject source) {
222 return !descendHierarchy;
223 }
224
225 @Override
226 public boolean pruneSubtrees(Resource source) {
227 return !descendHierarchy;
228 }
229
230 @Override
231 public boolean pruneFeature(EStructuralFeature feature) {
232 Object featureKey = toKey(feature);
233 if (observesFeature(featureKey) || countsFeature(featureKey)) {
234 return false;
235 }
236 if (feature instanceof EAttribute){
237 Object dataTypeKey = toKey(((EAttribute) feature).getEAttributeType());
238 if (observesDataType(dataTypeKey) || countsDataType(dataTypeKey)) {
239 return false;
240 }
241 }
242 return !(isInsertion && navigationHelper.isExpansionAllowed() && feature instanceof EReference
243 && !((EReference) feature).isContainment());
244 }
245
246 /**
247 * @param feature
248 * key of feature (EStructuralFeature or String id)
249 */
250 protected abstract boolean observesFeature(Object feature);
251
252 /**
253 * @param feature
254 * key of data type (EDatatype or String id)
255 */
256 protected abstract boolean observesDataType(Object type);
257
258 /**
259 * @param feature
260 * key of class (EClass or String id)
261 */
262 protected abstract boolean observesClass(Object eClass);
263
264 protected abstract boolean countsFeature(Object feature);
265
266 protected abstract boolean countsDataType(Object type);
267
268 protected abstract boolean countsClass(Object eClass);
269
270 @Override
271 public void visitElement(EObject source) {
272 EClass eClass = source.eClass();
273 if (eClass.eIsProxy()) {
274 eClass = (EClass) EcoreUtil.resolve(eClass, source);
275 }
276
277 final Object classKey = toKey(eClass);
278 if (observesClass(classKey)) {
279 if (isInsertion) {
280 instanceStore.insertIntoInstanceSet(classKey, source);
281 } else {
282 instanceStore.removeFromInstanceSet(classKey, source);
283 }
284 }
285 if (countsClass(classKey)){
286 if (isInsertion){
287 statsStore.addInstance(classKey);
288 } else {
289 statsStore.removeInstance(classKey);
290 }
291 }
292 }
293
294 @Override
295 public void visitAttribute(EObject source, EAttribute feature, Object target) {
296 Object featureKey = toKey(feature);
297 final Object eAttributeType = toKey(feature.getEAttributeType());
298 Object internalValueRepresentation = null;
299 if (observesFeature(featureKey)) {
300 // if (internalValueRepresentation == null) // always true
301 internalValueRepresentation = metaStore.toInternalValueRepresentation(target);
302 boolean unique = feature.isUnique();
303 if (isInsertion) {
304 instanceStore.insertFeatureTuple(featureKey, unique, internalValueRepresentation, source);
305 } else {
306 instanceStore.removeFeatureTuple(featureKey, unique, internalValueRepresentation, source);
307 }
308 }
309 if (countsFeature(featureKey)){
310 if (isInsertion) {
311 statsStore.addFeature(source, featureKey);
312 }else{
313 statsStore.removeFeature(source, featureKey);
314 }
315 }
316 if (observesDataType(eAttributeType)) {
317 if (internalValueRepresentation == null)
318 internalValueRepresentation = metaStore.toInternalValueRepresentation(target);
319 if (isInsertion) {
320 instanceStore.insertIntoDataTypeMap(eAttributeType, internalValueRepresentation);
321 } else {
322 instanceStore.removeFromDataTypeMap(eAttributeType, internalValueRepresentation);
323 }
324 }
325 if (countsDataType(eAttributeType)){
326 if (isInsertion){
327 statsStore.addInstance(eAttributeType);
328 } else {
329 statsStore.removeInstance(eAttributeType);
330 }
331 }
332 }
333
334 @Override
335 public void visitInternalContainment(EObject source, EReference feature, EObject target) {
336 visitReference(source, feature, target);
337 }
338
339 @Override
340 public void visitNonContainmentReference(EObject source, EReference feature, EObject target) {
341 visitReference(source, feature, target);
342 if (isInsertion) {
343 navigationHelper.considerForExpansion(target);
344 }
345 }
346
347 protected void visitReference(EObject source, EReference feature, EObject target) {
348 Object featureKey = toKey(feature);
349 if (observesFeature(featureKey)) {
350 boolean unique = feature.isUnique();
351 if (isInsertion) {
352 instanceStore.insertFeatureTuple(featureKey, unique, target, source);
353 } else {
354 instanceStore.removeFeatureTuple(featureKey, unique, target, source);
355 }
356 }
357 if (countsFeature(featureKey)){
358 if (isInsertion){
359 statsStore.addFeature(source, featureKey);
360 } else {
361 statsStore.removeFeature(source, featureKey);
362 }
363 }
364 }
365
366 @Override
367 // do not attempt to resolve proxies referenced from resources that are still being loaded
368 public boolean attemptProxyResolutions(EObject source, EReference feature) {
369 // emptyness is checked first to avoid costly resource lookup in most cases
370 if (navigationHelper.resolutionDelayingResources.isEmpty())
371 return true;
372 else
373 return ! navigationHelper.resolutionDelayingResources.contains(source.eResource());
374 }
375
376 @Override
377 public void visitProxyReference(EObject source, EReference reference, EObject targetObject, Integer position) {
378 if (isInsertion) { // only attempt to resolve proxies if they are inserted
379 // final Object result = source.eGet(reference, true);
380 // if (reference.isMany()) {
381 // // no idea which element to get, have to iterate through
382 // for (EObject touch : (Iterable<EObject>) result);
383 // }
384 if (navigationHelper.isFeatureResolveIgnored(reference))
385 return; // skip resolution; would be ignored anyways
386 if (position != null && reference.isMany() && attemptProxyResolutions(source, reference)) {
387 // there is added value in doing the resolution now, when we know the position
388 // this may save an iteration through the EList if successful
389 @SuppressWarnings("unchecked")
390 EObject touch = ((java.util.List<EObject>) source.eGet(reference, true)).get(position);
391 // if resolution successful, no further action needed
392 if (!touch.eIsProxy())
393 return;
394 }
395 // otherwise, attempt resolution later, at the end of the coalesced traversal block
396 navigationHelper.delayedProxyResolutions.addPairOrNop(source, reference);
397 }
398 }
399
400 protected Object toKey(EStructuralFeature feature) {
401 return metaStore.toKey(feature);
402 }
403
404 protected Object toKey(EClassifier eClassifier) {
405 return metaStore.toKey(eClassifier);
406 }
407
408 /**
409 * Decides whether the type must be observed in order to allow re-sampling of any of its features. If not
410 * well-behaving features are traversed and there is such a feature for this class, the class will be registered
411 * into the navigation helper, which may cause a re-traversal.
412 *
413 */
414 protected boolean isSampledClass(Object eClass) {
415 if (!traverseOnlyWellBehavingDerivedFeatures) {
416 // TODO we could save this reverse lookup if the calling method would have the EClass, not just the key
417 EClass knownClass = (EClass) metaStore.getKnownClassifierForKey(eClass);
418 // check features that are traversed, and whether there is any that must be sampled
419 for (EStructuralFeature feature : knownClass.getEAllStructuralFeatures()) {
420 EMFModelComprehension comprehension = navigationHelper.getComprehension();
421 if (comprehension.untraversableDirectly(feature))
422 continue;
423 final boolean visitorPrunes = pruneFeature(feature);
424 if (visitorPrunes)
425 continue;
426 // we found a feature to be visited
427 if (comprehension.onlySamplingFeature(feature)) {
428 // we found a feature that must be sampled
429 navigationHelper.registerEClasses(Collections.singleton(feature.getEContainingClass()), IndexingLevel.FULL);
430 return true;
431 }
432 }
433 }
434 return false;
435 }
436
437 @Override
438 public boolean descendAlongCrossResourceContainments() {
439 return this.navigationHelper.traversalDescendsAlongCrossResourceContainment();
440 }
441}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/TransitiveClosureHelperImpl.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/TransitiveClosureHelperImpl.java
deleted file mode 100644
index 552696cb..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/TransitiveClosureHelperImpl.java
+++ /dev/null
@@ -1,153 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base.core;
11
12import java.util.ArrayList;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Set;
16
17import org.eclipse.emf.ecore.EClass;
18import org.eclipse.emf.ecore.EObject;
19import org.eclipse.emf.ecore.EReference;
20import org.eclipse.emf.ecore.EStructuralFeature;
21import org.eclipse.emf.ecore.util.EContentAdapter;
22import tools.refinery.viatra.runtime.base.api.FeatureListener;
23import tools.refinery.viatra.runtime.base.api.IndexingLevel;
24import tools.refinery.viatra.runtime.base.api.InstanceListener;
25import tools.refinery.viatra.runtime.base.api.NavigationHelper;
26import tools.refinery.viatra.runtime.base.api.TransitiveClosureHelper;
27import tools.refinery.viatra.runtime.base.itc.alg.incscc.IncSCCAlg;
28import tools.refinery.viatra.runtime.base.itc.alg.misc.IGraphPathFinder;
29import tools.refinery.viatra.runtime.base.itc.igraph.ITcObserver;
30
31/**
32 * Implementation class for the {@link TransitiveClosureHelper}.
33 * It uses a {@link NavigationHelper} instance to wrap an EMF model
34 * and make it suitable for the {@link IncSCCAlg} algorithm.
35 *
36 * @author Tamas Szabo
37 *
38 */
39public class TransitiveClosureHelperImpl extends EContentAdapter implements TransitiveClosureHelper,
40 ITcObserver<EObject>, FeatureListener, InstanceListener {
41
42 private IncSCCAlg<EObject> sccAlg;
43 private Set<EStructuralFeature> features;
44 private Set<EClass> classes;
45 private EMFDataSource dataSource;
46 private List<ITcObserver<EObject>> tcObservers;
47 private NavigationHelper navigationHelper;
48 private boolean disposeBaseIndexWhenDisposed;
49
50 public TransitiveClosureHelperImpl(final NavigationHelper navigationHelper, boolean disposeBaseIndexWhenDisposed, Set<EReference> references) {
51 this.tcObservers = new ArrayList<ITcObserver<EObject>>();
52 this.navigationHelper = navigationHelper;
53 this.disposeBaseIndexWhenDisposed = disposeBaseIndexWhenDisposed;
54
55 //NavigationHelper only accepts Set<EStructuralFeature> upon registration
56 this.features = new HashSet<EStructuralFeature>(references);
57 this.classes = collectEClasses();
58 /*this.classes = Collections.emptySet();*/
59 if (!navigationHelper.isInWildcardMode())
60 navigationHelper.registerObservedTypes(classes, null, features, IndexingLevel.FULL);
61
62 this.navigationHelper.addFeatureListener(features, this);
63 this.navigationHelper.addInstanceListener(classes, this);
64
65 this.dataSource = new EMFDataSource(navigationHelper, references, classes);
66
67 this.sccAlg = new IncSCCAlg<EObject>(dataSource);
68 this.sccAlg.attachObserver(this);
69 }
70
71 private Set<EClass> collectEClasses() {
72 Set<EClass> classes = new HashSet<EClass>();
73 for (EStructuralFeature ref : features) {
74 classes.add(ref.getEContainingClass());
75 classes.add(((EReference) ref).getEReferenceType());
76 }
77 return classes;
78 }
79
80 @Override
81 public void attachObserver(ITcObserver<EObject> to) {
82 this.tcObservers.add(to);
83 }
84
85 @Override
86 public void detachObserver(ITcObserver<EObject> to) {
87 this.tcObservers.remove(to);
88 }
89
90 @Override
91 public Set<EObject> getAllReachableTargets(EObject source) {
92 return this.sccAlg.getAllReachableTargets(source);
93 }
94
95 @Override
96 public Set<EObject> getAllReachableSources(EObject target) {
97 return this.sccAlg.getAllReachableSources(target);
98 }
99
100 @Override
101 public boolean isReachable(EObject source, EObject target) {
102 return this.sccAlg.isReachable(source, target);
103 }
104
105 @Override
106 public void tupleInserted(EObject source, EObject target) {
107 for (ITcObserver<EObject> to : tcObservers) {
108 to.tupleInserted(source, target);
109 }
110 }
111
112 @Override
113 public void tupleDeleted(EObject source, EObject target) {
114 for (ITcObserver<EObject> to : tcObservers) {
115 to.tupleDeleted(source, target);
116 }
117 }
118
119 @Override
120 public void dispose() {
121 this.sccAlg.dispose();
122 this.navigationHelper.removeInstanceListener(classes, this);
123 this.navigationHelper.removeFeatureListener(features, this);
124
125 if (disposeBaseIndexWhenDisposed)
126 this.navigationHelper.dispose();
127 }
128
129 @Override
130 public void featureInserted(EObject host, EStructuralFeature feature, Object value) {
131 this.dataSource.notifyEdgeInserted(host, (EObject) value);
132 }
133
134 @Override
135 public void featureDeleted(EObject host, EStructuralFeature feature, Object value) {
136 this.dataSource.notifyEdgeDeleted(host, (EObject) value);
137 }
138
139 @Override
140 public void instanceInserted(EClass clazz, EObject instance) {
141 this.dataSource.notifyNodeInserted(instance);
142 }
143
144 @Override
145 public void instanceDeleted(EClass clazz, EObject instance) {
146 this.dataSource.notifyNodeDeleted(instance);
147 }
148
149 @Override
150 public IGraphPathFinder<EObject> getPathFinder() {
151 return this.sccAlg.getPathFinder();
152 }
153}
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/profiler/ProfilingNavigationHelperContentAdapter.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/profiler/ProfilingNavigationHelperContentAdapter.java
deleted file mode 100644
index 3ab15430..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/core/profiler/ProfilingNavigationHelperContentAdapter.java
+++ /dev/null
@@ -1,155 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Laszlo Gati, 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.base.core.profiler;
10
11import org.eclipse.emf.common.notify.Notification;
12import org.eclipse.emf.common.notify.Notifier;
13import tools.refinery.viatra.runtime.base.core.NavigationHelperContentAdapter;
14import tools.refinery.viatra.runtime.base.core.NavigationHelperImpl;
15
16/**
17 *
18 * @noinstantiate This class is not intended to be instantiated by clients.
19 * @noreference This class is not intended to be referenced by clients.
20 */
21public final class ProfilingNavigationHelperContentAdapter extends NavigationHelperContentAdapter {
22
23 private static class StopWatch {
24
25 private long currentStartTimeNs = 0l;
26 private long totalElapsedTimeNs = 0l;
27 private boolean running = false;
28
29 /**
30 * Puts the timer in running state and saves the current time.
31 */
32 private void start() {
33 currentStartTimeNs = System.nanoTime();
34 running = true;
35
36 }
37
38 /**
39 * Puts the the timer in stopped state and saves the total time spent in started
40 * state between the last reset and now
41 */
42 private void stop() {
43 totalElapsedTimeNs = getTotalElapsedTimeNs();
44 running = false;
45 }
46
47 /**
48 * @return time between the last start and now
49 */
50 private long getCurrentElapsedTimeNs() {
51 return System.nanoTime() - currentStartTimeNs;
52 }
53
54 /**
55 * @return the total time spent in started state between the last reset and now
56 */
57 private long getTotalElapsedTimeNs() {
58 return running ? getCurrentElapsedTimeNs() + totalElapsedTimeNs : totalElapsedTimeNs;
59 }
60
61 /**
62 * Saves the current time and resets all the time spent between the last reset and now.
63 */
64 private void resetTime() {
65 currentStartTimeNs = System.currentTimeMillis();
66 totalElapsedTimeNs = 0;
67 }
68 }
69
70 long notificationCount = 0l;
71 StopWatch watch = new StopWatch();
72 boolean isEnabled = false;
73
74 boolean measurement = false;
75
76 public ProfilingNavigationHelperContentAdapter(NavigationHelperImpl navigationHelper, boolean enabled) {
77 super(navigationHelper);
78 this.isEnabled = enabled;
79 }
80
81 @Override
82 public void notifyChanged(Notification notification) {
83 // Handle possibility of reentrancy
84 if (isEnabled && !measurement) {
85 try {
86 measurement = true;
87 notificationCount++;
88 watch.start();
89 super.notifyChanged(notification);
90 } finally {
91 watch.stop();
92 measurement = false;
93 }
94 } else {
95 super.notifyChanged(notification);
96 }
97 }
98
99 @Override
100 public void setTarget(Notifier target) {
101 // Handle possibility of reentrancy
102 if (isEnabled && !measurement) {
103 try {
104 measurement = true;
105 notificationCount++;
106 watch.start();
107 super.setTarget(target);
108 } finally {
109 watch.stop();
110 measurement = false;
111 }
112 } else {
113 super.setTarget(target);
114 }
115 }
116
117 @Override
118 public void unsetTarget(Notifier target) {
119 // Handle possibility of reentrancy
120 if (isEnabled && !measurement) {
121 try {
122 measurement = true;
123 notificationCount++;
124 watch.start();
125 super.unsetTarget(target);
126 } finally {
127 watch.stop();
128 measurement = false;
129 }
130 } else {
131 super.unsetTarget(target);
132 }
133 }
134
135 public long getNotificationCount() {
136 return notificationCount;
137 }
138
139 public long getTotalMeasuredTimeInMS() {
140 return watch.getTotalElapsedTimeNs() / 1_000_000l;
141 }
142
143 public boolean isEnabled() {
144 return isEnabled;
145 }
146
147 public void setEnabled(boolean isEnabled) {
148 this.isEnabled = isEnabled;
149 }
150
151 public void resetMeasurement() {
152 notificationCount = 0;
153 watch.resetTime();
154 }
155} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/exception/ViatraBaseException.java b/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/exception/ViatraBaseException.java
deleted file mode 100644
index fe656c34..00000000
--- a/subprojects/viatra-runtime-base/src/main/java/tools/refinery/viatra/runtime/base/exception/ViatraBaseException.java
+++ /dev/null
@@ -1,25 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, 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.base.exception;
11
12import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
13
14public class ViatraBaseException extends ViatraQueryRuntimeException {
15
16 private static final long serialVersionUID = -5145445047912938251L;
17
18 public static final String EMPTY_REF_LIST = "At least one EReference must be provided!";
19 public static final String INVALID_EMFROOT = "Emf navigation helper can only be attached on the contents of an EMF EObject, Resource, or ResourceSet.";
20
21 public ViatraBaseException(String s) {
22 super(s);
23 }
24
25}
diff --git a/subprojects/viatra-runtime-localsearch/build.gradle.kts b/subprojects/viatra-runtime-localsearch/build.gradle.kts
index 2d3886a5..31c0c634 100644
--- a/subprojects/viatra-runtime-localsearch/build.gradle.kts
+++ b/subprojects/viatra-runtime-localsearch/build.gradle.kts
@@ -10,6 +10,5 @@ plugins {
10 10
11dependencies { 11dependencies {
12 implementation(project(":refinery-viatra-runtime")) 12 implementation(project(":refinery-viatra-runtime"))
13 implementation(libs.ecore)
14 implementation(libs.slf4j.log4j) 13 implementation(libs.slf4j.log4j)
15} 14}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java
index 0f7c7b01..bfb76d9a 100644
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/ExecutionLoggerAdapter.java
@@ -3,41 +3,40 @@
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.localsearch; 9package tools.refinery.viatra.runtime.localsearch;
10 10
11import java.util.Optional;
12import java.util.function.Consumer;
13
14import tools.refinery.viatra.runtime.localsearch.matcher.ILocalSearchAdapter; 11import tools.refinery.viatra.runtime.localsearch.matcher.ILocalSearchAdapter;
15import tools.refinery.viatra.runtime.localsearch.matcher.LocalSearchMatcher; 12import tools.refinery.viatra.runtime.localsearch.matcher.LocalSearchMatcher;
16import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation; 13import tools.refinery.viatra.runtime.localsearch.operations.IPatternMatcherOperation;
17import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation; 14import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
18import tools.refinery.viatra.runtime.localsearch.operations.check.nobase.ScopeCheck;
19import tools.refinery.viatra.runtime.localsearch.plan.SearchPlan; 15import tools.refinery.viatra.runtime.localsearch.plan.SearchPlan;
20 16
17import java.util.Optional;
18import java.util.function.Consumer;
19
21/** 20/**
22 * @since 2.0 21 * @since 2.0
23 */ 22 */
24public final class ExecutionLoggerAdapter implements ILocalSearchAdapter { 23public final class ExecutionLoggerAdapter implements ILocalSearchAdapter {
25 24
26 volatile String indentation = ""; 25 volatile String indentation = "";
27 private final Consumer<String> outputConsumer; 26 private final Consumer<String> outputConsumer;
28 27
29 public ExecutionLoggerAdapter(Consumer<String> outputConsumer) { 28 public ExecutionLoggerAdapter(Consumer<String> outputConsumer) {
30 this.outputConsumer = outputConsumer; 29 this.outputConsumer = outputConsumer;
31 } 30 }
32 31
33 private void logMessage(String message) { 32 private void logMessage(String message) {
34 outputConsumer.accept(message); 33 outputConsumer.accept(message);
35 } 34 }
36 35
37 private void logMessage(String message, Object...args) { 36 private void logMessage(String message, Object...args) {
38 outputConsumer.accept(String.format(message, args)); 37 outputConsumer.accept(String.format(message, args));
39 } 38 }
40 39
41 @Override 40 @Override
42 public void patternMatchingStarted(LocalSearchMatcher lsMatcher) { 41 public void patternMatchingStarted(LocalSearchMatcher lsMatcher) {
43 logMessage(indentation + "[ START] " + lsMatcher.getQuerySpecification().getFullyQualifiedName()); 42 logMessage(indentation + "[ START] " + lsMatcher.getQuerySpecification().getFullyQualifiedName());
@@ -56,7 +55,7 @@ public final class ExecutionLoggerAdapter implements ILocalSearchAdapter {
56 55
57 @Override 56 @Override
58 public void operationSelected(SearchPlan plan, ISearchOperation operation, MatchingFrame frame, boolean isBacktrack) { 57 public void operationSelected(SearchPlan plan, ISearchOperation operation, MatchingFrame frame, boolean isBacktrack) {
59 String category = isBacktrack ? "[ BACK] " : "[SELECT] "; 58 String category = isBacktrack ? "[ BACK] " : "[SELECT] ";
60 logMessage(indentation + category + operation.toString()); 59 logMessage(indentation + category + operation.toString());
61 if (operation instanceof IPatternMatcherOperation) { 60 if (operation instanceof IPatternMatcherOperation) {
62 indentation = indentation + "\t"; 61 indentation = indentation + "\t";
@@ -66,7 +65,6 @@ public final class ExecutionLoggerAdapter implements ILocalSearchAdapter {
66 @Override 65 @Override
67 public void operationExecuted(SearchPlan plan, ISearchOperation operation, MatchingFrame frame, 66 public void operationExecuted(SearchPlan plan, ISearchOperation operation, MatchingFrame frame,
68 boolean isSuccessful) { 67 boolean isSuccessful) {
69 if (operation instanceof ScopeCheck) return;
70 if (operation instanceof IPatternMatcherOperation && indentation.length() > 0) { 68 if (operation instanceof IPatternMatcherOperation && indentation.length() > 0) {
71 indentation = indentation.substring(1); 69 indentation = indentation.substring(1);
72 } 70 }
@@ -77,9 +75,9 @@ public final class ExecutionLoggerAdapter implements ILocalSearchAdapter {
77 public void matchFound(SearchPlan plan, MatchingFrame frame) { 75 public void matchFound(SearchPlan plan, MatchingFrame frame) {
78 logMessage(indentation + "[ MATCH] " + plan.getSourceBody().getPattern().getFullyQualifiedName() + " " + frame.toString()); 76 logMessage(indentation + "[ MATCH] " + plan.getSourceBody().getPattern().getFullyQualifiedName() + " " + frame.toString());
79 } 77 }
80 78
81 @Override 79 @Override
82 public void duplicateMatchFound(MatchingFrame frame) { 80 public void duplicateMatchFound(MatchingFrame frame) {
83 logMessage(indentation + "[ DUPL.] " + frame.toString()); 81 logMessage(indentation + "[ DUPL.] " + frame.toString());
84 } 82 }
85} \ No newline at end of file 83}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java
index 9caf32bb..bdbc663c 100644
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/MatchingFrame.java
@@ -3,21 +3,19 @@
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.localsearch; 10package tools.refinery.viatra.runtime.localsearch;
11 11
12import java.util.Arrays;
13import java.util.stream.Collectors;
14
15import org.eclipse.emf.ecore.EObject;
16import org.eclipse.emf.ecore.EStructuralFeature;
17import tools.refinery.viatra.runtime.matchers.tuple.IModifiableTuple; 12import tools.refinery.viatra.runtime.matchers.tuple.IModifiableTuple;
18import tools.refinery.viatra.runtime.matchers.tuple.VolatileTuple; 13import tools.refinery.viatra.runtime.matchers.tuple.VolatileTuple;
19import tools.refinery.viatra.runtime.matchers.util.Preconditions; 14import tools.refinery.viatra.runtime.matchers.util.Preconditions;
20 15
16import java.util.Arrays;
17import java.util.stream.Collectors;
18
21/** 19/**
22 * A MatchingFrame is a Volatile Tuple implementation used by the local search engine internally. 20 * A MatchingFrame is a Volatile Tuple implementation used by the local search engine internally.
23 */ 21 */
@@ -34,7 +32,7 @@ public class MatchingFrame extends VolatileTuple implements IModifiableTuple {
34 public MatchingFrame(int frameSize) { 32 public MatchingFrame(int frameSize) {
35 this.frame = new Object[frameSize]; 33 this.frame = new Object[frameSize];
36 } 34 }
37 35
38 /** 36 /**
39 * Creates a copy of another matching frame; the two frames can be updated separately 37 * Creates a copy of another matching frame; the two frames can be updated separately
40 * @param other 38 * @param other
@@ -48,7 +46,7 @@ public class MatchingFrame extends VolatileTuple implements IModifiableTuple {
48 46
49 /** 47 /**
50 * Returns the value stored inside the matching frame. 48 * Returns the value stored inside the matching frame.
51 * 49 *
52 * @param position 50 * @param position
53 * @return the element stored in the selected position in the frame, or null if it is not yet set 51 * @return the element stored in the selected position in the frame, or null if it is not yet set
54 * @throws IndexOutOfBoundsException 52 * @throws IndexOutOfBoundsException
@@ -60,10 +58,10 @@ public class MatchingFrame extends VolatileTuple implements IModifiableTuple {
60 Preconditions.checkElementIndex(position, frame.length); 58 Preconditions.checkElementIndex(position, frame.length);
61 return frame[position]; 59 return frame[position];
62 } 60 }
63 61
64 /** 62 /**
65 * Sets the value of the variable at the given position. For internal use in LS matching only. 63 * Sets the value of the variable at the given position. For internal use in LS matching only.
66 * 64 *
67 * @param position the position of the variable within the frame 65 * @param position the position of the variable within the frame
68 * @param value the value to be set for the variable 66 * @param value the value to be set for the variable
69 */ 67 */
@@ -71,7 +69,7 @@ public class MatchingFrame extends VolatileTuple implements IModifiableTuple {
71 Preconditions.checkElementIndex(position, frame.length); 69 Preconditions.checkElementIndex(position, frame.length);
72 frame[position] = value; 70 frame[position] = value;
73 } 71 }
74 72
75 public boolean testAndSetValue(Integer position, Object value) { 73 public boolean testAndSetValue(Integer position, Object value) {
76 Preconditions.checkElementIndex(position, frame.length); 74 Preconditions.checkElementIndex(position, frame.length);
77 if (frame[position] == null) { 75 if (frame[position] == null) {
@@ -86,20 +84,14 @@ public class MatchingFrame extends VolatileTuple implements IModifiableTuple {
86 public String toString() { 84 public String toString() {
87 return Arrays.stream(frame).map(this::stringRepresentation).collect(Collectors.joining(", ", "[", "]")); 85 return Arrays.stream(frame).map(this::stringRepresentation).collect(Collectors.joining(", ", "[", "]"));
88 } 86 }
89 87
90 private String stringRepresentation(Object obj) { 88 private String stringRepresentation(Object obj) {
91 if (obj == null) { 89 if (obj == null) {
92 return "_"; 90 return "_";
93 } else if (obj instanceof EObject) {
94 EObject eObject = (EObject) obj;
95 final EStructuralFeature feature = eObject.eClass().getEStructuralFeature("identifier");
96 if (feature != null) {
97 return String.format("%s : %s", eObject.eGet(feature), eObject.eClass().getName());
98 }
99 } 91 }
100 return obj.toString(); 92 return obj.toString();
101 } 93 }
102 94
103 @Override 95 @Override
104 public int getSize() { 96 public int getSize() {
105 return frame.length; 97 return frame.length;
@@ -109,7 +101,7 @@ public class MatchingFrame extends VolatileTuple implements IModifiableTuple {
109 public Object get(int index) { 101 public Object get(int index) {
110 return getValue(index); 102 return getValue(index);
111 } 103 }
112 104
113 @Override 105 @Override
114 public Object[] getElements() { 106 public Object[] getElements() {
115 return Arrays.copyOf(frame, frame.length); 107 return Arrays.copyOf(frame, frame.length);
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java
index 380774bb..71aa4aac 100644
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/ISearchContext.java
@@ -3,20 +3,12 @@
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.localsearch.matcher; 9package tools.refinery.viatra.runtime.localsearch.matcher;
10 10
11import java.util.Collections;
12import java.util.Set;
13
14import org.apache.log4j.Logger; 11import org.apache.log4j.Logger;
15import org.eclipse.emf.ecore.EClass;
16import org.eclipse.emf.ecore.EDataType;
17import org.eclipse.emf.ecore.EStructuralFeature;
18import tools.refinery.viatra.runtime.base.api.IndexingLevel;
19import tools.refinery.viatra.runtime.base.api.NavigationHelper;
20import tools.refinery.viatra.runtime.localsearch.matcher.integration.IAdornmentProvider; 12import tools.refinery.viatra.runtime.localsearch.matcher.integration.IAdornmentProvider;
21import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; 13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
22import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider; 14import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
@@ -26,9 +18,11 @@ import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
26import tools.refinery.viatra.runtime.matchers.util.ICache; 18import tools.refinery.viatra.runtime.matchers.util.ICache;
27import tools.refinery.viatra.runtime.matchers.util.IProvider; 19import tools.refinery.viatra.runtime.matchers.util.IProvider;
28 20
21import java.util.Collections;
22
29/** 23/**
30 * The {@link ISearchContext} interface allows search operations to reuse platform services such as the indexer. 24 * The {@link ISearchContext} interface allows search operations to reuse platform services such as the indexer.
31 * 25 *
32 * @author Zoltan Ujhelyi 26 * @author Zoltan Ujhelyi
33 * @noreference This interface is not intended to be referenced by clients. 27 * @noreference This interface is not intended to be referenced by clients.
34 * @noimplement This interface is not intended to be implemented by clients. 28 * @noimplement This interface is not intended to be implemented by clients.
@@ -36,43 +30,36 @@ import tools.refinery.viatra.runtime.matchers.util.IProvider;
36 * 30 *
37 */ 31 */
38public interface ISearchContext { 32public interface ISearchContext {
39 33
40 /** 34 /**
41 * Provides access to the generic query runtime context of the current engine 35 * Provides access to the generic query runtime context of the current engine
42 * @since 1.7 36 * @since 1.7
43 */ 37 */
44 IQueryRuntimeContext getRuntimeContext(); 38 IQueryRuntimeContext getRuntimeContext();
45 39
46 /**
47 * @param classes
48 * @param dataTypes
49 * @param features
50 */
51 void registerObservedTypes(Set<EClass> classes, Set<EDataType> dataTypes, Set<EStructuralFeature> features);
52
53 /** 40 /**
54 * Returns a matcher for a selected query specification. 41 * Returns a matcher for a selected query specification.
55 * 42 *
56 * @throws ViatraQueryRuntimeException 43 * @throws ViatraQueryRuntimeException
57 * @since 1.5 44 * @since 1.5
58 */ 45 */
59 IQueryResultProvider getMatcher(CallWithAdornment dependency); 46 IQueryResultProvider getMatcher(CallWithAdornment dependency);
60 47
61 /** 48 /**
62 * Allows search operations to cache values through the entire lifecycle of the local search backend. The values are 49 * Allows search operations to cache values through the entire lifecycle of the local search backend. The values are
63 * calculated if not cached before using the given provider, or returned from the cache accordingly. 50 * calculated if not cached before using the given provider, or returned from the cache accordingly.
64 * 51 *
65 * @since 1.7 52 * @since 1.7
66 */ 53 */
67 <T> T accessBackendLevelCache(Object key, Class<? extends T> clazz, IProvider<T> valueProvider); 54 <T> T accessBackendLevelCache(Object key, Class<? extends T> clazz, IProvider<T> valueProvider);
68 55
69 /** 56 /**
70 * Returns the engine-specific logger 57 * Returns the engine-specific logger
71 * 58 *
72 * @since 2.0 59 * @since 2.0
73 */ 60 */
74 Logger getLogger(); 61 Logger getLogger();
75 62
76 /** 63 /**
77 * @noreference This class is not intended to be referenced by clients. 64 * @noreference This class is not intended to be referenced by clients.
78 * @noimplement This interface is not intended to be implemented by clients. 65 * @noimplement This interface is not intended to be implemented by clients.
@@ -80,34 +67,24 @@ public interface ISearchContext {
80 */ 67 */
81 public class SearchContext implements ISearchContext { 68 public class SearchContext implements ISearchContext {
82 69
83 private final NavigationHelper navigationHelper;
84 private final IQueryRuntimeContext runtimeContext; 70 private final IQueryRuntimeContext runtimeContext;
85 71
86 private final ICache backendLevelCache; 72 private final ICache backendLevelCache;
87 private final Logger logger; 73 private final Logger logger;
88 private final ResultProviderRequestor resultProviderRequestor; 74 private final ResultProviderRequestor resultProviderRequestor;
89 75
90 /** 76 /**
91 * Initializes a search context using an arbitrary backend context 77 * Initializes a search context using an arbitrary backend context
92 */ 78 */
93 public SearchContext(IQueryBackendContext backendContext, ICache backendLevelCache, 79 public SearchContext(IQueryBackendContext backendContext, ICache backendLevelCache,
94 ResultProviderRequestor resultProviderRequestor) { 80 ResultProviderRequestor resultProviderRequestor) {
95 this.resultProviderRequestor = resultProviderRequestor; 81 this.resultProviderRequestor = resultProviderRequestor;
96 this.runtimeContext = backendContext.getRuntimeContext(); 82 this.runtimeContext = backendContext.getRuntimeContext();
97 this.logger = backendContext.getLogger(); 83 this.logger = backendContext.getLogger();
98 this.navigationHelper = null; 84
99
100 this.backendLevelCache = backendLevelCache; 85 this.backendLevelCache = backendLevelCache;
101 } 86 }
102 87
103 public void registerObservedTypes(Set<EClass> classes, Set<EDataType> dataTypes, Set<EStructuralFeature> features) {
104 if (this.navigationHelper.isInWildcardMode()) {
105 // In wildcard mode, everything is registered (+ register throws an exception)
106 return;
107 }
108 this.navigationHelper.registerObservedTypes(classes, dataTypes, features, IndexingLevel.FULL);
109 }
110
111 /** 88 /**
112 * @throws ViatraQueryRuntimeException 89 * @throws ViatraQueryRuntimeException
113 * @since 2.1 90 * @since 2.1
@@ -121,7 +98,7 @@ public interface ISearchContext {
121 } 98 }
122 return Collections.emptySet(); 99 return Collections.emptySet();
123 }; 100 };
124 return resultProviderRequestor.requestResultProvider(dependency.getCall(), 101 return resultProviderRequestor.requestResultProvider(dependency.getCall(),
125 IAdornmentProvider.toHint(adornmentProvider)); 102 IAdornmentProvider.toHint(adornmentProvider));
126 } 103 }
127 104
@@ -133,11 +110,11 @@ public interface ISearchContext {
133 public IQueryRuntimeContext getRuntimeContext() { 110 public IQueryRuntimeContext getRuntimeContext() {
134 return runtimeContext; 111 return runtimeContext;
135 } 112 }
136 113
137 @Override 114 @Override
138 public Logger getLogger() { 115 public Logger getLogger() {
139 return logger; 116 return logger;
140 } 117 }
141 118
142 } 119 }
143} 120}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchBackendFactoryProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchBackendFactoryProvider.java
deleted file mode 100644
index bba381d3..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchBackendFactoryProvider.java
+++ /dev/null
@@ -1,29 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, 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.localsearch.matcher.integration;
10
11import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
12import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactoryProvider;
13
14/**
15 * @since 2.0
16 */
17public class LocalSearchBackendFactoryProvider implements IQueryBackendFactoryProvider {
18
19 @Override
20 public IQueryBackendFactory getFactory() {
21 return LocalSearchEMFBackendFactory.INSTANCE;
22 }
23
24 @Override
25 public boolean isSystemDefaultSearchBackend() {
26 return true;
27 }
28
29} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchEMFBackendFactory.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchEMFBackendFactory.java
deleted file mode 100644
index 5bffebac..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchEMFBackendFactory.java
+++ /dev/null
@@ -1,65 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, 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.localsearch.matcher.integration;
10
11import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
12import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend;
13import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
14import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
15import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17
18/**
19 * @author Marton Bur, Zoltan Ujhelyi
20 * @since 2.0
21 *
22 */
23public enum LocalSearchEMFBackendFactory implements IQueryBackendFactory {
24
25
26 INSTANCE;
27
28 /**
29 * @since 1.5
30 */
31 @Override
32 public IQueryBackend create(IQueryBackendContext context) {
33 return new LocalSearchBackend(context) {
34
35 @Override
36 protected AbstractLocalSearchResultProvider initializeResultProvider(PQuery query, QueryEvaluationHint hints) {
37 return new LocalSearchResultProvider(this, context, query, planProvider, hints);
38 }
39
40 @Override
41 public IQueryBackendFactory getFactory() {
42 return INSTANCE;
43 }
44 };
45 }
46
47 @Override
48 public Class<? extends IQueryBackend> getBackendClass() {
49 return LocalSearchBackend.class;
50 }
51
52 /**
53 * @since 1.4
54 */
55 @Override
56 public IMatcherCapability calculateRequiredCapability(PQuery query, QueryEvaluationHint hint) {
57 return LocalSearchHints.parse(hint);
58 }
59
60 @Override
61 public boolean isCaching() {
62 return false;
63 }
64
65}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java
index 75f338b6..5f3895be 100644
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchHints.java
@@ -3,63 +3,51 @@
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.localsearch.matcher.integration; 9package tools.refinery.viatra.runtime.localsearch.matcher.integration;
10 10
11import static tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHintOptions.ADORNMENT_PROVIDER;
12import static tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHintOptions.CALL_DELEGATION_STRATEGY;
13import static tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHintOptions.FLATTEN_CALL_PREDICATE;
14import static tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHintOptions.PLANNER_COST_FUNCTION;
15import static tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHintOptions.PLANNER_TABLE_ROW_COUNT;
16import static tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHintOptions.USE_BASE_INDEX;
17import static tools.refinery.viatra.runtime.matchers.backend.CommonQueryHintOptions.normalizationTraceCollector;
18
19import java.util.HashMap;
20import java.util.Map;
21import java.util.Objects;
22
23import tools.refinery.viatra.runtime.localsearch.planner.cost.ICostFunction; 11import tools.refinery.viatra.runtime.localsearch.planner.cost.ICostFunction;
24import tools.refinery.viatra.runtime.localsearch.planner.cost.impl.IndexerBasedConstraintCostFunction; 12import tools.refinery.viatra.runtime.localsearch.planner.cost.impl.IndexerBasedConstraintCostFunction;
25import tools.refinery.viatra.runtime.localsearch.planner.cost.impl.StatisticsBasedConstraintCostFunction; 13import tools.refinery.viatra.runtime.localsearch.planner.cost.impl.StatisticsBasedConstraintCostFunction;
26import tools.refinery.viatra.runtime.localsearch.planner.cost.impl.VariableBindingBasedCostFunction; 14import tools.refinery.viatra.runtime.matchers.backend.*;
27import tools.refinery.viatra.runtime.matchers.backend.ICallDelegationStrategy;
28import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
29import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
30import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
31import tools.refinery.viatra.runtime.matchers.backend.QueryHintOption;
32import tools.refinery.viatra.runtime.matchers.psystem.rewriters.DefaultFlattenCallPredicate;
33import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IFlattenCallPredicate; 15import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IFlattenCallPredicate;
34import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IRewriterTraceCollector; 16import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IRewriterTraceCollector;
35import tools.refinery.viatra.runtime.matchers.psystem.rewriters.NeverFlattenCallPredicate;
36import tools.refinery.viatra.runtime.matchers.psystem.rewriters.NopTraceCollector; 17import tools.refinery.viatra.runtime.matchers.psystem.rewriters.NopTraceCollector;
37 18
19import java.util.HashMap;
20import java.util.Map;
21import java.util.Objects;
22
23import static tools.refinery.viatra.runtime.localsearch.matcher.integration.LocalSearchHintOptions.*;
24import static tools.refinery.viatra.runtime.matchers.backend.CommonQueryHintOptions.normalizationTraceCollector;
25
38/** 26/**
39 * Type safe builder and extractor for Local search specific hints 27 * Type safe builder and extractor for Local search specific hints
40 * 28 *
41 * @author Grill Balázs 29 * @author Grill Balázs
42 * @since 1.4 30 * @since 1.4
43 * 31 *
44 */ 32 */
45public final class LocalSearchHints implements IMatcherCapability { 33public final class LocalSearchHints implements IMatcherCapability {
46 34
47 private Boolean useBase = null; 35 private Boolean useBase = null;
48 36
49 private Integer rowCount = null; 37 private Integer rowCount = null;
50 38
51 private ICostFunction costFunction = null; 39 private ICostFunction costFunction = null;
52 40
53 private IFlattenCallPredicate flattenCallPredicate = null; 41 private IFlattenCallPredicate flattenCallPredicate = null;
54 42
55 private ICallDelegationStrategy callDelegationStrategy = null; 43 private ICallDelegationStrategy callDelegationStrategy = null;
56 44
57 private IAdornmentProvider adornmentProvider = null; 45 private IAdornmentProvider adornmentProvider = null;
58 46
59 private IRewriterTraceCollector traceCollector = NopTraceCollector.INSTANCE; 47 private IRewriterTraceCollector traceCollector = NopTraceCollector.INSTANCE;
60 48
61 private IQueryBackendFactory backendFactory = null; 49 private IQueryBackendFactory backendFactory = null;
62 50
63 private LocalSearchHints() {} 51 private LocalSearchHints() {}
64 52
65 /** 53 /**
@@ -68,53 +56,14 @@ public final class LocalSearchHints implements IMatcherCapability {
68 public static LocalSearchHints getDefaultOverriddenBy(QueryEvaluationHint overridingHint){ 56 public static LocalSearchHints getDefaultOverriddenBy(QueryEvaluationHint overridingHint){
69 return parse(getDefault().build(overridingHint)); 57 return parse(getDefault().build(overridingHint));
70 } 58 }
71 59
72 /** 60 /**
73 * Default settings which are considered the most safe, providing a reasonable performance for most of the cases. Assumes the availability of the base indexer. 61 * Default settings which are considered the most safe, providing a reasonable performance for most of the cases. Assumes the availability of the base indexer.
74 */ 62 */
75 public static LocalSearchHints getDefault(){ 63 public static LocalSearchHints getDefault(){
76 LocalSearchHints result = new LocalSearchHints(); 64 return getDefaultGeneric();
77 result.useBase = USE_BASE_INDEX.getDefaultValue();
78 result.rowCount = PLANNER_TABLE_ROW_COUNT.getDefaultValue();
79 result.costFunction = PLANNER_COST_FUNCTION.getDefaultValue();
80 result.flattenCallPredicate = FLATTEN_CALL_PREDICATE.getDefaultValue();
81 result.callDelegationStrategy = CALL_DELEGATION_STRATEGY.getDefaultValue();
82 result.adornmentProvider = ADORNMENT_PROVIDER.getDefaultValue();
83 result.backendFactory = LocalSearchEMFBackendFactory.INSTANCE;
84 return result;
85 } 65 }
86 66
87 /**
88 * With this setting, the patterns are flattened before planning. This may cause performance gain in some cases compared to the {@link #getDefault()} settings,
89 * However this should be used with care for patterns containing calls with several bodies.
90 */
91 public static LocalSearchHints getDefaultFlatten(){
92 LocalSearchHints result = new LocalSearchHints();
93 result.useBase = true;
94 result.rowCount = 4;
95 result.costFunction = new IndexerBasedConstraintCostFunction();
96 result.flattenCallPredicate = new DefaultFlattenCallPredicate();
97 result.callDelegationStrategy = CALL_DELEGATION_STRATEGY.getDefaultValue();
98 result.adornmentProvider = ADORNMENT_PROVIDER.getDefaultValue();
99 result.backendFactory = LocalSearchEMFBackendFactory.INSTANCE;
100 return result;
101 }
102
103 /**
104 * Settings to be used when the base index is not available.
105 */
106 public static LocalSearchHints getDefaultNoBase(){
107 LocalSearchHints result = new LocalSearchHints();
108 result.useBase = false;
109 result.rowCount = 4;
110 result.costFunction = new VariableBindingBasedCostFunction();
111 result.flattenCallPredicate = new NeverFlattenCallPredicate();
112 result.callDelegationStrategy = ICallDelegationStrategy.FULL_BACKEND_ADHESION;
113 result.adornmentProvider = ADORNMENT_PROVIDER.getDefaultValue();
114 result.backendFactory = LocalSearchEMFBackendFactory.INSTANCE;
115 return result;
116 }
117
118 /** 67 /**
119 * Initializes the generic (not EMF specific) search backend with the default settings 68 * Initializes the generic (not EMF specific) search backend with the default settings
120 * @since 1.7 69 * @since 1.7
@@ -130,7 +79,7 @@ public final class LocalSearchHints implements IMatcherCapability {
130 result.backendFactory = LocalSearchGenericBackendFactory.INSTANCE; 79 result.backendFactory = LocalSearchGenericBackendFactory.INSTANCE;
131 return result; 80 return result;
132 } 81 }
133 82
134 /** 83 /**
135 * Initializes the default search backend with hybrid-enabled settings 84 * Initializes the default search backend with hybrid-enabled settings
136 * @since 2.1 85 * @since 2.1
@@ -142,7 +91,7 @@ public final class LocalSearchHints implements IMatcherCapability {
142 new DontFlattenIncrementalPredicate(), new DontFlattenDisjunctive()); 91 new DontFlattenIncrementalPredicate(), new DontFlattenDisjunctive());
143 return result; 92 return result;
144 } 93 }
145 94
146 /** 95 /**
147 * Initializes the generic (not EMF specific) search backend with hybrid-enabled settings 96 * Initializes the generic (not EMF specific) search backend with hybrid-enabled settings
148 * @since 2.1 97 * @since 2.1
@@ -154,10 +103,10 @@ public final class LocalSearchHints implements IMatcherCapability {
154 new DontFlattenIncrementalPredicate(), new DontFlattenDisjunctive()); 103 new DontFlattenIncrementalPredicate(), new DontFlattenDisjunctive());
155 return result; 104 return result;
156 } 105 }
157 106
158 public static LocalSearchHints parse(QueryEvaluationHint hint){ 107 public static LocalSearchHints parse(QueryEvaluationHint hint){
159 LocalSearchHints result = new LocalSearchHints(); 108 LocalSearchHints result = new LocalSearchHints();
160 109
161 result.useBase = USE_BASE_INDEX.getValueOrNull(hint); 110 result.useBase = USE_BASE_INDEX.getValueOrNull(hint);
162 result.rowCount = PLANNER_TABLE_ROW_COUNT.getValueOrNull(hint); 111 result.rowCount = PLANNER_TABLE_ROW_COUNT.getValueOrNull(hint);
163 result.flattenCallPredicate = FLATTEN_CALL_PREDICATE.getValueOrNull(hint); 112 result.flattenCallPredicate = FLATTEN_CALL_PREDICATE.getValueOrNull(hint);
@@ -165,15 +114,15 @@ public final class LocalSearchHints implements IMatcherCapability {
165 result.costFunction = PLANNER_COST_FUNCTION.getValueOrNull(hint); 114 result.costFunction = PLANNER_COST_FUNCTION.getValueOrNull(hint);
166 result.adornmentProvider = ADORNMENT_PROVIDER.getValueOrNull(hint); 115 result.adornmentProvider = ADORNMENT_PROVIDER.getValueOrNull(hint);
167 result.traceCollector = normalizationTraceCollector.getValueOrDefault(hint); 116 result.traceCollector = normalizationTraceCollector.getValueOrDefault(hint);
168 117
169 return result; 118 return result;
170 } 119 }
171 120
172 121
173 private Map<QueryHintOption<?>, Object> calculateHintMap() { 122 private Map<QueryHintOption<?>, Object> calculateHintMap() {
174 Map<QueryHintOption<?>, Object> map = new HashMap<>(); 123 Map<QueryHintOption<?>, Object> map = new HashMap<>();
175 if (useBase != null){ 124 if (useBase != null){
176 USE_BASE_INDEX.insertOverridingValue(map, useBase); 125 USE_BASE_INDEX.insertOverridingValue(map, useBase);
177 } 126 }
178 if (rowCount != null){ 127 if (rowCount != null){
179 PLANNER_TABLE_ROW_COUNT.insertOverridingValue(map, rowCount); 128 PLANNER_TABLE_ROW_COUNT.insertOverridingValue(map, rowCount);
@@ -195,43 +144,43 @@ public final class LocalSearchHints implements IMatcherCapability {
195 } 144 }
196 return map; 145 return map;
197 } 146 }
198 147
199 public QueryEvaluationHint build(){ 148 public QueryEvaluationHint build(){
200 Map<QueryHintOption<?>, Object> map = calculateHintMap(); 149 Map<QueryHintOption<?>, Object> map = calculateHintMap();
201 return new QueryEvaluationHint(map, backendFactory); 150 return new QueryEvaluationHint(map, backendFactory);
202 } 151 }
203 152
204 /** 153 /**
205 * @since 1.7 154 * @since 1.7
206 */ 155 */
207 public QueryEvaluationHint build(QueryEvaluationHint overridingHint) { 156 public QueryEvaluationHint build(QueryEvaluationHint overridingHint) {
208 if (overridingHint == null) 157 if (overridingHint == null)
209 return build(); 158 return build();
210 159
211 IQueryBackendFactory factory = (overridingHint.getQueryBackendFactory() == null) 160 IQueryBackendFactory factory = (overridingHint.getQueryBackendFactory() == null)
212 ? this.backendFactory 161 ? this.backendFactory
213 : overridingHint.getQueryBackendFactory(); 162 : overridingHint.getQueryBackendFactory();
214 163
215 Map<QueryHintOption<?>, Object> hints = calculateHintMap(); 164 Map<QueryHintOption<?>, Object> hints = calculateHintMap();
216 if (overridingHint.getBackendHintSettings() != null) { 165 if (overridingHint.getBackendHintSettings() != null) {
217 hints.putAll(overridingHint.getBackendHintSettings()); 166 hints.putAll(overridingHint.getBackendHintSettings());
218 } 167 }
219 168
220 return new QueryEvaluationHint(hints, factory); 169 return new QueryEvaluationHint(hints, factory);
221 } 170 }
222 171
223 public boolean isUseBase() { 172 public boolean isUseBase() {
224 return useBase; 173 return useBase;
225 } 174 }
226 175
227 public ICostFunction getCostFunction() { 176 public ICostFunction getCostFunction() {
228 return costFunction; 177 return costFunction;
229 } 178 }
230 179
231 public IFlattenCallPredicate getFlattenCallPredicate() { 180 public IFlattenCallPredicate getFlattenCallPredicate() {
232 return flattenCallPredicate; 181 return flattenCallPredicate;
233 } 182 }
234 183
235 /** 184 /**
236 * @since 2.1 185 * @since 2.1
237 */ 186 */
@@ -242,7 +191,7 @@ public final class LocalSearchHints implements IMatcherCapability {
242 public Integer getRowCount() { 191 public Integer getRowCount() {
243 return rowCount; 192 return rowCount;
244 } 193 }
245 194
246 /** 195 /**
247 * @since 1.5 196 * @since 1.5
248 */ 197 */
@@ -256,28 +205,28 @@ public final class LocalSearchHints implements IMatcherCapability {
256 public IRewriterTraceCollector getTraceCollector() { 205 public IRewriterTraceCollector getTraceCollector() {
257 return traceCollector == null ? normalizationTraceCollector.getDefaultValue() : traceCollector; 206 return traceCollector == null ? normalizationTraceCollector.getDefaultValue() : traceCollector;
258 } 207 }
259 208
260 public LocalSearchHints setUseBase(boolean useBase) { 209 public LocalSearchHints setUseBase(boolean useBase) {
261 this.useBase = useBase; 210 this.useBase = useBase;
262 return this; 211 return this;
263 } 212 }
264 213
265 public LocalSearchHints setRowCount(int rowCount) { 214 public LocalSearchHints setRowCount(int rowCount) {
266 this.rowCount = rowCount; 215 this.rowCount = rowCount;
267 return this; 216 return this;
268 } 217 }
269 218
270 public LocalSearchHints setCostFunction(ICostFunction costFunction) { 219 public LocalSearchHints setCostFunction(ICostFunction costFunction) {
271 this.costFunction = costFunction; 220 this.costFunction = costFunction;
272 return this; 221 return this;
273 } 222 }
274 223
275 public LocalSearchHints setFlattenCallPredicate(IFlattenCallPredicate flattenCallPredicate) { 224 public LocalSearchHints setFlattenCallPredicate(IFlattenCallPredicate flattenCallPredicate) {
276 this.flattenCallPredicate = flattenCallPredicate; 225 this.flattenCallPredicate = flattenCallPredicate;
277 return this; 226 return this;
278 } 227 }
279 228
280 229
281 /** 230 /**
282 * @since 2.1 231 * @since 2.1
283 */ 232 */
@@ -293,7 +242,7 @@ public final class LocalSearchHints implements IMatcherCapability {
293 this.traceCollector = traceCollector; 242 this.traceCollector = traceCollector;
294 return this; 243 return this;
295 } 244 }
296 245
297 /** 246 /**
298 * @since 1.5 247 * @since 1.5
299 */ 248 */
@@ -301,37 +250,37 @@ public final class LocalSearchHints implements IMatcherCapability {
301 this.adornmentProvider = adornmentProvider; 250 this.adornmentProvider = adornmentProvider;
302 return this; 251 return this;
303 } 252 }
304 253
305 public static LocalSearchHints customizeUseBase(boolean useBase){ 254 public static LocalSearchHints customizeUseBase(boolean useBase){
306 return new LocalSearchHints().setUseBase(useBase); 255 return new LocalSearchHints().setUseBase(useBase);
307 } 256 }
308 257
309 public static LocalSearchHints customizeRowCount(int rowCount){ 258 public static LocalSearchHints customizeRowCount(int rowCount){
310 return new LocalSearchHints().setRowCount(rowCount); 259 return new LocalSearchHints().setRowCount(rowCount);
311 } 260 }
312 261
313 public static LocalSearchHints customizeCostFunction(ICostFunction costFunction){ 262 public static LocalSearchHints customizeCostFunction(ICostFunction costFunction){
314 return new LocalSearchHints().setCostFunction(costFunction); 263 return new LocalSearchHints().setCostFunction(costFunction);
315 } 264 }
316 265
317 public static LocalSearchHints customizeFlattenCallPredicate(IFlattenCallPredicate predicate){ 266 public static LocalSearchHints customizeFlattenCallPredicate(IFlattenCallPredicate predicate){
318 return new LocalSearchHints().setFlattenCallPredicate(predicate); 267 return new LocalSearchHints().setFlattenCallPredicate(predicate);
319 } 268 }
320 269
321 /** 270 /**
322 * @since 2.1 271 * @since 2.1
323 */ 272 */
324 public static LocalSearchHints customizeCallDelegationStrategy(ICallDelegationStrategy strategy){ 273 public static LocalSearchHints customizeCallDelegationStrategy(ICallDelegationStrategy strategy){
325 return new LocalSearchHints().setCallDelegationStrategy(strategy); 274 return new LocalSearchHints().setCallDelegationStrategy(strategy);
326 } 275 }
327 276
328 /** 277 /**
329 * @since 1.5 278 * @since 1.5
330 */ 279 */
331 public static LocalSearchHints customizeAdornmentProvider(IAdornmentProvider adornmentProvider){ 280 public static LocalSearchHints customizeAdornmentProvider(IAdornmentProvider adornmentProvider){
332 return new LocalSearchHints().setAdornmentProvider(adornmentProvider); 281 return new LocalSearchHints().setAdornmentProvider(adornmentProvider);
333 } 282 }
334 283
335 /** 284 /**
336 * @since 1.6 285 * @since 1.6
337 */ 286 */
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchResultProvider.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchResultProvider.java
deleted file mode 100644
index a3017b18..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/matcher/integration/LocalSearchResultProvider.java
+++ /dev/null
@@ -1,56 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, 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.localsearch.matcher.integration;
10
11import tools.refinery.viatra.runtime.localsearch.plan.IPlanProvider;
12import tools.refinery.viatra.runtime.localsearch.planner.compiler.EMFOperationCompiler;
13import tools.refinery.viatra.runtime.localsearch.planner.compiler.IOperationCompiler;
14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
15import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
16import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
17import tools.refinery.viatra.runtime.matchers.context.IndexingService;
18import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
19
20/**
21 * @author Marton Bur, Zoltan Ujhelyi
22 *
23 */
24public class LocalSearchResultProvider extends AbstractLocalSearchResultProvider {
25
26 /**
27 * @throws ViatraQueryRuntimeException
28 * @since 1.5
29 */
30 public LocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query,
31 IPlanProvider planProvider) {
32 this(backend, context, query, planProvider, null);
33 }
34
35 /**
36 * @throws ViatraQueryRuntimeException
37 * @since 1.5
38 */
39 public LocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query,
40 IPlanProvider planProvider, QueryEvaluationHint userHints) {
41 super(backend, context, query, planProvider, userHints);
42 }
43
44 @Override
45 protected void indexInitializationBeforePlanning() {
46 super.indexInitializationBeforePlanning();
47
48 indexReferredTypesOfQuery(query, IndexingService.STATISTICS);
49 }
50
51 @Override
52 protected IOperationCompiler getOperationCompiler(IQueryBackendContext backendContext,
53 LocalSearchHints configuration) {
54 return new EMFOperationCompiler(runtimeContext, configuration.isUseBase());
55 }
56}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ContainmentCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ContainmentCheck.java
deleted file mode 100644
index 9dfb16f5..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/ContainmentCheck.java
+++ /dev/null
@@ -1,85 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, 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.localsearch.operations.check;
10
11import java.util.Arrays;
12import java.util.List;
13import java.util.function.Function;
14
15import org.eclipse.emf.ecore.EObject;
16import org.eclipse.emf.ecore.EStructuralFeature;
17import org.eclipse.emf.ecore.util.EcoreUtil;
18import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
19import tools.refinery.viatra.runtime.localsearch.exceptions.LocalSearchException;
20import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
21import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
22import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
23
24/**
25 * A simple operation that checks whether a {@link EStructuralFeature} connects two selected variables.
26 * @noextend This class is not intended to be subclassed by clients.
27 */
28public class ContainmentCheck implements ISearchOperation {
29
30 private class Executor extends CheckOperationExecutor {
31
32 @Override
33 protected boolean check(MatchingFrame frame, ISearchContext context) {
34 try {
35 EObject child = (EObject) frame.getValue(childPosition);
36 EObject container = (EObject)frame.getValue(containerPosition);
37
38 if (transitive) {
39 return EcoreUtil.isAncestor(container, child);
40 } else {
41 return child.eContainer().equals(container);
42 }
43 } catch (ClassCastException e) {
44 throw new LocalSearchException(LocalSearchException.TYPE_ERROR, e);
45 }
46 }
47
48 @Override
49 public ISearchOperation getOperation() {
50 return ContainmentCheck.this;
51 }
52 }
53
54 int childPosition;
55 int containerPosition;
56 private boolean transitive;
57
58 public ContainmentCheck(int childPosition, int containerPosition, boolean transitive) {
59 super();
60 this.childPosition = childPosition;
61 this.containerPosition = containerPosition;
62 this.transitive = transitive;
63 }
64
65 @Override
66 public ISearchOperationExecutor createExecutor() {
67 return new Executor();
68 }
69
70 @Override
71 public String toString() {
72 return toString(Object::toString);
73 }
74
75 @Override
76 public String toString(Function<Integer, String> variableMapping) {
77 return "check containment +"+variableMapping.apply(containerPosition)+" <>--> +"+childPosition+(transitive ? " transitively" : " directly");
78 }
79
80 @Override
81 public List<Integer> getVariablePositions() {
82 return Arrays.asList(childPosition, containerPosition);
83 }
84
85}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfClassCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfClassCheck.java
deleted file mode 100644
index 68d92040..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfClassCheck.java
+++ /dev/null
@@ -1,75 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, 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.localsearch.operations.check;
10
11import java.util.Arrays;
12import java.util.List;
13import java.util.Objects;
14import java.util.function.Function;
15
16import org.eclipse.emf.ecore.EClass;
17import org.eclipse.emf.ecore.EObject;
18import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
19import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
20import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22
23/**
24 * @author Zoltan Ujhelyi
25 * @noextend This class is not intended to be subclassed by clients.
26 */
27public class InstanceOfClassCheck implements ISearchOperation {
28
29 private class Executor extends CheckOperationExecutor {
30
31 @Override
32 protected boolean check(MatchingFrame frame, ISearchContext context) {
33 Objects.requireNonNull(frame.getValue(position), () -> String.format("Invalid plan, variable %s unbound", position));
34 if (frame.getValue(position) instanceof EObject) {
35 return clazz.isSuperTypeOf(((EObject) frame.getValue(position)).eClass());
36 }
37 return false;
38 }
39
40 @Override
41 public ISearchOperation getOperation() {
42 return InstanceOfClassCheck.this;
43 }
44 }
45
46 private int position;
47 private EClass clazz;
48
49 public InstanceOfClassCheck(int position, EClass clazz) {
50 this.position = position;
51 this.clazz = clazz;
52
53 }
54
55 @Override
56 public ISearchOperationExecutor createExecutor() {
57 return new Executor();
58 }
59
60 @Override
61 public String toString() {
62 return toString(Object::toString);
63 }
64
65 @Override
66 public String toString(Function<Integer, String> variableMapping) {
67 return "check "+clazz.getName()+"(+"+ variableMapping.apply(position)+")";
68 }
69
70 @Override
71 public List<Integer> getVariablePositions() {
72 return Arrays.asList(position);
73 }
74
75}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfDataTypeCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfDataTypeCheck.java
deleted file mode 100644
index 940104a2..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfDataTypeCheck.java
+++ /dev/null
@@ -1,71 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, 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.localsearch.operations.check;
10
11import java.util.Arrays;
12import java.util.List;
13import java.util.Objects;
14import java.util.function.Function;
15
16import org.eclipse.emf.ecore.EDataType;
17import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
18import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
19import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
20import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
21
22/**
23 * @author Zoltan Ujhelyi
24 * @noextend This class is not intended to be subclassed by clients.
25 */
26public class InstanceOfDataTypeCheck implements ISearchOperation {
27
28 private class Executor extends CheckOperationExecutor {
29
30 @Override
31 protected boolean check(MatchingFrame frame, ISearchContext context) {
32 Objects.requireNonNull(frame.getValue(position), () -> String.format("Invalid plan, variable %s unbound", position));
33 return dataType.isInstance(frame.getValue(position));
34 }
35
36 @Override
37 public ISearchOperation getOperation() {
38 return InstanceOfDataTypeCheck.this;
39 }
40 }
41
42 private int position;
43 private EDataType dataType;
44
45 public InstanceOfDataTypeCheck(int position, EDataType dataType) {
46 this.position = position;
47 this.dataType = dataType;
48
49 }
50
51 @Override
52 public ISearchOperationExecutor createExecutor() {
53 return new Executor();
54 }
55
56 @Override
57 public String toString() {
58 return toString(Object::toString);
59 }
60
61 @Override
62 public String toString(Function<Integer, String> variableMapping) {
63 return "check "+dataType.getName()+"(+"+variableMapping.apply(position)+")";
64 }
65
66 @Override
67 public List<Integer> getVariablePositions() {
68 return Arrays.asList(position);
69 }
70
71}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfJavaClassCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfJavaClassCheck.java
deleted file mode 100644
index 1da312a0..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/InstanceOfJavaClassCheck.java
+++ /dev/null
@@ -1,71 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, 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.localsearch.operations.check;
10
11import java.util.Arrays;
12import java.util.List;
13import java.util.Objects;
14import java.util.function.Function;
15
16import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
17import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
18import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20
21/**
22 * @author Zoltan Ujhelyi
23 * @since 1.4
24 * @noextend This class is not intended to be subclassed by clients.
25 */
26public class InstanceOfJavaClassCheck implements ISearchOperation {
27
28 private class Executor extends CheckOperationExecutor {
29
30 @Override
31 protected boolean check(MatchingFrame frame, ISearchContext context) {
32 Objects.requireNonNull(frame.getValue(position), () -> String.format("Invalid plan, variable %s unbound", position));
33 return clazz.isInstance(frame.getValue(position));
34 }
35
36 @Override
37 public ISearchOperation getOperation() {
38 return InstanceOfJavaClassCheck.this;
39 }
40 }
41
42 private int position;
43 private Class<?> clazz;
44
45 public InstanceOfJavaClassCheck(int position, Class<?> clazz) {
46 this.position = position;
47 this.clazz = clazz;
48
49 }
50
51 @Override
52 public ISearchOperationExecutor createExecutor() {
53 return new Executor();
54 }
55
56 @Override
57 public String toString() {
58 return toString(Object::toString);
59 }
60
61 @Override
62 public String toString(Function<Integer, String> variableMapping) {
63 return "check java "+clazz.getName()+"(+"+variableMapping.apply(position)+")";
64 }
65
66 @Override
67 public List<Integer> getVariablePositions() {
68 return Arrays.asList(position);
69 }
70
71}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/StructuralFeatureCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/StructuralFeatureCheck.java
deleted file mode 100644
index a3e5bc40..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/StructuralFeatureCheck.java
+++ /dev/null
@@ -1,91 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, 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.localsearch.operations.check;
10
11import java.util.Arrays;
12import java.util.Collection;
13import java.util.List;
14import java.util.Objects;
15import java.util.function.Function;
16
17import org.eclipse.emf.ecore.EObject;
18import org.eclipse.emf.ecore.EStructuralFeature;
19import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
20import tools.refinery.viatra.runtime.localsearch.exceptions.LocalSearchException;
21import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
22import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
23import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
24
25/**
26 * A simple operation that checks whether a {@link EStructuralFeature} connects two selected variables.
27 * @noextend This class is not intended to be subclassed by clients.
28 */
29public class StructuralFeatureCheck implements ISearchOperation {
30
31 private class Executor extends CheckOperationExecutor {
32
33 @Override
34 protected boolean check(MatchingFrame frame, ISearchContext context) {
35 Objects.requireNonNull(frame.getValue(sourcePosition), () -> String.format("Invalid plan, variable %s unbound", sourcePosition));
36 Objects.requireNonNull(frame.getValue(targetPosition), () -> String.format("Invalid plan, variable %s unbound", targetPosition));
37 try {
38 EObject source = (EObject) frame.getValue(sourcePosition);
39 if(! feature.getEContainingClass().isSuperTypeOf(source.eClass()) ){
40 // TODO planner should ensure the proper supertype relation, see bug 500968
41 return false;
42 }
43 Object target = frame.getValue(targetPosition);
44 if (feature.isMany()) {
45 return ((Collection<?>) source.eGet(feature)).contains(target);
46 } else {
47 return target.equals(source.eGet(feature));
48 }
49 } catch (ClassCastException e) {
50 throw new LocalSearchException(LocalSearchException.TYPE_ERROR, e);
51 }
52 }
53
54 @Override
55 public ISearchOperation getOperation() {
56 return StructuralFeatureCheck.this;
57 }
58 }
59
60 int sourcePosition;
61 int targetPosition;
62 EStructuralFeature feature;
63
64 public StructuralFeatureCheck(int sourcePosition, int targetPosition, EStructuralFeature feature) {
65 super();
66 this.sourcePosition = sourcePosition;
67 this.targetPosition = targetPosition;
68 this.feature = feature;
69 }
70
71 @Override
72 public ISearchOperationExecutor createExecutor() {
73 return new Executor();
74 }
75
76 @Override
77 public String toString() {
78 return toString(Object::toString);
79 }
80
81 @Override
82 public String toString(Function<Integer, String> variableMapping) {
83 return "check "+feature.getContainerClass().getSimpleName()+"."+feature.getName()+"(+"+variableMapping.apply(sourcePosition)+", +"+variableMapping.apply(targetPosition)+")";
84 }
85
86 @Override
87 public List<Integer> getVariablePositions() {
88 return Arrays.asList(sourcePosition, targetPosition);
89 }
90
91}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/nobase/ScopeCheck.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/nobase/ScopeCheck.java
deleted file mode 100644
index 06989fdc..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/check/nobase/ScopeCheck.java
+++ /dev/null
@@ -1,91 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.check.nobase;
10
11import java.util.Arrays;
12import java.util.List;
13import java.util.Objects;
14import java.util.function.Function;
15
16import org.eclipse.emf.ecore.EObject;
17import org.eclipse.emf.ecore.util.EcoreUtil;
18import tools.refinery.viatra.runtime.base.api.filters.IBaseIndexObjectFilter;
19import tools.refinery.viatra.runtime.emf.EMFScope;
20import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
21import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
22import tools.refinery.viatra.runtime.localsearch.operations.CheckOperationExecutor;
23import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
24
25/**
26 * This operation simply checks if a model element is part of the Query Scope
27 *
28 * @author Marton Bur
29 *
30 */
31public class ScopeCheck implements ISearchOperation {
32 private class Executor extends CheckOperationExecutor {
33
34 @Override
35 protected boolean check(MatchingFrame frame, ISearchContext context) {
36 Objects.requireNonNull(frame.getValue(position), () -> String.format("Invalid plan, variable %d unbound", position));
37 Object value = frame.getValue(position);
38 if(value instanceof EObject){
39 EObject eObject = (EObject) value;
40 IBaseIndexObjectFilter filterConfiguration = scope.getOptions().getObjectFilterConfiguration();
41 boolean filtered = false;
42 if(filterConfiguration != null){
43 filtered = filterConfiguration.isFiltered(eObject);
44 }
45 if(filtered){
46 return false;
47 } else {
48 return EcoreUtil.isAncestor(scope.getScopeRoots(), eObject);
49 }
50 } else {
51 return true;
52 }
53 }
54
55 @Override
56 public ISearchOperation getOperation() {
57 return ScopeCheck.this;
58 }
59
60 }
61
62 private int position;
63 private EMFScope scope;
64
65 public ScopeCheck(int position, EMFScope scope) {
66 this.position = position;
67 this.scope = scope;
68
69 }
70
71 @Override
72 public ISearchOperationExecutor createExecutor() {
73 return new Executor();
74 }
75
76 @Override
77 public String toString() {
78 return toString(Object::toString);
79 }
80
81
82 @Override
83 public String toString(Function<Integer, String> variableMapping) {
84 return "check +"+variableMapping.apply(position) +" in scope "+scope;
85 }
86
87 @Override
88 public List<Integer> getVariablePositions() {
89 return Arrays.asList(position);
90 }
91}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendToEStructuralFeatureSource.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendToEStructuralFeatureSource.java
deleted file mode 100644
index 04f0a8de..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendToEStructuralFeatureSource.java
+++ /dev/null
@@ -1,112 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend;
10
11import java.util.Arrays;
12import java.util.Iterator;
13import java.util.List;
14import java.util.function.Function;
15import java.util.stream.StreamSupport;
16
17import org.eclipse.emf.ecore.EObject;
18import org.eclipse.emf.ecore.EStructuralFeature;
19import tools.refinery.viatra.runtime.emf.types.EStructuralFeatureInstancesKey;
20import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
21import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
22import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
23import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
24import tools.refinery.viatra.runtime.matchers.context.IInputKey;
25import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
26import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
27import tools.refinery.viatra.runtime.matchers.tuple.VolatileMaskedTuple;
28
29/**
30 * Iterates over all sources of {@link EStructuralFeature} using an {@link IQueryRuntimeContext VIATRA Base indexer}.
31 * It is assumed that the indexer is initialized for the selected {@link EStructuralFeature}.
32 *
33 */
34public class ExtendToEStructuralFeatureSource implements IIteratingSearchOperation {
35
36 private class Executor extends SingleValueExtendOperationExecutor<EObject> {
37
38 private VolatileMaskedTuple maskedTuple;
39
40 public Executor(int position) {
41 super(position);
42 this.maskedTuple = new VolatileMaskedTuple(mask);
43 }
44
45
46 @Override
47 public Iterator<EObject> getIterator(MatchingFrame frame, ISearchContext context) {
48 maskedTuple.updateTuple(frame);
49 Iterable<? extends Object> values = context.getRuntimeContext().enumerateValues(type, indexerMask, maskedTuple);
50 return StreamSupport.stream(values.spliterator(), false)
51 .filter(EObject.class::isInstance)
52 .map(EObject.class::cast)
53 .iterator();
54 }
55
56 @Override
57 public ISearchOperation getOperation() {
58 return ExtendToEStructuralFeatureSource.this;
59 }
60 }
61
62 private final int sourcePosition;
63 private final int targetPosition;
64 private final EStructuralFeature feature;
65 private final IInputKey type;
66 private static final TupleMask indexerMask = TupleMask.fromSelectedIndices(2, new int[] {1});
67 private final TupleMask mask;
68
69 /**
70 * @since 1.7
71 */
72 public ExtendToEStructuralFeatureSource(int sourcePosition, int targetPosition, EStructuralFeature feature, TupleMask mask) {
73 this.sourcePosition = sourcePosition;
74 this.targetPosition = targetPosition;
75 this.feature = feature;
76 this.mask = mask;
77 this.type = new EStructuralFeatureInstancesKey(feature);
78 }
79
80 public EStructuralFeature getFeature() {
81 return feature;
82 }
83
84 @Override
85 public ISearchOperationExecutor createExecutor() {
86 return new Executor(sourcePosition);
87 }
88
89 @Override
90 public String toString() {
91 return toString(Object::toString);
92 }
93
94 @Override
95 public String toString(Function<Integer, String> variableMapping) {
96 return "extend "+feature.getContainerClass().getSimpleName()+"."+feature.getName()+"(-"+variableMapping.apply(sourcePosition)+", +"+variableMapping.apply(targetPosition)+") indexed";
97 }
98
99 @Override
100 public List<Integer> getVariablePositions() {
101 return Arrays.asList(sourcePosition, targetPosition);
102 }
103
104 /**
105 * @since 1.4
106 */
107 @Override
108 public IInputKey getIteratedInputKey() {
109 return type;
110 }
111
112}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendToEStructuralFeatureTarget.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendToEStructuralFeatureTarget.java
deleted file mode 100644
index 4304fc8d..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/ExtendToEStructuralFeatureTarget.java
+++ /dev/null
@@ -1,102 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend;
10
11import java.util.Arrays;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Iterator;
15import java.util.List;
16import java.util.function.Function;
17
18import org.eclipse.emf.ecore.EObject;
19import org.eclipse.emf.ecore.EStructuralFeature;
20import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
21import tools.refinery.viatra.runtime.localsearch.exceptions.LocalSearchException;
22import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
23import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
24
25/**
26 * Iterates over all sources of {@link EStructuralFeature}
27 */
28public class ExtendToEStructuralFeatureTarget implements ISearchOperation {
29
30 private class Executor extends SingleValueExtendOperationExecutor<Object> {
31
32 public Executor(int position) {
33 super(position);
34 }
35
36 @SuppressWarnings("unchecked")
37 @Override
38 public Iterator<?> getIterator(MatchingFrame frame, ISearchContext context) {
39 try {
40 final EObject value = (EObject) frame.getValue(sourcePosition);
41 if(! feature.getEContainingClass().isSuperTypeOf(value.eClass()) ){
42 // TODO planner should ensure the proper supertype relation
43 return Collections.emptyIterator();
44 }
45 final Object featureValue = value.eGet(feature);
46 if (feature.isMany()) {
47 if (featureValue != null) {
48 final Collection<Object> objectCollection = (Collection<Object>) featureValue;
49 return objectCollection.iterator();
50 } else {
51 return Collections.emptyIterator();
52 }
53 } else {
54 if (featureValue != null) {
55 return Collections.singletonList(featureValue).iterator();
56 } else {
57 return Collections.emptyIterator();
58 }
59 }
60 } catch (ClassCastException e) {
61 throw new LocalSearchException("Invalid feature source in parameter" + Integer.toString(sourcePosition), e);
62 }
63 }
64
65 @Override
66 public ISearchOperation getOperation() {
67 return ExtendToEStructuralFeatureTarget.this;
68 }
69 }
70
71 private final int sourcePosition;
72 private final int targetPosition;
73 private final EStructuralFeature feature;
74
75 public ExtendToEStructuralFeatureTarget(int sourcePosition, int targetPosition, EStructuralFeature feature) {
76 this.sourcePosition = sourcePosition;
77 this.targetPosition = targetPosition;
78 this.feature = feature;
79 }
80
81 @Override
82 public String toString() {
83 return toString(Object::toString);
84 }
85
86 @Override
87 public String toString(Function<Integer, String> variableMapping) {
88 return "extend "+feature.getEContainingClass().getName()+"."+feature.getName()+"(+"+variableMapping.apply(sourcePosition)+", -"+ variableMapping.apply(targetPosition) +")";
89 }
90
91 @Override
92 public ISearchOperationExecutor createExecutor() {
93 return new Executor(targetPosition);
94 }
95
96
97 @Override
98 public List<Integer> getVariablePositions() {
99 return Arrays.asList(sourcePosition, targetPosition);
100 }
101
102}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverChildren.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverChildren.java
deleted file mode 100644
index 10764aea..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverChildren.java
+++ /dev/null
@@ -1,90 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend;
10
11import java.util.Arrays;
12import java.util.Iterator;
13import java.util.List;
14import java.util.function.Function;
15
16import org.eclipse.emf.ecore.EObject;
17import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
18import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
19import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
20import tools.refinery.viatra.runtime.matchers.util.Preconditions;
21
22/**
23 * Iterates all child elements of a selected EObjects.
24 *
25 * @author Zoltan Ujhelyi
26 *
27 */
28public class IterateOverChildren implements ISearchOperation {
29
30 private class Executor extends SingleValueExtendOperationExecutor<EObject> {
31
32 public Executor(int position) {
33 super(position);
34 }
35
36 @Override
37 public Iterator<EObject> getIterator(MatchingFrame frame, ISearchContext context) {
38 Preconditions.checkState(frame.get(sourcePosition) instanceof EObject, "Only children of EObject elements are supported.");
39 EObject source = (EObject) frame.get(sourcePosition);
40 if(transitive) {
41 return source.eAllContents();
42 } else {
43 return source.eContents().iterator();
44 }
45 }
46
47 @Override
48 public ISearchOperation getOperation() {
49 return IterateOverChildren.this;
50 }
51 }
52
53 private final int position;
54 private int sourcePosition;
55 private final boolean transitive;
56
57 /**
58 *
59 * @param position the position of the variable storing the child elements
60 * @param sourcePosition the position of the variable storing the parent root; must be bound
61 * @param transitive if true, child elements are iterated over transitively
62 */
63 public IterateOverChildren(int position, int sourcePosition, boolean transitive) {
64 this.position = position;
65 this.sourcePosition = sourcePosition;
66 this.transitive = transitive;
67 }
68
69 @Override
70 public String toString() {
71 return toString(Object::toString);
72 }
73
74 @Override
75 public String toString(Function<Integer, String> variableMapping) {
76 return "extend containment +"+variableMapping.apply(sourcePosition)+" <>--> -"+variableMapping.apply(position)+(transitive ? " transitively" : " directly");
77 }
78
79 @Override
80 public ISearchOperationExecutor createExecutor() {
81 return new Executor(position);
82 }
83
84
85 @Override
86 public List<Integer> getVariablePositions() {
87 return Arrays.asList(position, sourcePosition);
88 }
89
90} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverContainers.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverContainers.java
deleted file mode 100644
index df7e18c9..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverContainers.java
+++ /dev/null
@@ -1,126 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend;
10
11import java.util.Arrays;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.List;
15import java.util.NoSuchElementException;
16import java.util.function.Function;
17
18import org.eclipse.emf.ecore.EObject;
19import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
20import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.matchers.util.Preconditions;
23
24/**
25 * Iterates all child elements of a selected EObjects.
26 *
27 * @author Zoltan Ujhelyi
28 *
29 */
30public class IterateOverContainers implements ISearchOperation {
31
32 /**
33 * A helper iterator for transitively traversing a parent of an object
34 */
35 private static final class ParentIterator implements Iterator<EObject> {
36 private EObject current;
37
38 public ParentIterator(EObject source) {
39 this.current = source;
40 }
41
42 @Override
43 public void remove() {
44 throw new UnsupportedOperationException();
45 }
46
47 @Override
48 public EObject next() {
49 EObject newObject = current.eContainer();
50 if (newObject == null) {
51 throw new NoSuchElementException(String.format("No more parents available for EObject %s", current));
52 }
53 current = newObject;
54 return current;
55 }
56
57 @Override
58 public boolean hasNext() {
59 return current.eContainer() != null;
60 }
61 }
62
63 private class Executor extends SingleValueExtendOperationExecutor<EObject> {
64
65 public Executor(int position) {
66 super(position);
67 }
68
69 @Override
70 public Iterator<EObject> getIterator(MatchingFrame frame, ISearchContext context) {
71 Preconditions.checkState(frame.get(sourcePosition) instanceof EObject, "Only children of EObject elements are supported.");
72 EObject source = (EObject) frame.get(sourcePosition);
73 EObject container = source.eContainer();
74 if (container == null) {
75 return Collections.emptyIterator();
76 } else if (transitive) {
77 return new ParentIterator(source);
78 } else {
79 return Collections.singleton(container).iterator();
80 }
81 }
82
83 @Override
84 public ISearchOperation getOperation() {
85 return IterateOverContainers.this;
86 }
87 }
88
89 private final int sourcePosition;
90 private final int containerPosition;
91 private final boolean transitive;
92
93 /**
94 *
95 * @param containerPosition the position of the variable storing the found parent elements
96 * @param sourcePosition the position of the variable storing the selected element; must be bound
97 * @param transitive if false, only the direct container is returned; otherwise all containers
98 */
99 public IterateOverContainers(int containerPosition, int sourcePosition, boolean transitive) {
100 this.containerPosition = containerPosition;
101 this.sourcePosition = sourcePosition;
102 this.transitive = transitive;
103 }
104
105
106 @Override
107 public ISearchOperationExecutor createExecutor() {
108 return new Executor(containerPosition);
109 }
110
111 @Override
112 public String toString() {
113 return toString(Object::toString);
114 }
115
116 @Override
117 public String toString(Function<Integer, String> variableMapping) {
118 return "extend containment -"+variableMapping.apply(sourcePosition)+" <>--> +"+variableMapping.apply(containerPosition)+(transitive ? " transitively" : " directly");
119 }
120
121 @Override
122 public List<Integer> getVariablePositions() {
123 return Arrays.asList(containerPosition, sourcePosition);
124 }
125
126}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEClassInstances.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEClassInstances.java
deleted file mode 100644
index 333ed1db..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEClassInstances.java
+++ /dev/null
@@ -1,97 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.List;
14import java.util.function.Function;
15
16import org.eclipse.emf.ecore.EClass;
17import tools.refinery.viatra.runtime.emf.types.EClassTransitiveInstancesKey;
18import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
19import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
20import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.matchers.context.IInputKey;
23import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
24import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
25import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
26
27/**
28 * Iterates all available {@link EClass} instances using an {@link IQueryRuntimeContext VIATRA Base indexer}. It is
29 * assumed that the base indexer has been registered for the selected type.
30 *
31 * @author Zoltan Ujhelyi
32 *
33 */
34public class IterateOverEClassInstances implements IIteratingSearchOperation {
35
36 private class Executor extends SingleValueExtendOperationExecutor<Object> {
37
38 public Executor(int position) {
39 super(position);
40 }
41
42 @Override
43 public Iterator<? extends Object> getIterator(MatchingFrame frame, ISearchContext context) {
44 return context.getRuntimeContext().enumerateValues(type, indexerMask, Tuples.staticArityFlatTupleOf()).iterator();
45 }
46
47 @Override
48 public ISearchOperation getOperation() {
49 return IterateOverEClassInstances.this;
50 }
51 }
52
53 private final EClass clazz;
54 private final EClassTransitiveInstancesKey type;
55 private static final TupleMask indexerMask = TupleMask.empty(1);
56 private final int position;
57
58 public IterateOverEClassInstances(int position, EClass clazz) {
59 this.position = position;
60 this.clazz = clazz;
61 type = new EClassTransitiveInstancesKey(clazz);
62 }
63
64 public EClass getClazz() {
65 return clazz;
66 }
67
68
69 @Override
70 public ISearchOperationExecutor createExecutor() {
71 return new Executor(position);
72 }
73
74 @Override
75 public String toString() {
76 return toString(Object::toString);
77 }
78
79 @Override
80 public String toString(Function<Integer, String> variableMapping) {
81 return "extend "+clazz.getName()+"(-"+ variableMapping.apply(position)+") indexed";
82 }
83
84 @Override
85 public List<Integer> getVariablePositions() {
86 return Collections.singletonList(position);
87 }
88
89 /**
90 * @since 1.4
91 */
92 @Override
93 public IInputKey getIteratedInputKey() {
94 return type;
95 }
96
97}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEDatatypeInstances.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEDatatypeInstances.java
deleted file mode 100644
index 248a3d27..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEDatatypeInstances.java
+++ /dev/null
@@ -1,96 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.List;
14import java.util.function.Function;
15
16import org.eclipse.emf.ecore.EDataType;
17import tools.refinery.viatra.runtime.emf.types.EDataTypeInSlotsKey;
18import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
19import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
20import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.matchers.context.IInputKey;
23import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
24import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
25import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
26
27
28/**
29 * Iterates over all {@link EDataType} instances using an {@link IQueryRuntimeContext VIATRA Base indexer}. It is
30 * assumed that the indexer is initialized for the selected {@link EDataType}.
31 *
32 */
33public class IterateOverEDatatypeInstances implements IIteratingSearchOperation {
34
35 private class Executor extends SingleValueExtendOperationExecutor<Object> {
36
37 public Executor(int position) {
38 super(position);
39 }
40
41 @Override
42 public Iterator<? extends Object> getIterator(MatchingFrame frame, ISearchContext context) {
43 return context.getRuntimeContext().enumerateValues(type, indexerMask, Tuples.staticArityFlatTupleOf()).iterator();
44 }
45
46 @Override
47 public ISearchOperation getOperation() {
48 return IterateOverEDatatypeInstances.this;
49 }
50 }
51
52 private final EDataType dataType;
53 private final EDataTypeInSlotsKey type;
54 private static final TupleMask indexerMask = TupleMask.empty(1);
55 private final int position;
56
57 public IterateOverEDatatypeInstances(int position, EDataType dataType) {
58 this.position = position;
59 this.dataType = dataType;
60 type = new EDataTypeInSlotsKey(dataType);
61 }
62
63 public EDataType getDataType() {
64 return dataType;
65 }
66
67 @Override
68 public ISearchOperationExecutor createExecutor() {
69 return new Executor(position);
70 }
71
72 @Override
73 public String toString() {
74 return toString(Object::toString);
75 }
76
77 @Override
78 public String toString(Function<Integer, String> variableMapping) {
79 return "extend "+dataType.getName()+"(-"+variableMapping.apply(position)+") indexed";
80 }
81
82 @Override
83 public List<Integer> getVariablePositions() {
84 return Collections.singletonList(position);
85 }
86
87 /**
88 * @since 1.4
89 */
90 @Override
91 public IInputKey getIteratedInputKey() {
92 return type;
93 }
94
95
96}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEStructuralFeatureInstances.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEStructuralFeatureInstances.java
deleted file mode 100644
index 961939fa..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/IterateOverEStructuralFeatureInstances.java
+++ /dev/null
@@ -1,115 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend;
10
11import java.util.Arrays;
12import java.util.Iterator;
13import java.util.List;
14import java.util.function.Function;
15
16import org.eclipse.emf.ecore.EStructuralFeature;
17import tools.refinery.viatra.runtime.emf.types.EStructuralFeatureInstancesKey;
18import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
19import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
20import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
21import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
22import tools.refinery.viatra.runtime.matchers.context.IInputKey;
23import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
25import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
26import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
27
28/**
29 * Iterates all available {@link EStructuralFeature} elements using an {@link IQueryRuntimeContext VIATRA Base
30 * indexer}. It is assumed that the base indexer has been registered for the selected reference type.
31 *
32 */
33public class IterateOverEStructuralFeatureInstances implements IIteratingSearchOperation{
34
35 private class Executor implements ISearchOperationExecutor {
36 private Iterator<Tuple> it;
37
38 @Override
39 public void onBacktrack(MatchingFrame frame, ISearchContext context) {
40 frame.setValue(sourcePosition, null);
41 frame.setValue(targetPosition, null);
42 it = null;
43 }
44
45 @Override
46 public void onInitialize(MatchingFrame frame, ISearchContext context) {
47 Iterable<Tuple> tuples = context.getRuntimeContext().enumerateTuples(type, indexerMask, Tuples.staticArityFlatTupleOf());
48
49 it = tuples.iterator();
50 }
51
52 @Override
53 public boolean execute(MatchingFrame frame, ISearchContext context) {
54 if (it.hasNext()) {
55 final Tuple next = it.next();
56 frame.setValue(sourcePosition, next.get(0));
57 frame.setValue(targetPosition, next.get(1));
58 return true;
59 } else {
60 return false;
61 }
62 }
63
64 @Override
65 public ISearchOperation getOperation() {
66 return IterateOverEStructuralFeatureInstances.this;
67 }
68 }
69
70 private final EStructuralFeature feature;
71 private final int sourcePosition;
72 private final int targetPosition;
73 private final EStructuralFeatureInstancesKey type;
74 private static final TupleMask indexerMask = TupleMask.empty(2);
75
76 public IterateOverEStructuralFeatureInstances(int sourcePosition, int targetPosition, EStructuralFeature feature) {
77 this.sourcePosition = sourcePosition;
78 this.targetPosition = targetPosition;
79 this.feature = feature;
80 type = new EStructuralFeatureInstancesKey(feature);
81 }
82
83 public EStructuralFeature getFeature() {
84 return feature;
85 }
86
87 @Override
88 public ISearchOperationExecutor createExecutor() {
89 return new Executor();
90 }
91
92 @Override
93 public String toString() {
94 return toString(Object::toString);
95 }
96
97 @Override
98 public String toString(Function<Integer, String> variableMapping) {
99 return "extend "+feature.getContainerClass().getSimpleName()+"."+feature.getName()+"(-"+variableMapping.apply(sourcePosition)+", -"+variableMapping.apply(targetPosition)+") indexed";
100 }
101
102 @Override
103 public List<Integer> getVariablePositions() {
104 return Arrays.asList(sourcePosition, targetPosition);
105 }
106
107 /**
108 * @since 1.4
109 */
110 @Override
111 public IInputKey getIteratedInputKey() {
112 return type;
113 }
114
115}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/AbstractIteratingExtendOperationExecutor.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/AbstractIteratingExtendOperationExecutor.java
deleted file mode 100644
index 954d4c88..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/AbstractIteratingExtendOperationExecutor.java
+++ /dev/null
@@ -1,54 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, 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.localsearch.operations.extend.nobase;
10
11import java.util.Collections;
12import java.util.Spliterator;
13import java.util.Spliterators;
14import java.util.stream.Stream;
15import java.util.stream.StreamSupport;
16
17import org.eclipse.emf.common.notify.Notifier;
18import org.eclipse.emf.ecore.EObject;
19import org.eclipse.emf.ecore.resource.Resource;
20import org.eclipse.emf.ecore.resource.ResourceSet;
21import tools.refinery.viatra.runtime.emf.EMFScope;
22import tools.refinery.viatra.runtime.localsearch.operations.extend.SingleValueExtendOperationExecutor;
23
24/**
25 * This abstract class provides a utility method for extenders to iterate over the given scope.
26 *
27 * @author Grill Balázs
28 * @noextend This class is not intended to be subclassed by clients.
29 *
30 */
31abstract class AbstractIteratingExtendOperationExecutor<T> extends SingleValueExtendOperationExecutor<T> {
32
33 private final EMFScope scope;
34
35 public AbstractIteratingExtendOperationExecutor(int position, EMFScope scope) {
36 super(position);
37 this.scope = scope;
38 }
39
40 protected Stream<Notifier> getModelContents() {
41 return scope.getScopeRoots().stream().map(input -> {
42 if (input instanceof ResourceSet) {
43 return ((ResourceSet) input).getAllContents();
44 } else if (input instanceof Resource) {
45 return ((Resource) input).getAllContents();
46 } else if (input instanceof EObject) {
47 return ((EObject) input).eAllContents();
48 }
49 return Collections.<Notifier> emptyIterator();
50 }).map(i -> StreamSupport.stream(Spliterators.spliteratorUnknownSize(i, Spliterator.ORDERED), false))
51 .flatMap(i -> i);
52 }
53
54}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/ExtendToEStructuralFeatureSource.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/ExtendToEStructuralFeatureSource.java
deleted file mode 100644
index fc79640b..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/ExtendToEStructuralFeatureSource.java
+++ /dev/null
@@ -1,118 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend.nobase;
10
11import java.util.Arrays;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Iterator;
15import java.util.List;
16import java.util.function.Function;
17
18import org.eclipse.emf.ecore.EObject;
19import org.eclipse.emf.ecore.EReference;
20import org.eclipse.emf.ecore.EStructuralFeature;
21import tools.refinery.viatra.runtime.base.api.NavigationHelper;
22import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
23import tools.refinery.viatra.runtime.localsearch.exceptions.LocalSearchException;
24import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
25import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
26import tools.refinery.viatra.runtime.localsearch.operations.extend.SingleValueExtendOperationExecutor;
27
28/**
29 * Iterates over all sources of {@link EStructuralFeature} using an {@link NavigationHelper VIATRA Base indexer}.
30 * It is assumed that the indexer is initialized for the selected {@link EStructuralFeature}.
31 *
32 */
33public class ExtendToEStructuralFeatureSource implements ISearchOperation {
34
35 private class Executor extends SingleValueExtendOperationExecutor<Object> {
36
37 private Executor() {
38 super(sourcePosition);
39 }
40
41 @SuppressWarnings("unchecked")
42 @Override
43 public Iterator<?> getIterator(MatchingFrame frame, ISearchContext context) {
44 if(!(feature instanceof EReference)){
45 throw new LocalSearchException("Without base index, inverse navigation only possible along "
46 + "EReferences with defined EOpposite.");
47 }
48 EReference oppositeFeature = ((EReference)feature).getEOpposite();
49 if(oppositeFeature == null){
50 throw new LocalSearchException("Feature has no EOpposite, so cannot do inverse navigation " + feature.toString());
51 }
52 try {
53 final EObject value = (EObject) frame.getValue(targetPosition);
54 if(! oppositeFeature.getEContainingClass().isSuperTypeOf(value.eClass()) ){
55 // TODO planner should ensure the proper supertype relation
56 return Collections.emptyIterator();
57 }
58 final Object featureValue = value.eGet(oppositeFeature);
59 if (oppositeFeature.isMany()) {
60 if (featureValue != null) {
61 final Collection<Object> objectCollection = (Collection<Object>) featureValue;
62 return objectCollection.iterator();
63 } else {
64 return Collections.emptyIterator();
65 }
66 } else {
67 if (featureValue != null) {
68 return Collections.singleton(featureValue).iterator();
69 } else {
70 return Collections.emptyIterator();
71 }
72 }
73 } catch (ClassCastException e) {
74 throw new LocalSearchException("Invalid feature target in parameter" + Integer.toString(targetPosition), e);
75 }
76 }
77
78 @Override
79 public ISearchOperation getOperation() {
80 return ExtendToEStructuralFeatureSource.this;
81 }
82 }
83
84 private int targetPosition;
85 private EStructuralFeature feature;
86 private int sourcePosition;
87
88 public ExtendToEStructuralFeatureSource(int sourcePosition, int targetPosition, EStructuralFeature feature) {
89 this.sourcePosition = sourcePosition;
90 this.targetPosition = targetPosition;
91 this.feature = feature;
92 }
93
94 public EStructuralFeature getFeature() {
95 return feature;
96 }
97
98 @Override
99 public ISearchOperationExecutor createExecutor() {
100 return new Executor();
101 }
102
103 @Override
104 public String toString() {
105 return toString(Object::toString);
106 }
107
108 @Override
109 public String toString(Function<Integer, String> variableMapping) {
110 return "extend "+feature.getContainerClass().getSimpleName()+"."+feature.getName()+"(-"+variableMapping.apply(sourcePosition)+", +"+variableMapping.apply(targetPosition)+") iterating";
111 }
112
113 @Override
114 public List<Integer> getVariablePositions() {
115 return Arrays.asList(sourcePosition, targetPosition);
116 }
117
118}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/IterateOverEClassInstances.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/IterateOverEClassInstances.java
deleted file mode 100644
index 0a4c46ec..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/IterateOverEClassInstances.java
+++ /dev/null
@@ -1,93 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend.nobase;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.List;
14import java.util.function.Function;
15
16import org.eclipse.emf.common.notify.Notifier;
17import org.eclipse.emf.ecore.EClass;
18import tools.refinery.viatra.runtime.base.api.NavigationHelper;
19import tools.refinery.viatra.runtime.emf.EMFScope;
20import tools.refinery.viatra.runtime.emf.types.EClassTransitiveInstancesKey;
21import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
22import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
23import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
24import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
25import tools.refinery.viatra.runtime.matchers.context.IInputKey;
26
27/**
28 * Iterates all available {@link EClass} instances without using an {@link NavigationHelper VIATRA Base indexer}.
29 *
30 * @author Zoltan Ujhelyi
31 */
32public class IterateOverEClassInstances implements IIteratingSearchOperation {
33
34 private class Executor extends AbstractIteratingExtendOperationExecutor<Notifier> {
35
36 public Executor(int position, EMFScope scope) {
37 super(position, scope);
38 }
39
40 @Override
41 public Iterator<? extends Notifier> getIterator(MatchingFrame frame, ISearchContext context) {
42 return getModelContents().filter(clazz::isInstance).iterator();
43 }
44
45 @Override
46 public ISearchOperation getOperation() {
47 return IterateOverEClassInstances.this;
48 }
49 }
50
51 private final int position;
52 private final EClass clazz;
53 private final EMFScope scope;
54
55 public IterateOverEClassInstances(int position, EClass clazz, EMFScope scope) {
56 this.position = position;
57 this.clazz = clazz;
58 this.scope = scope;
59 }
60
61 public EClass getClazz() {
62 return clazz;
63 }
64
65 @Override
66 public ISearchOperationExecutor createExecutor() {
67 return new Executor(position, scope);
68 }
69
70 @Override
71 public String toString() {
72 return toString(Object::toString);
73 }
74
75 @Override
76 public String toString(Function<Integer, String> variableMapping) {
77 return "extend "+clazz.getName()+"(-"+ variableMapping.apply(position)+") iterating";
78 }
79
80 @Override
81 public List<Integer> getVariablePositions() {
82 return Collections.singletonList(position);
83 }
84
85 /**
86 * @since 1.4
87 */
88 @Override
89 public IInputKey getIteratedInputKey() {
90 return new EClassTransitiveInstancesKey(clazz);
91 }
92
93}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/IterateOverEDatatypeInstances.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/IterateOverEDatatypeInstances.java
deleted file mode 100644
index 999e0a48..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/operations/extend/nobase/IterateOverEDatatypeInstances.java
+++ /dev/null
@@ -1,123 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, 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.localsearch.operations.extend.nobase;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.List;
14import java.util.Map;
15import java.util.Objects;
16import java.util.Set;
17import java.util.function.Function;
18import java.util.stream.Collectors;
19import java.util.stream.Stream;
20
21import org.eclipse.emf.ecore.EAttribute;
22import org.eclipse.emf.ecore.EClass;
23import org.eclipse.emf.ecore.EDataType;
24import org.eclipse.emf.ecore.EObject;
25import tools.refinery.viatra.runtime.base.api.NavigationHelper;
26import tools.refinery.viatra.runtime.emf.EMFScope;
27import tools.refinery.viatra.runtime.emf.types.EDataTypeInSlotsKey;
28import tools.refinery.viatra.runtime.localsearch.MatchingFrame;
29import tools.refinery.viatra.runtime.localsearch.matcher.ISearchContext;
30import tools.refinery.viatra.runtime.localsearch.operations.IIteratingSearchOperation;
31import tools.refinery.viatra.runtime.localsearch.operations.ISearchOperation;
32import tools.refinery.viatra.runtime.matchers.context.IInputKey;
33import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
34import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
35import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
36
37/**
38 * Iterates over all {@link EDataType} instances without using an {@link NavigationHelper VIATRA Base indexer}.
39 *
40 */
41public class IterateOverEDatatypeInstances implements IIteratingSearchOperation {
42
43 private class Executor extends AbstractIteratingExtendOperationExecutor<Object> {
44
45 public Executor(int position, EMFScope scope) {
46 super(position, scope);
47 }
48
49 @Override
50 public Iterator<? extends Object> getIterator(MatchingFrame frame, final ISearchContext context) {
51 return getModelContents().filter(EObject.class::isInstance).map(EObject.class::cast)
52 .map(input -> doGetEAttributes(input.eClass(), context)
53 .map(attribute -> {
54 if (attribute.isMany()) {
55 return ((List<?>) input.eGet(attribute)).stream();
56 } else {
57 Object o = input.eGet(attribute);
58 return o == null ? Stream.empty() : Stream.of(o);
59 }
60 }))
61 .flatMap(i -> i)
62 .<Object>flatMap(i -> i)
63 .iterator();
64 }
65
66 @Override
67 public ISearchOperation getOperation() {
68 return IterateOverEDatatypeInstances.this;
69 }
70 }
71
72 private final EDataType dataType;
73 private final int position;
74 private final EMFScope scope;
75
76 public IterateOverEDatatypeInstances(int position, EDataType dataType, EMFScope scope) {
77 this.position = position;
78 this.dataType = dataType;
79 this.scope = scope;
80 }
81
82 protected Stream<EAttribute> doGetEAttributes(EClass eclass, ISearchContext context){
83 @SuppressWarnings({ "unchecked"})
84 Map<Tuple, Set<EAttribute>> cache = context.accessBackendLevelCache(getClass(), Map.class, CollectionsFactory::createMap);
85 Tuple compositeKey = Tuples.staticArityFlatTupleOf(dataType, eclass);
86 return cache.computeIfAbsent(compositeKey, k ->
87 eclass.getEAllAttributes().stream().filter(input -> Objects.equals(input.getEType(), dataType)).collect(Collectors.toSet())
88 ).stream();
89 }
90
91 public EDataType getDataType() {
92 return dataType;
93 }
94
95 @Override
96 public ISearchOperationExecutor createExecutor() {
97 return new Executor(position, scope);
98 }
99
100 @Override
101 public String toString() {
102 return toString(Object::toString);
103 }
104
105 @Override
106 public String toString(Function<Integer, String> variableMapping) {
107 return "extend "+dataType.getName()+"(-"+variableMapping.apply(position)+") iterating";
108 }
109
110 @Override
111 public List<Integer> getVariablePositions() {
112 return Collections.singletonList(position);
113 }
114
115 /**
116 * @since 1.4
117 */
118 @Override
119 public IInputKey getIteratedInputKey() {
120 return new EDataTypeInSlotsKey(dataType);
121 }
122
123}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java
index 96fda930..eeac07ce 100644
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java
+++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PConstraintInfoInferrer.java
@@ -3,40 +3,18 @@
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.localsearch.planner; 9package tools.refinery.viatra.runtime.localsearch.planner;
10 10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collections;
14import java.util.HashSet;
15import java.util.List;
16import java.util.Objects;
17import java.util.Set;
18import java.util.function.Function;
19import java.util.function.Predicate;
20import java.util.stream.Collectors;
21import java.util.stream.Stream;
22
23import org.eclipse.emf.ecore.EReference;
24import org.eclipse.emf.ecore.EStructuralFeature;
25import tools.refinery.viatra.runtime.base.api.BaseIndexOptions;
26import tools.refinery.viatra.runtime.base.comprehension.EMFModelComprehension;
27import tools.refinery.viatra.runtime.emf.types.EStructuralFeatureInstancesKey;
28import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext; 11import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
29import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor; 12import tools.refinery.viatra.runtime.matchers.backend.ResultProviderRequestor;
30import tools.refinery.viatra.runtime.matchers.context.IInputKey; 13import tools.refinery.viatra.runtime.matchers.context.IInputKey;
31import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext; 14import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
32import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; 15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
33import tools.refinery.viatra.runtime.matchers.psystem.PVariable; 16import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
34import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.AggregatorConstraint; 17import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.*;
35import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
36import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation;
37import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Inequality;
38import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.PatternMatchCounter;
39import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint;
40import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.AbstractTransitiveClosure; 18import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.AbstractTransitiveClosure;
41import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue; 19import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
42import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall; 20import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
@@ -46,39 +24,42 @@ import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameterDirectio
46import tools.refinery.viatra.runtime.matchers.tuple.Tuple; 24import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
47import tools.refinery.viatra.runtime.matchers.util.Sets; 25import tools.refinery.viatra.runtime.matchers.util.Sets;
48 26
27import java.util.*;
28import java.util.function.Function;
29import java.util.function.Predicate;
30import java.util.stream.Collectors;
31import java.util.stream.Stream;
32
49 33
50/** 34/**
51 * @author Grill Balázs 35 * @author Grill Balázs
52 * @noreference This class is not intended to be referenced by clients. 36 * @noreference This class is not intended to be referenced by clients.
53 */ 37 */
54class PConstraintInfoInferrer { 38class PConstraintInfoInferrer {
55 39
56 private static final Predicate<PVariable> SINGLE_USE_VARIABLE = input -> input != null && input.getReferringConstraints().size() == 1; 40 private static final Predicate<PVariable> SINGLE_USE_VARIABLE = input -> input != null && input.getReferringConstraints().size() == 1;
57 41
58 private final boolean useIndex; 42 private final boolean useIndex;
59 private final Function<IConstraintEvaluationContext, Double> costFunction; 43 private final Function<IConstraintEvaluationContext, Double> costFunction;
60 private final EMFModelComprehension modelComprehension;
61 private final IQueryBackendContext context; 44 private final IQueryBackendContext context;
62 private final ResultProviderRequestor resultRequestor; 45 private final ResultProviderRequestor resultRequestor;
63 46
64 47
65 public PConstraintInfoInferrer(boolean useIndex, 48 public PConstraintInfoInferrer(boolean useIndex,
66 IQueryBackendContext backendContext, 49 IQueryBackendContext backendContext,
67 ResultProviderRequestor resultRequestor, 50 ResultProviderRequestor resultRequestor,
68 Function<IConstraintEvaluationContext, Double> costFunction) { 51 Function<IConstraintEvaluationContext, Double> costFunction) {
69 this.useIndex = useIndex; 52 this.useIndex = useIndex;
70 this.context = backendContext; 53 this.context = backendContext;
71 this.resultRequestor = resultRequestor; 54 this.resultRequestor = resultRequestor;
72 this.costFunction = costFunction; 55 this.costFunction = costFunction;
73 this.modelComprehension = new EMFModelComprehension(new BaseIndexOptions());
74 } 56 }
75 57
76 58
77 /** 59 /**
78 * Create all possible application condition for all constraint 60 * Create all possible application condition for all constraint
79 * 61 *
80 * @param constraintSet the set of constraints 62 * @param constraintSet the set of constraints
81 * @param runtimeContext the model dependent runtime contest
82 * @return a collection of the wrapper PConstraintInfo objects with all the allowed application conditions 63 * @return a collection of the wrapper PConstraintInfo objects with all the allowed application conditions
83 */ 64 */
84 public List<PConstraintInfo> createPConstraintInfos(Set<PConstraint> constraintSet) { 65 public List<PConstraintInfo> createPConstraintInfos(Set<PConstraint> constraintSet) {
@@ -106,7 +87,7 @@ class PConstraintInfoInferrer {
106 } else if (pConstraint instanceof AggregatorConstraint){ 87 } else if (pConstraint instanceof AggregatorConstraint){
107 createConstraintInfoAggregatorConstraint(resultList, pConstraint, ((AggregatorConstraint) pConstraint).getResultVariable()); 88 createConstraintInfoAggregatorConstraint(resultList, pConstraint, ((AggregatorConstraint) pConstraint).getResultVariable());
108 } else if (pConstraint instanceof PatternMatchCounter){ 89 } else if (pConstraint instanceof PatternMatchCounter){
109 createConstraintInfoAggregatorConstraint(resultList, pConstraint, ((PatternMatchCounter) pConstraint).getResultVariable()); 90 createConstraintInfoAggregatorConstraint(resultList, pConstraint, ((PatternMatchCounter) pConstraint).getResultVariable());
110 } else if (pConstraint instanceof PositivePatternCall){ 91 } else if (pConstraint instanceof PositivePatternCall){
111 createConstraintInfoPositivePatternCall(resultList, (PositivePatternCall) pConstraint); 92 createConstraintInfoPositivePatternCall(resultList, (PositivePatternCall) pConstraint);
112 } else if (pConstraint instanceof AbstractTransitiveClosure) { 93 } else if (pConstraint instanceof AbstractTransitiveClosure) {
@@ -115,10 +96,10 @@ class PConstraintInfoInferrer {
115 createConstraintInfoGeneric(resultList, pConstraint); 96 createConstraintInfoGeneric(resultList, pConstraint);
116 } 97 }
117 } 98 }
118 99
119 private void createConstraintInfoConstantValue(List<PConstraintInfo> resultList, 100 private void createConstraintInfoConstantValue(List<PConstraintInfo> resultList,
120 ConstantValue pConstraint) { 101 ConstantValue pConstraint) {
121 // A ConstantValue constraint has a single variable, which is allowed to be unbound 102 // A ConstantValue constraint has a single variable, which is allowed to be unbound
122 // (extending through ConstantValue is considered a cheap operation) 103 // (extending through ConstantValue is considered a cheap operation)
123 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables(); 104 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables();
124 Set<? extends Set<PVariable>> bindings = Sets.powerSet(affectedVariables); 105 Set<? extends Set<PVariable>> bindings = Sets.powerSet(affectedVariables);
@@ -126,7 +107,7 @@ class PConstraintInfoInferrer {
126 } 107 }
127 108
128 109
129 private void createConstraintInfoPositivePatternCall(List<PConstraintInfo> resultList, 110 private void createConstraintInfoPositivePatternCall(List<PConstraintInfo> resultList,
130 PositivePatternCall pCall) { 111 PositivePatternCall pCall) {
131 // A pattern call can have any of its variables unbound 112 // A pattern call can have any of its variables unbound
132 Set<PVariable> affectedVariables = pCall.getAffectedVariables(); 113 Set<PVariable> affectedVariables = pCall.getAffectedVariables();
@@ -147,23 +128,23 @@ class PConstraintInfoInferrer {
147 case OUT: 128 case OUT:
148 default: 129 default:
149 break; 130 break;
150 131
151 } 132 }
152 } 133 }
153 Iterable<Set<PVariable>> bindings = Sets.powerSet(inoutVariables).stream() 134 Iterable<Set<PVariable>> bindings = Sets.powerSet(inoutVariables).stream()
154 .map(input -> Stream.concat(input.stream(), inVariables.stream()).collect(Collectors.toSet())) 135 .map(input -> Stream.concat(input.stream(), inVariables.stream()).collect(Collectors.toSet()))
155 .collect(Collectors.toSet()); 136 .collect(Collectors.toSet());
156 137
157 doCreateConstraintInfos(resultList, pCall, affectedVariables, bindings); 138 doCreateConstraintInfos(resultList, pCall, affectedVariables, bindings);
158 } 139 }
159 140
160 private void createConstraintInfoBinaryTransitiveClosure(List<PConstraintInfo> resultList, 141 private void createConstraintInfoBinaryTransitiveClosure(List<PConstraintInfo> resultList,
161 AbstractTransitiveClosure closure) { 142 AbstractTransitiveClosure closure) {
162 // A pattern call can have any of its variables unbound 143 // A pattern call can have any of its variables unbound
163 144
164 List<PParameter> parameters = closure.getReferredQuery().getParameters(); 145 List<PParameter> parameters = closure.getReferredQuery().getParameters();
165 Tuple variables = closure.getVariablesTuple(); 146 Tuple variables = closure.getVariablesTuple();
166 147
167 Set<Set<PVariable>> bindings = new HashSet<>(); 148 Set<Set<PVariable>> bindings = new HashSet<>();
168 PVariable firstVariable = (PVariable) variables.get(0); 149 PVariable firstVariable = (PVariable) variables.get(0);
169 PVariable secondVariable = (PVariable) variables.get(1); 150 PVariable secondVariable = (PVariable) variables.get(1);
@@ -177,20 +158,20 @@ class PConstraintInfoInferrer {
177 if (parameters.get(1).getDirection() != PParameterDirection.IN) { 158 if (parameters.get(1).getDirection() != PParameterDirection.IN) {
178 bindings.add(Collections.singleton(firstVariable)); 159 bindings.add(Collections.singleton(firstVariable));
179 } 160 }
180 161
181 doCreateConstraintInfos(resultList, closure, closure.getAffectedVariables(), bindings); 162 doCreateConstraintInfos(resultList, closure, closure.getAffectedVariables(), bindings);
182 } 163 }
183
184
185 164
186 private void createConstraintInfoExportedParameter(List<PConstraintInfo> resultList, 165
166
167 private void createConstraintInfoExportedParameter(List<PConstraintInfo> resultList,
187 ExportedParameter parameter) { 168 ExportedParameter parameter) {
188 // In case of an exported parameter constraint, the parameter must be bound in order to execute 169 // In case of an exported parameter constraint, the parameter must be bound in order to execute
189 Set<PVariable> affectedVariables = parameter.getAffectedVariables(); 170 Set<PVariable> affectedVariables = parameter.getAffectedVariables();
190 doCreateConstraintInfos(resultList, parameter, affectedVariables, Collections.singleton(affectedVariables)); 171 doCreateConstraintInfos(resultList, parameter, affectedVariables, Collections.singleton(affectedVariables));
191 } 172 }
192 173
193 private void createConstraintInfoExpressionEvaluation(List<PConstraintInfo> resultList, 174 private void createConstraintInfoExpressionEvaluation(List<PConstraintInfo> resultList,
194 ExpressionEvaluation expressionEvaluation) { 175 ExpressionEvaluation expressionEvaluation) {
195 // An expression evaluation can only have its output variable unbound. All other variables shall be bound 176 // An expression evaluation can only have its output variable unbound. All other variables shall be bound
196 PVariable output = expressionEvaluation.getOutputVariable(); 177 PVariable output = expressionEvaluation.getOutputVariable();
@@ -203,41 +184,41 @@ class PConstraintInfoInferrer {
203 doCreateConstraintInfos(resultList, expressionEvaluation, affectedVariables, bindings); 184 doCreateConstraintInfos(resultList, expressionEvaluation, affectedVariables, bindings);
204 } 185 }
205 186
206 private void createConstraintInfoTypeFilterConstraint(List<PConstraintInfo> resultList, 187 private void createConstraintInfoTypeFilterConstraint(List<PConstraintInfo> resultList,
207 TypeFilterConstraint filter){ 188 TypeFilterConstraint filter){
208 // In case of type filter, all affected variables must be bound in order to execute 189 // In case of type filter, all affected variables must be bound in order to execute
209 Set<PVariable> affectedVariables = filter.getAffectedVariables(); 190 Set<PVariable> affectedVariables = filter.getAffectedVariables();
210 doCreateConstraintInfos(resultList, filter, affectedVariables, Collections.singleton(affectedVariables)); 191 doCreateConstraintInfos(resultList, filter, affectedVariables, Collections.singleton(affectedVariables));
211 } 192 }
212 193
213 private void createConstraintInfoInequality(List<PConstraintInfo> resultList, 194 private void createConstraintInfoInequality(List<PConstraintInfo> resultList,
214 Inequality inequality){ 195 Inequality inequality){
215 // In case of inequality, all affected variables must be bound in order to execute 196 // In case of inequality, all affected variables must be bound in order to execute
216 Set<PVariable> affectedVariables = inequality.getAffectedVariables(); 197 Set<PVariable> affectedVariables = inequality.getAffectedVariables();
217 doCreateConstraintInfos(resultList, inequality, affectedVariables, Collections.singleton(affectedVariables)); 198 doCreateConstraintInfos(resultList, inequality, affectedVariables, Collections.singleton(affectedVariables));
218 } 199 }
219 200
220 private void createConstraintInfoAggregatorConstraint(List<PConstraintInfo> resultList, 201 private void createConstraintInfoAggregatorConstraint(List<PConstraintInfo> resultList,
221 PConstraint pConstraint, PVariable resultVariable){ 202 PConstraint pConstraint, PVariable resultVariable){
222 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables(); 203 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables();
223 204
224 // The only variables which can be unbound are single-use 205 // The only variables which can be unbound are single-use
225 Set<PVariable> canBeUnboundVariables = 206 Set<PVariable> canBeUnboundVariables =
226 Stream.concat(Stream.of(resultVariable), affectedVariables.stream().filter(SINGLE_USE_VARIABLE)).collect(Collectors.toSet()); 207 Stream.concat(Stream.of(resultVariable), affectedVariables.stream().filter(SINGLE_USE_VARIABLE)).collect(Collectors.toSet());
227 208
228 Set<Set<PVariable>> bindings = calculatePossibleBindings(canBeUnboundVariables, affectedVariables); 209 Set<Set<PVariable>> bindings = calculatePossibleBindings(canBeUnboundVariables, affectedVariables);
229 210
230 doCreateConstraintInfos(resultList, pConstraint, affectedVariables, bindings); 211 doCreateConstraintInfos(resultList, pConstraint, affectedVariables, bindings);
231 } 212 }
232 213
233 /** 214 /**
234 * 215 *
235 * @param canBeUnboundVariables Variables which are allowed to be unbound 216 * @param canBeUnboundVariables Variables which are allowed to be unbound
236 * @param affectedVariables All affected variables 217 * @param affectedVariables All affected variables
237 * @return The set of possible bound variable sets 218 * @return The set of possible bound variable sets
238 */ 219 */
239 private Set<Set<PVariable>> calculatePossibleBindings(Set<PVariable> canBeUnboundVariables, Set<PVariable> affectedVariables){ 220 private Set<Set<PVariable>> calculatePossibleBindings(Set<PVariable> canBeUnboundVariables, Set<PVariable> affectedVariables){
240 final Set<PVariable> mustBindVariables = affectedVariables.stream().filter(input -> !canBeUnboundVariables.contains(input)).collect(Collectors.toSet()); 221 final Set<PVariable> mustBindVariables = affectedVariables.stream().filter(input -> !canBeUnboundVariables.contains(input)).collect(Collectors.toSet());
241 return Sets.powerSet(canBeUnboundVariables).stream() 222 return Sets.powerSet(canBeUnboundVariables).stream()
242 .map(input -> { 223 .map(input -> {
243 //some variables have to be bound before executing this constraint 224 //some variables have to be bound before executing this constraint
@@ -247,33 +228,23 @@ class PConstraintInfoInferrer {
247 }) 228 })
248 .collect(Collectors.toSet()); 229 .collect(Collectors.toSet());
249 } 230 }
250 231
251 private void createConstraintInfoGeneric(List<PConstraintInfo> resultList, PConstraint pConstraint){ 232 private void createConstraintInfoGeneric(List<PConstraintInfo> resultList, PConstraint pConstraint){
252 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables(); 233 Set<PVariable> affectedVariables = pConstraint.getAffectedVariables();
253 234
254 // The only variables which can be unbound are single use variables 235 // The only variables which can be unbound are single use variables
255 Set<PVariable> canBeUnboundVariables = affectedVariables.stream().filter(SINGLE_USE_VARIABLE).collect(Collectors.toSet()); 236 Set<PVariable> canBeUnboundVariables = affectedVariables.stream().filter(SINGLE_USE_VARIABLE).collect(Collectors.toSet());
256 237
257 Set<Set<PVariable>> bindings = calculatePossibleBindings(canBeUnboundVariables, affectedVariables); 238 Set<Set<PVariable>> bindings = calculatePossibleBindings(canBeUnboundVariables, affectedVariables);
258 239
259 doCreateConstraintInfos(resultList, pConstraint, affectedVariables, bindings); 240 doCreateConstraintInfos(resultList, pConstraint, affectedVariables, bindings);
260 } 241 }
261 242
262 private boolean canPerformInverseNavigation(EStructuralFeature feature){ 243 private void createConstraintInfoTypeConstraint(List<PConstraintInfo> resultList,
263 return ( // Feature has opposite (this only possible for references)
264 hasEOpposite(feature)
265 ||
266 (feature instanceof EReference) && ((EReference)feature).isContainment()
267 || ( // Indexing is enabled, and the feature can be indexed (not a non-well-behaving derived feature).
268 useIndex && modelComprehension.representable(feature)
269 ));
270 }
271
272 private void createConstraintInfoTypeConstraint(List<PConstraintInfo> resultList,
273 TypeConstraint typeConstraint) { 244 TypeConstraint typeConstraint) {
274 Set<PVariable> affectedVariables = typeConstraint.getAffectedVariables(); 245 Set<PVariable> affectedVariables = typeConstraint.getAffectedVariables();
275 Set<? extends Set<PVariable>> bindings = null; 246 Set<? extends Set<PVariable>> bindings = null;
276 247
277 IInputKey inputKey = typeConstraint.getSupplierKey(); 248 IInputKey inputKey = typeConstraint.getSupplierKey();
278 if(inputKey.isEnumerable()){ 249 if(inputKey.isEnumerable()){
279 bindings = Sets.powerSet(affectedVariables); 250 bindings = Sets.powerSet(affectedVariables);
@@ -281,23 +252,15 @@ class PConstraintInfoInferrer {
281 // For not enumerable types, this constraint can only be a check 252 // For not enumerable types, this constraint can only be a check
282 bindings = Collections.singleton(affectedVariables); 253 bindings = Collections.singleton(affectedVariables);
283 } 254 }
284 255
285 if(inputKey instanceof EStructuralFeatureInstancesKey){
286 final EStructuralFeature feature = ((EStructuralFeatureInstancesKey) inputKey).getEmfKey();
287 if(!canPerformInverseNavigation(feature)){
288 // When inverse navigation is not allowed or not possible, filter out operation masks, where
289 // the first variable would be free AND the feature is an EReference and has no EOpposite
290 bindings = excludeUnnavigableOperationMasks(typeConstraint, bindings);
291 }
292 }
293 doCreateConstraintInfos(resultList, typeConstraint, affectedVariables, bindings); 256 doCreateConstraintInfos(resultList, typeConstraint, affectedVariables, bindings);
294 } 257 }
295 258
296 private void doCreateConstraintInfos(List<PConstraintInfo> constraintInfos, 259 private void doCreateConstraintInfos(List<PConstraintInfo> constraintInfos,
297 PConstraint pConstraint, Set<PVariable> affectedVariables, Iterable<? extends Set<PVariable>> bindings) { 260 PConstraint pConstraint, Set<PVariable> affectedVariables, Iterable<? extends Set<PVariable>> bindings) {
298 Set<PConstraintInfo> sameWithDifferentBindings = new HashSet<>(); 261 Set<PConstraintInfo> sameWithDifferentBindings = new HashSet<>();
299 for (Set<PVariable> boundVariables : bindings) { 262 for (Set<PVariable> boundVariables : bindings) {
300 263
301 PConstraintInfo info = new PConstraintInfo(pConstraint, boundVariables, 264 PConstraintInfo info = new PConstraintInfo(pConstraint, boundVariables,
302 affectedVariables.stream().filter(input -> !boundVariables.contains(input)).collect(Collectors.toSet()), 265 affectedVariables.stream().filter(input -> !boundVariables.contains(input)).collect(Collectors.toSet()),
303 sameWithDifferentBindings, context, resultRequestor, costFunction); 266 sameWithDifferentBindings, context, resultRequestor, costFunction);
@@ -305,22 +268,11 @@ class PConstraintInfoInferrer {
305 sameWithDifferentBindings.add(info); 268 sameWithDifferentBindings.add(info);
306 } 269 }
307 } 270 }
308 271
309 private Set<Set<PVariable>> excludeUnnavigableOperationMasks(TypeConstraint typeConstraint, Set<? extends Set<PVariable>> bindings) { 272 private Set<Set<PVariable>> excludeUnnavigableOperationMasks(TypeConstraint typeConstraint, Set<? extends Set<PVariable>> bindings) {
310 PVariable firstVariable = typeConstraint.getVariableInTuple(0); 273 PVariable firstVariable = typeConstraint.getVariableInTuple(0);
311 return bindings.stream().filter( 274 return bindings.stream().filter(
312 boundVariablesSet -> (boundVariablesSet.isEmpty() || boundVariablesSet.contains(firstVariable))) 275 boundVariablesSet -> (boundVariablesSet.isEmpty() || boundVariablesSet.contains(firstVariable)))
313 .collect(Collectors.toSet()); 276 .collect(Collectors.toSet());
314 } 277 }
315
316 private boolean hasEOpposite(EStructuralFeature feature) {
317 if(feature instanceof EReference){
318 EReference eOpposite = ((EReference) feature).getEOpposite();
319 if(eOpposite != null){
320 return true;
321 }
322 }
323 return false;
324 }
325
326} 278}
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/EMFOperationCompiler.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/EMFOperationCompiler.java
deleted file mode 100644
index 7fd86f3c..00000000
--- a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/compiler/EMFOperationCompiler.java
+++ /dev/null
@@ -1,198 +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.localsearch.planner.compiler;
10
11import java.util.Map;
12
13import org.eclipse.emf.ecore.EReference;
14import org.eclipse.emf.ecore.EStructuralFeature;
15import tools.refinery.viatra.runtime.emf.EMFQueryRuntimeContext;
16import tools.refinery.viatra.runtime.emf.types.EClassTransitiveInstancesKey;
17import tools.refinery.viatra.runtime.emf.types.EClassUnscopedTransitiveInstancesKey;
18import tools.refinery.viatra.runtime.emf.types.EDataTypeInSlotsKey;
19import tools.refinery.viatra.runtime.emf.types.EStructuralFeatureInstancesKey;
20import tools.refinery.viatra.runtime.localsearch.operations.check.InstanceOfClassCheck;
21import tools.refinery.viatra.runtime.localsearch.operations.check.InstanceOfDataTypeCheck;
22import tools.refinery.viatra.runtime.localsearch.operations.check.InstanceOfJavaClassCheck;
23import tools.refinery.viatra.runtime.localsearch.operations.check.StructuralFeatureCheck;
24import tools.refinery.viatra.runtime.localsearch.operations.check.nobase.ScopeCheck;
25import tools.refinery.viatra.runtime.localsearch.operations.extend.ExtendToEStructuralFeatureSource;
26import tools.refinery.viatra.runtime.localsearch.operations.extend.ExtendToEStructuralFeatureTarget;
27import tools.refinery.viatra.runtime.localsearch.operations.extend.IterateOverContainers;
28import tools.refinery.viatra.runtime.localsearch.operations.extend.IterateOverEClassInstances;
29import tools.refinery.viatra.runtime.localsearch.operations.extend.IterateOverEDatatypeInstances;
30import tools.refinery.viatra.runtime.matchers.context.IInputKey;
31import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
32import tools.refinery.viatra.runtime.matchers.context.common.JavaTransitiveInstancesKey;
33import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
34import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
35import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint;
36import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
37import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
38
39/**
40 * Operation compiler implementation that uses EMF-specific operations.
41 *
42 * @author Zoltan Ujhelyi
43 * @since 1.7
44 *
45 */
46public class EMFOperationCompiler extends AbstractOperationCompiler {
47
48 private boolean baseIndexAvailable;
49
50 private final EMFQueryRuntimeContext runtimeContext;
51
52 public EMFOperationCompiler(IQueryRuntimeContext runtimeContext) {
53 this(runtimeContext, false);
54 }
55
56 public EMFOperationCompiler(IQueryRuntimeContext runtimeContext, boolean baseIndexAvailable) {
57 super(runtimeContext);
58 this.runtimeContext = (EMFQueryRuntimeContext) runtimeContext;
59 this.baseIndexAvailable = baseIndexAvailable;
60 }
61
62 @Override
63 protected void createCheck(TypeFilterConstraint typeConstraint, Map<PVariable, Integer> variableMapping) {
64 final IInputKey inputKey = typeConstraint.getInputKey();
65 if (inputKey instanceof JavaTransitiveInstancesKey) {
66 doCreateInstanceofJavaTypeCheck((JavaTransitiveInstancesKey) inputKey, variableMapping.get(typeConstraint.getVariablesTuple().get(0)));
67 } else if (inputKey instanceof EDataTypeInSlotsKey) { // TODO probably only occurs as TypeConstraint
68 doCreateInstanceofDatatypeCheck((EDataTypeInSlotsKey) inputKey, variableMapping.get(typeConstraint.getVariablesTuple().get(0)));
69 } else if (inputKey instanceof EClassUnscopedTransitiveInstancesKey) {
70 doCreateInstanceofUnscopedClassCheck((EClassUnscopedTransitiveInstancesKey) inputKey, variableMapping.get(typeConstraint.getVariablesTuple().get(0)));
71 } else {
72 String msg = UNSUPPORTED_TYPE_MESSAGE + inputKey;
73 throw new QueryProcessingException(msg, null, msg, null);
74 }
75 }
76
77 @Override
78 protected void createCheck(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) {
79 final IInputKey inputKey = typeConstraint.getSupplierKey();
80 if (inputKey instanceof EClassTransitiveInstancesKey) {
81 doCreateInstanceofClassCheck((EClassTransitiveInstancesKey)inputKey, variableMapping.get(typeConstraint.getVariablesTuple().get(0)));
82 } else if (inputKey instanceof EStructuralFeatureInstancesKey) {
83 int sourcePosition = variableMapping.get(typeConstraint.getVariablesTuple().get(0));
84 int targetPosition = variableMapping.get(typeConstraint.getVariablesTuple().get(1));
85 operations.add(new StructuralFeatureCheck(sourcePosition, targetPosition,
86 ((EStructuralFeatureInstancesKey) inputKey).getEmfKey()));
87 } else if (inputKey instanceof EDataTypeInSlotsKey) {
88 doCreateInstanceofDatatypeCheck((EDataTypeInSlotsKey) inputKey, variableMapping.get(typeConstraint.getVariablesTuple().get(0)));
89 } else {
90 String msg = UNSUPPORTED_TYPE_MESSAGE + inputKey;
91 throw new QueryProcessingException(msg, null, msg, null);
92 }
93 }
94
95 @Override
96 protected void createUnaryTypeCheck(IInputKey inputKey, int position) {
97 if (inputKey instanceof EClassTransitiveInstancesKey) {
98 doCreateInstanceofClassCheck((EClassTransitiveInstancesKey)inputKey, position);
99 } else if (inputKey instanceof EClassUnscopedTransitiveInstancesKey) {
100 doCreateInstanceofUnscopedClassCheck((EClassUnscopedTransitiveInstancesKey)inputKey, position);
101 } else if (inputKey instanceof EDataTypeInSlotsKey) {
102 doCreateInstanceofDatatypeCheck((EDataTypeInSlotsKey) inputKey, position);
103 } else if (inputKey instanceof JavaTransitiveInstancesKey) {
104 doCreateInstanceofJavaTypeCheck((JavaTransitiveInstancesKey) inputKey, position);
105 } else {
106 String msg = UNSUPPORTED_TYPE_MESSAGE + inputKey;
107 throw new QueryProcessingException(msg, null, msg, null);
108 }
109 }
110
111 private void doCreateInstanceofClassCheck(EClassTransitiveInstancesKey inputKey, int position) {
112 operations.add(new InstanceOfClassCheck(position, inputKey.getEmfKey()));
113 operations.add(new ScopeCheck(position, runtimeContext.getEmfScope()));
114 }
115
116 private void doCreateInstanceofUnscopedClassCheck(EClassUnscopedTransitiveInstancesKey inputKey, int position) {
117 operations.add(new InstanceOfClassCheck(position, inputKey.getEmfKey()));
118 }
119
120 private void doCreateInstanceofDatatypeCheck(EDataTypeInSlotsKey inputKey, int position) {
121 operations.add(new InstanceOfDataTypeCheck(position, inputKey.getEmfKey()));
122 }
123 private void doCreateInstanceofJavaTypeCheck(JavaTransitiveInstancesKey inputKey, int position) {
124 operations.add(new InstanceOfJavaClassCheck(position, inputKey.getInstanceClass()));
125 }
126
127 @Override
128 public void createExtend(TypeConstraint typeConstraint, Map<PVariable, Integer> variableMapping) {
129 final IInputKey inputKey = typeConstraint.getSupplierKey();
130 if (inputKey instanceof EDataTypeInSlotsKey) {
131 if(baseIndexAvailable){
132 operations.add(new IterateOverEDatatypeInstances(variableMapping.get(typeConstraint.getVariableInTuple(0)), ((EDataTypeInSlotsKey) inputKey).getEmfKey()));
133 } else {
134 int position = variableMapping.get(typeConstraint.getVariableInTuple(0));
135 operations
136 .add(new tools.refinery.viatra.runtime.localsearch.operations.extend.nobase.IterateOverEDatatypeInstances(position,
137 ((EDataTypeInSlotsKey) inputKey).getEmfKey(), runtimeContext.getEmfScope()));
138 operations.add(new ScopeCheck(position, runtimeContext.getEmfScope()));
139 }
140 } else if (inputKey instanceof EClassTransitiveInstancesKey) {
141 if(baseIndexAvailable){
142 operations.add(new IterateOverEClassInstances(variableMapping.get(typeConstraint.getVariableInTuple(0)),
143 ((EClassTransitiveInstancesKey) inputKey).getEmfKey()));
144 } else {
145 int position = variableMapping.get(typeConstraint.getVariableInTuple(0));
146 operations
147 .add(new tools.refinery.viatra.runtime.localsearch.operations.extend.nobase.IterateOverEClassInstances(
148 position,
149 ((EClassTransitiveInstancesKey) inputKey).getEmfKey(), runtimeContext.getEmfScope()));
150 operations.add(new ScopeCheck(position, runtimeContext.getEmfScope()));
151 }
152 } else if (inputKey instanceof EStructuralFeatureInstancesKey) {
153 final EStructuralFeature feature = ((EStructuralFeatureInstancesKey) inputKey).getEmfKey();
154
155 int sourcePosition = variableMapping.get(typeConstraint.getVariablesTuple().get(0));
156 int targetPosition = variableMapping.get(typeConstraint.getVariablesTuple().get(1));
157
158 boolean fromBound = variableBindings.get(typeConstraint).contains(sourcePosition);
159 boolean toBound = variableBindings.get(typeConstraint).contains(targetPosition);
160
161 if (fromBound && !toBound) {
162 operations.add(new ExtendToEStructuralFeatureTarget(sourcePosition, targetPosition, feature));
163 operations.add(new ScopeCheck(targetPosition, runtimeContext.getEmfScope()));
164 } else if(!fromBound && toBound){
165 if (feature instanceof EReference && ((EReference)feature).isContainment()) {
166 // The iterate is also used to traverse a single container (third parameter)
167 operations.add(new IterateOverContainers(sourcePosition, targetPosition, false));
168 operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope()));
169 } else if(baseIndexAvailable){
170 TupleMask mask = TupleMask.fromSelectedIndices(variableMapping.size(), new int[] {targetPosition});
171 operations.add(new ExtendToEStructuralFeatureSource(sourcePosition, targetPosition, feature, mask));
172 } else {
173 operations.add(new tools.refinery.viatra.runtime.localsearch.operations.extend.nobase.ExtendToEStructuralFeatureSource(
174 sourcePosition, targetPosition, feature));
175 operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope()));
176 }
177 } else {
178 // TODO Elaborate solution based on the navigability of edges
179 // As of now a static solution is implemented
180 if (baseIndexAvailable) {
181 operations.add(new IterateOverEClassInstances(sourcePosition, feature.getEContainingClass()));
182 operations.add(new ExtendToEStructuralFeatureTarget(sourcePosition, targetPosition, feature));
183 } else {
184 operations
185 .add(new tools.refinery.viatra.runtime.localsearch.operations.extend.nobase.IterateOverEClassInstances(
186 sourcePosition, feature.getEContainingClass(), runtimeContext.getEmfScope()));
187 operations.add(new ScopeCheck(sourcePosition, runtimeContext.getEmfScope()));
188 operations.add(new ExtendToEStructuralFeatureTarget(sourcePosition, targetPosition, feature));
189 operations.add(new ScopeCheck(targetPosition, runtimeContext.getEmfScope()));
190 }
191 }
192
193 } else {
194 throw new IllegalArgumentException(UNSUPPORTED_TYPE_MESSAGE + inputKey);
195 }
196 }
197
198}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java
deleted file mode 100644
index 16f40358..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java
+++ /dev/null
@@ -1,53 +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.matchers.scopes;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
13import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterBinary;
14import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterUnary;
15
16/**
17 * An abstract storage backend that instantiates tables and coordinates transactions.
18 *
19 * <p><strong>EXPERIMENTAL</strong>. This class or interface has been added as
20 * part of a work in progress. There is no guarantee that this API will
21 * work or that it will remain the same.
22 *
23 * @author Gabor Bergmann
24 *
25 * @since 2.1
26 */
27public interface IStorageBackend {
28
29
30 /**
31 * Marks the beginning of a transaction.
32 * In transaction mode, table updates may be temporarily delayed ({@link tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable} methods may return stale answers) for better performance.
33 */
34 void startTransaction();
35 /**
36 * Marks the end of a transaction.
37 * Any updates delayed during the transaction must now be flushed.
38 */
39 void finishTransaction();
40
41 /**
42 * Creates an index table for a simple value set.
43 * @param unique client promises to only insert a given tuple with multiplicity one
44 */
45 ITableWriterUnary.Table<Object> createUnaryTable(IInputKey key, ITableContext tableContext, boolean unique);
46 /**
47 * Creates an index table for a simple source-target bidirectional mapping.
48 * @param unique client promises to only insert a given tuple with multiplicity one
49 */
50 ITableWriterBinary.Table<Object,Object> createBinaryTable(IInputKey key, ITableContext tableContext, boolean unique);
51
52
53}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java
deleted file mode 100644
index fd1f7b7e..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.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 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
13import tools.refinery.viatra.runtime.matchers.scopes.tables.SimpleBinaryTable;
14import tools.refinery.viatra.runtime.matchers.scopes.tables.SimpleUnaryTable;
15
16/**
17 * Basic storage backend implementation based on local collections.
18 *
19 * <p><strong>EXPERIMENTAL</strong>. This class or interface has been added as
20 * part of a work in progress. There is no guarantee that this API will
21 * work or that it will remain the same.
22 *
23 * @author Gabor Bergmann
24 * @since 2.1
25 */
26public class SimpleLocalStorageBackend implements IStorageBackend {
27
28 @Override
29 public void startTransaction() {
30 // NOP
31 }
32
33 @Override
34 public void finishTransaction() {
35 // NOP
36 }
37
38 @Override
39 public SimpleUnaryTable<Object> createUnaryTable(IInputKey key, ITableContext tableContext, boolean unique) {
40 return new SimpleUnaryTable<>(key, tableContext, unique);
41 }
42
43 @Override
44 public SimpleBinaryTable<Object, Object> createBinaryTable(IInputKey key, ITableContext tableContext,
45 boolean unique) {
46 return new SimpleBinaryTable<>(key, tableContext, unique);
47 }
48
49
50
51}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java
deleted file mode 100644
index a3a827dc..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java
+++ /dev/null
@@ -1,132 +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.matchers.scopes;
11
12import java.lang.reflect.InvocationTargetException;
13import java.util.concurrent.Callable;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.context.IndexingService;
18import tools.refinery.viatra.runtime.matchers.context.common.JavaTransitiveInstancesKey;
19import tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22
23/**
24 * A simple demo implementation of the IQRC interface using tables.
25 *
26 * <p>
27 * Usage: first, instantiate {@link IIndexTable} tables with this as the 'tableContext' argument, and call
28 * {@link #registerIndexTable(IIndexTable)} manually to register them. Afterwards, they will be visible to the query
29 * backends.
30 * <p>
31 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
32 * part of a work in progress. There is no guarantee that this API will
33 * work or that it will remain the same.
34 *
35 * @author Gabor Bergmann
36 * @since 2.0
37 */
38public class SimpleRuntimeContext extends TabularRuntimeContext {
39
40 private IQueryMetaContext metaContext;
41
42 public SimpleRuntimeContext(IQueryMetaContext metaContext) {
43 this.metaContext = metaContext;
44 }
45
46 @Override
47 public void logError(String message) {
48 System.err.println(message);
49 }
50
51 @Override
52 public IQueryMetaContext getMetaContext() {
53 return metaContext;
54 }
55
56 @Override
57 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
58 try {
59 return callable.call();
60 } catch (Exception e) {
61 throw new InvocationTargetException(e);
62 }
63 }
64
65 @Override
66 public boolean isCoalescing() {
67 return false;
68 }
69
70 @Override
71 public boolean isIndexed(IInputKey key, IndexingService service) {
72 return peekIndexTable(key) != null;
73 }
74
75 @Override
76 public void ensureIndexed(IInputKey key, IndexingService service) {
77 if (peekIndexTable(key) == null)
78 throw new IllegalArgumentException(key.getPrettyPrintableName());
79 }
80
81 @Override
82 public Object wrapElement(Object externalElement) {
83 return externalElement;
84 }
85
86 @Override
87 public Object unwrapElement(Object internalElement) {
88 return internalElement;
89 }
90
91 @Override
92 public Tuple wrapTuple(Tuple externalElements) {
93 return externalElements;
94 }
95
96 @Override
97 public Tuple unwrapTuple(Tuple internalElements) {
98 return internalElements;
99 }
100
101 @Override
102 public void ensureWildcardIndexing(IndexingService service) {
103 throw new UnsupportedOperationException();
104 }
105
106 @Override
107 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException {
108 runnable.run();
109 }
110
111 @Override
112 protected boolean isContainedInStatelessKey(IInputKey key, ITuple seed) {
113 if (key instanceof JavaTransitiveInstancesKey) {
114 Class<?> instanceClass = forceGetWrapperInstanceClass((JavaTransitiveInstancesKey) key);
115 return instanceClass != null && instanceClass.isInstance(seed.get(0));
116 } else
117 throw new IllegalArgumentException(key.getPrettyPrintableName());
118 }
119
120 private Class<?> forceGetWrapperInstanceClass(JavaTransitiveInstancesKey key) {
121 Class<?> instanceClass;
122 try {
123 instanceClass = key.forceGetWrapperInstanceClass();
124 } catch (ClassNotFoundException e) {
125 logError(
126 "Could not load instance class for type constraint " + key.getWrappedKey() + ": " + e.getMessage());
127 instanceClass = null;
128 }
129 return instanceClass;
130 }
131
132}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java
deleted file mode 100644
index e99e24d3..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java
+++ /dev/null
@@ -1,119 +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.matchers.scopes;
11
12import java.util.Map;
13import java.util.Optional;
14
15import tools.refinery.viatra.runtime.matchers.context.AbstractQueryRuntimeContext;
16import tools.refinery.viatra.runtime.matchers.context.IInputKey;
17import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
18import tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable;
19import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
23import tools.refinery.viatra.runtime.matchers.util.Accuracy;
24import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
25
26/**
27 * An abstract runtime context that serves enumerable input key instances from tables.
28 *
29 * <p>
30 * Usage: first, instantiate {@link IIndexTable} tables with this as the 'tableContext' argument. Call
31 * {@link #registerIndexTable(IIndexTable)} to register them; this may happen either during a coalesced indexing, or on
32 * external initiation. Afterwards, they will be visible to the query backends.
33 * <p>
34 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
35 * part of a work in progress. There is no guarantee that this API will
36 * work or that it will remain the same.
37 *
38 * @author Gabor Bergmann
39 * @since 2.0
40 */
41public abstract class TabularRuntimeContext extends AbstractQueryRuntimeContext implements ITableContext {
42
43 private Map<IInputKey, IIndexTable> instanceTables = CollectionsFactory.createMap();
44
45 public void registerIndexTable(IIndexTable table) {
46 IInputKey inputKey = table.getInputKey();
47 instanceTables.put(inputKey, table);
48 }
49
50 /**
51 * @return null if the table is not registered
52 */
53 public IIndexTable peekIndexTable(IInputKey key) {
54 return instanceTables.get(key);
55 }
56
57 /**
58 * If the table is not registered, {@link #handleUnregisteredTableRequest(IInputKey)} is invoked; it may handle it
59 * by raising an error or e.g. on-demand index construction
60 */
61 public IIndexTable getIndexTable(IInputKey key) {
62 IIndexTable table = instanceTables.get(key);
63 if (table != null)
64 return table;
65 else
66 return handleUnregisteredTableRequest(key);
67 }
68
69 /**
70 * Override this to provide on-demand table registration
71 */
72 protected IIndexTable handleUnregisteredTableRequest(IInputKey key) {
73 throw new IllegalArgumentException(key.getPrettyPrintableName());
74 }
75
76 @Override
77 public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
78 return getIndexTable(key).countTuples(seedMask, seed);
79 }
80
81 @Override
82 public Optional<Long> estimateCardinality(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) {
83 return getIndexTable(key).estimateProjectionSize(groupMask, requiredAccuracy);
84 }
85
86 @Override
87 public Iterable<Tuple> enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
88 return getIndexTable(key).enumerateTuples(seedMask, seed);
89 }
90
91 @Override
92 public Iterable<? extends Object> enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) {
93 return getIndexTable(key).enumerateValues(seedMask, seed);
94 }
95
96 @Override
97 public boolean containsTuple(IInputKey key, ITuple seed) {
98 if (key.isEnumerable()) {
99 return getIndexTable(key).containsTuple(seed);
100 } else {
101 return isContainedInStatelessKey(key, seed);
102 }
103 }
104
105 @Override
106 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
107 getIndexTable(key).addUpdateListener(seed, listener);
108 }
109 @Override
110 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
111 getIndexTable(key).removeUpdateListener(seed, listener);
112 }
113
114 /**
115 * Handles non-enumerable input keys that are not backed by a table
116 */
117 protected abstract boolean isContainedInStatelessKey(IInputKey key, ITuple seed);
118
119}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java
deleted file mode 100644
index 7b557c33..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java
+++ /dev/null
@@ -1,266 +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.matchers.scopes.tables;
10
11import java.util.List;
12
13import tools.refinery.viatra.runtime.matchers.context.IInputKey;
14import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
20import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
21
22/**
23 * <p>
24 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
25 * part of a work in progress. There is no guarantee that this API will
26 * work or that it will remain the same.
27 *
28 * @since 2.0
29 * @author Gabor Bergmann
30 */
31public abstract class AbstractIndexTable implements IIndexTable {
32
33 private IInputKey inputKey;
34 protected ITableContext tableContext;
35
36 protected final TupleMask emptyMask;
37 protected final Tuple emptyTuple;
38
39
40 public AbstractIndexTable(IInputKey inputKey, ITableContext tableContext) {
41 this.inputKey = inputKey;
42 this.tableContext = tableContext;
43
44 this.emptyMask = TupleMask.empty(getInputKey().getArity());
45 this.emptyTuple = Tuples.flatTupleOf(new Object[inputKey.getArity()]);
46 }
47
48 @Override
49 public String toString() {
50 return this.getClass().getSimpleName() + ":" + inputKey.getPrettyPrintableName();
51 }
52
53 @Override
54 public IInputKey getInputKey() {
55 return inputKey;
56 }
57
58 protected void logError(String message) {
59 tableContext.logError(message);
60 }
61
62
63 /// UPDATE HANDLING SECTION
64
65 // The entire mechanism is designed to accommodate a large number of update listeners,
66 // but maybe there will typically be only a single, universal (unseeded) listener?
67 // TODO Create special handling for that case.
68
69 // Invariant: true iff #listenerGroupsAndSeed is nonempty
70 protected boolean emitNotifications = false;
71 // Subscribed listeners grouped by their seed mask (e.g. all those that seed columns 2 and 5 are together),
72 // groups are stored in a list for quick delivery-time iteration (at the expense of adding / removing);
73 // individual listeners can be looked up based on their seed tuple
74 protected List<IListenersWithSameMask> listenerGroups = CollectionsFactory.createObserverList();
75
76
77 /**
78 * Implementors shall call this to deliver all notifications.
79 * Call may be conditioned to {@link #emitNotifications}
80 */
81 protected void deliverChangeNotifications(Tuple updateTuple, boolean isInsertion) {
82 for (IListenersWithSameMask listenersForSeed : listenerGroups) {
83 listenersForSeed.deliver(updateTuple, isInsertion);
84 }
85 }
86
87 @Override
88 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
89 TupleMask seedMask;
90 if (seed == null) {
91 seed = emptyTuple;
92 seedMask = emptyMask;
93 } else {
94 seedMask = TupleMask.fromNonNullIndices(seed);
95 }
96 IListenersWithSameMask listenerGroup = getListenerGroup(seedMask);
97 if (listenerGroup == null) { // create new group
98 switch (seedMask.getSize()) {
99 case 0:
100 listenerGroup = new UniversalListeners();
101 break;
102 case 1:
103 listenerGroup = new ColumnBoundListeners(seedMask.indices[0]);
104 break;
105 default:
106 listenerGroup = new GenericBoundListeners(seedMask);
107 }
108 listenerGroups.add(listenerGroup);
109 emitNotifications = true;
110 }
111 listenerGroup.addUpdateListener(seed, listener);
112 }
113
114 @Override
115 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
116 TupleMask seedMask;
117 if (seed == null) {
118 seed = emptyTuple;
119 seedMask = emptyMask;
120 } else {
121 seedMask = TupleMask.fromNonNullIndices(seed);
122 }
123 IListenersWithSameMask listenerGroup = getListenerGroup(seedMask);
124 if (listenerGroup == null)
125 throw new IllegalStateException("no listener subscribed with mask" + seedMask);
126
127 if (listenerGroup.removeUpdateListener(seed, listener)) {
128 listenerGroups.remove(listenerGroup);
129 emitNotifications = !listenerGroups.isEmpty();
130 }
131 }
132
133 protected IListenersWithSameMask getListenerGroup(TupleMask seedMask) {
134 for (IListenersWithSameMask candidateGroup : listenerGroups) { // group already exists?
135 if (seedMask.equals(candidateGroup.getSeedMask())) {
136 return candidateGroup;
137 }
138 }
139 return null;
140 }
141
142
143 /**
144 * Represents all listeners subscribed to seeds with the given seed mask.
145 *
146 * @author Bergmann Gabor
147 */
148 protected static interface IListenersWithSameMask {
149
150 public TupleMask getSeedMask();
151
152 public void deliver(Tuple updateTuple, boolean isInsertion);
153
154 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener);
155 /**
156 * @return true if this was the last listener, and the {@link IListenersWithSameMask} can be disposed of.
157 */
158 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener);
159 }
160 /**
161 * Listeners interested in all tuples
162 */
163 protected final class UniversalListeners implements IListenersWithSameMask {
164 private final TupleMask mask = TupleMask.empty(inputKey.getArity());
165 private List<IQueryRuntimeContextListener> listeners = CollectionsFactory.createObserverList();
166
167 @Override
168 public TupleMask getSeedMask() {
169 return mask;
170 }
171 @Override
172 public void deliver(Tuple updateTuple, boolean isInsertion) {
173 IInputKey key = inputKey;
174 for (IQueryRuntimeContextListener listener : listeners) {
175 listener.update(key, updateTuple, isInsertion);
176 }
177 }
178 @Override
179 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
180 listeners.add(listener);
181 }
182 @Override
183 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
184 listeners.remove(listener);
185 return listeners.isEmpty();
186 }
187 }
188 /**
189 * Listeners interested in all tuples seeded by a single columns
190 */
191 protected final class ColumnBoundListeners implements IListenersWithSameMask {
192 private int seedPosition;
193 protected final TupleMask mask;
194 // indexed by projected seed tuple
195 protected IMultiLookup<Object,IQueryRuntimeContextListener> listeners =
196 CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
197
198 public ColumnBoundListeners(int seedPosition) {
199 this.seedPosition = seedPosition;
200 this.mask = TupleMask.selectSingle(seedPosition, inputKey.getArity());
201 }
202
203 @Override
204 public TupleMask getSeedMask() {
205 return mask;
206 }
207 @Override
208 public void deliver(Tuple updateTuple, boolean isInsertion) {
209 IInputKey key = inputKey;
210 Object projectedSeed = updateTuple.get(seedPosition);
211 for (IQueryRuntimeContextListener listener : listeners.lookupOrEmpty(projectedSeed)) {
212 listener.update(key, updateTuple, isInsertion);
213 }
214 }
215 @Override
216 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
217 Object projectedSeed = originalSeed.get(seedPosition);
218 listeners.addPair(projectedSeed, listener);
219 }
220 @Override
221 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
222 Object projectedSeed = originalSeed.get(seedPosition);
223 listeners.removePair(projectedSeed, listener);
224 return listeners.countKeys() == 0;
225 }
226 }
227 /**
228 * Listeners interested in all tuples seeded by a tuple of values
229 */
230 protected final class GenericBoundListeners implements IListenersWithSameMask {
231 protected final TupleMask mask;
232 // indexed by projected seed tuple
233 protected IMultiLookup<Tuple,IQueryRuntimeContextListener> listeners =
234 CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
235
236 public GenericBoundListeners(TupleMask mask) {
237 this.mask = mask;
238 }
239
240 @Override
241 public TupleMask getSeedMask() {
242 return mask;
243 }
244 @Override
245 public void deliver(Tuple updateTuple, boolean isInsertion) {
246 IInputKey key = inputKey;
247 Tuple projectedSeed = mask.transform(updateTuple);
248 for (IQueryRuntimeContextListener listener : listeners.lookupOrEmpty(projectedSeed)) {
249 listener.update(key, updateTuple, isInsertion);
250 }
251 }
252 @Override
253 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
254 Tuple projectedSeed = mask.transform(originalSeed);
255 listeners.addPair(projectedSeed, listener);
256 }
257 @Override
258 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
259 Tuple projectedSeed = mask.transform(originalSeed);
260 listeners.removePair(projectedSeed, listener);
261 return listeners.countKeys() == 0;
262 }
263 }
264
265
266} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java
deleted file mode 100644
index 39475d11..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java
+++ /dev/null
@@ -1,143 +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.matchers.scopes.tables;
10
11import java.util.Map;
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory;
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.util.Accuracy;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
23import tools.refinery.viatra.runtime.matchers.util.Direction;
24import tools.refinery.viatra.runtime.matchers.util.IMemory;
25
26/**
27 * Demo default implementation.
28 * <p>
29 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
30 * part of a work in progress. There is no guarantee that this API will
31 * work or that it will remain the same.
32 *
33 * @since 2.0
34 * @author Gabor Bergmann
35 */
36public class DefaultIndexTable extends AbstractIndexTable implements ITableWriterGeneric {
37
38 protected IMemory<Tuple> rows = CollectionsFactory.createMultiset(); // TODO use SetMemory if unique
39 protected Map<TupleMask, MaskedTupleMemory<?>> indexMemories = CollectionsFactory.createMap();
40 private boolean unique;
41
42 /**
43 * @param unique
44 * client promises to only insert a given tuple with multiplicity one
45 */
46 public DefaultIndexTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
47 super(inputKey, tableContext);
48 this.unique = unique;
49 }
50
51 @Override
52 public void write(Direction direction, Tuple row) {
53 if (direction == Direction.INSERT) {
54 boolean changed = rows.addOne(row);
55 if (unique && !changed) {
56 String msg = String.format(
57 "Error: trying to add duplicate row %s to the unique table %s. This indicates some errors in underlying model representation.",
58 row, getInputKey().getPrettyPrintableName());
59 logError(msg);
60 }
61 if (changed) {
62 for (MaskedTupleMemory<?> indexMemory : indexMemories.values()) {
63 indexMemory.add(row);
64 }
65 if (emitNotifications) {
66 deliverChangeNotifications(row, true);
67 }
68 }
69 } else { // DELETE
70 boolean changed = rows.removeOne(row);
71 if (unique && !changed) {
72 String msg = String.format(
73 "Error: trying to remove duplicate value %s from the unique table %s. This indicates some errors in underlying model representation.",
74 row, getInputKey().getPrettyPrintableName());
75 logError(msg);
76 }
77 if (changed) {
78 for (MaskedTupleMemory<?> indexMemory : indexMemories.values()) {
79 indexMemory.remove(row);
80 }
81 if (emitNotifications) {
82 deliverChangeNotifications(row, false);
83 }
84 }
85 }
86 }
87
88 @Override
89 public boolean containsTuple(ITuple seed) {
90 return rows.distinctValues().contains(seed);
91 }
92
93 private MaskedTupleMemory<?> getIndexMemory(TupleMask seedMask) {
94 return indexMemories.computeIfAbsent(seedMask, mask -> {
95 MaskedTupleMemory<?> memory = MaskedTupleMemory.create(seedMask, MemoryType.SETS, DefaultIndexTable.this);
96 for (Tuple tuple : rows.distinctValues()) {
97 memory.add(tuple);
98 }
99 return memory;
100 });
101 }
102
103 @Override
104 public int countTuples(TupleMask seedMask, ITuple seed) {
105 switch (seedMask.getSize()) {
106 case 0: // unseeded
107 return rows.size();
108 default:
109 return getIndexMemory(seedMask).getOrEmpty(seed).size();
110 }
111 }
112
113 @Override
114 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
115 // always exact count
116 if (groupMask.getSize() == 0) {
117 return rows.size() == 0 ? Optional.of(0L) : Optional.of(1L);
118 } else if (groupMask.getSize() == this.emptyTuple.getSize()) {
119 return Optional.of((long) rows.size());
120 } else {
121 return Optional.of((long)getIndexMemory(groupMask).getKeysetSize());
122 }
123 }
124
125 @Override
126 public Iterable<Tuple> enumerateTuples(TupleMask seedMask, ITuple seed) {
127 return getIndexMemory(seedMask).getOrEmpty(seed);
128 }
129
130 @Override
131 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
132 return getIndexMemory(seedMask).getOrEmpty(seed).stream();
133 }
134
135 @Override
136 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
137 // we assume there is a single omitted index in the mask
138 int queriedColumn = seedMask.getFirstOmittedIndex().getAsInt();
139 return getIndexMemory(seedMask).getOrEmpty(seed).stream()
140 .map(row2 -> row2.get(queriedColumn));
141 }
142
143}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java
deleted file mode 100644
index a3a65f14..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java
+++ /dev/null
@@ -1,192 +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.matchers.scopes.tables;
11
12import java.util.Collections;
13import java.util.List;
14import java.util.Objects;
15import java.util.Optional;
16import java.util.stream.Stream;
17
18import tools.refinery.viatra.runtime.matchers.context.IInputKey;
19import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
24import tools.refinery.viatra.runtime.matchers.util.Accuracy;
25import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
26
27/**
28 * Disjoint union of the provided child tables.
29 *
30 * Used e.g. to present a transitive instance table as a view composed from direct instance tables.
31 * <p>
32 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
33 * part of a work in progress. There is no guarantee that this API will
34 * work or that it will remain the same.
35 *
36 * @since 2.0
37 * @author Gabor Bergmann
38 */
39public class DisjointUnionTable extends AbstractIndexTable {
40
41 protected List<IIndexTable> childTables = CollectionsFactory.createObserverList();
42
43 public DisjointUnionTable(IInputKey inputKey, ITableContext tableContext) {
44 super(inputKey, tableContext);
45 }
46
47 public List<IIndexTable> getChildTables() {
48 return Collections.unmodifiableList(childTables);
49 }
50
51 /**
52 * Precondition: the new child currently is, and will forever stay, disjoint from any other child tables.
53 */
54 public void addChildTable(IIndexTable child) {
55 if (getInputKey().getArity() != child.getInputKey().getArity())
56 throw new IllegalArgumentException(child.toString());
57
58 childTables.add(child);
59
60 if (emitNotifications) {
61 for (Tuple tuple : child.enumerateTuples(emptyMask, Tuples.staticArityFlatTupleOf())) {
62 deliverChangeNotifications(tuple, true);
63 }
64 }
65 }
66
67 @Override
68 public int countTuples(TupleMask seedMask, ITuple seed) {
69 int count = 0;
70 for (IIndexTable child : childTables) {
71 count += child.countTuples(seedMask, seed);
72 }
73 return count;
74 }
75
76
77 @Override
78 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
79 // exact results for trivial projections
80 if (groupMask.getSize() == 0) {
81 for (IIndexTable child : childTables) {
82 if (0 != child.countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()))
83 return Optional.of(1L);
84 }
85 return Optional.of(0L);
86 } else if (groupMask.getSize() == emptyTuple.getSize()) {
87 return Optional.of((long)countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()));
88 }
89 // summing child tables is an upper bound
90 if (Accuracy.BEST_UPPER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) {
91 return Optional.of((long)countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()));
92 } else { // (Accuracy.BEST_LOWER_BOUND == requiredAccuracy)
93 //projections of child tables may coincide, but the largest one is still a lower bound
94 Optional<Long> maxProjection = Optional.empty();
95 for (IIndexTable child : childTables) {
96 Optional<Long> estimateOfChild = child.estimateProjectionSize(groupMask, requiredAccuracy);
97 if (estimateOfChild.isPresent()) {
98 maxProjection = Optional.of(Math.max(estimateOfChild.get(), maxProjection.orElse(0L)));
99 }
100 }
101 return maxProjection;
102 }
103 }
104
105 @Override
106 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
107 Stream<? extends Tuple> stream = Stream.empty();
108 for (IIndexTable child : childTables) {
109 Stream<? extends Tuple> childStream = child.streamTuples(seedMask, seed);
110 stream = Stream.concat(stream, childStream);
111 }
112 return stream;
113 }
114
115 @Override
116 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
117 Stream<? extends Object> stream = Stream.empty();
118 for (IIndexTable child : childTables) {
119 Stream<? extends Object> childStream = child.streamValues(seedMask, seed);
120 stream = Stream.concat(stream, childStream);
121 }
122 return stream;
123 }
124
125 @Override
126 public boolean containsTuple(ITuple seed) {
127 for (IIndexTable child : childTables) {
128 if (child.containsTuple(seed))
129 return true;
130 }
131 return false;
132 }
133
134 @Override
135 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
136 super.addUpdateListener(seed, listener);
137
138 for (IIndexTable table : childTables) {
139 table.addUpdateListener(seed, new ListenerWrapper(listener));
140 }
141 }
142 @Override
143 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
144 super.removeUpdateListener(seed, listener);
145
146 for (IIndexTable table : childTables) {
147 table.removeUpdateListener(seed, new ListenerWrapper(listener));
148 }
149 }
150
151
152 // TODO this would not be necessary
153 // if we moved from IQRCL to an interface that does not expose the input key
154 private class ListenerWrapper implements IQueryRuntimeContextListener {
155
156 private IQueryRuntimeContextListener wrappedListener;
157 public ListenerWrapper(IQueryRuntimeContextListener wrappedListener) {
158 this.wrappedListener = wrappedListener;
159 }
160
161 @Override
162 public void update(IInputKey key, Tuple updateTuple, boolean isInsertion) {
163 wrappedListener.update(getInputKey(), updateTuple, isInsertion);
164 }
165
166 @Override
167 public int hashCode() {
168 return Objects.hash(wrappedListener, DisjointUnionTable.this);
169 }
170 @Override
171 public boolean equals(Object obj) {
172 if (this == obj)
173 return true;
174 if (obj == null)
175 return false;
176 if (getClass() != obj.getClass())
177 return false;
178 ListenerWrapper other = (ListenerWrapper) obj;
179 if (!getOuterType().equals(other.getOuterType()))
180 return false;
181 return Objects.equals(wrappedListener, other.wrappedListener);
182 }
183 private DisjointUnionTable getOuterType() {
184 return DisjointUnionTable.this;
185 }
186 @Override
187 public String toString() {
188 return "Wrapper to DisjointUnion("+getInputKey().getPrettyPrintableName()+") for " + wrappedListener;
189 }
190 }
191
192}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java
deleted file mode 100644
index be375393..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java
+++ /dev/null
@@ -1,212 +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.matchers.scopes.tables;
10
11import java.util.Iterator;
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
18import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
19import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
21import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
22import tools.refinery.viatra.runtime.matchers.util.Accuracy;
23
24/**
25 * Read-only interface that provides the {@link IInputKey}-specific slice of an instance store to realize a
26 * {@link IQueryRuntimeContext}. Implemented by a customizable data store that is responsible for:
27 * <ul>
28 * <li>storing the instance tuples of the {@link IInputKey},</li>
29 * <li>providing efficient lookup via storage-specific indexing,</li>
30 * <li>delivering notifications. (TODO not designed yet)</li>
31 * </ul>
32 *
33 * <p>
34 * Can be specialized for unary / binary / etc., opposite edges or node subtypes, specific types, distributed storage,
35 * etc.
36 * <p>
37 * Writeable API is specific to the customized implementations (e.g. unary).
38 *
39 * <p>
40 * <b>Precondition:</b> the associated input key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
41 * <p>
42 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
43 * part of a work in progress. There is no guarantee that this API will
44 * work or that it will remain the same.
45 *
46 * @since 2.0
47 * @author Gabor Bergmann
48 * @noimplement This interface is not intended to be implemented directly. Extend {@link AbstractIndexTable} instead.
49 */
50public interface IIndexTable {
51
52 // TODO add superinterface that represents a statistics-only counter?
53
54 /**
55 * @return the input key indexed by this table
56 */
57 public IInputKey getInputKey();
58
59 /**
60 * Returns the tuples, optionally seeded with the given tuple.
61 *
62 * <p> Consider using the more idiomatic {@link #streamTuples(TupleMask, ITuple)} instead.
63 *
64 * @param seedMask
65 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
66 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
67 * once in seedMask.
68 * @param seed
69 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
70 * parameterSeedMask, so that for each considered row tuple,
71 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
72 * @return the tuples in the table for the given key and seed
73 */
74 @SuppressWarnings("unchecked")
75 public default Iterable<Tuple> enumerateTuples(TupleMask seedMask, ITuple seed) {
76 return () -> (Iterator<Tuple>) (streamTuples(seedMask, seed).iterator());
77 }
78
79 /**
80 * Returns the tuples, optionally seeded with the given tuple.
81 *
82 * @param seedMask
83 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
84 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
85 * once in seedMask.
86 * @param seed
87 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
88 * parameterSeedMask, so that for each considered row tuple,
89 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
90 * @return the tuples in the table for the given key and seed
91 * @since 2.1
92 */
93 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed);
94
95 /**
96 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
97 * by the seed except for one.
98 *
99 * <p>
100 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns the single value from
101 * each tuple which is not bound by the seed mask.
102 *
103 * <p> Consider using the more idiomatic {@link #streamValues(TupleMask, ITuple)} instead.
104 *
105 * @param seedMask
106 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
107 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
108 * once in seedMask, and seedMask must include all parameters in any arbitrary order except one.
109 * @param seed
110 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
111 * parameterSeedMask, so that for each considered row tuple,
112 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
113 * @return the objects in the table for the given key and seed
114 *
115 */
116 @SuppressWarnings("unchecked")
117 public default Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
118 return () -> (Iterator<Object>) (streamValues(seedMask, seed).iterator());
119 }
120
121 /**
122 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
123 * by the seed except for one.
124 *
125 * <p>
126 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns the single value from
127 * each tuple which is not bound by the seed mask.
128 *
129 * @param seedMask
130 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
131 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
132 * once in seedMask, and seedMask must include all parameters in any arbitrary order except one.
133 * @param seed
134 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
135 * parameterSeedMask, so that for each considered row tuple,
136 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
137 * @return the objects in the table for the given key and seed
138 *
139 * @since 2.1
140 */
141 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed);
142
143 /**
144 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
145 * by the seed.
146 *
147 * <p>
148 * Returns whether the given tuple is in the table identified by the input key.
149 *
150 * @param seed
151 * a row tuple of fixed values whose presence in the table is queried
152 * @return true iff there is a row tuple contained in the table that corresponds to the given seed
153 */
154 public boolean containsTuple(ITuple seed);
155
156 /**
157 * Returns the number of tuples, optionally seeded with the given tuple.
158 *
159 * <p>
160 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns their number.
161 *
162 * @param seedMask
163 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
164 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
165 * once in seedMask.
166 * @param seed
167 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
168 * parameterSeedMask, so that for each considered row tuple,
169 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
170 * @return the number of tuples in the table for the given key and seed
171 *
172 */
173 public int countTuples(TupleMask seedMask, ITuple seed);
174
175 /**
176 * Gives an estimate of the number of different groups the tuples of the table are projected into by the given mask
177 * (e.g. for an identity mask, this means the full relation size). The estimate must meet the required accuracy.
178 *
179 * <p> Derived tables may return {@link Optional#empty()} if it would be costly to provide an answer up to the required precision.
180 * Direct storage tables are expected to always be able to give an exact count.
181 *
182 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
183 *
184 * @since 2.1
185 */
186 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy);
187
188 /**
189 * Subscribes for updates in the table, optionally seeded with the given tuple.
190 * <p> This should be called after initializing a result cache by an enumeration method.
191 *
192 * @param seed can be null or a tuple with matching arity;
193 * if non-null, notifications will delivered only about those updates of the table
194 * that match the seed at positions where the seed is non-null.
195 * @param listener will be notified of future changes
196 *
197 * @since 2.1
198 */
199 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener);
200
201 /**
202 * Unsubscribes from updates in the table, optionally seeded with the given tuple.
203 *
204 * @param seed can be null or a tuple with matching arity;
205 * see {@link #addUpdateListener(Tuple, IQueryRuntimeContextListener)} for definition.
206 * @param listener will no longer be notified of future changes
207 *
208 * @since 2.1
209 */
210 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener);
211
212}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java
deleted file mode 100644
index 69e83cd7..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java
+++ /dev/null
@@ -1,29 +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.matchers.scopes.tables;
10
11/**
12 * Callbacks that {@link IIndexTable} implementations are expected to invoke on their environment.
13 * <p>
14 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
15 * part of a work in progress. There is no guarantee that this API will
16 * work or that it will remain the same.
17 *
18 * @since 2.0
19 * @author Gabor Bergmann
20 */
21public interface ITableContext {
22
23 // TODO notifications?
24
25 /**
26 * Indicates that an error has occurred in maintaining an index table, e.g. duplicate value.
27 */
28 public void logError(String message);
29}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java
deleted file mode 100644
index fb614014..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java
+++ /dev/null
@@ -1,53 +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.matchers.scopes.tables;
11
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of a binary {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 */
24public interface ITableWriterBinary<Source, Target> {
25 /**
26 * Adds/removes a row to/from the table.
27 *
28 * @param direction
29 * tells whether putting a row into the table or deleting
30 *
31 * TODO: store as multiset, return bool?
32 */
33 void write(Direction direction, Source source, Target target);
34
35 /**
36 * Intersection type for writers that are also tables
37 */
38 interface Table<Source, Target> extends ITableWriterBinary<Source, Target>, IIndexTable {
39 }
40
41 /**
42 * /dev/null implementation
43 *
44 * @author Gabor Bergmann
45 */
46 static class Nop<Source, Target> implements ITableWriterBinary<Source, Target> {
47 @Override
48 public void write(Direction direction, Source source, Target target) {
49 // NO-OP
50 }
51
52 }
53}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java
deleted file mode 100644
index fb1ebcc0..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java
+++ /dev/null
@@ -1,52 +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.matchers.scopes.tables;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of an {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 */
24public interface ITableWriterGeneric {
25
26 /**
27 * Adds/removes a row to/from the table.
28 *
29 * @param direction
30 * tells whether putting a row into the table or deleting TODO: store as multiset, return bool?
31 */
32 void write(Direction direction, Tuple row);
33
34 /**
35 * Intersection type for writers that are also tables
36 */
37 interface Table extends ITableWriterGeneric, IIndexTable {
38 }
39
40 /**
41 * /dev/null implementation
42 *
43 * @author Gabor Bergmann
44 */
45 static class Nop implements ITableWriterGeneric {
46 @Override
47 public void write(Direction direction, Tuple row) {
48 // NO-OP
49 }
50
51 }
52}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java
deleted file mode 100644
index f90d5362..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java
+++ /dev/null
@@ -1,52 +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.matchers.scopes.tables;
11
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of a unary {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 *
24 */
25public interface ITableWriterUnary<Value> {
26
27 /**
28 * Adds/removes a row to/from the table.
29 *
30 * @param direction
31 * tells whether putting a row into the table or deleting TODO: store as multiset, return bool?
32 */
33 void write(Direction direction, Value value);
34
35 /**
36 * Intersection type for writers that are also tables
37 */
38 interface Table<Value> extends ITableWriterUnary<Value>, IIndexTable {
39 }
40
41 /**
42 * /dev/null implementation
43 *
44 * @author Gabor Bergmann
45 */
46 static class Nop<Value> implements ITableWriterUnary<Value> {
47 @Override
48 public void write(Direction direction, Value value) {
49 // NO-OP
50 }
51 }
52}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java
deleted file mode 100644
index 588ed9d2..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java
+++ /dev/null
@@ -1,320 +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.matchers.scopes.tables;
10
11import java.util.Collections;
12import java.util.Optional;
13import java.util.Set;
14import java.util.stream.Stream;
15
16import tools.refinery.viatra.runtime.matchers.context.IInputKey;
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
21import tools.refinery.viatra.runtime.matchers.util.Accuracy;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
23import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
24import tools.refinery.viatra.runtime.matchers.util.Direction;
25import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
26import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
27import tools.refinery.viatra.runtime.matchers.util.IMultiLookup.ChangeGranularity;
28
29/**
30 * Simple source-target bidirectional mapping.
31 *
32 * <p>
33 * TODO: specialize for to-one features and unique to-many features
34 * <p>
35 * TODO: on-demand construction of valueToHolderMap
36 * <p>
37 * TODO: support for lean indexing, opposites, long surrogate ids, etc.
38 * <p>
39 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
40 * part of a work in progress. There is no guarantee that this API will
41 * work or that it will remain the same.
42 *
43 * @since 2.0
44 * @author Gabor Bergmann
45 */
46public class SimpleBinaryTable<Source, Target> extends AbstractIndexTable
47 implements ITableWriterBinary.Table<Source, Target> {
48
49 /**
50 * value -> holder(s)
51 * <p>
52 * this is currently the primary store, may hold duplicates depending on the unique parameter
53 */
54 private IMultiLookup<Target, Source> valueToHolderMap;
55 /**
56 * holder -> value(s); constructed on-demand, null if unused
57 */
58 private IMultiLookup<Source, Target> holderToValueMap;
59 private int totalRowCount = 0;
60 private boolean unique;
61
62 /**
63 * @param unique
64 * client promises to only insert a given tuple with multiplicity one
65 */
66 public SimpleBinaryTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
67 super(inputKey, tableContext);
68 this.unique = unique;
69 valueToHolderMap = CollectionsFactory.createMultiLookup(Object.class,
70 unique ? MemoryType.SETS : MemoryType.MULTISETS, Object.class);
71 if (2 != inputKey.getArity())
72 throw new IllegalArgumentException(inputKey.toString());
73 }
74
75 @Override
76 public void write(Direction direction, Source holder, Target value) {
77 if (direction == Direction.INSERT) {
78 try {
79 // TODO we currently assume V2H map exists
80 boolean changed = addToValueToHolderMap(value, holder);
81 if (holderToValueMap != null) {
82 addToHolderToValueMap(value, holder);
83 }
84 if (changed) {
85 totalRowCount++;
86 if (emitNotifications) {
87 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(holder, value), true);
88 }
89 }
90 } catch (IllegalStateException ex) { // if unique table and duplicate tuple
91 String msg = String.format(
92 "Error: trying to add duplicate value %s to the unique feature %s of host object %s. This indicates some errors in underlying model representation.",
93 value, getInputKey().getPrettyPrintableName(), holder);
94 logError(msg);
95 }
96 } else { // DELETE
97 try {
98 // TODO we currently assume V2H map exists
99 boolean changed = removeFromValueToHolderMap(value, holder);
100 if (holderToValueMap != null) {
101 removeFromHolderToValueMap(value, holder);
102 }
103 if (changed) {
104 totalRowCount--;
105 if (emitNotifications) {
106 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(holder, value), false);
107 }
108 }
109 } catch (IllegalStateException ex) { // if unique table and duplicate tuple
110 String msg = String.format(
111 "Error: trying to remove non-existing value %s from the feature %s of host object %s. This indicates some errors in underlying model representation.",
112 value, getInputKey().getPrettyPrintableName(), holder);
113 logError(msg);
114 }
115 }
116 }
117
118 private boolean addToHolderToValueMap(Target value, Source holder) {
119 return ChangeGranularity.DUPLICATE != holderToValueMap.addPair(holder, value);
120 }
121
122 private boolean addToValueToHolderMap(Target value, Source holder) {
123 return ChangeGranularity.DUPLICATE != valueToHolderMap.addPair(value, holder);
124 }
125
126 /**
127 * @throws IllegalStateException
128 */
129 private boolean removeFromHolderToValueMap(Target value, Source holder) {
130 return ChangeGranularity.DUPLICATE != holderToValueMap.removePair(holder, value);
131 }
132
133 /**
134 * @throws IllegalStateException
135 */
136 private boolean removeFromValueToHolderMap(Target value, Source holder) {
137 return ChangeGranularity.DUPLICATE != valueToHolderMap.removePair(value, holder);
138 }
139
140 @SuppressWarnings("unchecked")
141 @Override
142 public int countTuples(TupleMask seedMask, ITuple seed) {
143 switch (seedMask.getSize()) {
144 case 0: // unseeded
145 // TODO we currently assume V2H map exists
146 return totalRowCount;
147 case 1: // lookup by source or target
148 int seedIndex = seedMask.indices[0];
149 if (seedIndex == 0) { // lookup by source
150 Source source = (Source) seed.get(0);
151 return getDistinctValuesOfHolder(source).size();
152 } else if (seedIndex == 1) { // lookup by target
153 Target target = (Target) seed.get(0);
154 return getDistinctHoldersOfValue(target).size();
155 } else
156 throw new IllegalArgumentException(seedMask.toString());
157 case 2: // containment check
158 // hack: if mask is not identity, then it is [1,0]/2, which is its own inverse
159 Source source = (Source) seedMask.getValue(seed, 0);
160 Target target = (Target) seedMask.getValue(seed, 1);
161 if (containsRow(source, target))
162 return 1;
163 else
164 return 0;
165 default:
166 throw new IllegalArgumentException(seedMask.toString());
167 }
168 }
169
170 @Override
171 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
172 // always exact count
173 if (groupMask.getSize() == 0) {
174 return totalRowCount == 0 ? Optional.of(0L) : Optional.of(1L);
175 } else if (groupMask.getSize() == 2) {
176 return Optional.of((long)totalRowCount);
177 } else if (groupMask.indices[0] == 0) { // project to holder
178 return Optional.of((long)getHolderToValueMap().countKeys());
179 } else { // (groupMask.indices[0] == 0) // project to value
180 return Optional.of((long)getValueToHolderMap().countKeys());
181 }
182 }
183
184 @Override
185 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
186 switch (seedMask.getSize()) {
187 case 0: // unseeded
188 // TODO we currently assume V2H map exists
189 return getAllDistinctValuesStream()
190 .flatMap(value -> valueToHolderMap.lookup(value).distinctValues().stream()
191 .map(source -> Tuples.staticArityFlatTupleOf(source, value)));
192
193 case 1: // lookup by source or target
194 int seedIndex = seedMask.indices[0];
195 if (seedIndex == 0) { // lookup by source
196 @SuppressWarnings("unchecked")
197 Source source = (Source) seed.get(0);
198 return getDistinctValuesOfHolder(source).stream()
199 .map(target -> Tuples.staticArityFlatTupleOf(source, target));
200 } else if (seedIndex == 1) { // lookup by target
201 @SuppressWarnings("unchecked")
202 Target target = (Target) seed.get(0);
203 return getDistinctHoldersOfValue(target).stream()
204 .map(source -> Tuples.staticArityFlatTupleOf(source, target));
205 } else
206 throw new IllegalArgumentException(seedMask.toString());
207 case 2: // containment check
208 // hack: if mask is not identity, then it is [1,0]/2, which is its own inverse
209 @SuppressWarnings("unchecked")
210 Source source = (Source) seedMask.getValue(seed, 0);
211 @SuppressWarnings("unchecked")
212 Target target = (Target) seedMask.getValue(seed, 1);
213
214 if (containsRow(source, target))
215 return Stream.of(Tuples.staticArityFlatTupleOf(source, target));
216 else
217 return Stream.empty();
218 default:
219 throw new IllegalArgumentException(seedMask.toString());
220 }
221 }
222
223 @Override
224 @SuppressWarnings("unchecked")
225 public Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
226 if (seedMask.getSize() != 1)
227 throw new IllegalArgumentException(seedMask.toString());
228
229 int seedIndex = seedMask.indices[0];
230 if (seedIndex == 0) { // lookup by source
231 return getDistinctValuesOfHolder((Source) seed.get(0));
232 } else if (seedIndex == 1) { // lookup by target
233 return getDistinctHoldersOfValue((Target) seed.get(0));
234 } else
235 throw new IllegalArgumentException(seedMask.toString());
236
237 }
238 @Override
239 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
240 if (seedMask.getSize() != 1)
241 throw new IllegalArgumentException(seedMask.toString());
242
243 int seedIndex = seedMask.indices[0];
244 if (seedIndex == 0) { // lookup by source
245 return getDistinctValuesOfHolder((Source) seed.get(0)).stream();
246 } else if (seedIndex == 1) { // lookup by target
247 return getDistinctHoldersOfValue((Target) seed.get(0)).stream();
248 } else
249 throw new IllegalArgumentException(seedMask.toString());
250
251 }
252
253 @Override
254 @SuppressWarnings("unchecked")
255 public boolean containsTuple(ITuple seed) {
256 return containsRow((Source) seed.get(0), (Target) seed.get(1));
257 }
258
259 public boolean containsRow(Source source, Target target) {
260 // TODO we currently assume V2H map exists
261 if (valueToHolderMap != null) {
262 IMemoryView<Source> holders = valueToHolderMap.lookup(target);
263 return holders != null && holders.containsNonZero(source);
264 } else
265 throw new UnsupportedOperationException("TODO implement");
266 }
267
268 public Iterable<Source> getAllDistinctHolders() {
269 return getHolderToValueMap().distinctKeys();
270 }
271 public Stream<Source> getAllDistinctHoldersStream() {
272 return getHolderToValueMap().distinctKeysStream();
273 }
274 public Iterable<Target> getAllDistinctValues() {
275 return getValueToHolderMap().distinctKeys();
276 }
277 public Stream<Target> getAllDistinctValuesStream() {
278 return getValueToHolderMap().distinctKeysStream();
279 }
280
281 public Set<Source> getDistinctHoldersOfValue(Target value) {
282 IMemoryView<Source> holdersMultiset = getValueToHolderMap().lookup(value);
283 if (holdersMultiset == null)
284 return Collections.emptySet();
285 else
286 return holdersMultiset.distinctValues();
287 }
288
289 public Set<Target> getDistinctValuesOfHolder(Source holder) {
290 IMemoryView<Target> valuesMultiset = getHolderToValueMap().lookup(holder);
291 if (valuesMultiset == null)
292 return Collections.emptySet();
293 else
294 return valuesMultiset.distinctValues();
295 }
296
297 private IMultiLookup<Source, Target> getHolderToValueMap() {
298 if (holderToValueMap == null) {
299 holderToValueMap = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, // no duplicates, as
300 // this is the
301 // secondary
302 // collection
303 Object.class);
304
305 // TODO we currently assume V2H map exists
306 for (Target value : valueToHolderMap.distinctKeys()) {
307 for (Source holder : valueToHolderMap.lookup(value).distinctValues()) {
308 holderToValueMap.addPair(holder, value);
309 }
310 }
311 }
312 return holderToValueMap;
313 }
314
315 private IMultiLookup<Target, Source> getValueToHolderMap() {
316 // TODO we currently assume V2H map exists
317 return valueToHolderMap;
318 }
319
320}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java
deleted file mode 100644
index 428ea78b..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java
+++ /dev/null
@@ -1,140 +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.matchers.scopes.tables;
11
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
20import tools.refinery.viatra.runtime.matchers.util.Accuracy;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.Direction;
23import tools.refinery.viatra.runtime.matchers.util.IMemory;
24
25/**
26 * Simple value set.
27 * <p>
28 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
29 * part of a work in progress. There is no guarantee that this API will
30 * work or that it will remain the same.
31 *
32 * @since 2.0
33 * @author Gabor Bergmann
34 */
35public class SimpleUnaryTable<Value> extends AbstractIndexTable implements ITableWriterUnary.Table<Value> {
36
37 protected IMemory<Value> values = CollectionsFactory.createMultiset(); // TODO use SetMemory if unique
38
39 private boolean unique;
40
41 /**
42 * @param unique
43 * client promises to only insert a given tuple with multiplicity one
44 */
45 public SimpleUnaryTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
46 super(inputKey, tableContext);
47 this.unique = unique;
48 if (1 != inputKey.getArity())
49 throw new IllegalArgumentException(inputKey.toString());
50 }
51
52 @Override
53 public void write(Direction direction, Value value) {
54 if (direction == Direction.INSERT) {
55 boolean changed = values.addOne(value);
56 if (unique && !changed) {
57 String msg = String.format(
58 "Error: trying to add duplicate value %s to the unique set %s. This indicates some errors in underlying model representation.",
59 value, getInputKey().getPrettyPrintableName());
60 logError(msg);
61 }
62 if (changed && emitNotifications) {
63 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(value), true);
64 }
65 } else { // DELETE
66 boolean changed = values.removeOne(value);
67 if (unique && !changed) {
68 String msg = String.format(
69 "Error: trying to remove duplicate value %s from the unique set %s. This indicates some errors in underlying model representation.",
70 value, getInputKey().getPrettyPrintableName());
71 logError(msg);
72 }
73 if (changed && emitNotifications) {
74 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(value), false);
75 }
76 }
77 }
78
79 @Override
80 @SuppressWarnings("unchecked")
81 public boolean containsTuple(ITuple seed) {
82 return values.containsNonZero((Value) seed.get(0));
83 }
84
85 @Override
86 public int countTuples(TupleMask seedMask, ITuple seed) {
87 if (seedMask.getSize() == 0) { // unseeded
88 return values.size();
89 } else {
90 @SuppressWarnings("unchecked")
91 Value value = (Value) seed.get(0);
92 return values.containsNonZero(value) ? 1 : 0;
93 }
94 }
95
96
97 @Override
98 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
99 // always exact count
100 if (groupMask.getSize() == 0) {
101 return values.isEmpty() ? Optional.of(0L) : Optional.of(1L);
102 } else {
103 return Optional.of((long)values.size());
104 }
105 }
106
107
108 @Override
109 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
110 if (seedMask.getSize() == 0) { // unseeded
111 return values.distinctValues().stream().map(Tuples::staticArityFlatTupleOf);
112 } else {
113 @SuppressWarnings("unchecked")
114 Value value = (Value) seed.get(0);
115 if (values.containsNonZero(value))
116 return Stream.of(Tuples.staticArityFlatTupleOf(value));
117 else
118 return Stream.empty();
119 }
120 }
121
122 @Override
123 public Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
124 if (seedMask.getSize() == 0) { // unseeded
125 return values;
126 } else {
127 throw new IllegalArgumentException(seedMask.toString());
128 }
129 }
130 @Override
131 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
132 if (seedMask.getSize() == 0) { // unseeded
133 return values.asStream();
134 } else {
135 throw new IllegalArgumentException(seedMask.toString());
136 }
137 }
138
139
140}
diff --git a/subprojects/viatra-runtime/build.gradle.kts b/subprojects/viatra-runtime/build.gradle.kts
index 5d6e3de6..b1e65c94 100644
--- a/subprojects/viatra-runtime/build.gradle.kts
+++ b/subprojects/viatra-runtime/build.gradle.kts
@@ -9,9 +9,7 @@ plugins {
9} 9}
10 10
11dependencies { 11dependencies {
12 api(project(":refinery-viatra-runtime-base")) 12 api(project(":refinery-viatra-runtime-matchers"))
13 api(libs.ecore) 13 api(project(":refinery-viatra-runtime-base-itc"))
14 implementation(libs.eclipse)
15 implementation(libs.emf)
16 implementation(libs.slf4j.log4j) 14 implementation(libs.slf4j.log4j)
17} 15}
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}