EMF-IncQuery Examples and Demos

The examples below correspond to updated versions of the old examples.

Introductory example: school

The school example features a simple EMF model and some simple graph patterns to show the very basics of using EMF-IncQuery. Read this first before anything else!

Introductory example: BPMN validation

The BPMN validation example introduces the IncQuery Validation Engine, by which incrementally evaluated, on-the-fly well-formedness validation rules can be specified for any EMF model.

Metamodel pattern matching example: ECore Queries

Have you ever tried to query a meta-model, i.e. a model consisting of EClasses, EAttributes, and EReferences, against a meta-model pattern? For an example, look here. In this case, we want to look for a certain sub-configuration in an ECore metamodel, where two EClasses (each having an EAttribute of type EString) are connected by a 0-* EReference.

Use-cases of this technique include meta-transformation, meta-model analysis, higher-order transformations where transformation rules are generated/parameterized by metamodel analysis etc.

Using queries for derived features

We demonstrate how our high performance queries can be easily integrated with other EMF tools using an entirely new case study in which EMF-IncQuery is deeply integrated into the EMF modeling infrastructure to facilitate the incremental evaluation of derived EAttributes and EReferences.

Running IncQuery as a headless RCP application

IncQuery can be called without any graphical user interface or even a complete Eclipse installation. In this example we take an existing IncQuery project and create an Eclipse Application that can be executed from a console (command prompt) to print the matches for an arbitrary input model file.

Query-driven soft interconnections of EMF models

We demonstrate how the incremental query evaluation of EMF-IncQuery can be used to maintain soft interconnections between EMF models stored even if they are stored separately, moved or modified without the all the corresponding models loaded at all times.

Real-time gesture recognition with Jnect and the Esper CEP engine

This demo was prepared for EclipseCon Europe 2012. Using live input from Jnect, the body model of a human user is processed by EMF-IncQuery in real time to recognize gestures. Additionally, the Esper Complex Event Processor is integrated into the system to allow the recognition of gesture sequences in the event stream generated by IncQuery.

Introductory example: School

Overview

The aim of this page is to provide an easy-to-understand, step-by-step guide to EMF-IncQuery. For this purpose, the school example features a simple EMF model and some simple graph patterns to show the very basics of the query language and the core add-ons.

Obtaining the example

In the simple case, you can install the School example from the IncQuery Extra update site.

Alternatively (for advanced users): you will need two Eclipse workspaces to try this example.

You can launch the (school, school.edit, school.editor) projects in a Runtime Eclipse application (which will use the runtime workspace), or you can install them into your host Eclipse (in that case, no separate runtime workspace is necessary).

Source projects

  • host workspace / installed plugins: school, school.edit, school.editor

The school project contains the EMF metamodel (school.ecore) for representing schools, years, classes, students, teachers, and courses. The .edit and .editor projects are automatically generated by EMF (no manual tweaking on the school.genmodel was performed.)

Example query and instance model contents

  • runtime workspace: school.instancemodel/

This project contains two school instance models with a school, years, classes, students, teachers, and courses.
You can create your own model using the standard generated EMF features: New/Other/Example EMF Model Creation Wizards/School Model.

BUTE.school contains the following configuration (some details, such as attribute values, have been omitted for the sake of clarity):

 

Hogwarts.school is another simple instance model example, borrowing some characters from a famous novel.

  • runtime workspace: school.incquery/

This project is an EMF-IncQuery Project (created with New/Other/EMF-IncQuery/EMF-IncQuery Project). It also contains the tutorial queries (patterns) in the src/school/schoolqueries.eiq file, which has been created using the New/Other/EMF-IncQuery/EMF-IncQuery Query Definition wizard.

Jump right in - try the patterns!

  1. Make sure you are in the runtime workspace.
  2. Make sure the "Query Explorer" view of EMF-IncQuery is open (Window/Show view/EMF-IncQuery/Query Explorer).
  3. In the school.incquery project, right click in the schoolqueries.eiq file and choose EMF-IncQuery/Register patterns in Query Explorer.
    Alternatively, you can use the magical green button of the Query Explorer view (green triangle in the view toolbar) when the schoolqueries.eiq file is the active editor.
  4. Observe that the patterns have been registered by opening the left-side panel (Pattern registry) of the Query Explorer.
  5. Open BUTE.school file (either with the generated School editor, or the Sample Reflective Ecore model editor, both of them should work).
  6. Import the instance model into the Query Explorer by using the magical green button again (while the instance model editor is the active editor).
  7. Observe that the instance model has been loaded; expand the tree to see each pattern and their matches.
    You should see something like this:

Observe that both the Pattern Registry and the Details/Filters panels can be toggled, depending on whether you prefer to see their contents or not. The Details/Filters panel is also useful for parameterized (parameter-bound) queries (see later). If you double-click on a match (green dot icons), the selection corresponding to the match (containing all model elements referenced by pattern parameters) will be applied to the host editor (revealing the corresponding model elements automatically). This is useful if you want to locate the model elements in the editor.


Detailed step-by-step guide

Now we describe step-by-step how the sample queries/patterns have been created and what they do. The 7-step tutorial is intended to serve as a quick overview of the language and tooling features. To ease understanding, it is always a good idea to check the language overview and the FAQ. For performance considerations, be sure to check the performance guide.

Step 0 - header

When you first create an IncQuery query definition, an empty file will be created, with only a package declaration. The package declaration is primarily used to determine the Java packages of the code that IncQuery will generate.

In order to start working with IncQuery, you need to import an Ecore namespace, by typing the import keyword and then activating content assist (ctrl-space) and selecting a registered EPackage. Just after you have entered an import declaration, it is a good idea to include an appropriate plugin dependency to the contributing EMF .model plugin (in this case, school) in the MANIFEST.MF of the IncQuery project, and also take care to re-export this dependency.

Workspace EPackages will be usable with the EMF-IncQuery Generator Model (generator.eiqgen) by pointing to the genmodel file of the used metamodels. Once you add the resource URI to the eiqgen file, you can import with the nsUri in the eiq file.

Step 1 - simple queries

The most simple queries in IncQuery are graph patterns that identify nodes and edges of the EMF instance model.

  • nodes (EObjects) can be identified by their Ecore types, such as School or Teacher. A simple pattern consisting of a single node type constraint will yield all instances of that type in the query results, called match set in IncQuery terminology.
  • edges (EReference "instances", i.e. Java references) can be added as additional structural constraints by their Ecore types, such as School.teachers.
    • in the teachersOfSchool pattern above, we are looking for pairs of School-Teacher instances that are actually connected by a teachers edge.
    • Notice that IncQuery has type inference: as the types of the edges endpoints can be inferred from the metamodel, there is no need to include additional Teacher(T) and School(Sch) constraints. The types are defined in the pattern header only for the sake of end-user readability.
    • Notice that IncQuery implicitly makes all EReference navigation bidirectional: while you have to formulate the pattern in a syntactially correct way (specifying that the teachers edge is defined for the School EClass), the query evaluates all connected School-Teacher pairs and thus can be used to look for the Schools belonging to a particular Teacher instance (thus navigating backward along the teachers edge). This works regardless whether there is an EOpposite relationship defined or not.

Step 2 - pattern calls, negative application conditions

One of the most powerful reusability features of the IncQuery pattern language is the find keyword. You can use it to call patterns from other patterns, giving you the ability to factor out commonly used code segments and reuse them whereever necessary. The find keyword uses an intuitive parameter passing semantics, identifying (bound) objects by the parameter they are assigned to (i.e., in the example, wherever you write C, it means the same object).

The find keyword can be preceded by the neg modifier to invert the meaning, i.e. forbid the match of the called pattern with the given parameterization. In that case, unbound parameters (SC) will be "running parameters", i.e. they are not allowed to be matched by anything.

Step 3 - path expressions

Path expressions are useful to compacting patterns, wherever intermediate nodes along a path are not important. Notice that in this particular case, the direction of navigation is unimportant in the sense that both ways of connecting S and Sch yield the same result, because all the included EReferences have EOpposites.

Step 4 - check conditions

Check expressions are useful for specifying value constraints, most frequently for EAttributes. Technically, you write Xbase into a check() expression, making it possible to include complex (imperative) logic right inside the query definition.

  • For the limitations on check() expressions, see the language reference
    • 0.6 limitation: the basic rule of thumb is that you should never include navigation inside a check expression; only write (side effect free) code that accesses a single object from the pattern body and make sure your expression returns a boolean value in a deterministic and idempotent way (that is, the same value for the same input, independently of when it is invoked). Some of these limitations will be lifted for v0.7+.
    • 0.6 limitation: once IncQuery will have full type inference, the type casts (as) inside check() expressions will not be necessary.
  • For details on Xbase expressions, see the Xbase reference

Step 5 - counting

Counting can be used to refer to the size of the match set inside a query. This comes handy e.g. when you want to identify the model element with the minimum/maximum of something. Similarly to neg, cound find involves (a) running (unbound) variable(s) that act(s) as the objects (that)/(whose combinations) will be counted.

Step 6 - disjunction, transitive closure

By default, all clauses inside the pattern body are interpreted as a conjunction (i.e. AND). IncQuery also supports disjunction by OR patterns, whereby multiple pattern bodies can be assigned.

IncQuery includes a specific language construct to define transitive closures, i.e. the computation of reachability relationships where a single step is defined by a (binary) pattern (friendlyTo in the example). This construct is supported by a much more efficient evaluation back-end (evaluated for a recent ICGT conference paper). In order to try the transitive closure, we suggest you to edit the students inside the model, add/remove friendsWith relationships and observe how the match set of the inTheCircleOfFriends patterns change!

Step 7 - combining everything

In the final step of the walkthrough, we combine the previously defined patterns to define a multi-parameter query. It is important to note that in IncQuery, patterns can have an arbitrary number of parameters, any of which can be bound/unbound freely. The Query Explorer supports parameterized queries (parameter binding) through the Details/Filters panel on the right: by selecting a pattern in the tree, you have the ability to specify Filters for each parameter separately.

  • as pattern parameters can be scalars, such values can be entered by typing the string value or number, boolean literal etc.
  • object pattern parameters can be specified by the model element picker cell editor.

The finalPattern example is intended to highlight the most important advantage of the IncQuery pattern language over other (EMF) query languages: it has been designed to make the specification of complex graph queries involving multiple objects and inter-relationships compact and easy-to-understand.

This example also demonstrates the usage of IncQuery add-ons by query annotations:

  • @PatternUI allows the developer to customize the appearance of a pattern match in the Query Explorer tree. Inside the message, simple path expressions (only allowing direct EAttribute access) can be used inside $$ sections to include match-specific details.
  • @ObservableValue allows the developer to customize the appearance of a match inside the Details panel. It defines an observable value (in the JFace databinding sense) which can be bound to an Eclipse/JFace UI. This annotation will also trigger the generation of an additional .databinding side-project next to your IncQuery project, which includes some helper glue code that you can use to ease the integration of IncQuery into your application.
  • @Handler triggers the generation of a .ui side-project that contains a command handler class that can be used on instance model files inside e.g. the Package Explorer view (invokable from the right-click context menu, under the EMF-IncQuery submenu). The contents of this class illustrate the usage of the pattern matcher interface code that is generated by IncQuery inside your IncQuery project (inside the src-gen folder). This interface is used to invoke queries from Java code, and they are designed to make the integration of IncQuery features into any EMF application easy and straightforward.

Another annotation add-on, @Constraint (which is used to specify IncQuery-based well-formedness rules) is discussed in a separate example page: BPMN Validation.

Generated code overview

 

Outdated content

The contents of this section have been superseded by the following page on the Eclipse Wiki: 

http://wiki.eclipse.org/EMFIncQuery/UserDocumentation/API

We now briefly overview the source code generated by the IncQuery generator (inside the src-gen folder of your IncQuery project). This is not meant to be a very detailed description; it is recommended to check the code yourself for specific details and useful tidbits not discussed here.

Match and Matcher

The two most important components of the IncQuery Java integration interface are the _Match and _Matcher classes:

  • The _Match class represents a data transfer object, corresponding to a single match of your pattern. It is basically a tuple of objects that are identified by the header parameters of the pattern.
  • The _Matcher class is the main accessor interface to IncQuery's pattern matching engine:
    • 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).
    • it provides getter methods to retrieve the contents of the match set anytime.
    • it provides a convenience method (forEachMatch) for easy iteration over the match set -- the most frequent usecase.
    • finally, it provides a DeltaMonitor which can be used to track the changes in the match set in an efficient, event-driven fashion.

Using the Matcher

This example illustrates the most basic usage of the IncQuery API. In fact, this code is generated by the @Handler annotation add-on, and shows how to programmatically load and EMF instance model, initialize a matcher for it, and retrieve/process the results.

Introductory example: BPMN validation

Overview

The aim of this example is two-fold:

  • to demonstrate how well-formedness (validation) rules can be easily specified using EMF-IncQuery;
  • to demonstrate the generic integration capabilities of the IncQuery framework; that is, the ability to work with almost any EMF-based tool out-of-the-box, without having to touch the source code of the original tool.

It is a good idea to check the School example walkthrough before reading this page.

Prerequisites

A working configuration may look like this (note that there are other features installed here which are not strictly necessary for this example):

Getting the example

Download the IncQuery project and some sample instance models from github:

Make sure to build the bpmn.incquery project to ensure that the bpmn.incquery.validation auxiliary project is generated and compile error free.

Trying the example

  1. Run the bpmn.incquery and bpmn.incquery.validation projects in a runtime Eclipse Application.
  2. Open the bpmn.instancemodel/default.bpmn_diagram in the newly launched Eclipse.
  3. Activate the context menu inside the diagram editor, select Initialize EMF-IncQuery Validators.
  4. Make sure the Problems view is open. It should look as follows:

If you now insert a new Flow connector edge between "Lonely" and "SomeTask", the warning markers will be automatically removed on-the-fly by the IncQuery Validation Engine. Similarly, if you rename the "Simple" looping activity to "Looping activity", the "bad looping activity" marker will disappear.

  • You can try editing the model and observing how the validation status will change (hint: take a look at the sample code below, and check the two well-formedness rules badLoopingActivity and lonelyActvity).
  • You can also try clicking on the warning markers to reveal the offending instance model elements in the abstract syntax editor.
  • Finally, you can try how IncQuery validation performs on a larger, real-life BPMN model with some examples found in the bpmn.instancemodel/reallife folder.

Developing validation rules

In order to turn an IncQuery pattern definition into a well-formedness rule, you simply need to add the @Constraint annotation, which takes three parameters:

  • location identifies the pattern parameter which should represent a model element that will be the "location" of the violation of the rule. By design of the EMF Validation Marker API, only a single element is allowed to be designated as the location.
  • message defines the validation error/warning message that will be shown to the user.
  • severity can take either "error" or "warning", giving the developer the possibility to distinguish between these two frequent cases.

The @Constraint annotation will trigger the generation of an auxiliary .validation project which contains some glue code that registers your rule with the IncQuery Validation Engine. The Validation Engine is a generic component that works with the Reflective Ecore model editor, generated EMF tree editors and also GMF-based graphical editors such as the STP BPMN modeler. Additionally, the Query Explorer view is also generic in the sense that it supports the "Show location" feature (by right clicking on matches inside the tree, or double clicking on them) to reveal the instance model elements inside your GMF diagrams automatically.

As the general rule-of-thumb, a meaningful validation pattern should define the "bad case", i.e. match for those cases that represent a violation of the well-formedness constraint. A common technique to specify such patterns is to create a pattern for the "good case", and then use the neg keyword for negation (see lonelyActivity below for an example).

Metamodel pattern matching example: Ecore Queries

Overview

Have you ever tried to query a meta-model, i.e. a model consisting of EClasses, EAttributes, and EReferences, against a meta-model pattern? For an example, look here. In this case, we want to look for a certain sub-configuration in an Ecore metamodel, where two EClasses (each having an EAttribute of type EString) are connected by a 0-* EReference.

Use-cases of this technique include meta-transformation, meta-model analysis, higher-order transformations where transformation rules are generated/parameterized by metamodel analysis etc.

We would like to sincerely thank Christian Schweda for the inspiration for this example.

Obtaining the example

Make sure you run the latest IncQuery tooling and runtime by downloading and installing from the nightly update site.

Check out the source project from GitHub:

Running the example

  1. Import the ecorequery project into your workspace.
  2. There is a file in src/hu.bme.mit.incquery.ecorequeries.example directory: queries.eiq, right click on this, select EMF-IncQuery queries | Register patterns in Query Explorer.
  3. There is a useful, pre-prepared .ecore file in the models/sample directory: My.ecore. Open it, after that click on Load model in Query Explorer View (if you could not see this view then go to Window->Show View->Other->EMF-IncQuery->Query Explorer) .
  4. You should see the match of the pattern according to the specification found in hu.bme.mit.ecorequery/spec/example.pdf in Query Explorer view.

Sample pattern

The project contains a pattern named SampleQuery. This pattern looks for matches like the picture at the bottom in Ecore  Models.

In the first section the pattern filters out two EClasses (XElement,YElement) and the XElement contains a reference to YElement.

The find EReferenceWithStarMultiplicity(Relates); helper pattern filters out references only with star multiplicity. 

The find EClassWithEStringAttribute(XElement, Label1); and the find EClassWithEStringAttribute(YElement, Label2); helper pattern filters out EClasses which contains EString.

The neg find IsInECore(XElement); and the neg find IsInECore(YElement); excludes matching to elements located in Ecore.ecore.

Running EMF-IncQuery as an RCP application

 

Outdated content

The contents of this page have been superseded by the following page on the Eclipse Wiki: 

http://wiki.eclipse.org/EMFIncQuery/UserDocumentation/API

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:

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):

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).

Query-driven soft interconnection of EMF models (MODELS12)

We demonstrate how the incremental query evaluation of EMF-IncQuery can be used to maintain soft interconnections between EMF models stored even if they are stored separately, moved or modified without the all the corresponding models loaded at all times.

Overview

The interconnection of complex EMF-based system models imposes several technical problems due to the identification strategies of model elements in the EMF infrastructure. When serializing a model, a model element is either identified by a unique identifier generated by EMF, or by a relative path of containment hierarchy in the given EMF resource. These techniques are used when interconnecting models using associations (EReferences) e.g. for internal traceability purposes: the target end of the association points to an object resided in a different model resource. Such interconnections are also used in external traceability scenarios where inter-model links are introduced from traceability metamodel elements to existing metamodels which cannot be altered.

These scenarios demonstrate various shortcomings of the core EMF technology. First, (1) interconnected EMF model fragments with circular dependencies cannot be serialized. Furthermore, without truly intelligent multi-resource transaction management, (2) local changes in a model fragment may introduce broken links (and consequent runtime exceptions) unless all dependent model fragments are manipulated together in working memory. Such broken links require tool-specific resolutions --- with a worst case scenario of fixing the links manually by the designer using text editors (and not the modeling tool). Finally, (3) all traceability links captured by associations are explicitly persisted every time even if traceability links could be derived from existing unique identifiers.

Query-driven soft interconnections can overcome these challenges and due to the high performance of the EMF-IncQuery engine (see our Performance page), it can be applied in industry tools that handle models with millions of model elements. For example, in AUTOSAR the references between elements are defined in a way that only identifiers are stored and the references are created based on these. Our approach would be an elegant and efficient solution for managing the actual references between the elements using query-driven soft links

For more details on the approach, we suggest that readers to check out the complete paper.

Obtaining the example

  1. Install EMF-IncQuery as described here.
  2. Import the derivedModels, derivedModels.edit, derivedModels.editor, derivedTest, derivedTest.validation projects from the attached archive.
    1. Alternatively, you can check out the projects from https://github.com/ujhelyiz/EMF-IncQuery-Examples/tree/master/query-driven-soft-interconnections (see Generating the EMF-IncQuery code)

Demonstration

Used EMF metamodels

The process metamodel describes simplified business processes including activities (either tasks or gateways).

The system metamodel represents a set of jobs and data objects which are related to the tasks in processes.

The operation metamodel defines checklists which are connected to processes and contain menu and entry elements. Entries refer to tasks in the process of the checklist and jobs in the system model, while they also contain some runtime information as well. The runtime information is also referenced from the job connected to the entry.

  • System model
    • Job.tasks (refers to the Task in a Process model with the id included in the stored taskIds) and info (refers to an info that is contained by a checklist entry that refers this Job). Note that the definition of the Job.info soft link uses an other soft link (Data.jobs).

  • Data.writingTask and readingTask (both refer to Tasks in a Process model with the ids included in the stored taskIds)

  • Operation model
    • Checklist.process (refers to a process with the id stored in processId)

  • ChecklistEntry.task (refers to the Task in a Process model with the id included in the stored taskId) and jobs (since the elements in the System model do not have unique identifiers, the name of the Job and the name of the System that contains it are used as a path)

  1. Make sure to start a runtime Eclipse with each project included (derivedModels, derivedModels.edit, derivedModels.editor, derivedTest, derivedTest.validation).
    1. Alternatively, you can install these plugins into the host Eclipse using "Export -> Deployable plugins and fragments -> Install into host".

  1. Check out the derivedModels.example project from https://github.com/ujhelyiz/EMF-IncQuery-Examples/tree/master/query-driven-soft-interconnections into the workspace. The project contians 4 separate EMF models, which have no direct references to each other. This can be checked by opening one in it's own generated editor, or in the "Sample Reflective Ecore Model Editor". Referenced resources are loaded lazily, so you have to select each element to ensure that no other models are loaded (the models contain less than 10 elements each).
  2. First, open Simple.system in the "Sample Reflective Ecore Model Editor", navigate to the Job1 or Data elements. Note that the various task ids fields are set, but the tasks fields are not. These derived features will only have a value when the tasks they refer to are loaded.

  1. Next, use the "Load resource" menu, "Browse workspace", and select Simple.process, then press "OK" twice to load the EMF model into the editor. This model contains the tasks corresponding to the ids used by the soft links.

  1. Similarly, if you load the Simple.operation resource, the Job1.info field will be set, since the loaded operation model contains an entry that references Job1 using the name of the System that contains it and the name of Job1 as a path.

  1. Note, that you can move the files anywhere in the workspace (even in the file system), it won't break the soft links, since they are backed by queries that are evaluated on the loaded models and use information that doesn't depend on the location of the file. Similarly, you can also rename the files without affecting the soft links.

Since the soft-links are computed from attributes that use simple data type values, it is best to have integrated validation that can indicate broken links or links that violate some requirements. For example, the checklist entry refers to a task that is not part of the process that the checklist refers to:

Simply by adding the @Constraint annotation, the relevant source code is automatically generated. You can initialize the validation in the local menu of the "Sample Reflective Ecore Model Editor" (-> EMF-IncQuery -> Initialize EMF-IncQuery validators)

Check out our example for more details on the validation framework.

Developing soft links

Overview of the framework

To support soft links captured as derived features, the outputs of the EMF-IncQuery engine need to be integrated into the EMF model access layer at two points: (1) query results are provided in the getter functions of derived features, and (2) query result deltas are processed to generate EMF Notification objects that are passed through the standard EMF API so that application code can process them transparently.

 

The application accesses both the model and the query results through the standard EMF model access layer -- hence, no modification of application source code is necessary. In the background, our novel soft link handlers are attached to the EMF model plugin that integrate the generated query components (pattern matchers).
 
When an EMF application intends to read a soft link (B1), the current value is provided by the corresponding handler (B2) by simply retrieving the value from the cache of the related query. When the application modifies the EMF model (A1), this change is propagated to the generated query components of \incquery{} along notifications (A2), which may update the delta monitors of the handlers (A3). Changes of soft links and derived features may in turn trigger further changes in the results sets of other derived features (A4).

First, the soft-links are defined in the metamodels using features with the following configuration:

  • derived = true (to indicate that the value of the feature is computed from the model)
  • changeable = false (to remove setter methods)
  • transient = true (to avoid persisting the value into file)
  • volatile = true (to remove the field declaration in the object)

Next, the model code is generated and you can start preparing the query to back the derived feature. For defining derived features using queries, see our derived features example.

Generating the code

  1. Check out the derivedModels, derivedModels.edit, derivedModels.editor, derivedTest, derivedTest.validation projects from Git into an Eclipse with EMF-IncQuery installed.
  2. If the src-gen folder in the derivedTest  project is empty, invoke the code generation of EMF-IncQuery by selecting Project -> Clean from the menu.
  3. The glue code for initializing matchers and retrieving values from the handlers are automatically generated based on the @DerivedFeature annotations, as described in the linked example.

Using queries for derived features (ECMFA12)

 

We demonstrate how our high performance queries can be easily integrated with other EMF tools using an entirely new case study in which EMF-IncQuery is deeply integrated into the EMF modeling infrastructure to facilitate the incremental evaluation of derived EAttributes and EReferences.

Obtaining the example

  1. Install EMF-IncQuery as described here.
  2. Get the school-derived, school-derived.edit, school-derived.editor, school-derived-base projects from https://github.com/ujhelyiz/EMF-IncQuery-Examples/tree/master/derived-features-by-queries

Demonstration

  1. Open Perspective -> Plug-in Development
    1. Right click / Run As on school-derived-base/School-Derived.launch, select first option (School-Derived)
  2. In the runtime Eclipse, get school.derived.example from git (same repository and directory)
  3. Double-click on file My.school to open editor
    1. Right-click on the School element and select EMF-IncQuery-> Initialize EMF-IncQuery validators action
    2. Switch to Problems view
    3. Modify the model using the tree editor to see incremental update in markers
      1. Add new teachers to school (affects numberOfTeachers)
      2. Add new year and set startingDate higher than any existing year, also add classes to that year to see changes in the problems view (affects lastYear)
      3. Modify existing year, either set current last year startingDate lower or increase startingDate on another year (affects lastYear)
      4. Add courses and set teachers for them, or modify teachers for existing courses (affects teachersWithMostCourses)

Development

In order to integrate IncQuery into your own application, there are three different steps you have to perform. First, you have to indicate that given derived features in your model will be either volatile or provide proper notification themselves in case of changes. Second, you have to create the queries that correspond to the value of the feature. Finally, in case you would like to use derived features in future queries, you must indicate that the use of derived features is allowed in a particular pattern.

Well-behaving derived features

Derived features in general do not ensure that their value is volatile or that they will send notifications upon changes. Therefore, EMF-IncQuery, by default, does not explore the parts of the model which are only reachable through a derived feature, since the incremental query engine would not work properly without correct notifications. However, in some cases the application developer can ensure that a given derived feature will actually adhere to the above limitations (volatile or notification facility). In EMF-IncQuery, we call these features "well-behaving", since they behave correctly in regards to the query engine.

Well-behaving features can be registered through an extension point (org.eclipse.viatra2.emf.incquery.base.wellbehaving.derived.features), where the package namespace URI, the name of the classifier containing the feature and the name of the feature must be given. These extensions are read when the EMF-IncQuery runtime plug-in is loaded for the first time.

Example:

Implementing well-behaving features in Java

Existing applications that already make use of derived features most likely has some kind of implementation. In EMF applications, the value of a derived features is usually calculated from the value of local features of the given classifier or features of classifiers accessible through navigation from the classifier. Therefore, it is possible to define (during design) the set of dependant features that the value of a given derived feature depends on. These features are either non-derived features (and well-behaving by definition) or well-behaving by implementation, thus they will send notifications about changes.

In order to ensure that a derived feature is well-behaving, the notifications of dependant features must be listened to and proper change notifications must be sent when the value of the given derived feature changes due to a change in the value of a dependant feature. Implementing such behavior for each derived feature independently would require a huge effort, thus we decided to implement an enhanced version of the derived attribute notifier found here.

EMF-IncQuery now contains a Derived Feature Handler that can be used in any EMF application for registering dependant features for any derived feature. It provides a few convenience methods for adding dependant features and sends notifications about changes on the value of the derived feature. These methods can be used for adding local and navigated features to a handler for a given derived feature.

For example, if the teachersWithMostCourses, lastYear and numberOfTeachures features from the above example are used, registering can be done in the following way in the constructor of the classifier:

new DerivedFeatureAdapter(this, SchoolPackage.Literals.SCHOOL__NUMBER_OF_TEACHERS,
  SchoolPackage.Literals.SCHOOL__TEACHERS);

The number of teachers derived attribute only depends on the teacher local feature of School.

new DerivedFeatureAdapter(this, SchoolPackage.Literals.SCHOOL__LAST_YEAR,
  SchoolPackage.Literals.SCHOOL__YEARS, SchoolPackage.Literals.YEAR__STARTING_DATE);

The last year depends on the starting date attribute of the years of the given School.

new DerivedFeatureAdapter(this, SchoolPackage.Literals.SCHOOL__TEACHERS_WITH_MOST_COURSES, 
  SchoolPackage.Literals.SCHOOL__TEACHERS, SchoolPackage.Literals.TEACHER__COURSES);

The teachers with the most courses are calculated from the courses feature of the teachers in a given school.

IncQuery based derived features

Queries that are intended for use as derived features are developed in the same way as regular EMF-IncQuery queries. The only difference is that some of the generated code should be in the same project with the model code. Once the pattern builders, matchers and signatures are generated for the features, the glueing code is generated into the EMF model code directly.

Example queries, the derived features will be numberOfTeachers, teacherWithMostCourses and lastYear:

The @DerivedFeature annotation tells the code generator to handle the given pattern as a derived feature definition.

The generated code will look similar to the following:

First, at the first getter call of the derived feature, a derived feature handler is created with proper parameters:

The IncqueryFeatureHandler.getIncqueryDerivedFeature is a convenience method for instantiating and starting a feature handler. The first parameter is the source object, the second is the EStructuralFeature, the third is the pattern fully-qualified name usable for initializing the matcher for the appropriate query. The fourth parameter identifies which parameter of the signature is the given object, while the fifth identifies the target of the feature in the query signature. The sixth parameter defines what kind of derived feature value is required, counter kind will track the number of matches for the query, single and multi reference kinds define whether a single target or a list of targets are possible. The last two boolean parameters specify whether a cache is kept for the value and whether the query is matched in the containment subtree under the source or the whole resourceset (or resource if the resourceSet is not available).

The last thing to do is to implement the getter functions of the derived features. The IncQuery derived feature created previously has a getValue method that returns the current value of the given feature. In order to provide more type-safe ways of accessing the current value, there are three other methods: getIntValue() that returns the value of counter kind features, getSingleReference() returns a single object, while getManyReference returns a collection of objects. Note that in the case of many reference, the getter usually returns an EList, which should be instantiated in the getter as an unmodifiable list, this is already done with the getManyReferenceAsEList method.

Realtime gesture recognition with Jnect and Esper

Overview

This page is about a tech demo for EclipseCon Europe 2012. We connect Microsoft Kinect with Eclipse technologies using:
  • the Jnect plugin for processing Kinect Data
  • the Eclipse Modeling Framework as the underlying live model representation format
  • EMF-IncQuery for realtime pattern matching to recognize static gestures
  • the Esper complex event processor to recognize gesture sequences in the event stream generated by IncQuery.

The overall goal is to demonstrate that the combination of these technologies yields a system that is capable of recognizing gestures (both static states and dynamic sequences) in a (soft) realtime fashion with common, off-the-shelf hardware.

We are aware that gesture recognition can be implemented in many different (more efficient) ways, however the aim is to highlight the fact that Eclipse technologies and EMF(-IncQuery) in particular can be embedded into high performance applications, while retaining the well-known benefits of the model-driven/model-assisted approach.

Acknowledgements

We wish to thank István Dávid for help with Esper and Dr. Jonas Helming for providing the original idea for the "YMCA" demo.

Presentation

The following video illustrates the system in action as it was presented at EclipseCon Europe 2012:

 

The Jnect-IncQuery Realtime Complex Gesture Recognition Demo presented at ECE2012 from istvan Rath on Vimeo.

The following slideshow contains a high-level overview of the architecture:

 

Gesture recognition with Jnect, EMF-IncQuery, Esper and GEF3D from Istvan Rath

Trying the demo

Getting the code

The complete source code for this demo is available under open source licences at Github.

Please note that several modifications were required to the original Jnect source to make this work, so the Github repository contains all necessary sources for running the software - the original Jnect should not be present in your configuration.

Additional videos

YMCA

This video demonstrates the system in action. A test user performs the complete "YMCA" gesture sequence, where each character is represented by a particular body configuration as depicted here:

YMCA Gestures

Each character is recognized as a graph pattern match on the live body model, and converted into an " atomic recognition event". (Shown as e.g. "[Y]" in the upper text field.) The Esper CEP engine continuously analyzes the event stream (managing time windows while doing so) and whenever the complete "YMCA" (or "IQ") sequence is recognized the "[  YMCA  ]" character sequence is displayed.

The Robot Demo

This video demonstrates two features:

  • a gesture sequence (consisting of the "straight arm" as a starting state and the "bent arm" as the end state) is defined based on graph patterns and complex event patterns
  • this gesture sequence is then translated to operating system-level keypresses so that an external tool (Powerpoint) can be controlled.

How it works

The basis for this demo is the live EMF model maintained by the Jnect plugin. Essentially, Jnect converts the XML stream coming from the Microsoft Kinect SDK into an EMF instance model. In each "frame", the XML document contents are copied into the EMF model - these informations mostly contain coordinates of body parts. Approximately 20 such frames are processed per second.

Realtime pattern matching by EMF-IncQuery

Jnect's live EMF model is processed by EMF-IncQuery. EMF-IncQuery is an incremental query engine that instantiates complex graph-pattern based queries over EMF instance models, and automatically processes the model's changes (using the EMF Notification API) so that the query results are always kept up-to-date.

The "Y" pattern demonstrates an example for such a query. EMF-IncQuery queries are best read as a high-level, declarative specification (consisting of a set of constraints) that need to be fulfilled by the model. Those model parts that fulfil the constraints of the query make up the match set.

In this example, the "match set" of the Y query will consist of a tuple defined by the RH, RE, RS, LH, LE, LS, H variables that will be bound to the EObjects corresponding to the user's body parts. The Y pattern is fulfilled if the body of the user reaches a state where all sub-queries (constraints) of the Y pattern hold.

The "upperArmsInY" pattern may be of particular interest. This pattern is used to define a geometrical constraint on the upper arms of the user. EMF-IncQuery allows the developer to include Xbase expressions (that will be compiled to Java code) and here this feature is heavily used to wire vector math calculations into the query.

Complex event detection by Esper

EMF-IncQuery not only keeps the result/match set of queries up-to-date all the time, but it also provides event-driven deltas through its DeltaMonitor API that allows the developer to process changes in the query results in an efficient, event-driven way. 

Feeding IncQuery pattern match events into Esper's event stream

This code snippet demonstrates how the DeltaMonitor API can be used. In each turn (the callbackAfterUpdates callback Runnable is called ONLY if there is a change in the result set of the query -- that is, the body state has changed enough so that gestures need to be updated), the .matchFoundEvents and .matchLostEvents collections are processed and each newly found match is converted into a PatternMatchEvent DTO that will be pushed into the Event stream.

Recognizing IncQuery pattern match events in discrete time windows

The Esper complex event processor is then used to process the stream of such events.

The AtomicPatternFilter demonstrates a basic EPL query that picks out a single ("distinct") atomic pattern match event from a 1 second time window, and then

EventPatternListener provides feedback into the Esper event stream, turning the isolated low-level PatternMatchEvent into an EsperMatchEvent.

Recognizing complex event patterns

Finally, complex event filters such as YMCAFilterWithWindowFeedback are used to search the stream of higher level EsperMatchEvents for complete gesture sequences like "YMCA".

 
 
 

EMFxcel: Having Fun with Excel and Eclipse Modeling Tools

In order to be able to do advanced data processing and visualization with technologies I am familiar with, I created a simple tool to process Microsoft Excel® documents using Eclipse Modeling Framework. The solution consists of an Xcore-based Excel domain, and a slightly modified EMF generated editor that is able to open Excel files directly as EMF instance models via Apache POI, and automatically track and propagate changes as the opened file is being simultaneously modified in Excel. I demonstrate live data processing using EMF-IncQuery graph queries, and live data visualization using IncQuery Viewers.

The source code and sample models that belong to this example is found at https://github.com/ujhelyiz/EMF-IncQuery-Examples/tree/master/emfxcel, and it requires the brand new EMF-IncQuery 0.8 release that can be downloaded from the Eclipse Marketplace (among others).

The problem

In my experience, next to traditional programmer tools such as IDEs and compilers, Microsoft Excel® is one of the most frequently used software development programs. This is because even today, many organizations tend to keep documentation, requirements, and other auxiliary data related to software development processes in Microsoft Office documents, and particularly Excel spreadsheets. Managers love spreadsheets, right? :-)

So, many of us need to work with Excel documents, and sometimes this goes beyond just opening these files and looking at their contents. What if, say, you need to process the contents programmatically, in order to perform (non-trivial) calculations or extract data to feed into some other program? The obvious solution, one might think, is to use Excel's built-in facilities such as macros.

Here is a simple example problem that I had to solve the other day (I modified the contents and schema to simplify things quite a bit). We have a document that consists of multiple worksheets, each of which contains several rows and columns — in our example, students and courses. We want to check if there are any students who applied to multiple courses, and if there are any who applied to none. 

So, what if you are like me, and don't want to learn advanced Excel magic just to be able to do a few such tricks using Excel data? Furthermore, what if you are already familiar with Eclipse Modeling? Isn't there a way to map Excel into an EMF model and use your favourite Eclipse Modeling technologies such as EMF-IncQuery and Xtend to do the processing? Now there is.

The solution

I was initially sure that this is such a common problem that somebody must have already come up with something. It turned out not to be the case, so I rolled my own and it proved to be a very smooth and pleasant experience. Read on below.

Modeling Excel in Xcore

The first step is to create a simple domain model to represent Microsoft Excel documents as EMF instance models. I used the excellent Xcore framework to draft such an Ecore domain model in an easy-to-use textual syntax. See below for the code.

My approach was to build something simple but already powerful and easily extensible. The basic building blocks (Workbook, Worksheet, Row and Cell) are motivated by the concepts of the Apache POI library and I added a bit of redundancy (namely, explicit indices in Cell elements) to make data processing easier later on. Data types are handled by subtypes of Cell such as BooleanCell, StringCell and NumericCell. These few subtypes were enough for my purposes, but other can be easily added if necessary.

Generating the EMF Editor

The next step is to generate an EMF model editor, in order to be able to test drive our domain model. (I know, this could be done using dynamic instances, but I prefer generated editors.) So I added the @Ecore and @GenModel annotations to my Xcore file (see above) so that the necessary code is generated. Once that is done, I ran the generated editor as an Eclipse Application and created some example models similar to the one below.

Overriding the Editor

The final touch was to make sure that the editor can open actual Excel documents and instantiate my domain model with their contents. As stated before, I integrated the Apache POI library and wrote some simple code to do the transformation from POI objects to the corresponding EObject counterparts. See the populateResource() funtion below for details.

My editor contains a further enhancement: it registers a listener on the workspace, so that whenever the opened file is changed from the outside (e.g. by Excel), this change is picked up and the contents of the EMF instance model are repopulated with new data. This will be important later on. See the registerResourceChangeListener() function below for details.

Once these things were done, I was able to open actual .xlsx files with my editor and see their contents. Now on to the fun part.

Model Queries with EMF-IncQuery

Okay, let's do some live data processing on our Excel documents. To solve my problem, I wrote a couple of EMF-IncQuery queries. If you are not familiar with the syntax of the language or how the IncQuery development tools work, I suggest to read the IncQuery Wiki, and check out some other, more detailed examples.

Here, I am making full use of a new IncQuery 0.8 feature called "Query Libraries", which allows to reuse queries defined in a different file (which may be in a different project or bundle, as long as it is available on the classpath of my IncQuery project). So first, I wrote some generic queries that will be helpful to more concisely and simply code queries specific to my problem. See the code below.

In this query library shown in the snippet above, I wrote three helper queries:

  • CellInWorksheet(C: Cell, WorkSheetName, RowNum, ColNum) is useful to identify individual cells by a worksheet name (that you can see on the Excel UI), and the respective row and column indices (all integers starting from 0).
  • NamedColumn(WorkSheetName, ColName, ColNum) is useful to identify a column index as a "named" column, i.e. when the 0th row contains the string substituted for ColName.
  • valueInNamedColumn(wsName, colName, rowNum, value) is useful to "extract" a cell value from a worksheet and named column, indexed by row number (rowNum).

My problem-specific queries demonstrate the usage of the last one (the first two are actually only used internally). See below.

Here, I am now writing domain-specific queries using the generic queries defined in my query library above.

  • student(name, id)teacher(name) and enrolledStudent(courseName, teacherName, studentId) are helper queries that aid in identifying important concepts.
  • didNotApplyForAnyCourse(name) and appliedToMultipleCourses(name) are the queries that finally solve the original problem.

The screenshot below illustrates what I see after loading both the query definitions and my example instance model into the Query Explorer using the green play button.

Visualization with IncQuery Viewers

IncQuery Viewers is an add-on to EMF-IncQuery that is intended to support powerful and automatic data visualization using standard Eclipse UI technologies such as JFace and Zest. The basic idea is that using Viewers, query results can be automatically mapped to UI contents such as list/tree entries or graph nodes and edges. It is important to note that this is live visualization, which means that whenever the underlying model changes, the query results are incrementally recomputed by EMF-IncQuery, and these changes are also incrementally propagated to the UI through Viewers.

To showcase the powerful visualization capabilities of IncQuery Viewers, I added a couple of annotations to my domain-specific queries above.

  • @Item annotations are used to make students and teachers appear as items (list/tree entries and graph nodes),
  • @Edge annotations are used to make relationships computed as query match results appear as graph edges.

The screenshot below demonstrates how the results are automatically rendered by IncQuery Viewers as a 2D graph powered by the Zest framework. The IncQuery Viewers Sandbox view is triggered automatically by right clicking on the queries in the central section of the Query Explorer, and selecting "Reinitialize IncQuery Viewers" from the menu.

Tracking Changes Automatically

OK, on to the final touches: we want to make sure that whenever we edit the document in Excel, the changes are propagated into the Eclipse tool so that query results and visualization contents are automatically updated. We turn on native hooks in order to make Eclipse automatically react to external file changes (since Excel will be running outside of Eclipse, of course). The setting is found under Preferences.

Let's see how this works. The screenshot below shows my Excel documents at the staring point.

This is what I see in my Eclipse tool:

Now let's assume I do some editing in my Excel document (I add a new row to the Courses worksheet), and then push save:

After a few milliseconds, the changes are automatically propagated into Eclipse, and the contents of the Query Explorer and the IncQuery Viewers Sandbox are updated according to my changes.

That's it!