Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "VIATRA/Integration/MWE2 Integration"
(Finished up modifications) |
|||
Line 4: | Line 4: | ||
== Motivation == | == Motivation == | ||
− | + | Defining heterogeneous model transformation chains using a specialized description language. | |
− | *Sequence of model transformation steps can be easily specified and maintained. | + | * Sequence of model transformation steps can be easily specified and maintained. |
− | *Nontrivial side-effect relations between transformation steps can be handled. | + | * Nontrivial side-effect relations between transformation steps can be handled. |
− | *The execution of event-driven | + | * The execution of event-driven transformations can be explicitly controlled. |
− | *Because of the specialized language, the description code base is short and easily expandable. | + | * Because of the specialized language, the description code base is short and easily expandable. |
== MWE 2 Basics == | == MWE 2 Basics == | ||
Line 16: | Line 16: | ||
== VIATRA MWE2 Integration Library == | == VIATRA MWE2 Integration Library == | ||
− | The VIATRA MWE2 Integration library provides support for defining complex transformation chains using Xtext MWE 2 workflows. As it can be seen on the figure below, | + | ===Overview=== |
+ | The VIATRA MWE2 Integration library provides support for defining complex transformation chains using Xtext MWE 2 workflows. As it can be seen on the figure below, the transformation chain itself is an MWE2 component, meaning that it can be easily integrated into higher level modeling workflows. | ||
[[File:VIATRAMWE2.png]] | [[File:VIATRAMWE2.png]] | ||
− | + | The transformation chain consists of different typed transformation steps. These are the following: | |
+ | |||
+ | * Composite transformation steps: The composite steps are responsible for creating the control flow of the model transformation chain. These steps (Sequence, Loop, Conditional, Parallel) can contain other transformation steps. Once a given composite transformation step is executed, it will call its sub-steps in a specific manner (For example in case of Sequences, execute the contained steps in their order of appearance). | ||
+ | * Model Transformation Steps: These steps cannot contain any child steps, meaning that they are used for implementing actual model transformations. They have access to the workflow context, to and from which they can push and pull data. They can also communicate directly with each other using parametric messages. | ||
+ | |||
+ | ====Messaging==== | ||
+ | |||
+ | * The MWE2 integration library implements basic publish/subscribe based messaging. Transformation steps can publish messages to certain topics. If an other transformation step is subscribed to that given topic, it will receive the message as the execution token reaches the target step. Once the target step processes the message, the topic is informed about the act, and the message is deleted from the topic. | ||
+ | |||
+ | * Topic management: A message broker is responsible for the management of the individual topics. It enables the transformation steps to subscribe to any existing or new topic. It is also responsible for handing the incoming messages to the appropriate topic. Transformation steps can also query the message broker for the now messages on their subscribed topics. | ||
+ | |||
+ | * Message creation and processing: Message creation is done by message factories. These user specified objects can create messages with certain parameters. Message processors on the other hand are used by the transformation steps to process certain typed incoming messages. | ||
+ | |||
+ | * SubscribeTo and PublishTo objects: These objects represent publications and subscriptions on the transformation step's side. They store which message factory or processor should be used with the specified topic. | ||
+ | |||
+ | ====Control flow==== | ||
+ | As mentioned before, the execution sequence of transformation steps can be defined by a standard control statement hierarchy, similar to imperative languages. The following control statements are supported: | ||
+ | |||
+ | * Transformation Chain: Transformation chains area the root elements of the control hierarchy. They can contain other transformation steps (they cannot contain transformation chains), which will be executed in order of their addition to the chain. | ||
+ | |||
+ | * Sequence: Sequences are basic control elements. They contain other transformation steps, and execute them in the order of their addition. | ||
+ | |||
+ | * Conditional: Conditional statements decide which one of their child transformation steps will be executed (these can be sequences, loops etc.), based on the validity of a condition specified by the user. | ||
+ | |||
+ | * For loop: Simple 'for' loop, it will iterate through its child elements, N times, where N is directly specified by the user using a numeric literal, or calculated dynamically. | ||
+ | |||
+ | * Foreach loop: Loop that iterates through an IIterable element provided by the user. | ||
+ | |||
+ | * While loop: A simple 'while' loop that will iterate through its child elements as long as the condition provided by the user appears to be valid. | ||
+ | |||
+ | * Do..While loop: Similar to the 'while' loop, however instead of checking the condition '''before''' each cycle, this one checks it '''after''' it. | ||
+ | |||
+ | * Parallel: Control statement that enables the parallel execution of transformation steps. Steps contained by this element will be assigned to independent threads. Note, that trasnformation steps that take part in a two way communication with one another should not be added to parallel sections, as in case of parallel execution timing errors can occur(lost messages, double messages etc.). | ||
===Prerequisites and Installation=== | ===Prerequisites and Installation=== | ||
+ | ====Update site installation==== | ||
+ | |||
+ | '''No update site yet, This section will be revised after addition''' | ||
+ | |||
+ | ====Source Installation==== | ||
In order to use this library, the following Eclipse plug-ins are required: | In order to use this library, the following Eclipse plug-ins are required: | ||
− | *Eclipse Modeling 4. | + | *'''Eclipse Modeling 4.5 Mars''' recommended |
− | *EMF-IncQuery 1. | + | *'''EMF-IncQuery 1.1.0''' --> http://download.eclipse.org/incquery/updates/integration |
− | * | + | *'''Xtext SDK 2.8.3''' --> http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/ |
After the prerequisites are met clone the following repository and import the contained projects. Note, that it contains the source of the VIATRA framework as well. | After the prerequisites are met clone the following repository and import the contained projects. Note, that it contains the source of the VIATRA framework as well. | ||
https://github.com/lunkpeter/org.eclipse.viatra | https://github.com/lunkpeter/org.eclipse.viatra | ||
− | ===Library Classes=== | + | ===Library Classes and Interfaces=== |
− | The library defines a set of base classes which represent the main elements the previously described transformation workflow semantics. User defined behavior can be added | + | The library defines a set of interfaces and abstract base classes which represent the main elements the previously described transformation workflow semantics. User defined behavior can be added via the extension of these elements |
====Interfaces==== | ====Interfaces==== | ||
− | *''' | + | *'''ICompositeStep''': Defines the interface of composite transformation steps that can contain other steps. |
*'''ITransformationStep''': Interface that defines the main entry points of transformation steps. The user defined functionality can be implemented in the execute, initialize and dispose methods. | *'''ITransformationStep''': Interface that defines the main entry points of transformation steps. The user defined functionality can be implemented in the execute, initialize and dispose methods. | ||
− | *''' | + | *'''ITopic''': Defines the interface of topics. It includes methods for publishing and querying messages, as well as managing subscriptions. |
− | *''' | + | *'''IMessage''': Interface for messages, defines methods for getting and setting the message parameter. |
− | *''' | + | *'''IMessageFactory''': Provides an interface for creating certain typed messages. As messages contain parameters, message- and parameter types are specified as generic type parameters. |
− | *''' | + | *'''IMessageProcessor''': Provides an interface for creating certain typed messages. As messages can contain parameters, message- and parameter types are specified as generic type parameters. |
− | *''' | + | *'''ISubscribeTo''': Defines methods that enable the simple usage of topics and message factories. |
− | *''' | + | *'''IPublishTo''': Defines methods that enable the simple usage of topics and message processors. |
+ | *'''IMessageBroker''': Defines methods for the management of Topics and subscriptions. | ||
+ | |||
+ | =====Providers===== | ||
+ | *'''IProvider''': Basic provider interface that defined methods for adding the actual workflow context to a given provider. | ||
+ | *'''IConditionProvider''': Extends the IProvider, enables the user to provide dynamically calculated conditions for loops and conditional statements. | ||
+ | *'''IIterableProvider''': Extends the IProvider, enables the user to provide IIterable objects for 'foreach' loops. | ||
+ | *'''IIterationNumber''': Extends the IProvider, enables the user to dynamically calculate the number of iterations a 'for' loop does. | ||
====Classes==== | ====Classes==== | ||
− | *''' | + | *'''TransformationChain''': Implements the ICompositeStep and the MWE2 IWorkFlowComponent interface. As it is a composite step, it can contain additional transformation steps. In its execute method, the registered transformation steps are initialized and executed. |
− | + | *'''TransformationStep''':Abstract class that implements the ITransformationStep interface, that acts as a base class for user defined transformation steps. It incorporates the following features: | |
+ | ** Support for containing ISubscribeTo and IPublishTo objects | ||
+ | ** Initialize the context attribute in the initialize() method | ||
+ | ** Process all incoming messages | ||
+ | ** Support the addition of user defined initialization, execute functionality and message publication (doInitialize(), doExecute(), publishMessages()) | ||
− | *''' | + | *'''MessageBroker''': The MessageBroker is a singleton class that manages topics and subscriptions. It enables transformation steps to subscribe to topics, send and query messages, as well as acknowledge message processing (In case the message is successfully processed, the message itself will be removed from the topic's appropriate queue). |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | *''' | + | *'''Topic''': Topics contain subscribing transformation steps and messages sent to these subscribers. Messages are contained in a multi map whose key objects are transformation steps, while the value objects are lists of messages. |
− | *''' | + | *'''SubscribeTo''': SubscribeTo objects contain an IMessageProcessor implementation and specify the Topic to which the transformation step has subscribed. The event processor is used for processing the messages that are provided by the topic. This ISubscribeTo implementation also features the priority property, which help in defining an order in which conflicting channels can be processed. |
− | *''' | + | *'''PublishTo''': As specified in the IPublishTo interface, instances of this class contain an IMessageFactory object and the qualified name of a topic. The message factory is responsible for adding events to the aforementioned topic. The PublishTo class provides an easy to use interface for adding publishing messages. |
− | *''' | + | =====Control Structures===== |
+ | *'''Sequence''':Composite transformation step that implements a basic sequence control flow construction. It initializes and executes its contained steps in the same sequence they have been defined. | ||
− | *''' | + | *'''Conditional''': Composite transformation step that implements an 'IF' style conditional construction. The condition is specified by an IConditionProvider which enables the specification of dynamically evaluated conditions. If the condition evaluation returns true, the ifTrue step is executed, if otherwise, the ifFalse step is executed. As the condition is evaluated in run time, both of the steps is initialized. |
− | *''' | + | *'''ForLoop''': Composite transformation step that implements a 'for' style loop. The number of iterations can either be explicitly specified at compile time, using the iterations attribute, or dynamically calculated by an IIterationNumberProvider. |
− | *''' | + | *'''ForeachLoop''': Composite transformation step that implements a 'foreach' style loop. This kind of loop requires an IIterable object to iterate through. It is provided in run time by an IIterableProvider. |
− | + | *'''WhileLoop''': Composite transformation step that implements a 'while' style loop. similar to the conditional step, the dynamically evaluated loop condition is provided by an IConditionProvider. The condition is evaluated before the current iteration. | |
− | *''' | + | *'''DoWhileLoop''': Composite transformation step that implements a 'do..while' style loop. similar to the while loop, the dynamically evaluated loop condition is provided by an IConditionProvider. In this case however, the condition is evaluated after the current iteration instead. |
− | *''' | + | *'''Parallel''': Composite transformation step that enables the parallel execution of transformation steps. Each transformation step will be assigned to a new thread. |
+ | ** Be advised: The parallel regions should be independent from each other, as there is no order of execution defined. This means, that typically parallel regions should not send each other parametric messages. | ||
− | *''' | + | =====Provider Implementations===== |
+ | *'''BaseProvider''': Abstract base provider implementation that has an IWorkFlowContext attribute. This way inheriting classes can access the workflow context. | ||
+ | *'''BaseIterationNumberProvider''': Basic iteration number provider that extend the BaseProvider abstract class and returns the number handed to it in its constructor. | ||
− | + | =====Example Messages, Factories and Processors===== | |
− | *''' | + | *'''StringMessage''': Basic message implementation that has a String typed parameter. It serves as a basic example for implementing custom messages. |
− | *''' | + | *'''StringMessageFactory''': Message Factory that is responsible for the creation of StringMessage objects. Similar to the StringMessage class, this class serves as an example. |
− | + | *'''StringMessageProcessor''': Message Processor that is responsible for processing StringMessage objects. It serves as an example for user defined message processors. | |
− | == | + | |
− | + | ==Examples== | |
+ | All of the below stated examples can be found in the mwe2integration.examples project in the following repository: | ||
+ | *'''VIATRA examples repository'': http://git.eclipse.org/c/viatra/org.eclipse.viatra.examples.git/ | ||
+ | |||
+ | ===Basics=== | ||
+ | Typically the following steps are needed to create an MWE Transformation Chain: | ||
*Create a new Eclipse plug-in project via File Menu --> New --> Project | *Create a new Eclipse plug-in project via File Menu --> New --> Project | ||
*Create a new MWE2 file (in a not default package) using the similar method. If prompted, add the Xtext nature to the project. | *Create a new MWE2 file (in a not default package) using the similar method. If prompted, add the Xtext nature to the project. | ||
+ | *Define custom transformation steps, messages and other classes supporting them. | ||
+ | *Define workflow structure in the MWE2 file | ||
+ | *Run the MWE2 workflow or integrate it in the transformation architecture. | ||
+ | |||
+ | ===Simple Example=== | ||
+ | The usage of these classes can be most effectively described via a simple 'Hello World' example that defines two very simple transformation steps. These transformation steps do not communicate with each other using messages, and no complex control structures are used. | ||
====Define Transformation Steps==== | ====Define Transformation Steps==== | ||
− | In the | + | In the following step define two very simple transformation steps. Add these classes to the package created before. |
− | ''' | + | '''ExampleATransformationStep.java''' |
<source lang="java"> | <source lang="java"> | ||
− | + | /** | |
− | + | * An example transformation step. User defined transformation steps should extend the abstract class | |
+ | * TransformationStep. It already implements the core features of transformation steps, namely the management of | ||
+ | * publishings, subscriptions, as well as message processing and -creation. | ||
+ | * | ||
+ | */ | ||
+ | class ExampleATransformationStep extends TransformationStep { | ||
+ | override doInitialize(IWorkflowContext ctx) { | ||
+ | //this method is called after the workflow context is assigned to the step | ||
+ | //The transformation should be initialized here | ||
+ | System.out.println("Init A transformation") | ||
+ | //The context can be used to access global variables | ||
+ | //via ctx.get("String") | ||
+ | } | ||
+ | |||
+ | override void doExecute() { | ||
+ | //This method is executed during the execute method of a given transformation step, | ||
+ | //after the received messages are processed and before outgoing messages are sent- | ||
+ | //Run the transformation (or any other user defined function) here | ||
+ | System.out.println("A transformation executed") | ||
+ | } | ||
+ | |||
+ | override void dispose() { | ||
+ | // Dispose functions | ||
+ | System.out.println("Dispose A transformation") | ||
+ | } | ||
− | + | //In this method the sending of messages can be defined | |
− | + | //Typically the following implementation, which sends a given message type to all publishing topics, | |
− | + | //is sufficient | |
− | + | override void publishMessages() { | |
− | + | publishings.forEach[ | |
− | + | publishMessage("MESSAGE A") | |
− | + | ] | |
− | + | } | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
</source> | </source> | ||
− | ''' | + | '''ExampleBTransformationStep.java''' |
<source lang="java"> | <source lang="java"> | ||
− | + | /** | |
− | + | * An example transformation step. User defined transformation steps should extend the abstract class | |
+ | * TransformationStep. It already implements the core features of transformation steps, namely the management of | ||
+ | * publishings, subscriptions, as well as message processing and -creation. | ||
+ | * | ||
+ | * This class is the same as the A variant, it is needed as most of the examples call for two different | ||
+ | * transformation steps | ||
+ | */ | ||
+ | class ExampleBTransformationStep extends TransformationStep { | ||
+ | override doInitialize(IWorkflowContext ctx) { | ||
+ | //this method is called after the workflow context is assigned to the step | ||
+ | //The transformation should be initialized here | ||
+ | System.out.println("Init B transformation") | ||
+ | //The context can be used to access global variables | ||
+ | //via ctx.get("String") | ||
+ | } | ||
+ | |||
+ | override void doExecute() { | ||
+ | //This method is executed during the execute method of a given transformation step, | ||
+ | //after the received messages are processed and before outgoing messages are sent- | ||
+ | //Run the transformation (or any other user defined function) here | ||
+ | System.out.println("B transformation executed") | ||
+ | } | ||
+ | |||
+ | override void dispose() { | ||
+ | // Dispose functions | ||
+ | System.out.println("Dispose B transformation") | ||
+ | } | ||
− | + | //In this method the sending of messages can be defined | |
− | + | //Typically the following implementation, which send a given message type to all publishing topics, | |
− | + | //is sufficient | |
− | + | override void publishMessages() { | |
− | + | publishings.forEach[ | |
− | + | publishMessage("MESSAGE B") | |
− | + | ] | |
− | + | } | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
</source> | </source> | ||
Line 160: | Line 241: | ||
====Define Transformation Structure==== | ====Define Transformation Structure==== | ||
− | Define the transformation chain structure using the MWE2 language. Make sure to include all the referenced packages (if the classes are in the same package as the MWE2 file, include that package as well), and that the module name | + | Define the transformation chain structure using the MWE2 language. Make sure to include all the referenced packages (if the classes are in the same package as the MWE2 file, include that package as well), and that the module name should match the containing package as well. |
− | ''' | + | '''SimpleChainExample.mwe2''' |
<source lang="java"> | <source lang="java"> | ||
− | module org.eclipse.viatra.emf. | + | module org.eclipse.viatra.emf.mwe2integration.example.SimpleChainExample |
+ | //Import the necessary libraries | ||
+ | //Note, that the package containing the workflow needs to be imported as well (if it contains used resources) | ||
import org.eclipse.viatra.emf.mwe2integration.* | import org.eclipse.viatra.emf.mwe2integration.* | ||
import org.eclipse.viatra.emf.mwe2integration.mwe2impl.* | import org.eclipse.viatra.emf.mwe2integration.mwe2impl.* | ||
− | import org.eclipse.viatra.emf.mwe2integration. | + | import org.eclipse.viatra.emf.mwe2integration.mwe2impl.messages.* |
− | + | import org.eclipse.viatra.emf.mwe2integration.examples.resources.* | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
//The workflow and components are defined in the usual MWE2 fashion | //The workflow and components are defined in the usual MWE2 fashion | ||
Workflow { | Workflow { | ||
− | //Add | + | //Add a TransformationChain component |
− | + | //This component represents an MWE2 component that can contain numerous transformations | |
− | + | component = TransformationChain { | |
− | + | //Add transformation steps | |
− | + | //These classes all extend the TransformationStep abstract class, which implements their core features. | |
− | + | //User defined functionality can be added via overriding the doExecute() method | |
− | // | + | step = ExampleATransformationStep{} |
− | + | //Multiple transformation steps will be executed in order of their definition | |
− | + | //Note that in the other examples, more elaborate control constructions will be presented. | |
− | + | step = ExampleBTransformationStep{} | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
//You can add additional regular MWE2 components here | //You can add additional regular MWE2 components here | ||
Line 208: | Line 272: | ||
</source> | </source> | ||
− | + | After this, run the MWE2 file as an MWE 2 workflow. | |
+ | '''TODO finish''' | ||
+ | |||
+ | ===Simple Example with Conditional=== | ||
+ | ===Simple Example with Loops=== | ||
+ | ===Complex Example with Messaging=== | ||
+ | ===Complex Example with Parallel Execution=== | ||
===Complex Example (CPS)=== | ===Complex Example (CPS)=== | ||
Line 548: | Line 618: | ||
====Execution==== | ====Execution==== | ||
To run the specified workflow, simply run the mwe2 file as an 'MWE2 Workflow'. | To run the specified workflow, simply run the mwe2 file as an 'MWE2 Workflow'. | ||
+ | |||
+ | ==Advanced Features== | ||
+ | |||
+ | ===Wrapping fine grained event-driven transformations=== | ||
+ | |||
+ | *'''IController''': An interface that defines methods for explicitly controlling the execution of a fine-grained event-driven model transformation step. | ||
+ | |||
+ | *'''IEnabler''': Interface that defines methods that can enable and disable a fine-grained, event-driven event driven transformation step. | ||
+ | |||
+ | *'''ISchedulerController''': Interface that defines functions which are used when an IController object also wraps an IncQuery EVM Scheduler. | ||
+ | |||
+ | *'''MWE2ControllableExecutor''': An IncQuery EVM Executor, that enables the MWE 2 workflow to control any IncQuery EVM based fine-grained event-driven transformation, provided that the transformation's ExecutionSchema is created with this executor. It also implements the IController interface which enables the workflow to explicitly start the execution of the transformation. The MWE2ControllableExecutor also provides information about the state of the transformation (i.e.: if the transformation has reached a steady state or not). | ||
+ | |||
+ | *'''MWE2EnablerExecutor''': An IncQuery EVM Executor, that enables the MWE 2 workflow to control any EVM based fine-grained event-driven transformation, provided that the transformation's ExecutionSchema is created with this executor. It also implements the IEnabler interface which means that based on the state of other transformation steps, the event-driven transformation can be enabled or disabled. | ||
+ | |||
+ | *'''MWE2BaseControllableScheduler''': An EVM scheduler that enables the workflow to explicitly control the execution of a fine-grained event-driven transformation. As it implements the IController interface, its usage is similar to the MWE2ControllableExecutor. Internally, however, this solution uses a custom Scheduler object instead of an Executor. Using a custom Scheduler means, that the original IncQuery EVM Scheduler will be overridden. | ||
+ | |||
+ | Detailed information about the usage of these classes can be found in the CPS example. | ||
== Project Locations == | == Project Locations == |
Revision as of 10:46, 17 July 2015
Contents
- 1 Transformation Chains Using VIATRA MWE 2 Integration
- 1.1 Motivation
- 1.2 MWE 2 Basics
- 1.3 VIATRA MWE2 Integration Library
- 1.4 Examples
- 1.5 Advanced Features
- 1.6 Project Locations
Transformation Chains Using VIATRA MWE 2 Integration
Motivation
Defining heterogeneous model transformation chains using a specialized description language.
- Sequence of model transformation steps can be easily specified and maintained.
- Nontrivial side-effect relations between transformation steps can be handled.
- The execution of event-driven transformations can be explicitly controlled.
- Because of the specialized language, the description code base is short and easily expandable.
MWE 2 Basics
Generic modeling workflows can be easily described via using the Xtext Modeling Workflow Engine. It enables the creation of components with various attributes, and it executes them in order. More, exact information about the Xtext MWE 2 can be found at https://www.eclipse.org/Xtext/documentation/306_mwe2.html
VIATRA MWE2 Integration Library
Overview
The VIATRA MWE2 Integration library provides support for defining complex transformation chains using Xtext MWE 2 workflows. As it can be seen on the figure below, the transformation chain itself is an MWE2 component, meaning that it can be easily integrated into higher level modeling workflows.
The transformation chain consists of different typed transformation steps. These are the following:
- Composite transformation steps: The composite steps are responsible for creating the control flow of the model transformation chain. These steps (Sequence, Loop, Conditional, Parallel) can contain other transformation steps. Once a given composite transformation step is executed, it will call its sub-steps in a specific manner (For example in case of Sequences, execute the contained steps in their order of appearance).
- Model Transformation Steps: These steps cannot contain any child steps, meaning that they are used for implementing actual model transformations. They have access to the workflow context, to and from which they can push and pull data. They can also communicate directly with each other using parametric messages.
Messaging
- The MWE2 integration library implements basic publish/subscribe based messaging. Transformation steps can publish messages to certain topics. If an other transformation step is subscribed to that given topic, it will receive the message as the execution token reaches the target step. Once the target step processes the message, the topic is informed about the act, and the message is deleted from the topic.
- Topic management: A message broker is responsible for the management of the individual topics. It enables the transformation steps to subscribe to any existing or new topic. It is also responsible for handing the incoming messages to the appropriate topic. Transformation steps can also query the message broker for the now messages on their subscribed topics.
- Message creation and processing: Message creation is done by message factories. These user specified objects can create messages with certain parameters. Message processors on the other hand are used by the transformation steps to process certain typed incoming messages.
- SubscribeTo and PublishTo objects: These objects represent publications and subscriptions on the transformation step's side. They store which message factory or processor should be used with the specified topic.
Control flow
As mentioned before, the execution sequence of transformation steps can be defined by a standard control statement hierarchy, similar to imperative languages. The following control statements are supported:
- Transformation Chain: Transformation chains area the root elements of the control hierarchy. They can contain other transformation steps (they cannot contain transformation chains), which will be executed in order of their addition to the chain.
- Sequence: Sequences are basic control elements. They contain other transformation steps, and execute them in the order of their addition.
- Conditional: Conditional statements decide which one of their child transformation steps will be executed (these can be sequences, loops etc.), based on the validity of a condition specified by the user.
- For loop: Simple 'for' loop, it will iterate through its child elements, N times, where N is directly specified by the user using a numeric literal, or calculated dynamically.
- Foreach loop: Loop that iterates through an IIterable element provided by the user.
- While loop: A simple 'while' loop that will iterate through its child elements as long as the condition provided by the user appears to be valid.
- Do..While loop: Similar to the 'while' loop, however instead of checking the condition before each cycle, this one checks it after it.
- Parallel: Control statement that enables the parallel execution of transformation steps. Steps contained by this element will be assigned to independent threads. Note, that trasnformation steps that take part in a two way communication with one another should not be added to parallel sections, as in case of parallel execution timing errors can occur(lost messages, double messages etc.).
Prerequisites and Installation
Update site installation
No update site yet, This section will be revised after addition
Source Installation
In order to use this library, the following Eclipse plug-ins are required:
- Eclipse Modeling 4.5 Mars recommended
- EMF-IncQuery 1.1.0 --> http://download.eclipse.org/incquery/updates/integration
- Xtext SDK 2.8.3 --> http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/
After the prerequisites are met clone the following repository and import the contained projects. Note, that it contains the source of the VIATRA framework as well. https://github.com/lunkpeter/org.eclipse.viatra
Library Classes and Interfaces
The library defines a set of interfaces and abstract base classes which represent the main elements the previously described transformation workflow semantics. User defined behavior can be added via the extension of these elements
Interfaces
- ICompositeStep: Defines the interface of composite transformation steps that can contain other steps.
- ITransformationStep: Interface that defines the main entry points of transformation steps. The user defined functionality can be implemented in the execute, initialize and dispose methods.
- ITopic: Defines the interface of topics. It includes methods for publishing and querying messages, as well as managing subscriptions.
- IMessage: Interface for messages, defines methods for getting and setting the message parameter.
- IMessageFactory: Provides an interface for creating certain typed messages. As messages contain parameters, message- and parameter types are specified as generic type parameters.
- IMessageProcessor: Provides an interface for creating certain typed messages. As messages can contain parameters, message- and parameter types are specified as generic type parameters.
- ISubscribeTo: Defines methods that enable the simple usage of topics and message factories.
- IPublishTo: Defines methods that enable the simple usage of topics and message processors.
- IMessageBroker: Defines methods for the management of Topics and subscriptions.
Providers
- IProvider: Basic provider interface that defined methods for adding the actual workflow context to a given provider.
- IConditionProvider: Extends the IProvider, enables the user to provide dynamically calculated conditions for loops and conditional statements.
- IIterableProvider: Extends the IProvider, enables the user to provide IIterable objects for 'foreach' loops.
- IIterationNumber: Extends the IProvider, enables the user to dynamically calculate the number of iterations a 'for' loop does.
Classes
- TransformationChain: Implements the ICompositeStep and the MWE2 IWorkFlowComponent interface. As it is a composite step, it can contain additional transformation steps. In its execute method, the registered transformation steps are initialized and executed.
- TransformationStep:Abstract class that implements the ITransformationStep interface, that acts as a base class for user defined transformation steps. It incorporates the following features:
- Support for containing ISubscribeTo and IPublishTo objects
- Initialize the context attribute in the initialize() method
- Process all incoming messages
- Support the addition of user defined initialization, execute functionality and message publication (doInitialize(), doExecute(), publishMessages())
- MessageBroker: The MessageBroker is a singleton class that manages topics and subscriptions. It enables transformation steps to subscribe to topics, send and query messages, as well as acknowledge message processing (In case the message is successfully processed, the message itself will be removed from the topic's appropriate queue).
- Topic: Topics contain subscribing transformation steps and messages sent to these subscribers. Messages are contained in a multi map whose key objects are transformation steps, while the value objects are lists of messages.
- SubscribeTo: SubscribeTo objects contain an IMessageProcessor implementation and specify the Topic to which the transformation step has subscribed. The event processor is used for processing the messages that are provided by the topic. This ISubscribeTo implementation also features the priority property, which help in defining an order in which conflicting channels can be processed.
- PublishTo: As specified in the IPublishTo interface, instances of this class contain an IMessageFactory object and the qualified name of a topic. The message factory is responsible for adding events to the aforementioned topic. The PublishTo class provides an easy to use interface for adding publishing messages.
Control Structures
- Sequence:Composite transformation step that implements a basic sequence control flow construction. It initializes and executes its contained steps in the same sequence they have been defined.
- Conditional: Composite transformation step that implements an 'IF' style conditional construction. The condition is specified by an IConditionProvider which enables the specification of dynamically evaluated conditions. If the condition evaluation returns true, the ifTrue step is executed, if otherwise, the ifFalse step is executed. As the condition is evaluated in run time, both of the steps is initialized.
- ForLoop: Composite transformation step that implements a 'for' style loop. The number of iterations can either be explicitly specified at compile time, using the iterations attribute, or dynamically calculated by an IIterationNumberProvider.
- ForeachLoop: Composite transformation step that implements a 'foreach' style loop. This kind of loop requires an IIterable object to iterate through. It is provided in run time by an IIterableProvider.
- WhileLoop: Composite transformation step that implements a 'while' style loop. similar to the conditional step, the dynamically evaluated loop condition is provided by an IConditionProvider. The condition is evaluated before the current iteration.
- DoWhileLoop: Composite transformation step that implements a 'do..while' style loop. similar to the while loop, the dynamically evaluated loop condition is provided by an IConditionProvider. In this case however, the condition is evaluated after the current iteration instead.
- Parallel: Composite transformation step that enables the parallel execution of transformation steps. Each transformation step will be assigned to a new thread.
- Be advised: The parallel regions should be independent from each other, as there is no order of execution defined. This means, that typically parallel regions should not send each other parametric messages.
Provider Implementations
- BaseProvider: Abstract base provider implementation that has an IWorkFlowContext attribute. This way inheriting classes can access the workflow context.
- BaseIterationNumberProvider: Basic iteration number provider that extend the BaseProvider abstract class and returns the number handed to it in its constructor.
Example Messages, Factories and Processors
- StringMessage: Basic message implementation that has a String typed parameter. It serves as a basic example for implementing custom messages.
- StringMessageFactory: Message Factory that is responsible for the creation of StringMessage objects. Similar to the StringMessage class, this class serves as an example.
- StringMessageProcessor: Message Processor that is responsible for processing StringMessage objects. It serves as an example for user defined message processors.
Examples
All of the below stated examples can be found in the mwe2integration.examples project in the following repository:
- 'VIATRA examples repository: http://git.eclipse.org/c/viatra/org.eclipse.viatra.examples.git/
Basics
Typically the following steps are needed to create an MWE Transformation Chain:
- Create a new Eclipse plug-in project via File Menu --> New --> Project
- Create a new MWE2 file (in a not default package) using the similar method. If prompted, add the Xtext nature to the project.
- Define custom transformation steps, messages and other classes supporting them.
- Define workflow structure in the MWE2 file
- Run the MWE2 workflow or integrate it in the transformation architecture.
Simple Example
The usage of these classes can be most effectively described via a simple 'Hello World' example that defines two very simple transformation steps. These transformation steps do not communicate with each other using messages, and no complex control structures are used.
Define Transformation Steps
In the following step define two very simple transformation steps. Add these classes to the package created before.
ExampleATransformationStep.java
/** * An example transformation step. User defined transformation steps should extend the abstract class * TransformationStep. It already implements the core features of transformation steps, namely the management of * publishings, subscriptions, as well as message processing and -creation. * */ class ExampleATransformationStep extends TransformationStep { override doInitialize(IWorkflowContext ctx) { //this method is called after the workflow context is assigned to the step //The transformation should be initialized here System.out.println("Init A transformation") //The context can be used to access global variables //via ctx.get("String") } override void doExecute() { //This method is executed during the execute method of a given transformation step, //after the received messages are processed and before outgoing messages are sent- //Run the transformation (or any other user defined function) here System.out.println("A transformation executed") } override void dispose() { // Dispose functions System.out.println("Dispose A transformation") } //In this method the sending of messages can be defined //Typically the following implementation, which sends a given message type to all publishing topics, //is sufficient override void publishMessages() { publishings.forEach[ publishMessage("MESSAGE A") ] } }
ExampleBTransformationStep.java
/** * An example transformation step. User defined transformation steps should extend the abstract class * TransformationStep. It already implements the core features of transformation steps, namely the management of * publishings, subscriptions, as well as message processing and -creation. * * This class is the same as the A variant, it is needed as most of the examples call for two different * transformation steps */ class ExampleBTransformationStep extends TransformationStep { override doInitialize(IWorkflowContext ctx) { //this method is called after the workflow context is assigned to the step //The transformation should be initialized here System.out.println("Init B transformation") //The context can be used to access global variables //via ctx.get("String") } override void doExecute() { //This method is executed during the execute method of a given transformation step, //after the received messages are processed and before outgoing messages are sent- //Run the transformation (or any other user defined function) here System.out.println("B transformation executed") } override void dispose() { // Dispose functions System.out.println("Dispose B transformation") } //In this method the sending of messages can be defined //Typically the following implementation, which send a given message type to all publishing topics, //is sufficient override void publishMessages() { publishings.forEach[ publishMessage("MESSAGE B") ] } }
Define Transformation Structure
Define the transformation chain structure using the MWE2 language. Make sure to include all the referenced packages (if the classes are in the same package as the MWE2 file, include that package as well), and that the module name should match the containing package as well.
SimpleChainExample.mwe2
module org.eclipse.viatra.emf.mwe2integration.example.SimpleChainExample //Import the necessary libraries //Note, that the package containing the workflow needs to be imported as well (if it contains used resources) import org.eclipse.viatra.emf.mwe2integration.* import org.eclipse.viatra.emf.mwe2integration.mwe2impl.* import org.eclipse.viatra.emf.mwe2integration.mwe2impl.messages.* import org.eclipse.viatra.emf.mwe2integration.examples.resources.* //The workflow and components are defined in the usual MWE2 fashion Workflow { //Add a TransformationChain component //This component represents an MWE2 component that can contain numerous transformations component = TransformationChain { //Add transformation steps //These classes all extend the TransformationStep abstract class, which implements their core features. //User defined functionality can be added via overriding the doExecute() method step = ExampleATransformationStep{} //Multiple transformation steps will be executed in order of their definition //Note that in the other examples, more elaborate control constructions will be presented. step = ExampleBTransformationStep{} } //You can add additional regular MWE2 components here }
After this, run the MWE2 file as an MWE 2 workflow. TODO finish
Simple Example with Conditional
Simple Example with Loops
Complex Example with Messaging
Complex Example with Parallel Execution
Complex Example (CPS)
A more complex example can be found in the IncQuery CPS example project: https://github.com/IncQueryLabs/incquery-examples-cps/wiki. The project itself aims at providing an example, how EMF IncQuery related technologies can be used in a model driven development workflow.
Naturally, this example contains numerous different transformation methods and other auxiliary steps. The VIATRA MWE2 integration library can be used to define the structure of these transformation steps. The example project at https://github.com/lunkpeter/incquery-examples-cps/tree/MWE/addons/org.eclipse.incquery.examples.cps.mwe2integration.example contains both batch- and fine-grained, event-driven M2M transformations. In this section, a VIATRA based event driven M2M transformation will be used.
MWE Workflow Components
- Initializer component: This standard MWE 2 workflow component is responsible for the initialization of the transformation environment. It creates the model resources, generates the source model, instantiates the main IncQuery engine used by the transformation steps and creates the output project structure. It also adds the created resources to the workflow context.
Transformation Steps
- M2M Transformation Step: In this case, the model-to-model transformation is a VIATRA based incremental event-driven transformation, implemented in the following CPS project: https://github.com/lunkpeter/incquery-examples-cps/tree/master/transformations/org.eclipse.incquery.examples.cps.xform.m2m.incr.viatra
The transformation step contains the following attributes:
protected MWE2ControllableExecutor executor; //Executor that implements the IControllable interface. Responsible for controlling the ED transformation. protected AdvancedIncQueryEngine engine; //Main IncQuery engine used by the transformation steps. protected CPS2DeploymentTransformationViatra transformation; //The previously mentioned VIATRA based event-driven transformation.
It overrides the following methods:
@Override public void initialize(IWorkflowContext ctx) { //store the context this.context = ctx; //get the input model from the Workflow context (it was added by the initializer) CPSToDeployment cps2dep = (CPSToDeployment) ctx.get("model"); //get the main IncQuery engine from the Workflow context (it was added by the initializer) engine = (AdvancedIncQueryEngine) ctx.get("engine"); //create the EVM Executor that controls the transformation executor = new MWE2ControllableExecutor(IncQueryEventRealm.create(engine)); transformation = new CPS2DeploymentTransformationViatra(); //Initialize the transformation using the controller Executor transformation.setExecutor(executor); transformation.initialize(cps2dep, engine); System.out.println("Initialized model-to-model transformation"); } @Override public void execute() { //Process one incoming event processNextEvent(); //Command the event-driven transformation to run executor.run(); //Wait for the event-driven transformation while (!executor.isFinished()) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Model-to-model transformation executed"); //Send events to all target channels sendEventToAllTargets(); } @Override public void dispose() { //At the end of the workflow, stop the the Thread the transformation step is checking for new events and dispose the transformation itself isRunning = false; transformation.dispose(); System.out.println("Disposed model-to-model transformation"); }
- Change Monitor Transformation Step: This step detects the changes in the intermediary deployment model, and sends the changes themselves to the M2T transformation step.
The transformation step contains the following attributes:
protected AdvancedIncQueryEngine engine; //Main IncQuery engine used by the transformation steps. protected DeploymentChangeMonitor monitor; //A Change monitor class that collects all the changes in a specified deployment model, for a period of time.
It overrides the following methods:
@Override public void initialize(IWorkflowContext ctx) { //store the context this.context = ctx; //get the main IncQuery engine from the Workflow context (it was added by the initializer) engine = (AdvancedIncQueryEngine) ctx.get("engine"); //Get the deployment model root from the workflow context Deployment deployment = ((CPSToDeployment) ctx.get("model")).getDeployment(); //Initialize monitor and start monitoring. monitor = new DeploymentChangeMonitor(deployment, engine); try { monitor.startMonitoring(); } catch (IncQueryException e) { e.printStackTrace(); } } @Override public void execute() { //Process one incoming event processNextEvent(); //Create a new checkpoint that contains all the model changes since the previous checkpoint up to the current time. DeploymentChangeDelta delta = monitor.createCheckpoint(); System.out.println("Checkpoint created"); //Send the model changes to all target channels sendEventToAllTargets(delta); } @Override public void dispose() { //At the end of the workflow, stop the the Thread the transformation step is checking for new events isRunning = false; System.out.println("Disposed change monitor"); }
- M2T Transformation Step: The M2T transformation step uses a distributed code generator component that returns the output files as character sequences.
The transformation step contains the following attributes:
protected AdvancedIncQueryEngine engine; public ICPSGenerator generator; //Code Generator component public String projectName; //Name of the output project public String sourceFolder; //Location of the output project public List<M2TOutputRecord> output; //Output of the transformation public DeploymentChangeDelta delta; //Incoming delta
It overrides the following methods:
@Override public void initialize(IWorkflowContext ctx) { //store the context this.context = ctx; //get the main IncQuery engine from the Workflow context (it was added by the initializer) engine = (AdvancedIncQueryEngine) ctx.get("engine"); //get the output project name from the Workflow context (it was added by the initializer) projectName = (String) ctx.get("projectname"); //get the output project folder from the Workflow context (it was added by the initializer) sourceFolder = (String) ctx.get("folder"); //Create new code generator generator = new CodeGenerator(projectName,engine,true); } @Override public void execute() { processNextEvent(); ChangeM2TOutputProvider provider = new ChangeM2TOutputProvider(delta, generator, sourceFolder); output = provider.generateChanges(); System.out.println("Model-to-text transformation executed"); //Send output to serializer sendEventToAllTargets(output); } @Override public void dispose() { //At the end of the workflow, stop the the Thread in which the transformation step is checking for new events isRunning = false; System.out.println("Disposed model-to-text transformation"); }
- Serializer Transformation Step: Creates new source files based on the output provided by the M2T transformation.
The transformation step contains the following attributes:
private boolean firstRun = true; //If the serializer is run for the first time, it sends events to the Model modification step, otherwise quits the workflow. public DefaultSerializer serializer; //CPS serializer public String sourceFolder; //Location of the source folder public List<M2TOutputRecord> m2tOutput; //Output created by the M2T transformation
It overrides the following methods:
@Override public void initialize(IWorkflowContext ctx) { this.context = ctx; //Init serializer System.out.println("Initialized serializer"); serializer = new DefaultSerializer(); sourceFolder = (String) ctx.get("folder"); } @Override public void execute() { processNextEvent(); //Serialize output ListBasedOutputProvider provider = new ListBasedOutputProvider(m2tOutput); serializer.serialize(sourceFolder, provider, new JavaIOBasedFileAccessor()); System.out.println("Serialization completed"); //If the serializer is run for the first time, it sends events to the Model modification step, otherwise quits the workflow. if(firstRun){ getModifierChannel().createEvent(); firstRun = false; } else { getChainEndChannel().createEvent(); } } @Override public void dispose() { isRunning = false; System.out.println("Disposed serializer"); }
- Model Modifier Transformation Step: Modifies the source CPS model and sends events to the M2M transformation, meaning that the workflow has restarted.
The transformation step contains the following attributes:
protected CPSToDeployment model; //Model root protected CPSModelBuilderUtil modelBuilder = new CPSModelBuilderUtil(); //CPS model modification utility class
It overrides the following methods:
@Override public void initialize(IWorkflowContext ctx) { //receive the model root from the context model = (CPSToDeployment) ctx.get("model"); } @Override public void execute() { processNextEvent(); //modify model modifyModel(); System.out.println("Model modification executed"); sendEventToAllTargets(); } @Override public void dispose() { isRunning = false; System.out.println("Disposed model modifier"); }
Events, Event Factories, Processors
- ChangeDeltaEvent: Event type that contains the model modifications detected by a DeploymentChangeMonitor.
- M2TOutputEvent: Event Type that contains character sequences created by the M2T transformation.
- ChangeDeltaEventFactory: Event factory that creates a ChangeDeltaEvent.
- M2TOutputEventFactory: Event factory that creates a M2TOutputEvent.
- ChangeDeltaEventProcessor: Event processor that adds the ChangeDelta contained by a ChangeDeltaEvent to its parent Transformation Step.
- M2TOutputEventProcessor: Event processor that adds the M2T output character sequences contained by a M2TOutputEvent to its parent Transformation Step.
Workflow Structure
The structure of the workflow is specified in the ControllableEventDrivenTransformation.mwe2 file. After the previously defined transformation steps and workflow components have been imported to the module, they can be easily instantiated using the MWE2 description language. Note, that the package containing the .mwe2 file should be imported as well.
module org.eclipse.viatra.emf.mwe2integration.transdemo import org.eclipse.viatra.emf.mwe2integration.* import org.eclipse.viatra.emf.mwe2integration.mwe2impl.* import org.eclipse.incquery.examples.cps.integration.* import org.eclipse.incquery.examples.cps.integration.events.* import org.eclipse.incquery.examples.cps.integration.eventdriven.controllable.* //Define Channels here var chainStartChannel = MWE2Channel {} var chainEndChannel = MWE2Channel {} var M2MChannel = MWE2Channel {} var ChangeMonitorChannel = MWE2Channel {} var M2TChannel = MWE2Channel {} var SerializerChannel = MWE2Channel {} var ModifierChannel = MWE2Channel {} Workflow { //Add initializer workflow component component = InitializerComponent{ //Set the seed and model size for model generation seed = "11111" modelSize = "4" //Define location for model resource modelDir = "D:\\MWE_TEST\\model" modelName = "MWE_TEST" //Define output project location and name outputProjectLocation = "D:\\MWE_TEST" outputProjectName = "VIATRA_ED_Controllable" } //Use the MWE2TransformationChain class for defining transformation chains component = MWE2TransformationChain { //Define the start and end channels of the transformation chain startChannel = MWE2TargetChannel{channel = chainStartChannel} endChannel = MWE2ListeningChannel{channel = chainEndChannel} //Add an event driven viatra transformation step that listens to the chainStartChannel and the m2mChannel //It targets the change monitor transformationStep = M2MControllableEventDrivenViatraTransformationStep { chainStartChannel = MWE2ListeningChannel{channel = chainStartChannel} m2MChannel = MWE2ListeningChannel{channel = M2MChannel} changeMonitorChannel = MWE2TargetChannel{channel = ChangeMonitorChannel} } //Create a change monitor transformation step //Add a ChangeDeltaEventFactory to its target channel transformationStep = ChangeMonitorTransformationStep{ changeMonitorChannel = MWE2ListeningChannel{channel = ChangeMonitorChannel} m2TChannel = MWE2TargetChannel{channel = M2TChannel factory = ChangeDeltaEventFactory{}} } //Create a M2t transformation step //Add a ChangeDeltaEventProcessor to its listening channel //Add a M2TOutputEventFactoryto its target channel transformationStep = M2TDistributedTransformationStep { m2TChannel = MWE2ListeningChannel{channel = M2TChannel processor = ChangeDeltaEventProcessor{}} serializerChannel = MWE2TargetChannel{channel = SerializerChannel factory = M2TOutputEventFactory{}} } //Create a serializer transformation step //Add a M2TOutputEventProcessor to its listening channel //Define both chainEndChannel and ModifierChannel as target channels (the workflow will quit after two cycles) transformationStep = SerializerTransformationStep{ serializerChannel = MWE2ListeningChannel{channel = SerializerChannel processor = M2TOutputEventProcessor{}} chainEndChannel = MWE2TargetChannel{channel = chainEndChannel} modifierChannel = MWE2TargetChannel{channel = ModifierChannel} } //Create a serializer transformation step //Define both m2MChannel as target channel transformationStep = ModelModifierStep{ modifierChannel = MWE2ListeningChannel{channel = ModifierChannel} m2MChannel = MWE2TargetChannel{channel = M2MChannel} } } }
Execution
To run the specified workflow, simply run the mwe2 file as an 'MWE2 Workflow'.
Advanced Features
Wrapping fine grained event-driven transformations
- IController: An interface that defines methods for explicitly controlling the execution of a fine-grained event-driven model transformation step.
- IEnabler: Interface that defines methods that can enable and disable a fine-grained, event-driven event driven transformation step.
- ISchedulerController: Interface that defines functions which are used when an IController object also wraps an IncQuery EVM Scheduler.
- MWE2ControllableExecutor: An IncQuery EVM Executor, that enables the MWE 2 workflow to control any IncQuery EVM based fine-grained event-driven transformation, provided that the transformation's ExecutionSchema is created with this executor. It also implements the IController interface which enables the workflow to explicitly start the execution of the transformation. The MWE2ControllableExecutor also provides information about the state of the transformation (i.e.: if the transformation has reached a steady state or not).
- MWE2EnablerExecutor: An IncQuery EVM Executor, that enables the MWE 2 workflow to control any EVM based fine-grained event-driven transformation, provided that the transformation's ExecutionSchema is created with this executor. It also implements the IEnabler interface which means that based on the state of other transformation steps, the event-driven transformation can be enabled or disabled.
- MWE2BaseControllableScheduler: An EVM scheduler that enables the workflow to explicitly control the execution of a fine-grained event-driven transformation. As it implements the IController interface, its usage is similar to the MWE2ControllableExecutor. Internally, however, this solution uses a custom Scheduler object instead of an Executor. Using a custom Scheduler means, that the original IncQuery EVM Scheduler will be overridden.
Detailed information about the usage of these classes can be found in the CPS example.
Project Locations
The library itself can be found at https://github.com/lunkpeter/org.eclipse.viatra/tree/MWE/plugins/org.eclipse.viatra.emf.mwe2integration. The test project at https://github.com/lunkpeter/org.eclipse.viatra/tree/MWE/tests/org.eclipse.viatra.emf.mwe2integration.test contains a simple example as well. Note that at its current state, the library itself is not an integrated part of the VIATRA framework, however as this inclusion is intended in the future, the library is in the org.eclipse.viatra namespace.