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

Difference between revisions of "VIATRA/Query/UserDocumentation/API/Advanced"

(Disposing)
Line 25: Line 25:
 
<source lang="java">
 
<source lang="java">
 
public String executeDemo_GenericAPI(String modelPath, String patternFQN) {
 
public String executeDemo_GenericAPI(String modelPath, String patternFQN) {
final StringBuilder results = new StringBuilder();
+
final StringBuilder results = new StringBuilder();
Resource resource = loadModel(modelPath);
+
Resource resource = loadModel(modelPath);
if (resource != null) {
+
if (resource != null) {
try {
+
  try {
// get all matches of the pattern
+
  // get all matches of the pattern
// create an *unmanaged* engine to ensure that noone else is going
+
  // create an *unmanaged* engine to ensure that noone else is going
// to use our engine
+
  // to use our engine
IncQueryEngine engine = EngineManager.getInstance().createUnmanagedIncQueryEngine(resource);
+
  IncQueryEngine engine = EngineManager.getInstance().createUnmanagedIncQueryEngine(resource);
// instantiate a pattern matcher through the registry, by only knowing its FQN
+
  // instantiate a pattern matcher through the registry, by only knowing its FQN
IncQueryMatcher<? extends IPatternMatch> matcher = MatcherFactoryRegistry.getMatcherFactory(patternFQN).getMatcher(engine);
+
  IncQueryMatcher<? extends IPatternMatch> matcher = MatcherFactoryRegistry.getMatcherFactory(patternFQN).getMatcher(engine);
// assuming that there is a pattern definition registered matching 'patternFQN'
+
  // assuming that there is a pattern definition registered matching 'patternFQN'
if (matcher!=null) {
+
  if (matcher!=null) {
Collection<? extends IPatternMatch> matches = matcher.getAllMatches();
+
    Collection<? extends IPatternMatch> matches = matcher.getAllMatches();
prettyPrintMatches(results, matches);
+
    prettyPrintMatches(results, matches);
}
+
  }
// wipe the engine
+
  // wipe the engine
engine.wipe();
+
  engine.wipe();
// after a wipe, new patterns can be rebuilt with much less overhead than  
+
  // after a wipe, new patterns can be rebuilt with much less overhead than  
// complete traversal (as the base indexes will be kept)
+
  // complete traversal (as the base indexes will be kept)
// completely dispose of the engine once's it is not needed
+
  // completely dispose of the engine once's it is not needed
engine.dispose();
+
  engine.dispose();
resource.unload();
+
  resource.unload();
} catch (IncQueryException e) {
+
  } catch (IncQueryException e) {
e.printStackTrace();
+
  e.printStackTrace();
results.append(e.getMessage());
+
  results.append(e.getMessage());
}
+
  }  
} else {
+
} else {
results.append("Resource not found");
+
  results.append("Resource not found");
}
+
}
return results.toString();
+
return results.toString();
 
}
 
}
 
</source>
 
</source>
Line 86: Line 86:
 
<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
+
// (+) 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
+
// result set of the pattern you are interested in. Hence, they are called fewer times
// than the "afterUpdates" option, giving better performance.
+
// than the "afterUpdates" option, giving better performance.
// (-)  the downside is that the callbacks are *not* guaranteed to be called in a consistent
+
// (-)  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
+
// state (i.e. when the update propagation is settled), hence
//  * you must not invoke pattern matching and model manipulation _inside_ the callback method
+
//  * 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.
+
//  * the callbacks might encounter "hazards", i.e. when an appearance is followed immediately by a disappearance.
matcher.addCallbackOnMatchUpdate(new IMatchUpdateListener<IPatternMatch>() {
+
matcher.addCallbackOnMatchUpdate(new IMatchUpdateListener<IPatternMatch>() {
@Override
+
  @Override
public void notifyDisappearance(IPatternMatch match) {
+
  public void notifyAppearance(IPatternMatch match) {
// left empty
+
  results.append("\tNew match found by changeset low level callback: " + match.prettyPrint()+"\n");
}
+
  }
@Override
+
}, false);
public void notifyAppearance(IPatternMatch match) {
+
results.append("\tNew match found by changeset low level callback: " + match.prettyPrint()+"\n");
+
}
+
}, false);
+
 
}
 
}
 
</source>
 
</source>
Line 109: Line 105:
 
<source lang="java">
 
<source lang="java">
 
private void changeProcessing_deltaMonitor(final StringBuilder results, IncQueryMatcher<? extends IPatternMatch> matcher) {
 
private void changeProcessing_deltaMonitor(final StringBuilder results, IncQueryMatcher<? extends IPatternMatch> matcher) {
final DeltaMonitor<? extends IPatternMatch> dm = matcher.newDeltaMonitor(false);
+
final DeltaMonitor<? extends IPatternMatch> dm = matcher.newDeltaMonitor(false);
// (+) these updates are guaranteed to be called in a *consistent* state,
+
// (+) 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
+
// i.e. when the pattern matcher is guaranteed to be consistent with the model
// anything can be written into the callback method
+
// anything can be written into the callback method
// (-) the downside is that the callback is called after *every* update
+
// (-) 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
+
// 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
+
// influence the result set you are interested in. Hence, the performance is somewhat
// lower than for the "lowlevel" option.
+
// lower than for the "lowlevel" option.
matcher.addCallbackAfterUpdates(new Runnable() {
+
matcher.addCallbackAfterUpdates(new Runnable() {
@Override
+
  @Override
public void run() {
+
  public void run() {
for (IPatternMatch newMatch : dm.matchFoundEvents) {
+
  for (IPatternMatch newMatch : dm.matchFoundEvents) {
results.append("\tNew match found by changeset delta monitor: " + newMatch.prettyPrint()+"\n");
+
    results.append("\tNew match found by changeset delta monitor: " + newMatch.prettyPrint()+"\n");
}
+
  }
for (IPatternMatch lostMatch : dm.matchLostEvents) {
+
// left empty
+
}
+
}
+
});
+
 
}
 
}
 
</source>
 
</source>

Revision as of 12:38, 11 April 2013

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

TODO

Extracting reachability paths from transitive closure

TODO

Back to the top