aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/interpreter/src/main/java/tools/refinery/interpreter/internal/apiimpl/InterpreterEngineImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/interpreter/src/main/java/tools/refinery/interpreter/internal/apiimpl/InterpreterEngineImpl.java')
-rw-r--r--subprojects/interpreter/src/main/java/tools/refinery/interpreter/internal/apiimpl/InterpreterEngineImpl.java689
1 files changed, 689 insertions, 0 deletions
diff --git a/subprojects/interpreter/src/main/java/tools/refinery/interpreter/internal/apiimpl/InterpreterEngineImpl.java b/subprojects/interpreter/src/main/java/tools/refinery/interpreter/internal/apiimpl/InterpreterEngineImpl.java
new file mode 100644
index 00000000..8a2e4c5e
--- /dev/null
+++ b/subprojects/interpreter/src/main/java/tools/refinery/interpreter/internal/apiimpl/InterpreterEngineImpl.java
@@ -0,0 +1,689 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10
11package tools.refinery.interpreter.internal.apiimpl;
12
13import org.apache.log4j.Logger;
14import tools.refinery.interpreter.api.*;
15import tools.refinery.interpreter.api.impl.BaseMatcher;
16import tools.refinery.interpreter.api.scope.IBaseIndex;
17import tools.refinery.interpreter.api.scope.IEngineContext;
18import tools.refinery.interpreter.api.scope.IIndexingErrorListener;
19import tools.refinery.interpreter.api.scope.QueryScope;
20import tools.refinery.interpreter.exception.InterpreterException;
21import tools.refinery.interpreter.internal.engine.LifecycleProvider;
22import tools.refinery.interpreter.internal.engine.ModelUpdateProvider;
23import tools.refinery.interpreter.matchers.InterpreterRuntimeException;
24import tools.refinery.interpreter.matchers.backend.*;
25import tools.refinery.interpreter.matchers.context.IQueryBackendContext;
26import tools.refinery.interpreter.matchers.context.IQueryCacheContext;
27import tools.refinery.interpreter.matchers.context.IQueryResultProviderAccess;
28import tools.refinery.interpreter.matchers.context.IQueryRuntimeContext;
29import tools.refinery.interpreter.matchers.planning.QueryProcessingException;
30import tools.refinery.interpreter.matchers.psystem.analysis.QueryAnalyzer;
31import tools.refinery.interpreter.matchers.psystem.queries.PQueries;
32import tools.refinery.interpreter.matchers.psystem.queries.PQuery;
33import tools.refinery.interpreter.matchers.util.CollectionsFactory;
34import tools.refinery.interpreter.matchers.util.IMultiLookup;
35import tools.refinery.interpreter.matchers.util.Preconditions;
36import tools.refinery.interpreter.util.InterpreterLoggingUtil;
37
38import java.lang.ref.WeakReference;
39import java.lang.reflect.InvocationTargetException;
40import java.util.*;
41import java.util.concurrent.Callable;
42import java.util.function.Supplier;
43import java.util.stream.Collectors;
44
45/**
46 * A Refinery Interpreter engine back-end (implementation)
47 *
48 * @author Bergmann Gábor
49 */
50public final class InterpreterEngineImpl extends AdvancedInterpreterEngine
51 implements IQueryBackendHintProvider, IQueryCacheContext, IQueryResultProviderAccess {
52
53 /**
54 *
55 */
56 private static final String ERROR_ACCESSING_BACKEND = "Error while accessing query evaluator backend";
57 /**
58 *
59 */
60 private static final String QUERY_ON_DISPOSED_ENGINE_MESSAGE = "Cannot evaluate query on disposed engine!";
61
62 /**
63 * The model to which the engine is attached.
64 */
65 private final QueryScope scope;
66
67 /**
68 * The context of the engine, provided by the scope.
69 */
70 private final IEngineContext engineContext;
71
72 /**
73 * Initialized matchers for each query
74 */
75 private final IMultiLookup<IQuerySpecification<? extends InterpreterMatcher<?>>, InterpreterMatcher<?>> matchers =
76 CollectionsFactory.createMultiLookup(Object.class, CollectionsFactory.MemoryType.SETS, Object.class);
77
78 /**
79 * The RETE and other pattern matcher implementations of the Refinery Interpreter engine.
80 */
81 private final Map<IQueryBackendFactory, IQueryBackend> queryBackends = Collections.synchronizedMap(new HashMap<>());
82
83 /**
84 * The current engine default hints
85 */
86 private final InterpreterEngineOptions engineOptions;
87
88 /**
89 * Common query analysis provided to backends
90 */
91 private QueryAnalyzer queryAnalyzer;
92
93 /**
94 * true if message delivery is currently delayed, false otherwise
95 */
96 private boolean delayMessageDelivery = true;
97
98 private final LifecycleProvider lifecycleProvider;
99 private final ModelUpdateProvider modelUpdateProvider;
100 private Logger logger;
101 private boolean disposed = false;
102
103 /**
104 * @param scope
105 * @param engineDefaultHint
106 * @since 1.4
107 */
108 public InterpreterEngineImpl(QueryScope scope,
109 InterpreterEngineOptions engineOptions) {
110 super();
111 this.scope = scope;
112 this.lifecycleProvider = new LifecycleProvider(this, getLogger());
113 this.modelUpdateProvider = new ModelUpdateProvider(this, getLogger());
114 this.engineContext = scope.createEngineContext(this, taintListener, getLogger());
115
116 if (engineOptions != null) {
117 this.engineOptions = engineOptions;
118 } else {
119 this.engineOptions = InterpreterEngineOptions.getDefault();
120 }
121
122 }
123
124 /**
125 * @param manager
126 * null if unmanaged
127 * @param scope
128 * @param engineDefaultHint
129 */
130 public InterpreterEngineImpl(QueryScope scope) {
131 this(scope, InterpreterEngineOptions.getDefault());
132 }
133
134 @Override
135 public boolean isUpdatePropagationDelayed() {
136 return this.delayMessageDelivery;
137 }
138
139 @Override
140 public <V> V delayUpdatePropagation(Callable<V> callable) throws InvocationTargetException {
141 if (!delayMessageDelivery) {
142 throw new IllegalStateException("Trying to delay propagation while changes are being flushed");
143 }
144 try {
145 return callable.call();
146 } catch (Exception e) {
147 throw new InvocationTargetException(e);
148 }
149 }
150
151 @Override
152 public void flushChanges() {
153 if (!delayMessageDelivery) {
154 throw new IllegalStateException("Trying to flush changes while changes are already being flushed");
155 }
156 delayMessageDelivery = false;
157 try {
158 flushAllBackends();
159 } finally {
160 delayMessageDelivery = true;
161 }
162 }
163
164 private void flushAllBackends() {
165 for (IQueryBackend backend : this.queryBackends.values()) {
166 backend.flushUpdates();
167 }
168 }
169
170 @Override
171 public <T> T withFlushingChanges(Supplier<T> callback) {
172 if (!delayMessageDelivery) {
173 return callback.get();
174 }
175 delayMessageDelivery = false;
176 try {
177 flushAllBackends();
178 return callback.get();
179 } finally {
180 delayMessageDelivery = true;
181 }
182 }
183
184 @Override
185 public Set<? extends InterpreterMatcher<? extends IPatternMatch>> getCurrentMatchers() {
186 return matchers.distinctValuesStream().collect(Collectors.toSet());
187 }
188
189 @Override
190 public <Matcher extends InterpreterMatcher<? extends IPatternMatch>> Matcher getMatcher(
191 IQuerySpecification<Matcher> querySpecification) {
192 return getMatcher(querySpecification, null);
193 }
194
195 @Override
196 public <Matcher extends InterpreterMatcher<? extends IPatternMatch>> Matcher getMatcher(
197 IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalEvaluationHints) {
198 return withFlushingChanges(() -> {
199 IMatcherCapability capability = getRequestedCapability(querySpecification, optionalEvaluationHints);
200 Matcher matcher = doGetExistingMatcher(querySpecification, capability);
201 if (matcher != null) {
202 return matcher;
203 }
204 matcher = querySpecification.instantiate();
205
206 BaseMatcher<?> baseMatcher = (BaseMatcher<?>) matcher;
207 ((QueryResultWrapper) baseMatcher).setBackend(this,
208 getResultProvider(querySpecification, optionalEvaluationHints), capability);
209 internalRegisterMatcher(querySpecification, baseMatcher);
210 return matcher;
211 });
212 }
213
214 @Override
215 public <Matcher extends InterpreterMatcher<? extends IPatternMatch>> Matcher getExistingMatcher(
216 IQuerySpecification<Matcher> querySpecification) {
217 return getExistingMatcher(querySpecification, null);
218 }
219
220 @Override
221 public <Matcher extends InterpreterMatcher<? extends IPatternMatch>> Matcher getExistingMatcher(
222 IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalOverrideHints) {
223 return doGetExistingMatcher(querySpecification, getRequestedCapability(querySpecification, optionalOverrideHints));
224 }
225
226 @SuppressWarnings("unchecked")
227 private <Matcher extends InterpreterMatcher<? extends IPatternMatch>> Matcher doGetExistingMatcher(
228 IQuerySpecification<Matcher> querySpecification, IMatcherCapability requestedCapability) {
229 for (InterpreterMatcher<?> matcher : matchers.lookupOrEmpty(querySpecification)) {
230 BaseMatcher<?> baseMatcher = (BaseMatcher<?>) matcher;
231 if (baseMatcher.getCapabilities().canBeSubstitute(requestedCapability))
232 return (Matcher) matcher;
233 }
234 return null;
235 }
236
237 @Override
238 public InterpreterMatcher<? extends IPatternMatch> getMatcher(String patternFQN) {
239 throw new UnsupportedOperationException("Query specification registry is not available");
240 }
241
242 @Override
243 public IBaseIndex getBaseIndex() {
244 return engineContext.getBaseIndex();
245 }
246
247 public final Logger getLogger() {
248 if (logger == null) {
249 final int hash = System.identityHashCode(this);
250 logger = Logger.getLogger(InterpreterLoggingUtil.getLogger(InterpreterEngine.class).getName() + "." + hash);
251 if (logger == null)
252 throw new AssertionError(
253 "Configuration error: unable to create Refinery Interpreter runtime logger for engine " + hash);
254 }
255 return logger;
256 }
257
258 ///////////////// internal stuff //////////////
259 private void internalRegisterMatcher(IQuerySpecification<?> querySpecification, InterpreterMatcher<?> matcher) {
260 matchers.addPair(querySpecification, matcher);
261 lifecycleProvider.matcherInstantiated(matcher);
262 }
263
264 /**
265 * Provides access to the selected query backend component of the Refinery Interpreter engine.
266 */
267 @Override
268 public IQueryBackend getQueryBackend(IQueryBackendFactory iQueryBackendFactory) {
269 IQueryBackend iQueryBackend = queryBackends.get(iQueryBackendFactory);
270 if (iQueryBackend == null) {
271 // do this first, to make sure the runtime context exists
272 final IQueryRuntimeContext queryRuntimeContext = engineContext.getQueryRuntimeContext();
273
274 // maybe the backend has been created in the meantime when the indexer was initialized and queried for
275 // derived features
276 // no need to instantiate a new backend in that case
277 iQueryBackend = queryBackends.get(iQueryBackendFactory);
278 if (iQueryBackend == null) {
279
280 // need to instantiate the backend
281 iQueryBackend = iQueryBackendFactory.create(new IQueryBackendContext() {
282
283 @Override
284 public IQueryRuntimeContext getRuntimeContext() {
285 return queryRuntimeContext;
286 }
287
288 @Override
289 public IQueryCacheContext getQueryCacheContext() {
290 return InterpreterEngineImpl.this;
291 }
292
293 @Override
294 public Logger getLogger() {
295 return logger;
296 }
297
298 @Override
299 public IQueryBackendHintProvider getHintProvider() {
300 return InterpreterEngineImpl.this;
301 }
302
303 @Override
304 public IQueryResultProviderAccess getResultProviderAccess() {
305 return InterpreterEngineImpl.this;
306 }
307
308 @Override
309 public QueryAnalyzer getQueryAnalyzer() {
310 if (queryAnalyzer == null)
311 queryAnalyzer = new QueryAnalyzer(queryRuntimeContext.getMetaContext());
312 return queryAnalyzer;
313 }
314
315 @Override
316 public boolean areUpdatesDelayed() {
317 return InterpreterEngineImpl.this.delayMessageDelivery;
318 }
319
320 @Override
321 public IMatcherCapability getRequiredMatcherCapability(PQuery query,
322 QueryEvaluationHint hint) {
323 return engineOptions.getQueryBackendFactory(hint).calculateRequiredCapability(query, hint);
324 }
325
326
327
328 });
329 queryBackends.put(iQueryBackendFactory, iQueryBackend);
330 }
331 }
332 return iQueryBackend;
333 }
334
335 ///////////////// advanced stuff /////////////
336
337 @Override
338 public void dispose() {
339 wipe();
340
341 this.disposed = true;
342
343 // called before base index disposal to allow removal of base listeners
344 lifecycleProvider.engineDisposed();
345
346 try {
347 engineContext.dispose();
348 } catch (IllegalStateException ex) {
349 getLogger().warn(
350 "The base index could not be disposed along with the Refinery Interpreter engine, as there are " +
351 "still active listeners on it.");
352 }
353 }
354
355 @Override
356 public void wipe() {
357 for (IQueryBackend backend : queryBackends.values()) {
358 backend.dispose();
359 }
360 queryBackends.clear();
361 matchers.clear();
362 queryAnalyzer = null;
363 lifecycleProvider.engineWiped();
364 }
365
366 /**
367 * Indicates whether the engine is in a tainted, inconsistent state.
368 */
369 private boolean tainted = false;
370 private IIndexingErrorListener taintListener = new SelfTaintListener(this);
371
372 private static class SelfTaintListener implements IIndexingErrorListener {
373 WeakReference<InterpreterEngineImpl> queryEngineRef;
374
375 public SelfTaintListener(InterpreterEngineImpl queryEngine) {
376 this.queryEngineRef = new WeakReference<InterpreterEngineImpl>(queryEngine);
377 }
378
379 public void engineBecameTainted(String description, Throwable t) {
380 final InterpreterEngineImpl queryEngine = queryEngineRef.get();
381 if (queryEngine != null) {
382 queryEngine.tainted = true;
383 queryEngine.lifecycleProvider.engineBecameTainted(description, t);
384 }
385 }
386
387 private boolean noTaintDetectedYet = true;
388
389 protected void notifyTainted(String description, Throwable t) {
390 if (noTaintDetectedYet) {
391 noTaintDetectedYet = false;
392 engineBecameTainted(description, t);
393 }
394 }
395
396 @Override
397 public void error(String description, Throwable t) {
398 // Errors does not mean tainting
399 }
400
401 @Override
402 public void fatal(String description, Throwable t) {
403 notifyTainted(description, t);
404 }
405 }
406
407 @Override
408 public boolean isTainted() {
409 return tainted;
410 }
411
412 private <Match extends IPatternMatch> IQueryResultProvider getUnderlyingResultProvider(
413 final BaseMatcher<Match> matcher) {
414 // IQueryResultProvider resultProvider = reteEngine.accessMatcher(matcher.getSpecification());
415 return matcher.backend;
416 }
417
418 @Override
419 public <Match extends IPatternMatch> void addMatchUpdateListener(final InterpreterMatcher<Match> matcher,
420 final IMatchUpdateListener<? super Match> listener, boolean fireNow) {
421
422 Preconditions.checkArgument(listener != null, "Cannot add null listener!");
423 Preconditions.checkArgument(matcher.getEngine() == this, "Cannot register listener for matcher of different engine!");
424 Preconditions.checkArgument(!disposed, "Cannot register listener on matcher of disposed engine!");
425
426 final BaseMatcher<Match> bm = (BaseMatcher<Match>) matcher;
427
428 final IUpdateable updateDispatcher = (updateElement, isInsertion) -> {
429 Match match = null;
430 try {
431 match = bm.newMatch(updateElement.getElements());
432 if (isInsertion)
433 listener.notifyAppearance(match);
434 else
435 listener.notifyDisappearance(match);
436 } catch (Throwable e) { // NOPMD
437 if (e instanceof Error)
438 throw (Error) e;
439 logger.warn(
440 String.format(
441 "The incremental pattern matcher encountered an error during %s a callback on %s of match %s of pattern %s. Error message: %s. (Developer note: %s in %s callback)",
442 match == null ? "preparing" : "invoking", isInsertion ? "insertion" : "removal",
443 match == null ? updateElement.toString() : match.prettyPrint(),
444 matcher.getPatternName(), e.getMessage(), e.getClass().getSimpleName(), listener),
445 e);
446 }
447
448 };
449
450 IQueryResultProvider resultProvider = getUnderlyingResultProvider(bm);
451 resultProvider.addUpdateListener(updateDispatcher, listener, fireNow);
452 }
453
454 @Override
455 public <Match extends IPatternMatch> void removeMatchUpdateListener(InterpreterMatcher<Match> matcher,
456 IMatchUpdateListener<? super Match> listener) {
457 Preconditions.checkArgument(listener != null, "Cannot remove null listener!");
458 Preconditions.checkArgument(matcher.getEngine() == this, "Cannot remove listener from matcher of different engine!");
459 Preconditions.checkArgument(!disposed, "Cannot remove listener from matcher of disposed engine!");
460
461 final BaseMatcher<Match> bm = (BaseMatcher<Match>) matcher;
462
463 try {
464 IQueryResultProvider resultProvider = getUnderlyingResultProvider(bm);
465 resultProvider.removeUpdateListener(listener);
466 } catch (Exception e) {
467 logger.error(
468 "Error while removing listener " + listener + " from the matcher of " + matcher.getPatternName(),
469 e);
470 }
471 }
472
473 @Override
474 public void addModelUpdateListener(InterpreterModelUpdateListener listener) {
475 modelUpdateProvider.addListener(listener);
476 }
477
478 @Override
479 public void removeModelUpdateListener(InterpreterModelUpdateListener listener) {
480 modelUpdateProvider.removeListener(listener);
481 }
482
483 @Override
484 public void addLifecycleListener(InterpreterEngineLifecycleListener listener) {
485 lifecycleProvider.addListener(listener);
486 }
487
488 @Override
489 public void removeLifecycleListener(InterpreterEngineLifecycleListener listener) {
490 lifecycleProvider.removeListener(listener);
491 }
492
493 /**
494 * Returns an internal interface towards the query backend to feed the matcher with results.
495 *
496 * @param query
497 * the pattern for which the result provider should be delivered
498 *
499 * @throws InterpreterRuntimeException
500 */
501 public IQueryResultProvider getResultProvider(IQuerySpecification<?> query) {
502 Preconditions.checkState(!disposed, QUERY_ON_DISPOSED_ENGINE_MESSAGE);
503
504 return getResultProviderInternal(query, null);
505 }
506
507 /**
508 * Returns an internal interface towards the query backend to feed the matcher with results.
509 *
510 * @param query
511 * the pattern for which the result provider should be delivered
512 *
513 * @throws InterpreterRuntimeException
514 */
515 public IQueryResultProvider getResultProvider(IQuerySpecification<?> query, QueryEvaluationHint hint) {
516 Preconditions.checkState(!disposed, QUERY_ON_DISPOSED_ENGINE_MESSAGE);
517
518 return getResultProviderInternal(query, hint);
519 }
520
521 /**
522 * This method returns the result provider exactly as described by the passed hint. Query cannot be null! Use
523 * {@link #getQueryEvaluationHint(IQuerySpecification, QueryEvaluationHint)} before passing a hint to this method to
524 * make sure engine and query specific hints are correctly applied.
525 *
526 * @throws InterpreterRuntimeException
527 */
528 private IQueryResultProvider getResultProviderInternal(IQuerySpecification<?> query, QueryEvaluationHint hint) {
529 return getResultProviderInternal(query.getInternalQueryRepresentation(), hint);
530 }
531
532 /**
533 * This method returns the result provider exactly as described by the passed hint. Query cannot be null! Use
534 * {@link #getQueryEvaluationHint(IQuerySpecification, QueryEvaluationHint)} before passing a hint to this method to
535 * make sure engine and query specific hints are correctly applied.
536 *
537 * @throws InterpreterRuntimeException
538 */
539 private IQueryResultProvider getResultProviderInternal(PQuery query, QueryEvaluationHint hint) {
540 Preconditions.checkArgument(query != null, "Query cannot be null!");
541 Preconditions.checkArgument(query.getStatus() != PQuery.PQueryStatus.ERROR, "Cannot initialize a result provider for the erronoues query `%s`.", query.getSimpleName());
542 final IQueryBackend backend = getQueryBackend(engineOptions.getQueryBackendFactory(getQueryEvaluationHint(query, hint)));
543 return backend.getResultProvider(query, hint);
544 }
545
546 /**
547 * Returns the query backend (influenced by the hint system), even if it is a non-caching backend.
548 *
549 * @throws InterpreterRuntimeException
550 */
551 private IQueryBackend getQueryBackend(PQuery query) {
552 final IQueryBackendFactory factory = engineOptions.getQueryBackendFactory(getQueryEvaluationHint(query));
553 return getQueryBackend(factory);
554 }
555
556 /**
557 * Returns a caching query backend (influenced by the hint system).
558 *
559 * @throws InterpreterRuntimeException
560 */
561 private IQueryBackend getCachingQueryBackend(PQuery query) {
562 IQueryBackend regularBackend = getQueryBackend(query);
563 if (regularBackend.isCaching())
564 return regularBackend;
565 else
566 return getQueryBackend(engineOptions.getDefaultCachingBackendFactory());
567 }
568
569 @Override
570 public boolean isResultCached(PQuery query) {
571 try {
572 return null != getCachingQueryBackend(query).peekExistingResultProvider(query);
573 } catch (InterpreterException iqe) {
574 getLogger().error(ERROR_ACCESSING_BACKEND, iqe);
575 return false;
576 }
577 }
578
579 @Override
580 public IQueryResultProvider getCachingResultProvider(PQuery query) {
581 try {
582 return getCachingQueryBackend(query).getResultProvider(query);
583 } catch (InterpreterException iqe) {
584 getLogger().error(ERROR_ACCESSING_BACKEND, iqe);
585 throw iqe;
586 }
587 }
588
589 private QueryEvaluationHint getEngineDefaultHint() {
590 return engineOptions.getEngineDefaultHints();
591 }
592
593 @Override
594 public QueryEvaluationHint getQueryEvaluationHint(PQuery query) {
595 return getEngineDefaultHint().overrideBy(query.getEvaluationHints());
596 }
597
598 private QueryEvaluationHint getQueryEvaluationHint(IQuerySpecification<?> querySpecification,
599 QueryEvaluationHint optionalOverrideHints) {
600 return getQueryEvaluationHint(querySpecification.getInternalQueryRepresentation())
601 .overrideBy(optionalOverrideHints);
602 }
603
604 private QueryEvaluationHint getQueryEvaluationHint(PQuery query, QueryEvaluationHint optionalOverrideHints) {
605 return getQueryEvaluationHint(query).overrideBy(optionalOverrideHints);
606 }
607
608 private IMatcherCapability getRequestedCapability(IQuerySpecification<?> querySpecification,
609 QueryEvaluationHint optionalOverrideHints) {
610 final QueryEvaluationHint hint = getQueryEvaluationHint(querySpecification, optionalOverrideHints);
611 return engineOptions.getQueryBackendFactory(hint)
612 .calculateRequiredCapability(querySpecification.getInternalQueryRepresentation(), hint);
613 }
614
615 @Override
616 public void prepareGroup(IQueryGroup queryGroup, final QueryEvaluationHint optionalEvaluationHints) {
617 try {
618 Preconditions.checkState(!disposed, QUERY_ON_DISPOSED_ENGINE_MESSAGE);
619
620 final Set<IQuerySpecification<?>> specifications = new HashSet<IQuerySpecification<?>>(
621 queryGroup.getSpecifications());
622 final Collection<PQuery> patterns = specifications.stream().map(
623 IQuerySpecification::getInternalQueryRepresentation).collect(Collectors.toList());
624 patterns.forEach(PQuery::ensureInitialized);
625
626 Collection<String> erroneousPatterns = patterns.stream().
627 filter(PQueries.queryStatusPredicate(PQuery.PQueryStatus.ERROR)).
628 map(PQuery::getFullyQualifiedName).
629 collect(Collectors.toList());
630 Preconditions.checkState(erroneousPatterns.isEmpty(), "Erroneous query(s) found: %s",
631 erroneousPatterns.stream().collect(Collectors.joining(", ")));
632
633 // TODO maybe do some smarter preparation per backend?
634 try {
635 engineContext.getBaseIndex().coalesceTraversals(new Callable<Void>() {
636 @Override
637 public Void call() throws Exception {
638 for (IQuerySpecification<?> query : specifications) {
639 getResultProviderInternal(query, optionalEvaluationHints);
640 }
641 return null;
642 }
643 });
644 } catch (InvocationTargetException ex) {
645 final Throwable cause = ex.getCause();
646 if (cause instanceof QueryProcessingException)
647 throw (QueryProcessingException) cause;
648 if (cause instanceof InterpreterException)
649 throw (InterpreterException) cause;
650 if (cause instanceof RuntimeException)
651 throw (RuntimeException) cause;
652 assert (false);
653 }
654 } catch (QueryProcessingException e) {
655 throw new InterpreterException(e);
656 }
657 }
658
659 @Override
660 public QueryScope getScope() {
661 return scope;
662 }
663
664 @Override
665 public InterpreterEngineOptions getEngineOptions() {
666 return engineOptions;
667 }
668
669 @Override
670 public IQueryResultProvider getResultProviderOfMatcher(InterpreterMatcher<? extends IPatternMatch> matcher) {
671 return ((QueryResultWrapper) matcher).backend;
672 }
673
674 @Override
675 public IQueryResultProvider getResultProvider(PQuery query, QueryEvaluationHint overrideHints) {
676 try {
677 return getResultProviderInternal(query, overrideHints);
678 } catch (InterpreterException e) {
679 getLogger().error(ERROR_ACCESSING_BACKEND, e);
680 throw e;
681 }
682 }
683
684 @Override
685 public boolean isDisposed() {
686 return disposed;
687 }
688
689}