IncQuery Demo @ MODELS2010 HOWTO (archived)

IncQuery HOWTO

Tutorial slides

Available here: http://mit.bme.hu/~rath/ppt/EMF-IncQuery_Talk_MODELS10_Rath.pdf

How to try the contents of the demo package?

We provide a prepared package to demonstrate EMF-IncQuery. The domain (Ecore metamodel) used in the example is (the standard EMF representation of) UML2, and the example contains some model queries over UML2 models. To illustrate the operation of the model query code generated from these queries, the example is bundled with a version of the popular UML editor Papyrus, and a separate plug-in is provided to extend Papyrus with on-the-fly model validation capabilities, based on the incremental model queries.

Obtaining the demo package

The demo package is available here for the win32 platform. If you need to use it on a different OS, we suggest obtaining a fresh copy of the appropriate distribution of Eclipse Modeling (version Helios), making sure that ANTLR is installed, and copying the dropins folder provided with the demo package into the dropins/ folder of your eclipse installation.

Files and folder structure

  • hu.bme.mit.incquery.demo.dropins/

This folder contains the dropins needed for the EMF-IncQuery sandbox environment. Namely, the development-time components of Viatra2, the development-time Eclipse project creation and code generation support of EMF-IncQuery, the run-time component of EMF-IncQuery and release snapshot 1.12.0 of Papyrus.

  • eclipse-win32/

This is the Eclipse installation. Contains an Eclipse Modeling installation (Helios version, win32 platform), with ANTLR installed.

The dropins are already copied into the dropins/ folder.

  • eclipse-win32/eclipse.exe

Start this executable.

  • development-workspace/

Open this workspace in the launched Eclipse environment. You will use this to develop your graph patterns, generate your EMF-IncQuery plug-in project and create a plug-in that extends Papyrus and uses the model queries.

  • development-workspace/hu.bme.mit.uml2.validator

This is the EMF-IncQuery project, that hosts the graph patterns as well as the generated Eclipse plug-in code. Important locations:

  • models/vtcl/

  Put your graph patterns in this folder in .vtcl format. The demo already ships with a file defining numerous queries.

  • models/model.vpml

  A Viatra2 model space that can help you test and debug your graph patterns before code generation.

  • uml2.incquery

  This is the IncQuery generator model. Right click and issue "Generate EMF-IncQuery Source Code" to generate Java code from the graph patterns.

  • src-gen/

  Generated Java code will go here.

  • src/

  It is possible to put your own code here, although the folder is currently unused.

  • development-workspace/hu.bme.mit.incquery.demo.papyrus

A demo Eclipse plug-in project that depends on the generated plug-in. It extends the Papyrus user interface and provides UI contributions based on the incremental queries, to achieve some very basic validation functionality.

  • runtime-workspace/

This workspace will be used by the runtime Eclipse instance, that you launch from the development Eclipse instance (Debug / Run plug-in projects from workspace). You can create Papyrus projects here, and unleash the rudimentary incremental validation functionality on them; the demo package already contains one. 

Running the demo

Start the Eclipse instance from the eclipse-win32/ folder; make sure that development-workspace/ is loaded as a workspace. The contents of the workspace (a plugin containing the generated query code and another one extending Papyrus) should successfully go through Java compilation, i.e. after "Bulding workspace" finishes, there should be no error markers on Java files or elsewhere in the plug-in projects. Finally, start the runtime instance of Eclipse by finding the debug icon (little green insect) on the Eclipse toolbar, and selecting UmlValidator from the drop-down menu.

The runtime instance should start up and load the workspace folder runtime-workspace/ and show the Papyrus perspective. The demo package ships a Papyrus project in the workspace, with a UML model inside. After opening the model, right-click a class and select "Initialize INCQuery validation" (the extension contributed by the plug-in hu.bme.mit.incquery.demo.papyrus). Through this action, a reference to the EMF Resource containing the model will be obtained, the generated EMF-IncQuery pattern matchers will be initialized over the model and the toy model validator functionality will start monitoring the model. The validator will continuously report matches of graph patterns as errors in the Problems view of Eclipse. The provided example model already contains some parts that appear in the result set of the various pre-defined model queries; feel free to "fix" these modeling mistakes or introduce new ones and observe how the contents of the problem view is dynamically updated.

Example UML model queries

The demo ships with a number of validation queries. They are all defined in the file hu.bme.mit.uml2.validator/models/vtcl/my_uml_validation.vtcl and used by the other plug-in.

  • In some environments, inheritance diamonds are considered an anti-pattern. The graph pattern "inheritanceDiamond" selects four classes A, B, C, D such as B and C are both superclasses of A, and D is a common superclass of both B and C, without B being a superclass of C or vica versa. The definition only assumes transitive superclass relationships, i.e no direct generalization edge is neccessary. Note that every match of the pattern appears twice, with the roles of B and C reversed; in theory you can filter by e.g. an ordering between B and C to break the symmetry and get rid of the duplicate matches. This pattern demonstrates positive and negative pattern calls (graph pattern reusal) to build a complex pattern that is difficult to check manually; while the called pattern transitiveSuperClass illustrates capturing the transitive closure of an acyclic relationship.
  • A design guideline might force you to always have an association between classes that exchange messages. The graph pattern "messageWithoutAssociation" selects a Message from an Intercation model (typically a Sequence diagram), that connects two Lifelines that represent Classes that are not connected by an association. This pattern demonstates how complicated details of the UML abstract syntax can be neatly wrapped into higher level graph patterns that reuse each other in a complex web, and also the fact that queries operate on models and are therefore able to find hard-to-notice problems that are distributed over several diagrams and modeling styles.
  • While sometimes benign, it can be a sign of incompleteness if a class is defined but not referenced by any attribute, association, variable, parameter, lifeline, etc., in short any TypedElement anywhere. The pattern "unreferencedClass" matches such classes. As a future improvement, it could probably be extended to make it more useful, e.g. filter out classes whose supertypes do have references.
  • It is a sign of bad separation of concerns if low-level DB design details have crept up into the model level. The pattern "classWithID" selects classes that have a property (local or inherited) with the name ID. This pattern was included to demonstrate how attribute values can be accessed and conditions can be imposed on them.

As future improvement, it would be interesting to extend the current set of queries in a number of ways.

  • Instead of checking whether the attribute name is "ID", the query could output the name of the attribute as a parameter. EMF-IncQuery provides the feature of retrieving a restricted result set of a query, with some parameters bound to values. Leaving behind the goal of model validation, this modified query could provide the user with a useful search function that would enumerate all classes that have an attribute with the given name.
  • Currently if you change the name of a class, the error entries in the Problems view will still reflect the old name. However, model queries can simply output the value of the "name" EAttribute alongside the class. One benefit is that this name attribute can be directly used to compile the error message. Additionally, whenever the name of the class is changed, the previous match of the pattern is retracted and a new match will appear with the updated name, resulting in the replacement of the Problems view entry.     

A crash course on developing queries with EMF-IncQuery

Project creation

  • New project wizard | EMF-IncQuery | Create Incremental Query Project

Metamodel initialization

You need to specify the EMF metamodels that contain the types (EClasses) that your queries will reference. These Ecore models will be loaded (~copied) into the EMF-IncQuery project.

  • Open the generator of your new your EMF-IncQuery project, located at models/generator.incquery; right-click in the opened tree editor, issue Load resource and select the desired .genmodel file (we need the .genmodel and NOT the .ecore).
  • In the .incquery editor, find the root element ("Inc Query Genmodel"), right-click on it and issue New Child | Ecore Model. Set the newly created elements' Models reference (using the Properties View) to the GenModel element you want to use (as present in the previously loaded .genmodel resource).
  • Finally, select the "Inc Query Genmodel" root element, right-click and issue Load GenModels into EMF-IncQuery project. This will initialize the VIATRA2 model space (located at models/model.vpml) in your project and import the Ecore metamodels.

Important: you need to repeat these steps whenever

  • you wish to make new metamodels available to your queries, or
  • any of the referenced metamodels change.

To learn more about VIATRA2 models and model spaces, read this: http://wiki.eclipse.org/VIATRA2/GettingStarted/Model_Editing

Creating queries

Create a new VIATRA Textual Command Language script (a VTCL file) in the models/vtcl folder of your new incquery project (use the New wizard for this, in the VIATRA2 R3 category). All graph patterns will be compiled into EMF-IncQuery queries. As the first step, the textual pattern definitions will be parsed in GTASM models whenever you save the VTCL file (the model files are stored in the models/machines sub-folder of the project, you can open and check these files using the Reflective Ecore Model editor, for example).

To learn more about the VIATRA Textual Command Language and graph patterns, read these:

A more complex, end-to-end example describing the details of the language is available here:

http://wiki.eclipse.org/VIATRA2/Activity_Diagrams_to_Petri_Nets

Generating pattern matcher code

Right-click on the models/generator.incquery file and issue EMF-IncQuery | Generate EMF-IncQuery Source Code. The result of the generation will be visible under the src-gen/ folder.

Using the generated pattern matcher code

To use the generated EMF-IncQuery pattern matchers, either create your own plug-in project and add a dependency on the generated EMF-IncQuery plug-in (the EMF plug-ins corresponding to the referenced metamodels are automatically re-exported and made available to your code), or simply put your own code in the src/ folder of the generated project.

To match a pattern on an EMF instance model, find the corresponding generated class from src-gen/patternmatchers/ and instantiate it with your EMF ResourceSet. The object will have useful methods such as getAllMatches..(), some of them declared in the class itself, some of them in the interface IncQueryMatcher. Refer to the Javadoc on method usage.

During the lifetime of the ResourceSet, the match sets will be incrementally maintained and therefore the pattern match retriever methods of the matcher object always return the up-to-date results virtually instantly. The actual ("heavy") pattern matcher is constructed behind the scenes, the generated ...Matcher class is only a lightweight wrapper; therefore you can instantiate it for the same ResourceSet multiple times without significant performance penalties.

Altogether, the public pattern query API can be used very simply to:

  • initialize an incremental pattern matcher on any Notifier (Resource, ResourceSet, or EMF elements representing their respective containment subtrees).
  • execute a query any time on the model, retrieving the result set immediately
  • register a delta monitor to incrementally and efficiently track changes in the result sets of queries

Usage examples

To see an example on how to invoke EMF-IncQuery pattern matchers from your code, select the models/generator.incquery file again, right-click and issue EMF-IncQuery | Generate Sample UI project for EMF-IncQuery. A separate plug-in project will be generated that contributes a UI action for each of your patterns; these actions simply pop up a message box showing the result set of the pattern over the EMF resource.

For a more complex example, refer to the distributed Papyrus demo; the hu.bme.mit.incquery.demo.papyrus project provides an example of using generated pattern matchers.

Advanced language notes

Language restricitons

  1. Patterns involving two or more datatype variables should be declared shareable (add injectivity constraints manually if needed). It is not easy to predict what equality semantics can be maintained between attribute values in context of the VPM modelspace or an EMF resource; valid matches with two attributes having the same native value could be erroneously filtered as a consequence. Therefore please avoid asserting injectivity between variables referring to attributes.
  2. Patterns should not expose relations in their parameters, as this is not translatable to EMF - you cannot capture structural feature instances as individual objects in general. In fact, even inside the pattern, don't use variables representing a relation, apart from declaring them.
  3. Only permitted type declarations are (the Viatra representation of) EClasses and ERelations and EAttributes, from the nemf.packages.PACKAGENAME namespace. Ecore itself (found at nemf.ecore) and the data types (from nemf.ecore.datatypes) should be also fine. Do not use other types.
  4. Generics (instanceOf, supertypeOf) will not work currently. Maybe one day this will (partially) change.
  5. Attribute values can be exposed as symbolic parameters, but over EMF they are not really entities, so do not use them apart from discovering them with the EAttribute edge and checking their value() in check() expressions. By breaking the equivalence between the behaviour over VPM and EMF though, it is possible to join on attribute values.
  6. Check() expressions cannot use native functions or ASMFunctions. They can use attribute values wrapped in value() and converted to the native type using toInteger() and co (these steps are required over VPM, and AFAIK ignored over EMF), so as to hide that they are represented as string-valued model elements in VPM. Keep in mind that fqn() is off limits, and usually name() doesn't work either (though there may be some limited heuristic support for the latter).

How to check attributes (so that it actually works over EMF too)

In the graph pattern, use the EAttribute edges from the EObject to discover the attribute value. The attribute value can then be used in a check() expression, but it first has to be wrapped into value(), and than toInteger(), toString(), etc. according to the type. 

Examples:

  • check(toDouble(value(HeightOfVehicle)) < toDouble(value(HeightOfTunnel)) - 0.3);
  • check(toBoolean(value(IsJobCritical)) == false);
  • check(toString(value(CardSuite)) == "SUITE_SPADES"); // This is the recommended way to check EEnums