Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

VIATRA/Query/UserDocumentation/API/Advanced

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,

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

Using the Generic API:

public String executeDemo_GenericAPI(String modelPath, String patternFQN) {
 final StringBuilder results = new StringBuilder();
 Resource resource = loadModel(modelPath);
 if (resource != null) {
  try {
   // get all matches of the pattern
   // create an *unmanaged* engine to ensure that noone else is going
   // to use our engine
   IncQueryEngine engine = EngineManager.getInstance().createUnmanagedIncQueryEngine(resource);
   // instantiate a pattern matcher through the registry, by only knowing its FQN
   IncQueryMatcher<? extends IPatternMatch> matcher = MatcherFactoryRegistry.getMatcherFactory(patternFQN).getMatcher(engine);
   // assuming that there is a pattern definition registered matching 'patternFQN'
   if (matcher!=null) {
    Collection<? extends IPatternMatch> matches = matcher.getAllMatches();
    prettyPrintMatches(results, matches);
   }
   // wipe the engine
   engine.wipe();
   // after a wipe, new patterns can be rebuilt with much less overhead than 
   // complete traversal (as the base indexes will be kept)
   // completely dispose of the engine once's it is not needed
   engine.dispose();
   resource.unload();
  } catch (IncQueryException e) {
   e.printStackTrace();
   results.append(e.getMessage());
  } 
 } else {
  results.append("Resource not found");
 }
 return results.toString();
}

API interfaces

  • IPatternMatch Javadoc
    • reflection: pattern(), patternName()
    • getters and setters
    • utility functions (toArray, prettyPrint)
  • IncQueryMatcher Javadoc
    • 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 The IMatcherFactory interface Javadoc

  • reflection
  • initialize the matcher


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 notifyAppearance(IPatternMatch match) {
   results.append("\tNew match found by changeset low level callback: " + match.prettyPrint()+"\n");
  }
 }, false);
}

After update callbacks and DeltaMonitors

The DeltaMonitor can do this for you in a convenient way. It is a monitoring object that connects to the rete network as a receiver to reflect changes since an arbitrary state acknowledged by the client. If a new matching is found, it appears in the matchFoundEvents collection, and disappears when that particular matching cannot be found anymore. If the event of finding a match has been processed by the client, it can be removed manually. In this case, when a previously found matching is lost, the Tuple will appear in the matchLostEvents collection, and disappear upon finding the same matching again. "Matching lost" events can also be acknowledged by removing a Tuple from the collection. If the matching is found once again, it will return to matchFoundEvents.

 
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");
   }
}

Advanced IncQuery Lifecycle management

Managed vs. unmanaged IncQueryEngines

Disposing

  • wipe
  • dispose

IncQuery Base

This topic is currently covered in http://incquery.net/incquery/documentation/base

Extracting reachability paths from transitive closure

TODO

Back to the top