Skip to main content
Jump to: navigation, search


< VIATRA‎ | Integration
Revision as of 06:56, 29 October 2013 by (Talk | contribs) (Metamodel (Library.xcoreiq))

Aim of the project

The Xcore [4] project aims to provide a textual syntax for the definition of EMF metamodels. You can use it not only to specify the structure of your model, but also the behavior of your operations and derived features as well as the conversion logic of your data types. It eliminates the dividing line between modeling and programming, combining the advantages of each.

Viewing the scope of the EMF-IncQuery [1][3] project an idea may immediately arise; it would be really nice to use the powerful pattern language of EMF-IncQuery to define derived features in your Xcore metamodel. This project aims to support exactly this functionality, that is, beyond the standard Xcore way to define derived features (basically with Xbase expressions), it is now possible to refer to pattern definitions in the Xcore files. One can specify which pattern should serve as the underlying logic for the evaluation of the given derived feature in runtime.

Another key benefit of using EMF-IncQuery to define derived features is that these features are well-behaving features [6] as opposed to most of the standard derived features in EMF. A derived feature is well-behaving if proper change notifications are sent upon modifications of the underlying model elements. However, this does not hold for regular derived features which usually have no field (meaning that they do not store the current value) therefore they are unable to send proper notifications (e.g. SET oldValud to newValue).

The integration was developed as seamlessly as possible; all the original Xcore semantics and toolset are still available, however, the IncQuery Xcore editor now supports the definition of the above mentioned features with additional features like validation, proposal providers, etc.


  1. Java JRE or JDK (1.6 or above)
  2. Eclipse Kepler (4.3)
  3. Xtext 2.5 M2 SDK
  4. EMF all in one SDK 2.10 milestone & Xcore
  5. EMF Transaction
  6. GEF4 Zest Visualization Toolkit SDK integration (optional - install it if you want to use the GEF4 feature of EMF-IncQuery)
  7. GMF Runtime SDK, Graphiti SDK from Kepler update site (optional - install it if you want to use the GMF / Graphiti feature of EMF-IncQuery)
  8. EMF-IncQuery with Xcore integration

Overview and example

You can get a really good overview about the Xcore project if you browse through the official tutorial In this section we will use the same metamodel but with additional derived feature definitions. In order to start trying out the tool, create a new Xcore project and an IncQuery & Xcore file with the file extension .xcoreiq.

Note that, at the moment you can only use the IncQuery support for Xcore files if the metamodel and the patterns are defined in the same project, that is, the project must have both Xcore (Xtext) and IncQuery natures.

The metamodel is originated from the well-known library example from the EMF examples. We will model some simple entities like Library, Books and Writers. We also want to store the authors of these books and various properties like citations between the books, the own books of an author, etc. You can obtain the library examples from the EMF-IncQuery Examples git repository [2] (library folder). The metamodel in the library.domain.base project contains some basic derived features while the metamodel in the library.domain project contains other, more complex derived feature definitions.

Two kinds of IncQuery-backed derived features can be defined:

  • attributes (EAttribute) with the 'incquery-derived' keyword. Naturally, the type of these features can only be primitive types
  • references (EReference) with the 'incquery-derived refers' keyword. The type of these features can be any reference type (user-defined classes for example)

Metamodel (Library.xcoreiq)

class Library {  
	String name 
	contains Writer[] writers opposite library
	contains Book[] books opposite library
	// derived features
	incquery-derived refers Book[] suspiciousBooks spec validation.suspiciousBook
	incquery-derived BookCategory mostPopularBookCategory spec mostPopularBookCategory

class Writer {
	String firstName   
	String lastName
	container Library library opposite writers
	refers Book[] books opposite writers
	// derived features
	incquery-derived String name spec writerName
	incquery-derived Double averageNumberOfCoauthorsPerBook spec averageNumberOfCoauthorsPerBook
	incquery-derived refers Writer[] coAuthors spec coAuthorsOfWriter
	incquery-derived refers Book[] ownBooks spec ownBooksOfWriter

class Book {
	String title = "" // set a default value
	Integer pages
	BookCategory bookCategory
	refers Book[] citations
	refers Writer[] writers opposite books
	container Library library opposite books

	// derived features
	incquery-derived Integer numberOfCitations spec numberOfCitations 
	incquery-derived refers Book[] allCitations spec allBookCitations 
	incquery-derived Integer numberOfWriters spec numberOfWriters

enum BookCategory {
	Mystery = 0,
	ScienceFiction = 1,
	Biography = 2

Here we have defined 3 classes and the BookCategory enumeration for specifying the category of a book. The formal definitions of the derived features:

  • Library.suspiciousBooks (reference): the list of those books which (1) has an empty title or (2) transitively cites itself
  • Library.mostPopularBookCategory (attribute): the most popular book category of the library (no other category has more books)

  • Writer.ownBooks (reference): the feature should return only those books that have the writer as the only author (no co-authors for the given book)
  • Writer.writerName (attribute): the name of the writer is simply obtained by concatenating the first name and the last name together
  • Writer.coAuthorsOfWriter (reference): the feature references all other writers who is a co-author of this writer (they share a Book)
  • Writer.averageNumberOfCoauthorsPerBook (attribute): the number of co-authors divided by the number of books of the writer

  • Book.allCitations (reference): the feature should return all citations for the given book. This will be computed transitively, that is, if the citations are B1 -> B2 and B2 -> B3 then the set of all citations for the B1 book will contain both B2 and B3.
  • Book.numberOfCitations (attribute): the size of the Book.allCitations feature's value (the number of all citations)
  • Book.numberOfWriters (attribute): the number of the co-authors for the given book

Pattern definitions (LibraryPatterns.eiq)

pattern ownBooksOfWriter(W : Writer, B : Book) {
	Writer.books(W, B);
	find numberOfWriters(B, N);
	N == 1;
pattern allBookCitations(B1 : Book, B2 : Book) {
	find bookCitation+(B1, B2);

pattern bookCitation(B1 : Book, B2 : Book) {
	Book.citations(B1, B2);

pattern numberOfCitations(B1 : Book, N) {
	N == count find allBookCitations(B1, _B2);

pattern numberOfBooksOfWriter(W : Writer, N) {
	N == count find bookOfWriter(W, _B);

pattern numberOfWriters(B : Book, N) {
	N == count find writerOfBook(B, _W);

pattern writerOfBook(B : Book, W : Writer) {
	Book.writers(B, W);

pattern bookOfWriter(W : Writer, B : Book) {
	Writer.books(W, B);

Details of some pattern definitions:

  • numberOfWriters: returns the number of Writers for a given Book. It uses the count construct with the writerOfBook pattern.
  • numberOfBooksOfWriter: returns the number of Books for a given Writer. Similarly, it uses the count construct, but with the bookOfWriter pattern.
  • allBookCitations: returns all of the citations for the given Book. It uses the transitive closure of the bookCitation pattern.
  • ownBooksOfWriter: returns the own Books of a given Writer. It uses the numberOfWriters pattern, where the value of parameter N must be exactly 1.

Referring to the generated EPackage in the eiq file

An interesting problem arises when we want to develop the xcore and eiq files in parallel: in the metamodel we would like to specify derived features which would use pattern definitions which rely on the metamodel elements. To overcome this cyclic dependency problem, the eiq file editor uses the Xtext index and scoping when proposing EPackage imports. During the editing of the xcoreiq file, the corresponding EPackage is generated in the runtime, but the appropriate entry will only be inserted into the plugin.xml file if the xcoreiq file is error-free.

Generated Artifacts

If you edit and save the xcoreiq file the genmodel for the Ecore metamodel will be regenerated and the EMF model code will also be generated under the src-gen folder. You can customize further the various aspects of the code generation (name of the edit / editor plugins, source folders, etc. basically everything that you are used to while editing the properties of a standard Ecore metamodel). I just want to point out two annotations that you can use in the xcoreiq file:

  • @GenModel(editDirectory="/incquery.xcore.library.example.edit/src"): specifies the directory of the sources for the edit plug-in
  • @GenModel(editorDirectory="/incquery.xcore.test.editor/src"): specifies the directory of the sources for the editor plug-in

If the given projects do not exist, then those will be created and the appropriate code will be (re)generated.

The generated metamodel artifacts can be used in two different use cases:

  1. Dynamic Instance Mode: debugging of metamodels and queries are made easy with this functionality. One can develop the metamodel and queries at the same time, in the same workspace. You just need to create a dynamic instance model and you can modify your model on the fly. All the values of the features can be observed through the Properties View of Eclipse. Note that, this mode does not require the code to be generated, it infers everything from the xcoreiq file itself. The creation of a Dynamic Instance Model is described in the Xcore tutorial briefly.
  2. Using the Generated Code: this is the standard way of using the generated EMF plug-ins (model/edit/editor/test). Note that, if you have created your metamodel with Xcore there will not be any genmodel file present, the same functionality is provided by the xcoreiq file itself. Actually, the plugin.xml entry about the org.eclipse.emf.ecore.generated_package extension refers to the full path of the xcore

In either case, the IncQuery engine will be automatically initialized and maintained after model changes without any additional user interaction. The IncQuery backed derived features are well behaving features and they provide proper EMF notifications after model manipulations.

Advanced issues

This section describes some interesting aspects of the implementation. 

The Xtext language and language artifacts for the project

The language extends the Xcore language and adds some additional metamodel elements for the definition of the IncQuery based derived features. The Ecore metamodel of the language is created explicitly (not generated by the Xtext generator). The mwe2 workflow was customized to generate only those language artifacts which cannot be reused from Xcore (own proposal provider, additional validators, etc. were implemented).


The value of the derived features is computed by SettingDelegates [5] in both cases. The org.eclipse.incquery.querybasedfeatures.runtime.QueryBasedFeatureSettingDelegateFactory class is used to create the delegates. This class is registered in an org.eclipse.emf.ecore.setting_delegate extension point.

In the Dynamic Instance case the delegate instance is simply set for the EStructuralFeature.Internal object with the following code:

IQuerySpecification<? extends IncQueryMatcher<? extends IPatternMatch>> spec = QuerySpecificationRegistry.getOrCreateQuerySpecification(pattern);
                        ((EStructuralFeature.Internal) eStructuralFeature).
                            setSettingDelegate(((QueryBasedFeatureSettingDelegateFactory) factory).
                                    createSettingDelegate(eStructuralFeature, spec, true, true));

The generated EMF model code is a bit different, because there we use special annotations for the Ecore metamodel. First we annotate the EPackage itself to use the query based feature factory for the creation of setting delegates and then we annotate the features itself. The annotation will hold the fully qualified name of the pattern that should be used for the evaluation of the feature. This way the query based feature factory will know which matcher to look up from the available ones and the delegate will be backed by that given matcher instance. The EMF code generator will then generate the appropriate contents for the EMF Impl classes based on SettingDelegates. For more details take a look at the org.eclipse.incquery.xcore.generator.IncQueryXcoreGenerator.xtend class.

Class inference for the Dynamic Instance Model

If you create a new Dynamic Instance Model and open the Sample Reflective Editor you will see that a lot of Resources are loaded under the ResourceSet. This is because some Java classes are loaded during the inference of the pattern matcher artifacts. However, if you want to edit the contents of a reference in the instance model you will see that for the first time you have to wait 1-2 minutes until the editor will be responsive again. This is because the Properties View triggers some code which will load a lot of Java classes into the ResourceSet, even if those classes are not needed at all later. This would also affect the performance of the EMF-IncQuery engine, so the scope of the pattern matching is restricted to Resource scope. Another important thing is that the EMF-IncQuery Base Index is working in Dynamic EMF mode for the Dynamic Instance Model case.

Nevertheless, you will not notice any performance degradation when you use the generated EMF model plug-in in your own application.


  • Interlinking separate EMF instance models
  • Most of the tools provide hard links (like Autosar); storing identifiers of inter-model elements as Strings or some numeric id
  • EMF-IncQuery backed derived features introduce the so called soft-links

Resources and useful links

  1. EMF-IncQuery git repository:
  2. EMF-IncQuery Examples git repository:
  3. EMF-IncQuery homepage:
  4. Xcore tutorial:
  5. An overview about the EStructuralFeature SettingDelegates:
  6. An overview about the EMF-IncQuery backed derived features:


  • Traceability modeling should be also discussed in the example.
  • Validation of instance models. Model elements can have a derived 'isValid' feature; additional functionality (in this case validation) can be defined in the model itself. * IncQuery Viewers may be included in the example.

Back to the top