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"

< VIATRA‎ | Query
Line 9: Line 9:
  
 
The most up-to-date Javadocs for the EMF-IncQuery API can be found online at http://eclipse.org/incquery/javadoc/  
 
The most up-to-date Javadocs for the EMF-IncQuery API can be found online at http://eclipse.org/incquery/javadoc/  
 +
 +
== Headless Execution Example  ==
 +
 +
=== Overview  ===
 +
 +
EMF-IncQuery can be used without any graphical user interface (headless). In this example, we take an existing IncQuery project and based on it, we create a (headless) Eclipse Application that can be executed from a console (command prompt) to print the matches for an arbitrary input model file.<br>First, the IncQuery project headless.incquery can be downloaded from: [https://github.com/ujhelyiz/EMF-IncQuery-Examples/tree/master/headless https://github.com/ujhelyiz/EMF-IncQuery-Examples/tree/master/headless] The project contains a single pattern that matches on Ecore models:<br>
 +
 +
<source lang="java">
 +
import "http://www.eclipse.org/emf/2002/Ecore"
 +
 +
pattern EClassNames(C: EClass, N : EString)= {
 +
EClass.name(C,N);
 +
}
 +
</source>
 +
 +
Next, observe the application project org.eclipse.viatra2.emf.incquery.application (available at the same place). The project includes two class files:
 +
 +
*'''IncQueryApplication''': by implementing the IApplication interface, it provides a single entrypoint that is also capable of handling command line parameters. It checks that the input model is provided using the -m &lt;modelPath&gt; switch, the query name provided using the -p &lt;patternFQN&gt; switch and then invokes the pattern matcher.
 +
**To execute the example (on Windows), call as follows (assuming the current folder contains eclipse.exe and the model can be found at c:/test/input.ecore): eclipse.exe -m c:/test/input.ecore - p somePackage.somePattern
 +
*'''IncQueryHeadless''': with a single method execute(String modelPath) that will first try to load the model found at modelPath into an EMF Resource, and if that was successful, it creates a matcher (for the EClassNames pattern) and retrieves the matches as a collection. The actual code also includes some additional fragments to illustrate performance measurements (timed execution for the EMF loading, IncQuery initialization and matchset retrieval phases). Finally, the matches are printed using IPatternMatch.prettyPrint().
 +
 +
Next, the application itself is registered through the org.eclipse.core.runtime.applications extension point. The plugin.xml file defines the extension.<br>Finally, a product configuration is required in order to run this application as an Eclipse product, and to be able to export it into a standalone application that can be called from the console. Apart from adding the required plugins to the configuration, an org.eclipse.core.runtime.products extension is required as well (also found in plugin.xml):
 +
 +
<source lang="xml">
 +
<extension id="org.eclipse.incquery.application.app"
 +
point="org.eclipse.core.runtime.applications">
 +
<application cardinality="singleton-global" thread="main" visible="true">
 +
  <run class="org.eclipse.incquery.application.IncQueryApplication">
 +
  </run>
 +
</application>
 +
</extension>
 +
 +
<extension id="incquery" point="org.eclipse.core.runtime.products">
 +
<product application="org.eclipse.incquery.application.app" name="IncQuery Application">
 +
  <property name="appName" value="IncQuery Application">
 +
  </property>
 +
</product>
 +
</extension>
 +
</source>
 +
 +
If only the minimum required plugins are exported, the resulting eclipse folder is around 30 MB, which is quite small considering that an Eclipse Modeling distribution is around 300 MB.<br>Note that you may have to remove the platform-specific features that are for different platforms (e.g. Linux and MacOS X when using Windows).
  
 
== EMF-IncQuery Java API  ==
 
== EMF-IncQuery Java API  ==
  
 
There are two ways you can use the EMF-IncQuery Pattern Matcher in your application. Either you can use the generic pattern matcher components, or the pattern-specific generated components. In most cases you won’t need the generic pattern matcher, which is much more complex to use. However they conform to the same reflective interfaces, and there is no performance difference between the two. Here we will present a simple introduction to the generated components, which contains many features to help you to integrate it into your java application.  
 
There are two ways you can use the EMF-IncQuery Pattern Matcher in your application. Either you can use the generic pattern matcher components, or the pattern-specific generated components. In most cases you won’t need the generic pattern matcher, which is much more complex to use. However they conform to the same reflective interfaces, and there is no performance difference between the two. Here we will present a simple introduction to the generated components, which contains many features to help you to integrate it into your java application.  
 +
 +
=== Generic API  ===
 +
 +
<source lang="java">
 +
public String execute(String modelPath, String patternFQN) {
 +
ResourceSet resourceSet = new ResourceSetImpl();
 +
URI fileURI = URI.createFileURI(modelPath);
 +
Resource resource = resourceSet.getResource(fileURI, true);
 +
if (resource != null) {
 +
  try {
 +
  IncQueryMatcher matcher = MatcherFactoryRegistry.getMatcherFactory(patternFQN).getMatcher(resource);
 +
  Collection<IPatternMatch> matches = matcher.getAllMatches();
 +
  for (IPatternMatch match : matches) {
 +
    IncQueryEngine.getDefaultLogger().logError(match.prettyPrint());
 +
    results.append(match.prettyPrint());
 +
  }
 +
  } catch (IncQueryRuntimeException e) {
 +
  e.printStackTrace();
 +
  }
 +
}
 +
}
 +
</source>
  
 
=== Generated API  ===
 
=== Generated API  ===

Revision as of 05:05, 22 March 2013

Overview

This page presents the basics of EMF-IncQuery's Java API. It supersedes the following contents of the original documentation on IncQuery.net:

Javadoc

The most up-to-date Javadocs for the EMF-IncQuery API can be found online at http://eclipse.org/incquery/javadoc/

Headless Execution Example

Overview

EMF-IncQuery can be used without any graphical user interface (headless). In this example, we take an existing IncQuery project and based on it, we create a (headless) Eclipse Application that can be executed from a console (command prompt) to print the matches for an arbitrary input model file.
First, the IncQuery project headless.incquery can be downloaded from: https://github.com/ujhelyiz/EMF-IncQuery-Examples/tree/master/headless The project contains a single pattern that matches on Ecore models:

import "http://www.eclipse.org/emf/2002/Ecore"
 
pattern EClassNames(C: EClass, N : EString)= {
 EClass.name(C,N);
}

Next, observe the application project org.eclipse.viatra2.emf.incquery.application (available at the same place). The project includes two class files:

  • IncQueryApplication: by implementing the IApplication interface, it provides a single entrypoint that is also capable of handling command line parameters. It checks that the input model is provided using the -m <modelPath> switch, the query name provided using the -p <patternFQN> switch and then invokes the pattern matcher.
    • To execute the example (on Windows), call as follows (assuming the current folder contains eclipse.exe and the model can be found at c:/test/input.ecore): eclipse.exe -m c:/test/input.ecore - p somePackage.somePattern
  • IncQueryHeadless: with a single method execute(String modelPath) that will first try to load the model found at modelPath into an EMF Resource, and if that was successful, it creates a matcher (for the EClassNames pattern) and retrieves the matches as a collection. The actual code also includes some additional fragments to illustrate performance measurements (timed execution for the EMF loading, IncQuery initialization and matchset retrieval phases). Finally, the matches are printed using IPatternMatch.prettyPrint().

Next, the application itself is registered through the org.eclipse.core.runtime.applications extension point. The plugin.xml file defines the extension.
Finally, a product configuration is required in order to run this application as an Eclipse product, and to be able to export it into a standalone application that can be called from the console. Apart from adding the required plugins to the configuration, an org.eclipse.core.runtime.products extension is required as well (also found in plugin.xml):

<extension id="org.eclipse.incquery.application.app"
 point="org.eclipse.core.runtime.applications">
 <application cardinality="singleton-global" thread="main" visible="true">
  <run class="org.eclipse.incquery.application.IncQueryApplication">
  </run>
 </application>
</extension>
 
<extension id="incquery" point="org.eclipse.core.runtime.products">
 <product application="org.eclipse.incquery.application.app" name="IncQuery Application">
  <property name="appName" value="IncQuery Application">
  </property>
 </product>
</extension>

If only the minimum required plugins are exported, the resulting eclipse folder is around 30 MB, which is quite small considering that an Eclipse Modeling distribution is around 300 MB.
Note that you may have to remove the platform-specific features that are for different platforms (e.g. Linux and MacOS X when using Windows).

EMF-IncQuery Java API

There are two ways you can use the EMF-IncQuery Pattern Matcher in your application. Either you can use the generic pattern matcher components, or the pattern-specific generated components. In most cases you won’t need the generic pattern matcher, which is much more complex to use. However they conform to the same reflective interfaces, and there is no performance difference between the two. Here we will present a simple introduction to the generated components, which contains many features to help you to integrate it into your java application.

Generic API

public String execute(String modelPath, String patternFQN) {
 ResourceSet resourceSet = new ResourceSetImpl();
 URI fileURI = URI.createFileURI(modelPath);
 Resource resource = resourceSet.getResource(fileURI, true);
 if (resource != null) {
  try {
   IncQueryMatcher matcher = MatcherFactoryRegistry.getMatcherFactory(patternFQN).getMatcher(resource);
   Collection<IPatternMatch> matches = matcher.getAllMatches();
   for (IPatternMatch match : matches) {
    IncQueryEngine.getDefaultLogger().logError(match.prettyPrint());
    results.append(match.prettyPrint());
   }
  } catch (IncQueryRuntimeException e) {
   e.printStackTrace();
  }
 }
}

Generated API

Most important classes and relationships

For every pattern a Match, a Matcher, a MatcherFactory, a Processor and optionally several Evaluator classes are generated. Let’s look into what these classes are responsible for:

  • Match: This represents a match of the pattern. Basically it is used to transfer data to and from the pattern matcher. The generated variables represent the pattern header parameters. You can use it to specify fixed input parameters to a query, and the results of you queries will be instances of this class. Note, that in each case the pattern parameters can be partially filled. It can be used in conjunction with the Matcher class.
  • Matcher: This is the main entry point in our API, with pattern-specific query methods. First of all it provides means to initialize a pattern matcher for a given EMF instance model which can either be a Resource, a ResourceSet, or an EObject (in this latter case, the scope of the matching will be the containment tree under the passed EObject). We recommend the use of ResourceSets if possible to avoid cross-reference related issues. After the initialization of the engine the Matcher provides getter methods to retrieve the contents of the match set anytime. For easy iteration over the match set it provides a convenience method (forEachMatch) as well, as this is the most frequent use case in our observation. Of course it contains other handy features (e.g.: countMatches, hasMatch) to help integration. Finally, it provides a DeltaMonitor which can be used to track the changes in the match set in an efficient, event-driven fashion.
  • MatcherFactory: A pattern-specific factory that can instantiate a Matcher class in a type-safe way. You can get an instance of it via the Matcher class’s factory() method. There are two ways to instantiate a Matcher, with a Notifier (e.g.: Resource, ResourceSet and EObject) as we mentioned already, or with an IncQueryEngine. In both cases if the pattern is already registered (with the same root in the case of the Notifier method) then only a lightweight reference is created which points to the existing engine.
  • MatchProcessor: The Matcher provides a function to iterate over the match set and invoke the process() method of the IMatchProcessor interface with every match. To help with the processing an abstract processor class is generated, which you can override to implement the logic you would like to use. The abstract class unpacks the match variables so it can be used directly in the process() method.
  • Evaluator: If your pattern contains check expressions an evaluator java code is generated from it. It is used by the engine during a query to evaluate the expression’s result. In most cases you don’t need to deal with these classes.

Lifecycle management

We have an EngineManager singleton class to orchestrate the lifecycle of the IncQueryEngines. There are two types of engines: managed and unmanaged. We recommend the use of managed engines, this is the default behavior, as these engines can share common indices and caches to save memory and cpu time. The EngineManager ensures that there will be no duplicated engine for the same root object. The managed engines can be disposed from the manager if needed. On the other hand creating an unmanaged engine will give you the power and responsibility to use it correctly. It will have no common part with other engines.

The IncQueryEngine is attached to an EMF resource (Resource, ResourceSet or EObject) and hosts the pattern matchers. It will listen on EMF update notifications stemming from the given model in order to maintain live results. Pattern matchers can be registered in the following ways:

  • Instantiate the specific matcher class generated for the pattern, by passing to the constructor either this engine or the EMF model root.
  • Use the matcher factory associated with the generated matcher class to achieve the same.
  • Use the GenericPatternMatcher or the GenericMatcherFactory instead of the various generated classes.

If you want to remove the matchers from the engine you can call the wipe() method on it. It discards any pattern matcher caches and forgets the known patterns. The base index built directly on the underlying EMF model, however, is kept in memory to allow reuse when new pattern matchers are built. If you don’t want to use it anymore call the dispose() instead, to completely disconnect and dismantle the engine.

Typical programming patterns

We recommend trying out the @Handler annotation first, if you’re unfamiliar with the use of the EMF-IncQuery! It generates a sample code with a handler and a dialog that shows the matches of the query in a selected file resource. However you will only need to write just a few lines of code to start working with the pattern matcher:

ResourceSet resourceSet = ... // Get hold of an EMF ResourceSet
try{
    YourMatcher matcher = YourMatcher.factory().getMatcher(resourceSet);
    for (YourMatch yourMatch :matcher.getAllMatches()) {
        // Do something with the matches
    }
} catch (IncQueryException e) {
    e.printStackTrace();
}
Using the MatchProcessor

With the MatchProcessor you can iterate over the matches of a pattern quite easily:

ResourceSet resourceSet = ... // Get hold of an EMF ResourceSet
try{
    YourMatcher matcher = YourMatcher.factory().getMatcher(resourceSet);
    matcher.forEachMatch(new YourProcessor() {
	@Override
	public void process(YourVariable variable) {
	    // Do something with a match
	}
    });
} catch (IncQueryException e) {
    e.printStackTrace();
}
Using the DeltaMonitor

There are some usecases where you don’t want to follow every change of a pattern’s match, just gather them together and process them when you’re ready. 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.

Back to the top