diff options
Diffstat (limited to 'subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java')
-rw-r--r-- | subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java new file mode 100644 index 00000000..eab92128 --- /dev/null +++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java | |||
@@ -0,0 +1,241 @@ | |||
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 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.matchers.backend; | ||
10 | |||
11 | import java.util.AbstractMap; | ||
12 | import java.util.Collections; | ||
13 | import java.util.HashMap; | ||
14 | import java.util.Map; | ||
15 | import java.util.Objects; | ||
16 | import java.util.stream.Collectors; | ||
17 | |||
18 | import tools.refinery.viatra.runtime.matchers.util.Preconditions; | ||
19 | |||
20 | /** | ||
21 | * Provides VIATRA Query with additional hints on how a query should be evaluated. The same hint can be provided to multiple queries. | ||
22 | * | ||
23 | * <p> This class is immutable. Overriding options will create a new instance. | ||
24 | * | ||
25 | * <p> | ||
26 | * Here be dragons: for advanced users only. | ||
27 | * | ||
28 | * @author Bergmann Gabor | ||
29 | * | ||
30 | */ | ||
31 | public class QueryEvaluationHint { | ||
32 | |||
33 | /** | ||
34 | * @since 2.0 | ||
35 | * | ||
36 | */ | ||
37 | public enum BackendRequirement { | ||
38 | /** | ||
39 | * The current hint does not specify any backend requirement | ||
40 | */ | ||
41 | UNSPECIFIED, | ||
42 | /** | ||
43 | * The current hint specifies that the default search backend of the engine should be used | ||
44 | */ | ||
45 | DEFAULT_SEARCH, | ||
46 | /** | ||
47 | * The current hint specifies that the default caching backend of the engine should be used | ||
48 | */ | ||
49 | DEFAULT_CACHING, | ||
50 | /** | ||
51 | * The current hint specifies that a specific backend is to be used | ||
52 | */ | ||
53 | SPECIFIC | ||
54 | } | ||
55 | |||
56 | final IQueryBackendFactory queryBackendFactory; | ||
57 | final Map<QueryHintOption<?>, Object> backendHintSettings; | ||
58 | final BackendRequirement requirement; | ||
59 | |||
60 | /** | ||
61 | * Specifies the suggested query backend requirements, and value settings for additional backend-specific options. | ||
62 | * | ||
63 | * <p> | ||
64 | * The backend requirement type must not be {@link BackendRequirement#SPECIFIC} - for that case, use the constructor | ||
65 | * {@link #QueryEvaluationHint(Map, IQueryBackendFactory)}. | ||
66 | * | ||
67 | * @param backendHintSettings | ||
68 | * if non-null, each entry in the map overrides backend-specific options regarding query evaluation | ||
69 | * (null-valued map entries permitted to erase hints); passing null means default options associated with | ||
70 | * the query | ||
71 | * @param backendRequirementType | ||
72 | * defines the kind of backend requirement | ||
73 | * @since 2.0 | ||
74 | */ | ||
75 | public QueryEvaluationHint(Map<QueryHintOption<?>, Object> backendHintSettings, BackendRequirement backendRequirementType) { | ||
76 | super(); | ||
77 | Preconditions.checkArgument(backendRequirementType != null, "Specific requirement needs to be set"); | ||
78 | Preconditions.checkArgument(backendRequirementType != BackendRequirement.SPECIFIC, "Specific backend requirement needs providing a corresponding backend type"); | ||
79 | this.queryBackendFactory = null; | ||
80 | this.requirement = backendRequirementType; | ||
81 | this.backendHintSettings = (backendHintSettings == null) | ||
82 | ? Collections.<QueryHintOption<?>, Object> emptyMap() | ||
83 | : new HashMap<>(backendHintSettings); | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * Specifies the suggested query backend, and value settings for additional backend-specific options. The first | ||
88 | * parameter can be null; if the second parameter is null, it is expected that the other constructor is called | ||
89 | * instead with a {@link BackendRequirement#UNSPECIFIED} parameter. | ||
90 | * | ||
91 | * @param backendHintSettings | ||
92 | * if non-null, each entry in the map overrides backend-specific options regarding query evaluation | ||
93 | * (null-valued map entries permitted to erase hints); passing null means default options associated with | ||
94 | * the query | ||
95 | * @param queryBackendFactory | ||
96 | * overrides the query evaluator algorithm; passing null retains the default algorithm associated with | ||
97 | * the query | ||
98 | * @since 1.5 | ||
99 | */ | ||
100 | public QueryEvaluationHint( | ||
101 | Map<QueryHintOption<?>, Object> backendHintSettings, | ||
102 | IQueryBackendFactory queryBackendFactory) { | ||
103 | super(); | ||
104 | this.queryBackendFactory = queryBackendFactory; | ||
105 | this.requirement = (queryBackendFactory == null) ? BackendRequirement.UNSPECIFIED : BackendRequirement.SPECIFIC; | ||
106 | this.backendHintSettings = (backendHintSettings == null) | ||
107 | ? Collections.<QueryHintOption<?>, Object> emptyMap() | ||
108 | : new HashMap<>(backendHintSettings); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * Returns the backend requirement described by this hint. If a specific backend is required, that can be queried by {@link #getQueryBackendFactory()}. | ||
113 | * @since 2.0 | ||
114 | */ | ||
115 | public BackendRequirement getQueryBackendRequirementType() { | ||
116 | return requirement; | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * A suggestion for choosing the query evaluator algorithm. | ||
121 | * | ||
122 | * <p> | ||
123 | * Returns null iff {@link #getQueryBackendRequirementType()} does not return {@link BackendRequirement#SPECIFIC}; | ||
124 | * in such cases a corresponding default backend is selected inside the engine | ||
125 | */ | ||
126 | public IQueryBackendFactory getQueryBackendFactory() { | ||
127 | return queryBackendFactory; | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * Each entry in the immutable map overrides backend-specific options regarding query evaluation. | ||
132 | * | ||
133 | * <p>The map is non-null, even if empty. | ||
134 | * Null-valued map entries are also permitted to erase hints via {@link #overrideBy(QueryEvaluationHint)}. | ||
135 | * | ||
136 | * @since 1.5 | ||
137 | */ | ||
138 | public Map<QueryHintOption<?>, Object> getBackendHintSettings() { | ||
139 | return backendHintSettings; | ||
140 | } | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Override values in this hint and return a consolidated instance. | ||
145 | * | ||
146 | * @since 1.4 | ||
147 | */ | ||
148 | public QueryEvaluationHint overrideBy(QueryEvaluationHint overridingHint){ | ||
149 | if (overridingHint == null) | ||
150 | return this; | ||
151 | |||
152 | BackendRequirement overriddenRequirement = this.getQueryBackendRequirementType(); | ||
153 | if (overridingHint.getQueryBackendRequirementType() != BackendRequirement.UNSPECIFIED) { | ||
154 | overriddenRequirement = overridingHint.getQueryBackendRequirementType(); | ||
155 | } | ||
156 | Map<QueryHintOption<?>, Object> hints = new HashMap<>(this.getBackendHintSettings()); | ||
157 | if (overridingHint.getBackendHintSettings() != null) { | ||
158 | hints.putAll(overridingHint.getBackendHintSettings()); | ||
159 | } | ||
160 | if (overriddenRequirement == BackendRequirement.SPECIFIC) { | ||
161 | IQueryBackendFactory factory = this.getQueryBackendFactory(); | ||
162 | if (overridingHint.getQueryBackendFactory() != null) { | ||
163 | factory = overridingHint.getQueryBackendFactory(); | ||
164 | } | ||
165 | return new QueryEvaluationHint(hints, factory); | ||
166 | } else { | ||
167 | return new QueryEvaluationHint(hints, overriddenRequirement); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * Returns whether the given hint option is overridden. | ||
173 | * @since 1.5 | ||
174 | */ | ||
175 | public boolean isOptionOverridden(QueryHintOption<?> option) { | ||
176 | return getBackendHintSettings().containsKey(option); | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * Returns the value of the given hint option from the given hint collection, or null if not defined. | ||
181 | * @since 1.5 | ||
182 | */ | ||
183 | @SuppressWarnings("unchecked") | ||
184 | public <HintValue> HintValue getValueOrNull(QueryHintOption<HintValue> option) { | ||
185 | return (HintValue) getBackendHintSettings().get(option); | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * Returns the value of the given hint option from the given hint collection, or the default value if not defined. | ||
190 | * Intended to be called by backends to find out the definitive value that should be considered. | ||
191 | * @since 1.5 | ||
192 | */ | ||
193 | public <HintValue> HintValue getValueOrDefault(QueryHintOption<HintValue> option) { | ||
194 | return option.getValueOrDefault(this); | ||
195 | } | ||
196 | |||
197 | @Override | ||
198 | public int hashCode() { | ||
199 | return Objects.hash(backendHintSettings, queryBackendFactory, requirement); | ||
200 | } | ||
201 | |||
202 | @Override | ||
203 | public boolean equals(Object obj) { | ||
204 | if (this == obj) | ||
205 | return true; | ||
206 | if (obj == null) | ||
207 | return false; | ||
208 | if (getClass() != obj.getClass()) | ||
209 | return false; | ||
210 | QueryEvaluationHint other = (QueryEvaluationHint) obj; | ||
211 | return Objects.equals(backendHintSettings, other.backendHintSettings) | ||
212 | && | ||
213 | Objects.equals(queryBackendFactory, other.queryBackendFactory) | ||
214 | && | ||
215 | Objects.equals(requirement, other.requirement) | ||
216 | ; | ||
217 | } | ||
218 | |||
219 | @Override | ||
220 | public String toString() { | ||
221 | StringBuilder sb = new StringBuilder(); | ||
222 | |||
223 | if (getQueryBackendFactory() != null) | ||
224 | sb.append("backend: ").append(getQueryBackendFactory().getBackendClass().getSimpleName()); | ||
225 | if (! backendHintSettings.isEmpty()) { | ||
226 | sb.append("hints: "); | ||
227 | if(backendHintSettings instanceof AbstractMap){ | ||
228 | sb.append(backendHintSettings.toString()); | ||
229 | } else { | ||
230 | // we have to iterate on the contents | ||
231 | |||
232 | String joinedHintMap = backendHintSettings.entrySet().stream() | ||
233 | .map(setting -> setting.getKey() + "=" + setting.getValue()).collect(Collectors.joining(", ")); | ||
234 | sb.append('{').append(joinedHintMap).append('}'); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | final String result = sb.toString(); | ||
239 | return result.isEmpty() ? "defaults" : result; | ||
240 | } | ||
241 | } | ||