Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "VIATRA/Query/UserDocumentation/API/Advanced"
< VIATRA | Query | UserDocumentation/API
Line 1: | Line 1: | ||
= Overview = | = Overview = | ||
− | + | This page overviews advanced use-cases for EMF-IncQuery. The topics cover | |
+ | * the Generic API, to be used when the features supported by the generated API do not suffice (e.g. when working with dynamically defined patterns, or patterns whose handles are not known at compile time) | ||
+ | * Advanced change processing APIs, and advanced lifecycle management techniques to be used for performance-critical and/or resource-constrained applications | ||
+ | * IncQuery Base, the low-level query and indexer layer underneath EMF-IncQuery pattern matchers | ||
+ | |||
== Running example == | == Running example == | ||
All the code examples and explanations will be given in the context of the [[EMFIncQuery/UserDocumentation/HeadlessExecution|Headless]] example. | All the code examples and explanations will be given in the context of the [[EMFIncQuery/UserDocumentation/HeadlessExecution|Headless]] example. | ||
Line 41: | Line 45: | ||
=== API interfaces === | === API interfaces === | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | * IPatternMatch | |
− | + | * reflection: pattern(), patternName() | |
− | + | * getters and setters | |
− | + | * utility functions (toArray, prettyPrint) | |
− | + | * IncQueryMatcher | |
− | + | * reflection | |
− | + | * get all matches | |
− | * | + | * get single/arbitrary match |
− | + | * check for a match | |
− | + | * number of matches | |
− | + | * process matches | |
− | + | * access change processing features | |
− | + | * create a new Match for input binding | |
− | + | * access projected value sets | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
== The Pattern Registry and Matcher Factories == | == The Pattern Registry and Matcher Factories == | ||
Line 217: | Line 128: | ||
<source lang="java"> | <source lang="java"> | ||
private void changeProcessing_lowlevel(final StringBuilder results, IncQueryMatcher<? extends IPatternMatch> matcher) { | private void changeProcessing_lowlevel(final StringBuilder results, IncQueryMatcher<? extends IPatternMatch> matcher) { | ||
− | + | // (+) these update callbacks are called whenever there is an actual change in the | |
− | + | // result set of the pattern you are interested in. Hence, they are called fewer times | |
− | + | // than the "afterUpdates" option, giving better performance. | |
− | + | // (-) the downside is that the callbacks are *not* guaranteed to be called in a consistent | |
− | + | // state (i.e. when the update propagation is settled), hence | |
− | + | // * you must not invoke pattern matching and model manipulation _inside_ the callback method | |
− | + | // * the callbacks might encounter "hazards", i.e. when an appearance is followed immediately by a disappearance. | |
− | + | matcher.addCallbackOnMatchUpdate(new IMatchUpdateListener<IPatternMatch>() { | |
− | + | @Override | |
− | + | public void notifyDisappearance(IPatternMatch match) { | |
− | + | // left empty | |
− | + | } | |
− | + | @Override | |
− | + | public void notifyAppearance(IPatternMatch match) { | |
− | + | results.append("\tNew match found by changeset low level callback: " + match.prettyPrint()+"\n"); | |
− | + | } | |
− | + | }, false); | |
− | + | } | |
− | + | /source> | |
== After update callbacks and DeltaMonitors == | == After update callbacks and DeltaMonitors == | ||
<source lang="java"> | <source lang="java"> | ||
− | + | private void changeProcessing_deltaMonitor(final StringBuilder results, IncQueryMatcher<? extends IPatternMatch> matcher) { | |
− | + | final DeltaMonitor<? extends IPatternMatch> dm = matcher.newDeltaMonitor(false); | |
− | + | // (+) these updates are guaranteed to be called in a *consistent* state, | |
− | + | // i.e. when the pattern matcher is guaranteed to be consistent with the model | |
− | + | // anything can be written into the callback method | |
− | + | // (-) the downside is that the callback is called after *every* update | |
− | + | // that propagates through the matcher, i.e. also when the updates do not actually | |
− | + | // influence the result set you are interested in. Hence, the performance is somewhat | |
− | + | // lower than for the "lowlevel" option. | |
− | + | matcher.addCallbackAfterUpdates(new Runnable() { | |
− | + | @Override | |
− | + | public void run() { | |
− | + | for (IPatternMatch newMatch : dm.matchFoundEvents) { | |
− | + | results.append("\tNew match found by changeset delta monitor: " + newMatch.prettyPrint()+"\n"); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | }); | + | for (IPatternMatch lostMatch : dm.matchLostEvents) { |
− | + | // left empty | |
+ | } | ||
+ | } | ||
+ | }); | ||
+ | } | ||
</source> | </source> | ||
Revision as of 11:39, 11 April 2013
Contents
Overview
This page overviews advanced use-cases for EMF-IncQuery. The topics cover
- the Generic API, to be used when the features supported by the generated API do not suffice (e.g. when working with dynamically defined patterns, or patterns whose handles are not known at compile time)
- Advanced change processing APIs, and advanced lifecycle management techniques to be used for performance-critical and/or resource-constrained applications
- IncQuery Base, the low-level query and indexer layer underneath EMF-IncQuery pattern matchers
Running example
All the code examples and explanations will be given in the context of the Headless example. The up-to-date sample source code to this page is found in Git here: http://git.eclipse.org/c/incquery/org.eclipse.incquery.examples.git/tree/headless Most notably,
- the patterns are found in headlessQueries.eiq
- and the API usage samples are found in IncQueryHeadless.java and IncQueryHeadlessAdvanced.java
Javadoc
The most up-to-date Javadocs for the EMF-IncQuery API can be found online at http://eclipse.org/incquery/javadoc/
The IncQuery Generic API
The "generic" API differs from the generated one in two key aspects:
- it can be used to apply queries and use other IncQuery features without generating code and loading the resulting bundles into the running configuration. In other words, you just need to supply the EMF-based in-memory representation (an instance of the Pattern class)
- the generic API is not "type safe" in the sense that the Java types of your pattern variables is not known and needs to be handled dynamically (e.g. by instanceof - typecase combos).
Initializing matchers and accessing results
Sample code
With the Generic API:
public String executeGeneric(String modelPath, String patternFQN) { StringBuilder results = new StringBuilder(); Resource resource = loadModel(modelPath); if (resource != null) { try { // get all matches of the pattern IncQueryMatcher matcher = MatcherFactoryRegistry.getMatcherFactory(patternFQN).getMatcher(resource); Collection<IPatternMatch> matches = matcher.getAllMatches(); prettyPrintMatches(results, matches); } catch (IncQueryException e) { e.printStackTrace(); results.append(e.getMessage()); } } else { results.append("Resource not found"); } return results.toString(); }
API interfaces
- IPatternMatch
* reflection: pattern(), patternName() * getters and setters * utility functions (toArray, prettyPrint)
- IncQueryMatcher
* reflection * get all matches * get single/arbitrary match * check for a match * number of matches * process matches * access change processing features * create a new Match for input binding * access projected value sets
The Pattern Registry and Matcher Factories
TODO
IMatcherFactory
/** * Interface for an IncQuery matcher factory. Each factory is associated with a pattern. Methods instantiate a matcher * of the pattern with various parameters. * * @author Bergmann Gábor * */ public interface IMatcherFactory<Matcher extends IncQueryMatcher<? extends IPatternMatch>> { /** * @throws IncQueryException * if there was an error loading the pattern definition * @returns the pattern for which matchers can be instantiated. */ public Pattern getPattern(); /** * Identifies the pattern for which matchers can be instantiated. */ public String getPatternFullyQualifiedName(); /** * Initializes the pattern matcher over a given EMF model root (recommended: Resource or ResourceSet). If a pattern * matcher is already constructed with the same root, only a lightweight reference is created. * * <p> * The scope of pattern matching will be the given EMF model root and below (see FAQ for more precise definition). * <p> * The match set will be incrementally refreshed upon updates from this scope. * * <p> * The matcher will be created within the managed {@link IncQueryEngine} belonging to the EMF model root, so * multiple matchers will reuse the same engine and benefit from increased performance and reduced memory footprint. * * @param emfRoot * the root of the EMF tree where the pattern matcher will operate. Recommended: Resource or ResourceSet. * @throws IncQueryException * if an error occurs during pattern matcher creation */ public Matcher getMatcher(Notifier emfRoot) throws IncQueryException; /** * Initializes the pattern matcher within an existing {@link IncQueryEngine}. If the pattern matcher is already * constructed in the engine, only a lightweight reference is created. * <p> * The match set will be incrementally refreshed upon updates. * * @param engine * the existing EMF-IncQuery engine in which this matcher will be created. * @throws IncQueryException * if an error occurs during pattern matcher creation */ public Matcher getMatcher(IncQueryEngine engine) throws IncQueryException; }
Advanced query result set change processing
Match update callbacks
private void changeProcessing_lowlevel(final StringBuilder results, IncQueryMatcher<? extends IPatternMatch> matcher) { // (+) these update callbacks are called whenever there is an actual change in the // result set of the pattern you are interested in. Hence, they are called fewer times // than the "afterUpdates" option, giving better performance. // (-) the downside is that the callbacks are *not* guaranteed to be called in a consistent // state (i.e. when the update propagation is settled), hence // * you must not invoke pattern matching and model manipulation _inside_ the callback method // * the callbacks might encounter "hazards", i.e. when an appearance is followed immediately by a disappearance. matcher.addCallbackOnMatchUpdate(new IMatchUpdateListener<IPatternMatch>() { @Override public void notifyDisappearance(IPatternMatch match) { // left empty } @Override public void notifyAppearance(IPatternMatch match) { results.append("\tNew match found by changeset low level callback: " + match.prettyPrint()+"\n"); } }, false); } /source> == After update callbacks and DeltaMonitors == <source lang="java"> private void changeProcessing_deltaMonitor(final StringBuilder results, IncQueryMatcher<? extends IPatternMatch> matcher) { final DeltaMonitor<? extends IPatternMatch> dm = matcher.newDeltaMonitor(false); // (+) these updates are guaranteed to be called in a *consistent* state, // i.e. when the pattern matcher is guaranteed to be consistent with the model // anything can be written into the callback method // (-) the downside is that the callback is called after *every* update // that propagates through the matcher, i.e. also when the updates do not actually // influence the result set you are interested in. Hence, the performance is somewhat // lower than for the "lowlevel" option. matcher.addCallbackAfterUpdates(new Runnable() { @Override public void run() { for (IPatternMatch newMatch : dm.matchFoundEvents) { results.append("\tNew match found by changeset delta monitor: " + newMatch.prettyPrint()+"\n"); } for (IPatternMatch lostMatch : dm.matchLostEvents) { // left empty } } }); }
Advanced IncQuery Lifecycle management
Managed vs. unmanaged IncQueryEngines
TODO
* dispose * wipe
IncQuery Base
TODO
Extracting reachability paths from transitive closure
TODO