blob: d185f5ec6f91491879f935a1f314517963ab3db7 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-language" content="en">
<meta name="description" content="Scalable Reactive Model Transformations">
<meta name="MobileOptimized" content="width" />
<meta name="HandheldFriendly" content="true" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="/viatra/js/googleAnalytics.js"></script>
<script type="text/javascript" src="/viatra/js/magnific-popup.video.js"></script>
<script type="text/javascript" src="/viatra/js/magnific-popup.min.js"></script>
<script type="text/javascript" src="/viatra/js/functions.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="/viatra/angular/viatra.js"></script>
<script src="/viatra/highlight.js/highlight.min.js"></script>
<link rel="stylesheet" type="text/css" href="//www.eclipse.org/eclipse.org-common/themes/solstice/public/stylesheets/vendor/cookieconsent/cookieconsent.min.css" />
<script src="//www.eclipse.org/eclipse.org-common/themes/solstice/public/javascript/vendor/cookieconsent/default.min.js"></script>
<link rel="shortcut icon" type="image/x-icon" href="/viatra/favicon.ico" />
<title>Viatra - Scalable reactive model transformations</title>
<link type="text/css" rel="stylesheet" href="/viatra/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="/viatra/css/style.css" />
<link type="text/css" rel="stylesheet" href="/viatra/css/media.css" />
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300italic,700,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="https://use.fontawesome.com/ef6567f233.css">
<link rel="stylesheet" href="/viatra/highlight.js/styles/foundation.min.css">
<link rel="stylesheet" type="text/css" href="/viatra/css/asciidoctor.css"/>
</head>
<body ng-app="viatra" ng-controller="main" class="cloak">
<ng-include src="'/viatra/angular/blocks/header.html'"></ng-include>
<div class="clear"></div>
<div id="body_wrapper">
<h1 class="page_title">The Event-driven Virtual Machine</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Nowadays, collaboration and scalability challenges in modeling tools are typically addressed with dedicated problem-specific solutions e.g.:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>On-the-fly constraint evaluation engines (to provide scalability for model validation)</p>
</li>
<li>
<p>Incremental model transformation tools (to address performance issues of e.g. model synchronization)</p>
</li>
<li>
<p>Incremental model comparison algorithms (to support versioning and model merge in collaborative scenarios)</p>
</li>
<li>
<p>Design space exploration tools (to optimize models towards a design goal).</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The common recurring task in these applications is to capture and process not only the models, but also their changes as a stream of events (operations that affect models). We generalized this approach to provide a common conceptual framework for an <strong>event-driven virtual machine</strong> (EVM) architecture.</p>
</div>
<div class="paragraph">
<p>The EVM is a rule-based system with a special focus on versatile model transformations, with built-in support for reacting to model and query result changes and user interactions. The EVM integrates various execution schemes into a uniform and flexible architecture, to provide a common framework that even allows for combinations of advanced model transformation scenarios, e.g. by the interleaving of various execution strategies (batch, live/triggered and exploratory) within a single transformation program.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_core_architecture"><a class="link" href="#_core_architecture">1. Core architecture</a></h2>
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="./images/transformation/evm-overview.png" alt="Overview of the Event-driven VM">
</div>
</div>
<div class="paragraph">
<p>The event-driven virtual machine allows the central management of executable actions defined on event sources and can execute these actions automatically with a predefined schedule.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>An <strong>activation</strong> is wrapper of a pattern match with a corresponding rule instance and state.</p>
<div class="ulist">
<ul>
<li>
<p>Activation <strong>states</strong> are: inactive, appeared, fired, updated, disappeared</p>
</li>
</ul>
</div>
</li>
<li>
<p>A <strong>rule instance</strong> manages the activations corresponding to a rule specification in a given VIATRA Query engine.</p>
</li>
<li>
<p>A <strong>rule specification</strong> defines the life cycle for changing the activation state in response to events and the possible actions that can be executed on an activation in a given state.</p>
<div class="ulist">
<ul>
<li>
<p><strong>Events</strong> related to a life cycle are: match appears/disappears/updates, activation fires</p>
</li>
<li>
<p>State <strong>transitions</strong> in a life cycle always have a source state, an event and a target state. There can be only one (source state, event) pair in the life cycle, thus the target state is always deterministic.</p>
</li>
<li>
<p><strong>Jobs</strong> are atomic actions that are performed if an activation is fired when in a state defined by the job.</p>
</li>
<li>
<p>An activation is <strong>enabled</strong> if there is at least one job that is defined for the current state of the activation.</p>
</li>
</ul>
</div>
</li>
<li>
<p>An <strong>agenda</strong> is a collection of rule instances with an added responsibility of ordering the enabled activations of all rule instances related to the same VIATRA Query engine</p>
<div class="ulist">
<ul>
<li>
<p>The agenda keeps track of the activations of the rule instances by an <strong>activation notification</strong> mechanism. Rule instances notify the agenda if one of their activations changed state in response to an event.</p>
</li>
</ul>
</div>
</li>
<li>
<p>An <strong>executor</strong> is responsible for executing enabled activations in the agenda when it is scheduled to do so, and to provide an execution <strong>context</strong> to store execution results or other data related to execution.</p>
</li>
<li>
<p>A <strong>scheduler</strong> is defined to respond to some kind of global event (e.g. transaction commit, user request, or VIATRA Query Base update callback) by scheduling its executor.</p>
</li>
<li>
<p>A <strong>rule engine</strong> is created for a given VIATRA Query engine and an optional set of rule specifications, and has its own agenda.</p>
</li>
<li>
<p>A <strong>execution schema</strong> is a special rule engine, that also has a scheduler set up.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_example_code"><a class="link" href="#_example_code">2. Example code</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>We illustrate the two main usage modes of the EVM with UML models. First, we have to define the preconditions with patterns, then define the rule specifications which can be added to a rule engine or execution schema.</p>
</div>
<div class="paragraph">
<p>The example project is on the repository: <a href="http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/papyrus-uml/org.eclipse.viatra.examples.uml.evm/">UML EVM Example</a></p>
</div>
<div class="sect2">
<h3 id="_precondition_pattern_definition"><a class="link" href="#_precondition_pattern_definition">2.1. Precondition pattern definition</a></h3>
<div class="paragraph">
<p>The code example below shows the <strong>possibleSuperClass</strong> and <strong>onlyInheritedOperations</strong> patterns of that are based on the UML example, the complete query definition can be found in our repository: <a href="http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/papyrus-uml/org.eclipse.viatra.examples.uml.evm/src/org/eclipse/viatra/examples/uml/evm/queries/preconditions.vql">preconditions.vql</a></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-vql hljs" data-lang="vql">/* Precondition for add generalization rule */
pattern possibleSuperClass(cl : Class, sup : Class) {
neg find superClass(cl, _otherSup);
neg find superClass(_cl2, sup);
}
/* Precondition for create owned operation */
pattern onlyInheritedOperations(cl : Class) {
find hasOperation(cl, _op);
neg find ownsOperation(cl, _ownOp);
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rule_specifications"><a class="link" href="#_rule_specifications">2.2. Rule specifications</a></h3>
<div class="paragraph">
<p>We define two rule specifications, both encapsulated by a method in <a href="http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/papyrus-uml/org.eclipse.viatra.examples.uml.evm/src/org/eclipse/viatra/examples/uml/evm/UMLexampleForEVM.java">UMLexampleForEVM.java</a>.</p>
</div>
<div class="paragraph">
<p>The first rule specification uses the <strong>possibleSuperClass</strong> pattern as a precondition and when executed for a given class pair, it creates a new Generalization element to set the class <strong>sup</strong> as a superclass for <strong>cl</strong>. The life-cycle is the most simple, where neither the updated, nor the disappeared state is used.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// the job specifies what to do when an activation is fired in the given state
Job job = Jobs.newStatelessJob(CRUDActivationStateEnum.APPEARED, new PossibleSuperClassProcessor() {
@Override
public void process(Class cl, Class sup) {
System.out.println("Found cl " + cl + " without superclass");
Generalization generalization = UMLFactory.eINSTANCE.createGeneralization();
generalization.setGeneral(sup);
generalization.setSpecific(cl);
}
});
// the life-cycle determines how events affect the state of activations
DefaultActivationLifeCycle lifecycle = DefaultActivationLifeCycle.DEFAULT_NO_UPDATE_AND_DISAPPEAR;
// the factory is used to initialize the matcher for the precondition
IMatcherFactory&lt;PossibleSuperClassMatcher&gt; factory = PossibleSuperClassMatcher.factory();
// the rule specification is a model-independent definition that can be used to instantiate a rule
RuleSpecification spec = Rules.newSimpleMatcherRuleSpecification(factory, lifecycle, Sets.newHashSet(job));</code></pre>
</div>
</div>
<div class="paragraph">
<p>The second rule specification is similar, it uses the <code>onlyInheritedOperations</code> pattern and when executed it creates a new operation with name <strong>newOp</strong> and adds it to the class which had no own property before.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Job job = Jobs.newStatelessJob(CRUDActivationStateEnum.APPEARED, new OnlyInheritedOperationsProcessor() {
@Override
public void process(Class cl) {
System.out.println("Found class " + cl + " without operation");
Operation operation = UMLFactory.eINSTANCE.createOperation();
operation.setName("newOp");
operation.setClass_(cl);
}
});
DefaultActivationLifeCycle lifecycle = DefaultActivationLifeCycle.DEFAULT_NO_UPDATE_AND_DISAPPEAR;
IMatcherFactory&lt;OnlyInheritedOperationsMatcher&gt; factory = OnlyInheritedOperationsMatcher.factory();
RuleSpecification spec = Rules.newSimpleMatcherRuleSpecification(factory, lifecycle, Sets.newHashSet(job));</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_fire_activations_manually_using_a_rule_engine"><a class="link" href="#_fire_activations_manually_using_a_rule_engine">2.3. Fire activations manually using a rule engine</a></h3>
<div class="paragraph">
<p>The first option when using the EVM is creating a rule engine, which manages the set of activations, but will not fire the enabled activations. A rule engine has no context of its own, so the user can create one to use when firing activations. The rule specifications above are returned by the two getter methods, and the <code>addRule</code> method is used on the rule engine to instantiate the rules.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// create rule engine over query engine
RuleEngine ruleEngine = RuleEngines.createViatraQueryRuleEngine(engine);
// create context for execution
Context context = Context.create();
// prepare rule specifications
RuleSpecification createGeneralization = getCreateGeneralizationRule();
RuleSpecification createOperation = getCreateOperationRule();
// add rule specifications to engine
ruleEngine.addRule(createGeneralization);
ruleEngine.addRule(createOperation);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Once a rule specification is added to the rule engine, the existing activations of a given rule can be retrieved from the rule engine and can fire them manually. Alternatively, the next activation as selected by the conflict resolver (which is a simple hash set without ordering) can be retrieved and fired.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// check rule applicability
Set&lt;Activation&gt; createClassesActivations = ruleEngine.getActivations(createGeneralization);
if (!createClassesActivations.isEmpty()) {
// fire activation of a given rule
createClassesActivations.iterator().next().fire(context);
}
// check for any applicable rules
while (!ruleEngine.getConflictingActivations().isEmpty()) {
// fire next activation as long as possible
ruleEngine.getNextActivation().fire(context);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>As long as the rule engine exists, it will keep on managing the activations of added rules. It is possible to remove a single rule, which will remove all its activations from the rule engine, and the rule engine can be disposed when not needed anymore.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// rules that are no longer needed can be removed
ruleEngine.removeRule(createGeneralization);
// rule engine manages the activations of the added rules until disposed
ruleEngine.dispose();</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_fire_activations_automatically_with_an_execution_schema"><a class="link" href="#_fire_activations_automatically_with_an_execution_schema">2.4. Fire activations automatically with an execution schema</a></h3>
<div class="paragraph">
<p>The second option for using the EVM is to create an execution schema that has a scheduler to fire activations after predefined events and an executor that specifies how to fire activations when scheduled. In the example, we use the feature in VIATRA Query Base that allows us to register a callback on model changes. An execution schema is created using a VIATRA Query engine and a scheduler factory, then the rules are added, in the same way as for the rule engine.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// use IQBase update callback for scheduling execution
UpdateCompleteBasedSchedulerFactory schedulerFactory = Schedulers.getIQEngineSchedulerFactory(engine);
// create execution schema over ViatraQueryEngine
ExecutionSchema executionSchema = ExecutionSchemas.createViatraQueryExecutionSchema(engine, schedulerFactory);
// prepare rule specifications
RuleSpecification createGeneralization = getCreateGeneralizationRule();
RuleSpecification createOperation = getCreateOperationRule();
// add rule specifications to engine
executionSchema.addRule(createGeneralization);
executionSchema.addRule(createOperation);</code></pre>
</div>
</div>
<div class="paragraph">
<p>In the example we simply modify the model by removing a generalization from a random class. When the model modification is handled by VIATRA Query, the callback notifies the scheduler, which starts the executor, which in turn will fire enabled activations as-long-as-possible. The scheduler in the example uses the model update listener of the engine (<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=398744">see bug 398744</a>) to get callbacks on changes.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// execution schema waits for a scheduling to fire activations
// we trigger this by removing one generalization at random
SuperClassMatcher.factory().getMatcher(engine).forOneArbitraryMatch(new SuperClassProcessor() {
@Override
public void process(Class sub, Class sup) {
sub.getGeneralizations().remove(0);
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>Similarly to the rule engine, it is possible to remove a rule from the execution schema or to dispose it when not needed any longer. The main difference between the rule engine and the execution schema is, that once a rule has been added, the activations that are enabled will be executed automatically every time the scheduler is notified. This allows us to implement components that can react to changes incrementally, without requiring additional scaffolding.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// rules that are no longer needed can be removed
executionSchema.removeRule(createGeneralization);
// execution schema manages and fires the activations of the added
// rules until disposed
executionSchema.dispose();</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_impose_ordering_between_activations_of_different_rules"><a class="link" href="#_impose_ordering_between_activations_of_different_rules">2.5. Impose ordering between activations of different rules</a></h3>
<div class="paragraph">
<p>Activations that are enabled are in conflict with each other since firing any of them can cause the other activations to become disabled.
The conflict set of a rule engine is the set of enabled activations of all rules, and users can define a conflict resolver that provides
an ordering in the conflict set (<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=403825">bug 403825</a>).</p>
</div>
</div>
<div class="sect2">
<h3 id="_enabling_log_messages_in_evm"><a class="link" href="#_enabling_log_messages_in_evm">2.6. Enabling log messages in EVM</a></h3>
<div class="paragraph">
<p>Due to the event-driven nature of EVM, it is often difficult to debug your program, since the control flow will go through EVM internals and activation life-cycle is handled independently of activation firing.
In order to see exactly what happens inside EVM, you can set the log level of the Log4J logger of rule engines to display DEBUG or even TRACE level messages.
The log will include events, activation state changes, scheduling and executor events, firing and other useful information.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// just set the log level of the engine as needed
ruleEngine.getLogger().setLevel(Level.DEBUG);</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="evm-adapters"><a class="link" href="#evm-adapters">3. Observing EVM Execution with Adapters</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>To ease the development of reactive transformations over EVM, it is beneficial have support for debuggers, profilers and similar tools. These all require to allow observing the execution of the transformation and/or provide indirect control over transformations. The Adapter Framework for EVM provides a generic, easy-to-use technique for creating user defined adapter and listener implementations.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="./images/transformation/adapter_framework.png" alt="High level adapters" width="1000">
</div>
<div class="title">Figure 1. High level architecture</div>
</div>
<div class="paragraph">
<p>The most important concepts of the Adapter Framework are as follows:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">Adapter Interface</dt>
<dd>
<p>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.</p>
</dd>
<dt class="hdlist1">Listener Interface</dt>
<dd>
<p>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.</p>
</dd>
<dt class="hdlist1">Adaptable EVM</dt>
<dd>
<p>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.</p>
</dd>
<dt class="hdlist1">Adapter Configuration</dt>
<dd>
<p>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</p>
</dd>
</dl>
</div>
<div class="sect2">
<h3 id="_connection_with_evm"><a class="link" href="#_connection_with_evm">3.1. Connection with EVM</a></h3>
<div class="paragraph">
<p>The class diagram below depicts the relations between the internal EVM elements and members of the EVM adapter framework. The classes with color <strong>green</strong> are API classes through which the user can define EVM based programs; <strong>blue</strong> marks internal EVM classes and interfaces while <strong>yellow</strong> marks the adaptable classes.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="./images/transformation/evm_adapter_classes.png" alt="Class Diagram for Adaptable EVM instances" width="1500">
</div>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>AdaptableEVM</strong>:</p>
<div class="ulist">
<ul>
<li>
<p>Aggregates listeners and adapters</p>
</li>
<li>
<p>Assembles an adapter supporting EVM instance</p>
<div class="ulist">
<ul>
<li>
<p>ExecutionSchema</p>
</li>
<li>
<p>RuleEngine</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
<li>
<p><strong>IEVMAdapter</strong>: Callback methods for manipulation the set of EVM Activations to be executed</p>
<div class="ulist">
<ul>
<li>
<p>Wraps a handed Iterator with one defined by the adapter implementation &#8594; manipulate the Activations handed to the executor.</p>
</li>
<li>
<p>Wraps a handed ChangeableConflictSet with one defined by the adapter implementation &#8594; Activations returned by the conflict set can be manipulated.</p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>IEVMListener</strong>: 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)</p>
<div class="ulist">
<ul>
<li>
<p>Initialization/disposal</p>
</li>
<li>
<p>Before/after activation firing</p>
</li>
<li>
<p>Before/after transaction</p>
</li>
<li>
<p>Activation state change</p>
</li>
<li>
<p>Activation removed</p>
</li>
<li>
<p>Activation created</p>
</li>
<li>
<p>EVM rule added/removed</p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>AdaptableRulebase</strong>: 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.</p>
</li>
<li>
<p><strong>AdaptableExecutor</strong>: 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.</p>
</li>
<li>
<p><strong>AdaptableActivationNotificationListener</strong>: 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.</p>
</li>
<li>
<p><strong>AdaptableConflictResolver</strong>: 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.</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Not all EVM instances are adaptable because the notification handling may have an effect on performance. However, there are APIs available that create adaptable EVM instances when an adapter or listener is added, otherwise rely on the default, non-adaptable version.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_defining_adapter_and_listener_implementations"><a class="link" href="#_defining_adapter_and_listener_implementations">3.2. Defining adapter and listener implementations</a></h3>
<div class="sect3">
<h4 id="_evm_listener_implementation_example"><a class="link" href="#_evm_listener_implementation_example">3.2.1. EVM Listener implementation example</a></h4>
<div class="paragraph">
<p>EVM listener implementations should implement the <code>IEVMListener</code> interface, or extend the <code>AbstractTransformationListener</code> 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 <code>IEVMAdapter</code> interface. The following source code example shows a simple logging listener implementation.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class FiringLoggingEVMListener extends AbstractTransformationListener{
private final Logger logger;
public FiringLoggingEVMListener(Logger logger) {
this.logger = logger;
}
@Override
public void beforeFiring(Activation&lt;?&gt; activation) {
logger.debug("BEFORE FIRING " + activation.toString());
}
@Override
public void afterFiring(Activation&lt;?&gt; activation) {
logger.debug("AFTER FIRING " + activation.toString());
}
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_evm_adapter_implementation_example"><a class="link" href="#_evm_adapter_implementation_example">3.2.2. EVM Adapter implementation example</a></h4>
<div class="paragraph">
<p>Similar to the listeners, EVM adapters can either implement the <code>IEVMAdapter</code> interface or the <code>AbstractTransformationAdapter</code> 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.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class ExecutorIteratorManipulatorAdapter extends AbstractTransformationAdapter{
@Override
public Iterator&lt;Activation&lt;?&gt;&gt; getExecutableActivations(Iterator&lt;Activation&lt;?&gt;&gt; iterator) {
if(iterator instanceof ConflictSetIterator){
return iterator;
}else{
return new ExecutorIteratorManipulatorIterator(iterator);
}
}
public class ExecutorIteratorManipulatorIterator implements Iterator&lt;Activation&lt;?&gt;&gt;{
private final Set&lt;Activation&lt;?&gt;&gt; activations = Sets.newHashSet();
public ExecutorIteratorManipulatorIterator(Iterator&lt;Activation&lt;?&gt;&gt; delegatedIterator){
while(delegatedIterator.hasNext()){
activations.add(delegatedIterator.next());
}
}
@Override
public boolean hasNext() {
return !activations.isEmpty();
}
@Override
public Activation&lt;?&gt; next() {
return getActivation(activations);
}
@Override
public void remove() {
throw new UnsupportedOperationException("Deletion from this iterator is not supported.");
}
}
private Activation&lt;?&gt; getActivation(Set&lt;Activation&lt;?&gt;&gt; activations){
//Get the next activation to be fired
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_assembling_an_adaptable_evm_infrastructure"><a class="link" href="#_assembling_an_adaptable_evm_infrastructure">3.3. Assembling an Adaptable EVM infrastructure</a></h3>
<div class="paragraph">
<p>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 (<code>this</code> refers to the AdaptableEVM instance).</p>
</div>
<div class="listingblock">
<div class="title">Assembling an Adaptable RuleBase</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-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);
}
&lt;/source&gt;</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
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 (<a href="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</a>) and BatchTransformationStatements (<a href="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</a>) classes.
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="title">Assembling an Adaptable ExecutionSchema</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-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;
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_usage_scenarios"><a class="link" href="#_usage_scenarios">4. Usage scenarios</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Both the data binding and validation frameworks of VIATRA use the EVM for handling events.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Data binding: observable match result collections are created in the createRuleSpecification method of ObservableCollectionHelper (org.eclipse.viatra.databinding.runtime.collection package)</p>
</li>
<li>
<p>Validation constraints are created in the constructor of ConstraintAdapter (org.eclipse.viatra.validation.runtime package)</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_programming_against_the_evm_api"><a class="link" href="#_programming_against_the_evm_api">4.1. Programming against the EVM API</a></h3>
<div class="paragraph">
<p>The basic usage of the EVM is to react to match set changes easily.</p>
</div>
<div class="sect3">
<h4 id="_efficiently_reacting_to_pattern_match_set_changes"><a class="link" href="#_efficiently_reacting_to_pattern_match_set_changes">4.1.1. Efficiently reacting to pattern match set changes</a></h4>
<div class="paragraph">
<p>If you want to efficiently react to appearing, changing or disappearing matches, the EVM is a perfect choice.
Just define a rule specification with the correct life-cycle and jobs and create an execution schema as described above.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>If you only want to react to appearance events: use <code>DefaultActivationLifeCycle.DEFAULT_NO_UPDATE_AND_DISAPPEAR</code> and a single APPEARED job.</p>
</li>
<li>
<p>If you want to react to both appearance and disappearance: use <code>DefaultActivationLifeCycle.DEFAULT_NO_UPDATE</code> and two jobs, one with APPEARED and the other with DISAPPEARED state.</p>
</li>
<li>
<p>If you want to react to changes of match parameters (e.g. an attribute value changes, but the match still exists): use <code>DefaultActivationLifeCycle.DEFAULT</code> and add an additional job with UPDATED state.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_roll_your_own_event_provider_for_evm"><a class="link" href="#_roll_your_own_event_provider_for_evm">4.2. Roll your own event provider for EVM</a></h3>
<div class="paragraph">
<p>The EVM core is independent of EMF and VIATRA Query, see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=406558" class="bare">https://bugs.eclipse.org/bugs/show_bug.cgi?id=406558</a>
You can create your own event realm and use the EVM core concepts to execute event-driven rules. You can see a small example in <a href="http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/evm-proto" class="bare">http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/evm-proto</a></p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_design_decisions_and_code_style"><a class="link" href="#_design_decisions_and_code_style">5. Design decisions and code style</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>These guidelines are derived from the main decision to create a defensive framework to minimize the internal argument checks and other defensive programming measures required.</p>
</div>
<div class="sect2">
<h3 id="_user_interaction_with_the_framework"><a class="link" href="#_user_interaction_with_the_framework">5.1. User interaction with the framework</a></h3>
<div class="ulist">
<ul>
<li>
<p>Users interact with rules and activations through Façade classes:</p>
<div class="ulist">
<ul>
<li>
<p>RuleEngine façade provides access to an Agenda and it&#8217;s rule instances</p>
</li>
<li>
<p>ExecutionSchema façade provides access to a Scheduler and through that to the Executor</p>
</li>
<li>
<p>These Façade classes can be retrieved through the static methods of EventDrivenVM or by static create methods (for specific implementations)</p>
</li>
</ul>
</div>
</li>
<li>
<p>Any object that a user can access through the Façade must have only public methods that do not endanger their engine (e.g. Activation.fire(), but not Activation.setState())</p>
</li>
<li>
<p>Any collection that a user can access through the Façade must be immutable to avoid modifications (e.g. getActivations)</p>
</li>
<li>
<p>Any object that is provided by the user must be copied if it&#8217;s later modification can cause internal problems (e.g. life cycle for rules)</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_parameters_input_checking_and_logging"><a class="link" href="#_parameters_input_checking_and_logging">5.2. Parameters, input checking and logging</a></h3>
<div class="ulist">
<ul>
<li>
<p>Method parameters cannot be null!</p>
<div class="ulist">
<ul>
<li>
<p>This is checked by Preconditions.checkNotNull(ref, msg). Return a meaningful message on null.</p>
</li>
<li>
<p>Use the <code>this.field = checkNotNull(field, msg)</code> form in constructors when possible.</p>
</li>
<li>
<p>Define delegate methods where optional parameters are allowed.</p>
</li>
</ul>
</div>
</li>
<li>
<p>All logging is done through the rule base, use the debug level for detailed report messages and error or warning when encountering a real problem (e.g. ViatraQueryException)</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_default_implementations"><a class="link" href="#_default_implementations">5.3. Default implementations</a></h3>
<div class="paragraph">
<p>There are a high number of notification mechanisms and event processing, that must have an interface for extendibility, a good default implementation and a clear way of overriding.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>In RuleInstance notification providers and listeners are created in prepareX methods.</p>
</li>
<li>
<p>Default life cycles prepared with unmodifiable static instances.</p>
</li>
<li>
<p>Update complete provider implementations (IQBase and EMF transaction).</p>
</li>
<li>
<p>Scheduler implementations (update complete and timed).</p>
</li>
<li>
<p>Job implementations (stateless with a single match processor, and recording for transactional model modification).</p>
<div class="ulist">
<ul>
<li>
<p>Job implementations can specify their own error handling (<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=404307" class="bare">https://bugs.eclipse.org/bugs/show_bug.cgi?id=404307</a>)</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_usage_example"><a class="link" href="#_usage_example">6. Usage Example</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>This section will sketch out how EVM can be used to describe transformation steps over an EMF model. At first, a VIATRA Query Engine is to be initialized over an EMFScope. This EMFScope contains the resource set in which the source and the target of the transformation can be found. The main part of the demo is in the <code>execute</code> method. As domain of this transformation,</p>
</div>
<div class="sect2">
<h3 id="_transformation_rules"><a class="link" href="#_transformation_rules">6.1. Transformation rules</a></h3>
<div class="paragraph">
<p>We have two main rule: the hostMapping and appMapping.</p>
</div>
<div class="paragraph">
<p>The hostMapping has three job (one for all states of the life cycle):</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The pattern: This rule is based on the hostInstances pattern. This pattern finds all host instances.</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><em>ActivationState.CREATED</em>: This job create deployment hosts for host instances. The ip of the deployment host is set here.</p>
</li>
<li>
<p><em>ActivationState.DELETED</em>: This removes deployment pairs of disappeared host instances.</p>
</li>
<li>
<p><em>ActivationState.UPDATED</em>: This will be invoked when the hostInstances pattern updated (so when a host type or host instance is modified). The description of the deployment host is set to <code>modified</code>.</p>
</li>
</ol>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>The appMapping has only two job:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The pattern: This rule is based on the applicationsInstances pattern. This finds application instances which is allocated to host instance which has a pair in the deployment.</p>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><em>ActivationState.CREATED</em>: Creates the deployment application (sets the id).</p>
</li>
<li>
<p><em>ActivationState.DELETED</em>: Removes the deployment application.</p>
</li>
</ol>
</div>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_resolver"><a class="link" href="#_resolver">6.2. Resolver</a></h3>
<div class="paragraph">
<p>There is an InvertedDisappearancePriorityConflictResolver which can be used to order activations.</p>
</div>
</div>
<div class="sect2">
<h3 id="_execution_versions"><a class="link" href="#_execution_versions">6.3. Execution versions</a></h3>
<div class="sect3">
<h4 id="_execution_schema"><a class="link" href="#_execution_schema">6.3.1. Execution Schema</a></h4>
<div class="paragraph">
<p>This is the simple way of the execution. For this you need to set the <strong><code>simple</code> field to <code>true</code></strong> (at the top of the class).</p>
</div>
<div class="paragraph">
<p>A scheduler factory is created for the ViatraQueryEngine and an execution schema is created based on this factory and the ViatraQueryEngine. After these steps the conflict resolver is set and rules are added to the schema. The execution is triggered by the <code>startUnscheduledExecution</code> method.</p>
</div>
<div class="paragraph">
<p>Code:</p>
</div>
<div id="evm-initialize" class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// Create schema
val schedulerFactory = Schedulers.getQueryEngineSchedulerFactory(engine)
val schema = ExecutionSchemas.createViatraQueryExecutionSchema(engine, schedulerFactory)
// Setup conflict resolver
schema.conflictResolver = resolver
// Add rules to the schema
schema.addRule(hostMapping)
schema.addRule(appMapping)
schema.startUnscheduledExecution</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_advanced_executions"><a class="link" href="#_advanced_executions">6.3.2. Advanced executions</a></h4>
<div class="paragraph">
<p>Here are the versions of manual executions of activations. For these the value of the <strong><code>simple</code> field should be <code>false</code></strong>.</p>
</div>
<div class="sect4">
<h5 id="_common_parts"><a class="link" href="#_common_parts">6.3.2.1. Common parts</a></h5>
<div class="paragraph">
<p>For all advanced version of execution need a rule engine (based on the ViatraQueryEngine), a context, and the setup of these elements (conflict resolver and addition of rules for the rule engine).</p>
</div>
<div class="paragraph">
<p>Code:</p>
</div>
<div id="evm-common" class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// Create rule engine over ViatraQueryEngine
val ruleEngine = RuleEngines.createViatraQueryRuleEngine(engine)
// Create context for execution
val context = Context.create()
// Conflict resolver also can be used here
ruleEngine.conflictResolver = resolver
// Add rule specifications to engine
ruleEngine.addRule(hostMapping)
ruleEngine.addRule(appMapping)</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_fire_one_activation_of_a_specific_rule"><a class="link" href="#_fire_one_activation_of_a_specific_rule">6.3.2.2. Fire one activation of a specific rule</a></h5>
<div class="paragraph">
<p>Activations of a rule can be queried from the rule engine. This is a set which can be iterated and the activation can be fired (with the context) so we can <strong>fire the first one</strong>.</p>
</div>
<div class="paragraph">
<p>Code:</p>
</div>
<div id="evm-createrule" class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// Check rule applicability
val createClassesActivations = ruleEngine.getActivations(hostMapping)
if (!createClassesActivations.empty) {
// Fire activation of a given rule
createClassesActivations.iterator.next.fire(context)
}</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_fire_all_activations"><a class="link" href="#_fire_all_activations">6.3.2.3. Fire all activations</a></h5>
<div class="paragraph">
<p>Next activation from the rule engine is fired while the set of conflicting activations is not empty so we can <strong>fire all activations</strong>. After firing all activations <strong>rules are removed</strong> from the rule engine.</p>
</div>
<div class="paragraph">
<p>Code:</p>
</div>
<div id="evm-firing" class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// Check for any applicable rules
while (!ruleEngine.conflictingActivations.empty) {
// Fire next activation as long as possible
ruleEngine.nextActivation?.fire(context)
}
// Remove rules after execution
ruleEngine.removeRule(appMapping)
ruleEngine.removeRule(hostMapping)</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_filter_activations"><a class="link" href="#_filter_activations">6.3.2.4. Filter activations</a></h5>
<div class="paragraph">
<p>First of all a <strong>custom event filter</strong> is created. This filter works over <code>HostInctanceMatch</code> objects and filter out match which contains host instance with the specified nodeIp. The rule should be added to the rule engine with the filter (if we want that the unfiltered rule does not cause a problem it should be removed) and after this we can iterate over the activations just like in the previous version (but only one deployment host will be created if the original rule has been removed).</p>
</div>
<div class="paragraph">
<p>Code:</p>
</div>
<div id="evm-filter" class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// Create custom filter for IP
var eventFilter = new EventFilter&lt;HostInstancesMatch&gt;() {
override isProcessable(HostInstancesMatch eventAtom) {
eventAtom.hostInstance.nodeIp == FILTERED_IP
}
}
// Replace the simple rule with the rule-&gt;filter pair in the engine
ruleEngine.removeRule(hostMapping)
ruleEngine.addRule(hostMapping, eventFilter)
// Fire all activations
while (!ruleEngine.conflictingActivations.empty) {
// Fire next activation as long as possible
val nextActivation = ruleEngine.nextActivation
nextActivation?.fire(context)
}</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_manage_conflict_set_manually"><a class="link" href="#_manage_conflict_set_manually">6.3.2.5. Manage conflict set manually</a></h5>
<div class="paragraph">
<p>At this version a different filter is created: a <code>ViatraQueryMatchEventFilter</code> which works with a specific match. This match is created for a host instance. We need to add the hostMapping-filter pair to the rule engine. The removal of the original rule is not necessary.</p>
</div>
<div class="paragraph">
<p>Code for filter:</p>
</div>
<div id="evm-filter2" class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// Create query match filter with a partial match object
val matchFilter = ViatraQueryMatchEventFilter.createFilter(
HostInstancesMatch.newMatch(
engine.hostInstancesByIp.getOneArbitraryMatch(null, FILTERED_IP).hostInstance
)
)
// Add the rule-&gt;filter pair to the engine
ruleEngine.addRule(hostMapping, matchFilter)</code></pre>
</div>
</div>
<div class="paragraph">
<p>The main part of this section is the next: a <strong>scoped conflict set is created</strong> from the rule engine. It expects a resolver and a multi map of rules and filters. Because of this last point the original rule does not need to be removed from the rule engine. <strong>Important</strong> that the simple rule addition uses <strong>empty filter</strong> (and not a null value) when registers the rule so at the map empty filter should be used for these rules. The <code>nextActivation</code> method of this conflict set gives the next activation which can be fired (if no activation can be fired the return value will be <code>null</code> so a null check is necessary before the fire).</p>
</div>
<div class="paragraph">
<p>Code for conflict set:</p>
</div>
<div id="evm-conflictset" class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">// Check that there is any conflicting activation
if(!ruleEngine.conflictingActivations.empty) {
// Create the conflict set
val conflictSet = ruleEngine.createScopedConflictSet(resolver,
// From filtered hostMapping rule and unfiltered appMapping
ImmutableMultimap.of(
hostMapping, matchFilter,
appMapping, appMapping.createEmptyFilter
)
)
// Iterate over activations of the conflict set
var nextActivation = conflictSet.nextActivation
while(nextActivation != null) {
nextActivation.fire(context)
nextActivation = conflictSet.nextActivation
}
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>hljs.initHighlighting()</script>
</div>
<div class="clear"></div>
<ng-include src="'/viatra/angular/blocks/footer.html'"></ng-include>
</body>
</html>