-
Notifications
You must be signed in to change notification settings - Fork 0
Event driven Programming over the Xtext Index
The following figure describes the internal data model of the Xtext index:
The Manager is the top level component of the index, that stores resource descriptions, representing files. A resource description exports a set of object descriptions that describe objects that can be referenced from another file using a Qualified name. Furthermore, it contains Reference Descriptions to describe all elements that are imported/referenced from another resource.
The EObjectDescription instances do not contain any direct references to the EObject instance it was created from; but it contains enough information to resolve from the resource if required. It is also possible to store language-specific information in the userData field, but there is no language-independent way to process this information. If some additional information not stored in the index is required, the backing resource needs to be resolved, and the results processed. This is in line with the indexing mechanism of JDT, where the Java Object Model contains the high level structure of the Java files; and an AST can be parsed by opening the backing model.
It is also possible to get notifications from index changes, where a change event can be described using the following interfaces:
/**
* A delta describing the differences between two versions of the same {@link IResourceDescription}. Instances have
* to follow the rule :
* <p>
* <code>getNew()==null || getOld()==null || getOld().getURI().equals(getNew().getURI())</code>
* </p>
* and
* <p>
* <code>getNew()!=getOld()</code>
* </p>
*
*/
interface Delta {
/**
*@return the uri for the resource description delta.
*/
URI getUri();
/**
* @return the old resource description, or null if the change is an addition
*/
IResourceDescription getOld();
/**
* @return the new resource description, or null if the change is a deletion
*/
IResourceDescription getNew();
/**
* @return whether there are differences between the old and the new resource description.
*/
boolean haveEObjectDescriptionsChanged();
}
interface Event {
/**
* @return the list of changes. It is never <code>null</code> but may be empty.
*/
ImmutableList<Delta> getDeltas();
}
To summarize, a change Event contains a list of Delta instances, while a Delta describes all changes in a single resource. It has the old and new version of the Resource Description, so it is possible to calculate a change from it. However, it is important to note that it is not possible to resolve the references for the old version, as the old version of the backing resource is not available anymore. In other words, the event handler has to make sure the traceability information are keyed using the contents of the index instead of the AST of the language.
The Github repository incquery-evm-xtext contains a prototype integration of the event-driven virtual machine (EVM) used by EMF-IncQuery and VIATRA that uses the Xtext index as an event source.
Considering the various aspects, we have identified two event models using the Xtext index:
- The Xtext index contains all information required for the view definition (e.g. we want to list all classes inferred from Xbase languages), the Xtext index events contain enough information, and the view can be defined easily. For this to work, we have to react to object change events.
- The view uses additional information information only available in the abstract syntax tree, but we want to update the view if the model changes. By receiving notification for resource change events, it is possible to limit what part of our model needs to be updated.
An important aspect of EVM is that it separates event receiving and event handling, thus it is possible to only fire transformation rules when the input model is in a consistent state (e.g. in case of Xtext, the Xtext builder is not running, or manual updates).
The following figure depicts how the Xtext-EVM integration works:
After a file is changed in a project with the Xtext nature, the Xtext builder is triggered. This builder has multiple responsibilities: in addition to creating the generated code, it also makes sure that the Xtext index used for resolutions is up-to-date.
The EVM instance can register listeners on the Xtext Index, thus receiving Xtext Event instances. These Events are converted into EVM-specific internal events of two categories: resource description changes and object description changes. When creating an application over EVM, these events are handled by corresponding rules.
Furthermore, EVM provides two additional components to specify the execution of the rules: schedulers and conflict resolvers. The scheduler is responsible for triggering rule executions - it is expected that rules are triggered only when the environment is in a consistent state. We have a scheduler instance available that schedules rule execution every time a build is completed. A conflict resolver is used to specify rules of how to select the next rule to activate - e.g. based on priorities.
To illustrate how to set up rules, lets consider a simple logging example that prints out every model change automatically.
An example for defining a rule that reacts to resource change events can be done as follows by printing the change to the standard output:
resourceRule.action(XtextIndexActivationState.APPEARED) [
println("Resource appeared: " + it.URI)
].action(XtextIndexActivationState.UPDATED) [
println("Resource updated: " + it.URI)
].action(XtextIndexActivationState.DISAPPEARED) [
println("Resource disappeared: " + it.URI)
].build
A similar example for a rule that reacts to object change events (note that each lambda has now two parameters):
objectRule.action(XtextIndexActivationState.APPEARED) [resource, object |
println('''«object.EClass.name» «object.name» appeared in «resource.URI»''')
].action(XtextIndexActivationState.UPDATED) [resource, object |
println('''«object.EClass.name» «object.name» appeared in «resource.URI»''')
].action(XtextIndexActivationState.DISAPPEARED) [resource, object |
println('''«object.EClass.name» «object.name» appeared in «resource.URI»''')
].build
In order to demonstrate how this approach works, we have set up three further examples that reuse the same event-driven virtual machine, but can be set up one by one separately. The first example is a Console logger: a rule that logs all events to the Console view. The second example presents all inferred JVM types as a list in a separate view: this example uses only information directly available in the Xtext Index, thus it does not require to load the models. Finally, a graphical view is created for a specific programming language, that draws a call graph between different elements. To find these connections, the EMF-based IncQuery Viewers framework is reused; and the Xtext-EVM integration is used to make sure that all required elements are loaded and updated correctly for the viewer.
- Home
- [Incremental View over Xtext Models - Overview](Incremental View over Xtext Models)
- Event driven Programming over the Xtext Index
- Getting Started
- Examples