Skip to main content

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.

Jump to: navigation, search

Difference between revisions of "VIATRA/Transformation/EVM Adapter Framework"

 
(12 intermediate revisions by one other user not shown)
Line 1: Line 1:
 +
{{caution|Old information|This page is not updated anymore; for more up-to-date details look at the language specification at https://www.eclipse.org/viatra/documentation/transformations.html instead.}}
 
== Motivation ==
 
== Motivation ==
  
Line 9: Line 10:
  
 
=== Components ===
 
=== Components ===
* *Transformation Debug Listener*: Repsonsible for displaying the state of the VIATRA transformation using a specific Debugger UI.
+
* '''Adapter Interface''': The Adapter Interface defines a set of callback methods that are executed at certain points during the transformation execution. These actions are capable of altering the execution sequence of transformation rules. A number of Adapters can implement this interface, in order to define additional functionality that should be undertaken at certain points in the transformation.
* *Transformation Debug Adapter*: Responsible for halting the execution of the transformation if a breakpoint is reached. Once the breakpoint is encountered, it allows the user to select the next action to be taken via the Debugger UI.
+
* '''Listener Interface''': The Listener Interface defines a set of callback methods that are executed at certain points during the transformation execution. The actions defined in these methods can have no effect on the transformation itself, purely aim at providing a solution to listening to certain transformation-related events. A number of Adapters can implement this interface, in order to define additional functionality that should be undertaken at certain points in the transformation.
* *Debugger UI*: Responsible for displaying the internal state of the model transformation in progress, and it allows the transformation developer to manipulate the execution sequence. Using this component enables the transformation debugger component to remain UI independent, and support the definition of custom user interface implementations.
+
'''Adaptable EVM''': The Adaptable EVM is responsible aggregating the used Adapter and Listener instances and delegates the callback method calls from the internal VIATRA objects towards the appropriate callback method of each adapter or listener at certain points during execution. The Adaptable EVM is also responsible for setting up VIATRA transformation to utilize adapters.
  * *Console Debugger UI*: This default UI implementation uses the standard input and output in order to communicate with the transformation developer.
+
* '''Adapter Configuration''': The adapter configurations serve multiple purposes. They can either define dependency relations between adapter imple-mentations, or specify complex use cases which requires more than one adapter to func-tion properly
  * *VIATRA Viewers Debugger UI*: In this case the VIATRA Viewers framework is utilized to visualize the target and source model state via using annotated VIATRA queries.
+
 
* *Breakpoints*: Each breakpoint realization compares a given activation to a set of constraints. If the constraints match, the debugger is informed that it should halt the execution of the transformation, and wait for a response from the transformation developer.
+
The Adapter Framework provides a generic, easy-to-use technique for creating user defined adapter and listener implementations. The Adapter Framework is utilized in order to implement a set of debugging-related use cases.
  * *Rule Activation Breakpoints*: Contains references to a transformation rule, a lifecycle state, and a set of source model elements that have triggered the activation. This way the debugger can check if the activation being fired has a breakpoint attached to it or not.
+
  * *Conditional Breakpoints*: These breakpoints are able to define global constraints that are not only affected by the current activation. A similar concept is available in the Eclipse Java Development Tools (JDT). The constraints are defined by using the VIATRA query language.
+
* *Transformation Debugger Configuration*: This configuration binds the transformation debug adapter and listenercomponents together and allows a more straightforward usage.
+
  
 
== Connection with EVM ==
 
== Connection with EVM ==
[[File:EVMAdapter_Class.png]]
+
 
 +
The class diagram below depicts the relations between the internal EVM elements and members of the EVM adapter framework.
 +
 
 +
Legend:
 +
* '''Green''': API classes through which the user can define EVM based programs.
 +
* '''Blue''': Internal EVM classes and interfaces.
 +
* '''Yellow''': Adaptable EVM classes
 +
 
 +
[[File:EVMAdapter_Class.png | 1500px]]
 +
 
 +
* '''AdaptableEVM''':
 +
** Aggregates listeners and adapters
 +
** Assembles an adapter supporting EVM instance
 +
*** ExecutionSchema
 +
*** RuleEngine
 +
* '''IEVMAdapter''': Callback methods for manipulation the set of EVM Activations to be executed
 +
** Wraps a handed Iterator with one defined by the adapter implementation --> manipulate the Activations handed to the executor.
 +
** Wraps a handed ChangeableConflictSet with one defined by the adapter implementation --> Activations returned by the conflict set can be manipulated.
 +
* '''IEVMListener''': Defines a set of callback methods that can be used to listen to certain EVM-based events, and react to them accordingly. However these callback methods cannot manipulate the EVM rule execution sequence in any way. Callback methods can be defined for the following events: (for details check Javadoc)
 +
** Initialization/disposal
 +
** Before/after activation firing
 +
** Before/after transaction
 +
** Activation state change
 +
** Activation removed
 +
** Activation created
 +
** EVM rule added/removed
 +
* '''AdaptableRulebase''': The Adaptable RuleBase extends the EVM Rulebase. It has a reference to an AdaptableEVM object, through this it can notify adapters about the addition and removal of EVM rule Specifications.
 +
* '''AdaptableExecutor''': The Adaptable Executor as the same responsibilities as the EVM Executor, however, it can also notify EVM listeners about the starting/ending transactions and activations firings. It also enables adapters to alter the set of Activations the executor is assigned to fire.
 +
* '''AdaptableActivationNotificationListener''': Delegates a default EVM activation notification listener. apart from calling the respective methods of the delegated activation change listener, it also notifies EVM listeners about activation state changes.
 +
* '''AdaptableConflictResolver''': The adaptable conflict resolver allows EVM adapters to override or alter the conflict set created by a delegated conflict resolver instance, in order to modify the execution sequence of an EVM-based program.
  
 
== Defining adapter and listener implementations ==
 
== Defining adapter and listener implementations ==
 +
 +
=== EVM Listener implementation example ===
 +
 +
EVM listener implementations should implement the '''IEVMListener''' interface, or extend the '''AbstractTransformationListener''' abstract class. Usage of the abstract class is recommended, as it enables the developer to only subscribe to a certain set of EVM events without implementing every method if the '''IEVMAdapter''' interface. The following source code example shows a simple logging listener implementation.
 +
 +
<source lang="java">
 +
public class FiringLoggingEVMListener extends AbstractTransformationListener{
 +
    private final Logger logger;
 +
 +
    public FiringLoggingEVMListener(Logger logger) {
 +
        this.logger = logger;
 +
    }
 +
 +
    @Override
 +
    public void beforeFiring(Activation<?> activation) {
 +
        logger.debug("BEFORE FIRING " + activation.toString());
 +
 +
    }
 +
 +
    @Override
 +
    public void afterFiring(Activation<?> activation) {
 +
        logger.debug("AFTER FIRING " + activation.toString());
 +
 +
    }
 +
}
 +
</source>
 +
 +
=== EVM Adapter implementation example ===
 +
Similar to the listeners, EVM adapters can either implement the '''IEVMAdapter''' interface or the '''AbstractTransformationAdapter''' abstract class. The following example shows a simple adapter that is capable of changing the set of adapters executed during the EVM program execution. Note that the actual activation selection is not implemented, the example only focuses on showing a viable skeleton implementation for changing EVM execution sequences.
 +
 +
<source lang="java">
 +
public class ExecutorIteratorManipulatorAdapter extends AbstractTransformationAdapter{
 +
       
 +
    @Override
 +
    public Iterator<Activation<?>> getExecutableActivations(Iterator<Activation<?>> iterator) {
 +
    if(iterator instanceof ConflictSetIterator){
 +
    return iterator;
 +
    }else{
 +
    return new ExecutorIteratorManipulatorIterator(iterator);
 +
    }
 +
   
 +
    }
 +
       
 +
    public class ExecutorIteratorManipulatorIterator implements Iterator<Activation<?>>{
 +
    private final Set<Activation<?>> activations = Sets.newHashSet();
 +
   
 +
    public ExecutorIteratorManipulatorIterator(Iterator<Activation<?>> delegatedIterator){
 +
    while(delegatedIterator.hasNext()){
 +
    activations.add(delegatedIterator.next());
 +
    }
 +
    }
 +
   
 +
@Override
 +
public boolean hasNext() {
 +
return !activations.isEmpty();
 +
}
 +
 +
@Override
 +
public Activation<?> next() {
 +
return getActivation(activations);
 +
}
 +
 +
@Override
 +
public void remove() {
 +
throw new UnsupportedOperationException("Deletion from this iterator is not supported.");
 +
 +
}
 +
   
 +
    }
 +
   
 +
    private Activation<?> getActivation(Set<Activation<?>> activations){
 +
        //Get the next activation to be fired
 +
    }
 +
}
 +
</source>
 +
 +
== Assembling an Adaptable EVM infrastructure ==
 +
As mentioned before, the assembly of the adaptable EVM infrastructure is handled by the AdaptableEVM class. However this class is only capable of crating an infrastructure that contains all of the above mentioned adaptable entities. The assembly however is relatively simple and can be done manually as well. the following examples present the assembly sequence via showing code fragments from the AdaptableEVM class ('''this''' refers to the AdaptableEVM instance).
 +
 +
=== Assembling an Adaptable RuleBase ===
 +
 +
<source lang="java">
 +
public RuleEngine createAdaptableRuleEngine(ViatraQueryEngine queryEngine) {
 +
        //Create an adaptable conflict resolver that wraps a default arbitrary conflict resolver
 +
        //If an adaptable conflict resolver is not needed, create the arbitrary conflict resolver
 +
        AdaptableConflictResolver conflictResolver = new AdaptableConflictResolver(new ArbitraryOrderConflictResolver(),
 +
                this);
 +
       
 +
        //Create an agenda based on the created conflict resolver regardless of adaptability
 +
        Agenda debugAgenda = new Agenda(conflictResolver);
 +
        //Set the used activation state change listener. At this point either an adaptable listener, or a default listener can be handed to the Agenda.
 +
        //Note, that the adaptable listener wraps the default one
 +
        debugAgenda.setActivationListener(
 +
                new AdaptableActivationNotificationListener(debugAgenda.getActivationListener(), this));
 +
       
 +
        //Create an adaptable rule based based on the created adaptable or default EVM components.
 +
        //If listening to rule additions is not needed the adaptable RuleBase can be replaced with an EVM default one.
 +
        RuleBase debugRulebase = new AdaptableRuleBase(ViatraQueryEventRealm.create(queryEngine), debugAgenda, this);
 +
       
 +
        //Create the RuleEngine based on the rule base.
 +
        return RuleEngine.create(debugRulebase);
 +
    }
 +
</source>
 +
 +
Note: if you are planning to use an adaptable rule base and want to access the full adapter functionality, use an Adaptable Executor to fire activations. See the VIATRA BatchTransformation ([http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/transformation/plugins/org.eclipse.viatra.transformation.runtime.emf/src/org/eclipse/viatra/transformation/runtime/emf/transformation/batch/BatchTransformation.java source]) and BatchTransformationStatements ([http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/transformation/plugins/org.eclipse.viatra.transformation.runtime.emf/src/org/eclipse/viatra/transformation/runtime/emf/transformation/batch/BatchTransformationStatements.xtend source])  classes
 +
 +
=== Assembling an Adaptable ExecutionSchema ===
 +
 +
<source lang="java">
 +
public ExecutionSchema createAdaptableExecutionSchema(ViatraQueryEngine queryEngine,
 +
            ISchedulerFactory schedulerFactory, ConflictResolver conflictResolver) {
 +
       
 +
        //Create an adaptable executor that wraps a default EVM executor
 +
        //If an adaptable Executor is not needed, create the default EVM one.
 +
        IExecutor executor = new AdaptableExecutor(new Executor(), this);
 +
       
 +
        //Create an adaptable conflict resolver that wraps a default arbitrary conflict resolver
 +
        //If an adaptable conflict resolver is not needed, create the arbitrary conflict resolver
 +
        ConflictResolver adaptableConflictResolver = new AdaptableConflictResolver(conflictResolver, this);
 +
       
 +
        //Create an agenda based on the created conflict resolver regardless of adaptability
 +
        Agenda debugAgenda = new Agenda(adaptableConflictResolver);
 +
        //Set the used activation state change listener. At this point either an adaptable listener, or a default listener can be handed to the Agenda.
 +
        //Note, that the adaptable listener wraps the default one
 +
        debugAgenda.setActivationListener(
 +
                new AdaptableActivationNotificationListener(debugAgenda.getActivationListener(), this));
 +
       
 +
        //Create an adaptable rule based based on the created adaptable or default EVM components.
 +
        //If listening to rule additions is not needed the adaptable RuleBase can be replaced with an EVM default one.
 +
        RuleBase debugRulebase = new AdaptableRuleBase(ViatraQueryEventRealm.create(queryEngine), debugAgenda, this);
 +
       
 +
        //Create a scheduled execution instance based on the executor and rule base objects. (regardless of adaptability)
 +
        //The scheduled execution is responsible for handling scheduling reentry.
 +
        ScheduledExecution execution = new ScheduledExecution(debugRulebase, executor);
 +
       
 +
        //Create a scheduler instance based on the scheduled execution object. (regardless of adaptability)
 +
        Scheduler scheduler = schedulerFactory.prepareScheduler(execution);
 +
       
 +
        //Create execution schema
 +
        final ExecutionSchema schema = ExecutionSchema.create(scheduler);
 +
        //Ser the conflcit resolve of the schema
 +
        schema.setConflictResolver(adaptableConflictResolver);
 +
        return schema;
 +
}
 +
</source>

Latest revision as of 09:37, 30 November 2017

Stop.png
Old information
This page is not updated anymore; for more up-to-date details look at the language specification at https://www.eclipse.org/viatra/documentation/transformations.html instead.

Motivation

The development and debugging of reactive event-driven model transformations is not a trivial exercise, the basic concepts of software debugging however can be mapped to the field of model transformations. Debuggers can be used for detecting bugs, as well as better understanding the structure and behavior of programs. Direct control over a program allows the programmer to follow the flow of execution or stop the program at any desired point. Then it is possible to inspect its current state and verify the correctness of the software. These properties are very desirable in the field of model transformations as well. The VIATRA framework possesses a solution for implementing transformation debugging related functionalities.

A full featured transformation debugger requires a software solution that is able to observe and control model transformations. Such an extension is able to insert additional functionality into certain points during model transformations. The transformation adapter framework allows the definition of additional functionalities that are executed at certain points in event-driven model transformations. The previously described debug functionalities are implemented using the EVM adapter framework.

High level architecture

VIATRA adapter arch.png

Components

  • Adapter Interface: The Adapter Interface defines a set of callback methods that are executed at certain points during the transformation execution. These actions are capable of altering the execution sequence of transformation rules. A number of Adapters can implement this interface, in order to define additional functionality that should be undertaken at certain points in the transformation.
  • Listener Interface: The Listener Interface defines a set of callback methods that are executed at certain points during the transformation execution. The actions defined in these methods can have no effect on the transformation itself, purely aim at providing a solution to listening to certain transformation-related events. A number of Adapters can implement this interface, in order to define additional functionality that should be undertaken at certain points in the transformation.
  • Adaptable EVM: The Adaptable EVM is responsible aggregating the used Adapter and Listener instances and delegates the callback method calls from the internal VIATRA objects towards the appropriate callback method of each adapter or listener at certain points during execution. The Adaptable EVM is also responsible for setting up VIATRA transformation to utilize adapters.
  • Adapter Configuration: The adapter configurations serve multiple purposes. They can either define dependency relations between adapter imple-mentations, or specify complex use cases which requires more than one adapter to func-tion properly

The Adapter Framework provides a generic, easy-to-use technique for creating user defined adapter and listener implementations. The Adapter Framework is utilized in order to implement a set of debugging-related use cases.

Connection with EVM

The class diagram below depicts the relations between the internal EVM elements and members of the EVM adapter framework.

Legend:

  • Green: API classes through which the user can define EVM based programs.
  • Blue: Internal EVM classes and interfaces.
  • Yellow: Adaptable EVM classes

EVMAdapter Class.png

  • AdaptableEVM:
    • Aggregates listeners and adapters
    • Assembles an adapter supporting EVM instance
      • ExecutionSchema
      • RuleEngine
  • IEVMAdapter: Callback methods for manipulation the set of EVM Activations to be executed
    • Wraps a handed Iterator with one defined by the adapter implementation --> manipulate the Activations handed to the executor.
    • Wraps a handed ChangeableConflictSet with one defined by the adapter implementation --> Activations returned by the conflict set can be manipulated.
  • IEVMListener: Defines a set of callback methods that can be used to listen to certain EVM-based events, and react to them accordingly. However these callback methods cannot manipulate the EVM rule execution sequence in any way. Callback methods can be defined for the following events: (for details check Javadoc)
    • Initialization/disposal
    • Before/after activation firing
    • Before/after transaction
    • Activation state change
    • Activation removed
    • Activation created
    • EVM rule added/removed
  • AdaptableRulebase: The Adaptable RuleBase extends the EVM Rulebase. It has a reference to an AdaptableEVM object, through this it can notify adapters about the addition and removal of EVM rule Specifications.
  • AdaptableExecutor: The Adaptable Executor as the same responsibilities as the EVM Executor, however, it can also notify EVM listeners about the starting/ending transactions and activations firings. It also enables adapters to alter the set of Activations the executor is assigned to fire.
  • AdaptableActivationNotificationListener: Delegates a default EVM activation notification listener. apart from calling the respective methods of the delegated activation change listener, it also notifies EVM listeners about activation state changes.
  • AdaptableConflictResolver: The adaptable conflict resolver allows EVM adapters to override or alter the conflict set created by a delegated conflict resolver instance, in order to modify the execution sequence of an EVM-based program.

Defining adapter and listener implementations

EVM Listener implementation example

EVM listener implementations should implement the IEVMListener interface, or extend the AbstractTransformationListener abstract class. Usage of the abstract class is recommended, as it enables the developer to only subscribe to a certain set of EVM events without implementing every method if the IEVMAdapter interface. The following source code example shows a simple logging listener implementation.

public class FiringLoggingEVMListener extends AbstractTransformationListener{
    private final Logger logger;
 
    public FiringLoggingEVMListener(Logger logger) {
        this.logger = logger;
    }
 
    @Override
    public void beforeFiring(Activation<?> activation) {
        logger.debug("BEFORE FIRING " + activation.toString());
 
    }
 
    @Override
    public void afterFiring(Activation<?> activation) {
        logger.debug("AFTER FIRING " + activation.toString());
 
    }
}

EVM Adapter implementation example

Similar to the listeners, EVM adapters can either implement the IEVMAdapter interface or the AbstractTransformationAdapter abstract class. The following example shows a simple adapter that is capable of changing the set of adapters executed during the EVM program execution. Note that the actual activation selection is not implemented, the example only focuses on showing a viable skeleton implementation for changing EVM execution sequences.

public class ExecutorIteratorManipulatorAdapter extends AbstractTransformationAdapter{
 
    @Override
    public Iterator<Activation<?>> getExecutableActivations(Iterator<Activation<?>> iterator) {
    	if(iterator instanceof ConflictSetIterator){
    		return iterator;
    	}else{
    		return new ExecutorIteratorManipulatorIterator(iterator);
    	}
 
    }
 
    public class ExecutorIteratorManipulatorIterator implements Iterator<Activation<?>>{
    	private final Set<Activation<?>> activations = Sets.newHashSet();
 
    	public ExecutorIteratorManipulatorIterator(Iterator<Activation<?>> delegatedIterator){
    		while(delegatedIterator.hasNext()){
    			activations.add(delegatedIterator.next());
    		}
    	}
 
		@Override
		public boolean hasNext() {
			return !activations.isEmpty();
		}
 
		@Override
		public Activation<?> next() {
			return getActivation(activations);
		}
 
		@Override
		public void remove() {
			throw new UnsupportedOperationException("Deletion from this iterator is not supported.");
 
		}
 
    }
 
    private Activation<?> getActivation(Set<Activation<?>> activations){
        //Get the next activation to be fired
    }
}

Assembling an Adaptable EVM infrastructure

As mentioned before, the assembly of the adaptable EVM infrastructure is handled by the AdaptableEVM class. However this class is only capable of crating an infrastructure that contains all of the above mentioned adaptable entities. The assembly however is relatively simple and can be done manually as well. the following examples present the assembly sequence via showing code fragments from the AdaptableEVM class (this refers to the AdaptableEVM instance).

Assembling an Adaptable RuleBase

public RuleEngine createAdaptableRuleEngine(ViatraQueryEngine queryEngine) {
        //Create an adaptable conflict resolver that wraps a default arbitrary conflict resolver 
        //If an adaptable conflict resolver is not needed, create the arbitrary conflict resolver
        AdaptableConflictResolver conflictResolver = new AdaptableConflictResolver(new ArbitraryOrderConflictResolver(),
                this);
 
        //Create an agenda based on the created conflict resolver regardless of adaptability
        Agenda debugAgenda = new Agenda(conflictResolver);
        //Set the used activation state change listener. At this point either an adaptable listener, or a default listener can be handed to the Agenda. 
        //Note, that the adaptable listener wraps the default one
        debugAgenda.setActivationListener(
                new AdaptableActivationNotificationListener(debugAgenda.getActivationListener(), this));
 
        //Create an adaptable rule based based on the created adaptable or default EVM components.
        //If listening to rule additions is not needed the adaptable RuleBase can be replaced with an EVM default one.
        RuleBase debugRulebase = new AdaptableRuleBase(ViatraQueryEventRealm.create(queryEngine), debugAgenda, this);
 
        //Create the RuleEngine based on the rule base.
        return RuleEngine.create(debugRulebase);
    }

Note: if you are planning to use an adaptable rule base and want to access the full adapter functionality, use an Adaptable Executor to fire activations. See the VIATRA BatchTransformation (source) and BatchTransformationStatements (source) classes

Assembling an Adaptable ExecutionSchema

public ExecutionSchema createAdaptableExecutionSchema(ViatraQueryEngine queryEngine,
            ISchedulerFactory schedulerFactory, ConflictResolver conflictResolver) {
 
        //Create an adaptable executor that wraps a default EVM executor
        //If an adaptable Executor is not needed, create the default EVM one.
        IExecutor executor = new AdaptableExecutor(new Executor(), this);
 
        //Create an adaptable conflict resolver that wraps a default arbitrary conflict resolver
        //If an adaptable conflict resolver is not needed, create the arbitrary conflict resolver
        ConflictResolver adaptableConflictResolver = new AdaptableConflictResolver(conflictResolver, this);
 
        //Create an agenda based on the created conflict resolver regardless of adaptability
        Agenda debugAgenda = new Agenda(adaptableConflictResolver);
        //Set the used activation state change listener. At this point either an adaptable listener, or a default listener can be handed to the Agenda. 
        //Note, that the adaptable listener wraps the default one
        debugAgenda.setActivationListener(
                new AdaptableActivationNotificationListener(debugAgenda.getActivationListener(), this));
 
        //Create an adaptable rule based based on the created adaptable or default EVM components.
        //If listening to rule additions is not needed the adaptable RuleBase can be replaced with an EVM default one.
        RuleBase debugRulebase = new AdaptableRuleBase(ViatraQueryEventRealm.create(queryEngine), debugAgenda, this);
 
        //Create a scheduled execution instance based on the executor and rule base objects. (regardless of adaptability)
        //The scheduled execution is responsible for handling scheduling reentry.
        ScheduledExecution execution = new ScheduledExecution(debugRulebase, executor);
 
        //Create a scheduler instance based on the scheduled execution object. (regardless of adaptability)
        Scheduler scheduler = schedulerFactory.prepareScheduler(execution);
 
        //Create execution schema
        final ExecutionSchema schema = ExecutionSchema.create(scheduler);
        //Ser the conflcit resolve of the schema
        schema.setConflictResolver(adaptableConflictResolver);
        return schema;
}

Back to the top