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

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

Back to the top