Overview

The CPS Demonstrator is specified to cover a usual workflow in Model-driven Engineering, where a system is (1) first described in a source domain model, then (2) automated model-to-model transformations are used to derive a target domain model. Finally, (3) model-to-text transformation is performed to generate code from the target domain. In addition, a model generator that can automatically create source domain models can support the correctness testing and performance evaluation of the components.

CPS Demonstrator overview
Figure 1. CPS Demonstrator overview

In this example, the source domain (CPS) represents a Cyber-Physical System with applications with dynamic behaviour allocated to connected hosts. The target domain (Deployment) represents the system deployment configuration, with stateful applications contained by hosts. Instance models of the two domains are connected by a traceability model for maintaining correspondence between related elements. These domains are modelled in Ecore and instance models are handled using the code generated by EMF.

For more information about the domains, consult section Domains.

CPS-to-Deployment Transformation

The CPS-to-Deployment model-to-model transformation derives a deployment model from a CPS model and also creates the correspondence in a traceability model. In addition, model-to-model transformations should be able synchronize changes in the CPS model to the deployment model and the traceability model. Alternative transformation methods can be implemented, with some variant offering only batch execution functionalities (recreating the deployment and traceability models every time), while other alternatives are capable of incremental execution, where only changes are propagated.

The transformation creates deployment hosts for each CPS host instance, then creates deployment applications in these hosts for all application instances allocated to the corresponding CPS host. Next, the state machine of the application type for each mapped application instance is mapped to a deployment behaviour of the deployment application. This includes creating states and transitions as well, although the two metamodels represent state machines and behaviours in a slightly different way. Finally, transition actions are processed and trigger references are created between behaviour transitions if the model structure and the actions are set up in a given way (Step 6. in the specification).

Deployment Code Generation

The Deployment Code Generation model-to-text transformation takes a deployment model and outputs Java code that can simulate the dynamic behaviour of the system. Each host is executed on separate threads by host runners, while inter-host triggers are implemented by message passing through a simple communication network object. Once again, based on a single specification, multiple model-to-text alternatives can be provided, with incremental approaches re-generating only parts of the source code that are affected by deployment model changes. These changes are collected using a deployment change monitor, which uses VIATRA Query to aggregate low level deployment model modifications and provide deltas that specify the changed elements (hosts, applications, behaviours).

The code generator creates source code fragments from elements of the deployment model, these include:

  • Deployment for creating the top level configuration that sets up host objects

  • Host for creating the code that sets the applications for a host

  • Application for creating code that sets up an application, with a current state

  • Behavior for creating code for a deployment behaviour including states and transitions (with triggers).

The generated code uses base classes that contain model-independent code and some common classes that are used for the execution (e.g. communication network).

Further information

Domains

Cyber Physical System

The CPS domain specifies application and host types and their instances, requests and requirements on applications and resource requirements of applications towards hosts. Application types have a state machine that describes their behavior through states and transitions. Finally, application instances can be allocated to host instances that can communicate with each other.

Cyber Physical System model Ecore diagram
  • Host instances have a unique node IP address.

  • Application instances have a unique identifier.

  • State machines can define an initial state.

  • Transitions may specify an action for sending or waiting for a signal. A signal can be sent by providing an application type (with its ID) and a signal identifier, while waiting for a signal is done by specifying its identifier.

Deployment

In the deployment model, host instances contain the applications that are running on them, while each application has a behavior with states and transitions. The behavior has a current state and transitions may trigger other transitions when the triggered transition is waiting for the signal they are sending and the application type is correct.

Deployment model Ecore diagram

Traceability

The traceability model describes the correspondence between a CPS and a deployment model. The traceability is stored in a set of traces that refer to zero, one or multiple CPS and deployment elements.

Traceability model Ecore diagram

CPS-to-Deployment Transformation

Specification

This specification describes what is expected from any CPS-to-Deployment implementation variant.

Input

Output

Rules

  1. Host mapping: All host instances in the CPS are transformed into deployment hosts.

    • The IP address of the host instance is copied to the deployment model.

    • Traceability: A trace is created between each host instance and related deployment host (1-to-1).

  2. Application mapping: All application instances allocated to a host instances in the CPS are transformed into deployment applications.

    • The identifier of the application instance is copied to the deployment model.

    • Traceability: A trace is created between each application instance and related deployment application (1-to-1).

  3. State machine mapping: All deployment applications will contain a deployment behavior transformed from the state machine of their application type.

    • The identifier of the state machine is copied to the description of the deployment behavior.

    • Traceability: A trace is created for each state machine and it refers to all deployment behaviors mapped from that state machine (1-to-n).

  4. State mapping: Each state of state machines are transformed as behavior states into all deployment behaviors for the given state machine.

    • The identifier of the state is copied to the description of the behavior state.

    • Traceability: A trace is created for each state and it refers to all behavior states mapped from that state (1-to-n).

  5. Transition mapping: Each transition of state machines are transformed as behavior transitions into all deployment behaviors for the given state machine.

    • The identifier of the transition is copied to the description of the behavior transition.

    • The behavior transition is added to the outgoing transitions of the behavior state mapped from the state containing the transition to the given deployment behavior.

    • The to reference of the behavior transition is set to the behavior state mapped from the target state of the transition to the given deployment behavior.

    • Traceability: A trace is created for each transition and it refers to all behavior transition mapped from that transition (1-to-n).

  6. Action mapping: The actions of transitions are transformed into trigger references between behavior transitions.

    • A behavior transition SBT related to a CPS transition STr with action sendSignal(appTypeId,signalId) will trigger all behavior transitions WBT related to CPS transitions WTr with action waitForSignal(signalId), if:

      • The identifier of the application type that contains the state machine of WTr is appTypeId.

      • The application instance related to the deployment application containing SBT is allocated to host instance H1.

      • The application instance related to the deployment application containing WBT is allocated to host instance H2.

      • H1 can communicate with H2 transitively:

        • H1 and H2 may be the same

        • H2 is included in the set of values of communicatesWith in H1

    • Traceability: No trace records are created for the created triggers.

Testing

We provide unit tests that are defined based on this specification and can test the correctness of any transformation variant.

Transformation Implementations

The VIATRA project has already provided multiple implementations for the demonstrator. These variants differ from each other in at least one characteristics to support comparison and evaluation. Characteristics include:

  • execution mode (batch or incremental)

  • used technologies (Xtend, VIATRA, other transformation tools)

  • model traversal vs. event-driven transformation

  • execution on partially transformed model

These implementations will be created under the transformations folder in the repository and under the org.eclipse.viatra.query.examples.cps.xfrom.m2m.<id> namespace.

Batch

  1. Xtend (id = batch.simple, details)

  2. Xtend + VIATRA Query (id = batch.eiq, details)

  3. VIATRA Batch API (id = batch.viatra, details)

Incremental

For the incremental alternatives, a differentiating factor is the method to identify changes in the source model which must be synchronized to the target ("dirty flag")

  1. Direct notification (id = incr.direct)

    • dirty: EMF adapter/IQBase

  2. Explicit traceability (id = incr.expl)

    • dirty: traceability model state

    • Details here

  3. Query result traceability (id = incr.qrt)

    • dirty: query result bookmarking, traceability saved in deltamonitor

    • Details here

  4. Partial batch transformation (id = incr.aggr)

    • dirty: consider query results as notifications/events, low level change aggregation (transform bigger parts)

    • advanced: notifications independent of source model, transformation may run in background

    • Details here

  5. Change-driven transformations (id = incr.cdt)

    • dirty: EVM activation life-cycle

  6. VIATRA EMF-based transformation API (id = incr.viatra)

Summary

We currently implemented the above mentioned different variants (if you know VIATRA Query well you may argue that the LS based should be considered as a separate one :-) ) for this transformation and in the future might add some additional ones built on our technology stack. However, we would like to invite variants using other transformation tools. Since the demonstrator is open source, this may involve users of other tools or even submitted as a case to the Transformation Tool Contest.

Simple and Optimized Xtend Batch M2M Transformation

Introduction

The basic idea for the batch transformations - both for the simple and optimized versions - is to programmatically traverse the model that is to be transformed and apply all the transformation rules where they are applicable. Model traversal is done by using only basic language concepts and without using any advanced technologies or complex frameworks.

How does it work

The basic concept of this batched transformation is to transform a CPS model to a complete deployment model. This solution doesn’t support incremental transformation, only the whole model can be transformed, and it uses the following steps:

  • It receives a root element for a mapping model which connects a CPS model root and a Deployment model root. The initialization step is to clear all traces from the mapping model and to delete all deployment hosts, if there is any.

  • Iterates over every HostInstance in the CPS model using foreach and transforms each of them to DeploymentHosts. In every iteration DeploymentApplications are also created from ApplicationInstances (see next step) and added to the hosts' containments which are allocated to the host being processed.

  • For each ApplicationInstance a DeploymentApplication is created. If the ApplicationType of the ApplicationInstance refers to a StateMachine, a DeploymentBehavior is also added for the ApplicationInstance (see next step)

  • The States of the StateMachine referred by the ApplicationType are transformed to BehaviorStates. For each State, the Transitions are transformed to BehaviorTransitions (see next step)

  • For each Transition between States of a StateMachine a BehaviorTransition is created connecting the corresponding BehaviorStates.

Handling of 1-to-n mappings

Mappings with 1-to-n multiplicity are created in the following cases

  • StateMachine - DeploymentBehavior

  • State - BehaviorState

  • Transition - BehaviorTransition

This means that a trace is only created once for each of these CPS elements, and as the transformation advances the list of deployment elements of the trace might expand.

Creation of triggers

Triggers are created after all other model elements are created. First all mappings for Transitions in the CPS model are collected. In the next step all Transitions are selected which are sending a message (at this point we use that every transition can send/receive up to one message). When this is done all corresponding receiver Transitions are searched based on the action string. After this a trigger is created for each BehaviorTransition mapped to the sender Trace and each BehaviorTransition mapped to the receiver Traces if their container DeploymentHosts can communicate with each other.

To inspect DeploymentHost communication capability, their corresponding HostInstances are used: the communicatesWith relation is traversed using DFS. When the receiver HostInstances in the CPS model can be reached, the corresponding DeploymentHost is regarded as reachable.

Class of the transformation and example

The class for the transformation is an Xtend class named CPS2DeploymentBatchTransformationSimple. To apply the transformation, just instantiate the class with a traceability model pointing to the CPS and Deployment model roots and invoke the execute method :

// we assume there is an initialization row before like CPSToDeployment cps2dep = ...
xform = new CPS2DeploymentBatchTransformationSimple(cps2dep)
xform.execute

Optimized batch M2M transformation

In order to speed up the Xtend based variant we also developed a so called optimized version (CPS2DeploymentBatchTransformationOptimized). It is based on the simple batch transformation, however, includes the following optimizations:

  • A caching mechanism that is to store the created traceability information for created model elements in map data structures (one map for both directions) to avoid traversal of traceability model. In case of BehaviorTransitions, the application type ID, action ID and HostInstance are also stored based on the CPS model for faster trigger creation.

  • Code restructuring for better loop execution

  • When creating triggers, the data for the receiver behavior transition are obtained in the outer for loop instead of the inner for loop.

This version can be executed using the following commands:

xform = new CPS2DeploymentBatchTransformationOptimized(cps2dep)
xform.execute

Summary and comparison

These two batch transformation methods, compared to the other implemented transformation techniques, have proven to be the least time-effective. However, it can be said that the optimized version preformed the same transformation during half the time of the simple transformation. The memory consumption is not necessarily low, but it was not the bottleneck concerning the performance.

The introduced transformations are not taking changes into consideration, they always perform a complete traversal of the CPS model. This is the main reason for the bad performance results compared to the incremental transformations when there is a change in the CPS model, that needs to be propagated via a repeated, complete transformation to the Deployment model.

Simple Xtend and Query M2M transformation

Introduction

The idea behind this transformation variant is similar in concept to the simple Xtend batch variant. Traverse the model and transform the elements according to the specification. The main difference is the usage of VIATRA Query patterns in place of complex queries (e.g. finding send and wait signal pairs), making the transformation faster and more memory efficient.

How does it work

The transformation can be separated into 2 distinct steps. Building the deployment model itself and, wherever required, setting the relationships of the model elements.

To build the model, the transformation walks through the CPS model in the following hierarchy:

  • HostInstance

    • ApplicationInstance

      • StateMachine

        • State

        • Transition

The transformation is described by the following steps.

  1. The first step is to iterate through each HostInstance and create the DeploymentHost representing it, set its IP address and add it to the Deployment model.

    1. For each ApplicationInstance inside the HostInstance a DeploymentInstance is created, its id is set to be the same as the ApplicationInstance’s and is added to the proper DeploymentHost.

      1. If the ApplicationInstance’s type has a StateMachine specified a DeploymentBehavior representing it is created, its description is set and is added to the proper ApplicationInstance.

        1. For each State in the StateMachine a BehaviorState based on the original State is created, its description is set and is added to the proper DeploymentBehavior.

        2. For each State’s each Transition a BehaviorTransition is created, its description is set and is added to both the proper DeploymentBehavior and as an outgoing transition of the BehaviorState. At this point using the Transition’s target state, the BehaviorTransition’s to reference can be set.

        3. The DeploymentBehavior’s current state is set to the corresponding StateMachine’s initial state.

  2. At this point, the triggers are set as specified by the transformation. This is done via getting the Transition for each BehaviorTransition. If the Transition has a send action, the directly reachable hosts are checked for Transitions under the correct ApplicationType’s StateMachine, and if any are found, their BehaviorTransition counterparts are added.

Each time a new element of the deployment model is created, the traceability model gets modified as required.

Handling of 1-to-n mappings

Since the transformation is done via traversing the CPS model hierarchy, the 1-to-n mappings are created automatically. The most important thing to consider is the nature of the traceability model. Since for example each State can have multiple corresponding BehaviorStates, when searching for a specific DeploymentApplication’s BehaviorState using the traceability model, the correct one should be filtered.

Creation of triggers

The creation of the triggers was mostly done leveraging the power of VIATRA Query.

The main pattern used is the one named "triggerPair". This pattern returns the BehaviorTransition for every Tansition with wait action corresponding to the specified Transition with send action.

The other important pattern is "communicatingAppInstances". This pattern searches for every ApplicationInstance pair allocated to hosts that can directly communicate with each other.

Class of the transformation

The implementation of the transformation can be found in the following class: CPS2DeploymentBatchTransformationEiq.xtend

Summary and comparison

This method of transformation proved to be the fastest of all alternatives, while being the most memory efficient of the transformation variants using VIATRA Query. This is mainly due to the fact that it is not required to build complex VIATRA Query patterns aimed at tracking changes in the model. This is also it’s main handicap since the transformation is not incremental, thus it needs to traverse the cps model and rebuild the traceability and deployment model to maintain consistency.

VIATRA Transformation API-based Batch M2M Transformation

Introduction

The idea behind this transformation variant is similar in concept to the Xtend and Query batch variant. Traverse the model and transform the elements according to the specification using VIATRA Query patterns. The main difference is the usage of the VIATRA Batch Transformations and Statements API.

How does it work

In this variant the transformation steps are executed in the following order:

  1. Transformation of the host instances

    • Create a new DeploymentHost in the deployment model representing the matched HostInstance. Add trace to traceability.

    • Related patterns:

      • hostInstance

  2. Transformation of the application instances

    • Create a new DeploymentApplication in the deployment model representing the matched ApplicationInstance. Add trace to traceability.

    • Related patterns:

      • applicationInstance

      • cps2depTrace

  3. Transformation of the state machines

    • Create a new DeploymentBehavior in the deployment model representing the matched StateMachine for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine. Add DeploymentBehavior to proper trace in traceability. If it does not exist, create it.

    • Related patterns:

      • appInstanceWithStateMachine

      • applicationInstance

      • cps2depTrace

  4. Transformation of the states of the state machines

    • Create a new BehaviorState in the deployment model representing the matched State for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine containing the State. Set the DeploymentBehavior’s current state to the created BehaviorState if the original State was an initial state of it’s state machine. Add BehaviorState to proper trace in traceability. If it does not exist, create it.

    • Related patterns:

      • state

      • appInstanceWithStateMachine

      • applicationInstance

      • cps2depTrace

  5. Transformation of the transitions of the state machines

    • Create a new BehaviorTransition in the deployment model representing the matched State for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine containing the State containing the Transition. Add BehaviorTransition to proper trace in traceability. If it does not exist, create it.

    • Related patterns:

      • transition

      • state

      • appInstanceWithStateMachine

      • applicationInstance

      • cps2depTrace

  6. Transformation of actions of the transitions

    • Set the trigger between the BehaviorTransitions representing the matched Transitions.

    • Related patterns:

      • action

      • sendAction

      • waitAction

      • actionPair

      • reachableHosts

      • transition

      • state

      • appInstanceWithStateMachine

      • applicationInstance

      • cps2depTrace

Handling of 1-to-n mappings

The 1-to-n mappings are mainly handled inside the VIATRA Query patterns. Each pattern is written in a way so that it will match each applicable ApplicationInstance, e.g. if a State exists the CPS model and there are 3 ApplicationInstances of the type that defines the StateMachine, then 3 matches will occur, and each of them will add a new BehaviorState to the corresponding DeploymentApplication’s DeploymentBehavior.

Creation of triggers

The creation of the triggers was mostly done leveraging the power of VIATRA Query.

The main pattern used is the one named "actionPair". This pattern returns a Transition with send action, another Transition with the corresponding wait action and an application instance for each of these transitions.

The other important pattern is "reachableHosts". This pattern searches for every HostInstance pair that can directly communicate with each other. Using this pattern we can filter the results of the "actionPair" pattern so we only have to handle the relevant action pair - aplication instance combinations.

Class of the transformation

The implementation of the transformation can be found in the following class: CPS2DeploymentBatchViatra.xtend

Summary and comparison

If compared to the batch VIATRA Query variant, while being simpler and easier to maintain than its counterpart due to the simplified, more transformation oriented VIATRA API, this implementation offers the same functionality and performance as well.

Explicit Traceability M2M Transformation

This page contains the documentation of the incremental model transformation using Xtend and VIATRA Query with the explicit traceability model used for identifying unsynchronized changes between the CPS and deployment models.

Introduction

This transformation variant uses the Event-driven Virtual Machine (EVM) that is part of VIATRA for specifying and executing a set of independent transformation rules. The rules are developed to monitor the traceability model between a CPS and a deployment model and any element in the CPS model without corresponding traces is transformed to synchronize the CPS and deployment models.

How does it work

For each type in the CPS metamodel, we create several rules for identifying their appearance, disappearance and optionally updates. The preconditions of these rules are defined by VIATRA Query patterns cpsXformM2M.vql with the following naming convention:

  • unmappedCPSElement: match a CPSElement (e.g. host instance) that has no corresponding trace

  • monitoredCPSElement: match a CPSElement that has complete trace

  • deletedDeploymentElement: match a DeploymentElement that has a trace, but the related CPS element does not exist

The naming convention of rules that use these patterns is the following:

  • CPSElementMapping: matches of unmappedCPSElement pattern are processed to create corresponding elements in the deployment model (e.g. DeploymentApplication for ApplicationInstance) and the trace

  • CPSElementUpdate: matches of monitoredCPSElement pattern are processed to monitor the CPSElement and synchronize attribute changes (e.g. the IP of the host instance is changed)

  • CPSElementRemoval: matches of deletedDeploymentElement pattern are processed to remove the corresponding elements from the deployment model and the trace

There are rules defined for:

  • Host instances

  • Application instances allocated to mapped hosts

  • State machines for each mapped application instance

  • States

  • Transitions

  • Triggers (update is not used)

The transformation execution is completely event-driven, without any priority between rules or imperative control structures. The set of rules are collected and an execution schema is created with a scheduler that is called every time the model has changed. The scheduler invokes the EVM executor that fires all activations that are enabled for any of the rules. Activations are not ordered in any way, the executor simply takes the next enabled in a while loop that runs as long as there is any enabled activation.

Handling of 1-to-n mappings

Since the transformation watches the traceability model, a missing mapping for any 1-to-n mapping is represented as a match of the corresponding unmappedCPSElement pattern. If an application type has 3 instances which are already transformed then there will be 3 unmappedStateMachine matches and also 3 activations of the StateMachineMapping rule.

Creation of triggers

Triggers are found in the CPS model by VIATRA Query patterns that evaluate the actions of transitions, check communication between host instance and check allocation of application instances to hosts. In addition, the traceability model is used to find those BehaviorTransition elements that correspond to the CPS transitions. Note that this is needed since instances of the application type may be allocated to different hosts. Therefore, two CPS transitions with matching send and wait actions may only represent triggers for some or none of the application instances.

Technical details

API

The API of the transformation is the following class: CPS2DeploymentTransformation.xtend (source)

Usage example

The following is a simple example for executing the transformation:

// assume cps2dep is a CPSToDeployment object
// assume engine is an VIATRA Query engine initialized on the resource set containing cps2dep
xform = new CPS2DeploymentTransformation
xform.initialize(cps2dep, engine)
xform.execute()
// model changes are incrementally synchronized
// calling execute later has no effect
xform.dispose

Summary and comparison

The explicit traceability variant implements the CPS-to-Deployment transformation by watching the state of the traceability model and synchronizes any changes incrementally from the CPS model to the Deployment model. After the initial execution (when the traceability and deployment models are empty), the event-driven rules are executed whenever model changes happen and only changed elements are transformed instead of the whole model. Additionally, this variant can be started even if the CPS, deployment and traceability models are already transformed (e.g. by a batch transformation) and it is able to correctly work incrementally from that point. Compared to the Query result traceability M2M transformation, it behaves correctly even if only the CPS model has been changed after a previous transformation.

Query result traceability M2M transformation

This gives a short introduction on the incremental query result traceability M2M transformation.

Introduction

This transformation variant is closely related to the Explicit Traceability variant. The concept of this transformation method is to use VIATRA Query patterns on the CPS model and react to changes in the match results by updating the deployment and traceability models incrementally.

How does it work

This transformation method is heavily based on the Event-driven Virtual Machine (EVM) provided by VIATRA. Each transformation step is triggered by an appearing or disappearing VIATRA Query pattern match. The transformation steps are detailed in the listing below.

  • HostInstance

    • Related patterns:

      • hostInstance (Event Trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Create a new DeploymentHost in the deployment model representing the appeared HostInstance. Add trace to traceability.

    • Update: Update the IP address if required.

    • Disappear: Remove the DeploymentHost representing the disappeared HostInstance from the deployment model. Remove trace from traceability.

  • ApplicationInstance

    • Related patterns:

      • applicationInstance (Event Trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Create a new DeploymentApplication in the deployment model representing the appeared ApplicationInstance. Add trace to traceability.

    • Update: Update the id if required.

    • Disappear: Remove the DeploymentApplication representing the disappeared ApplicationInstance from the deployment model. Remove trace from traceability.

  • StateMachine

    • Related patterns:

      • stateMachine (Event Trigger)

      • applicationInstance (Referenced by event trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Create a new DeploymentBehavior in the deployment model representing the appeared StateMachine for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine. Add DeploymentBehavior to proper trace in traceability. If it does not exist, create it.

    • Update: Update the description if required.

    • Disappear: Remove the DeploymentBehaviors representing the disappeared StateMachines from the deployment model. Remove DeploymentBehavior from proper trace in traceability. If no DeploymentBehaviors are left in the trace, remove it.

  • State

    • Related patterns:

      • state (Event Trigger)

      • stateMachine (Referenced by event trigger)

      • applicationInstance (Referenced by event trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Create a new BehaviorState in the deployment model representing the appeared State for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine containing the State. Set the DeploymentBehavior’s current state to the created BehaviorState if the original State was an initial state of it’s state machine. Add BehaviorState to proper trace in traceability. If it does not exist, create it.

    • Update: Update the description and the current state of the state machine if required.

    • Disappear: Remove the BehaviorStates representing the disappeared State from the deployment model. If this BehaviorState was the current state of it’s DeploymentBehavior, set the behavior’s current state to null. Remove BehaviorStates from proper trace in traceability. If no BehaviorStates are left in the trace, remove it.

  • Transition

    • Related patterns:

      • transition (Event Trigger)

      • state (Referenced by event trigger)

      • stateMachine (Referenced by event trigger)

      • applicationInstance (Referenced by event trigger)

      • cps2depTrace (Used in transformation)

      • depBehaviorsStateAndTransitions (Used in transformation)

    • Appear: Create a new BehaviorTransition in the deployment model representing the appeared State for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine containing the State containing the Transition. Add BehaviorTransition to proper trace in traceability. If it does not exist, create it.

    • Update: Update the description, the source and target states if required.

    • Disappear: Remove the BehaviorTransitions representing the disappeared Transition from the deployment model. Remove BehaviorTransitions from proper trace in traceability. If no BehaviorTransitions are left in the trace, remove it.

  • Trigger

    • Related patterns:

      • triggerPair (Event Trigger)

      • sendTransitionAppSignal (Referenced by event trigger)

      • waitTransitionAppSignal (Referenced by event trigger)

      • appInstanceTransition (Referenced by event trigger)

      • applicationInstance (Referenced by event trigger)

      • applicationInstanceWithHost (Referenced by event trigger)

      • reachableHosts (Referenced by event trigger)

      • hostCommunication (Referenced by event trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Set the trigger between the BehaviorTransitions representing the matched Transitions.

    • Disappear: Remove the trigger between the BehaviorTransitions representing the matched Transitions.

To resolve ordering issues, the events processing order is defined based on priorities as follows: HostInstance > ApplicationInstance > StateMachine > State > Transition > Trigger

(A > B means event A will be processed before event B)

The above order is true for each appear and update event. In the case of disappear events the order is reversed.

Handling of 1-to-n mappings

The 1-to-n mappings are mainly handled inside the event trigger patterns. Each pattern is written in a way so that it will create an event for each applicable ApplicationInstance, e.g. if a new State is added to the CPS model and there are 3 ApplicationInstances of the type that defines the StateMachine, then 3 appeared events will occur, and each of them will add a new BehaviorState to the corresponding DeploymentApplication’s DeploymentBehavior.

Creation of triggers

Detecting new trigger pairs is entirely the job of VIATRA Query using the above specified patterns.

Class of the transformation

The implementation of the transformation can be found in the following class: CPS2DeploymentTransformationQrt.xtend

Summary and comparison

Compared to the Explicit Traceability version, the reduced pattern complexity of this transformation method allows more memory efficient transformation at the price of loosing the ability to start the transformation on an already existing, partially transformed model. The speed of the transformation is comparable to that of the Explicit Traceability, while its memory consumption is more akin to the Simple Xtend and Query variant.

Partial batch M2M transformation

This page provides a summary for the partial batch transformation.

Introduction

The partial batch transformation performs an initial, complete transformation for the model, which is basically the simple VIATRA Query solution described in Simple Xtend and Query M2M-transformation. Then, the changes of the source CyberPhysicalSystem model are traced and collected using a change monitor. From the collected changes in source cyber physical system model the transformation - when run again - modifies only the corresponding parts of the deployment model, this way dramatically reducing re-transformation time if the source model contains changes.

How does it work

This transformation uses the Event-driven Virtual Machine (EVM) feature of VIATRA Query. Registrations of changes are triggered by an appearing or disappearing VIATRA Query pattern match. Based on the appearance, disappearance or update of a model element since the last transformation, actions are to be taken when the transformation is initiated again.

The VIARA Query query definitions used for the transformation of the model elements are detailed below.

  • hostInstances

    • Finds all host instances who have host type assigned.

    • Used for transforming host instances to deployment hosts. The attribute values are obtained from the host instance object.

  • appInstances

    • Finds all application instance which have application type.

    • Used for creating deployment applications.

  • appTypes

    • Returns all application types in the cyber physical system model.

    • Used for determining the state machine application based on the type. The state machine is transformed to a behavior using the rule assigned to the stateMachines pattern.

  • stateMachines

    • Gets the state machines assigned to any application type.

    • Used for creating behaviors of deployment applications.

  • states

    • Returns states that are part of a given state machine.

    • Used for the creation of deployment behavior states within a behavior.

  • transitions

    • Gets all transitions that are outgoing transitions of a state.

    • Based on the matches of this pattern behavior transitions and triggers between them are created.

Handling of 1-to-n mappings

The 1-to-n mappings are handled within a separate method called addTraceOneToN. This is required for transforming state machines, states and transitions. When deletions occur in the source model, then the corresponding mappings are found using an VIATRA Query matcher, then removed by hand from the mappings.

Class of the transformation

The implementation of the transformation can be found in the following class: CPS2DeploymentPartialBatchTransformationEiq.xtend, which is located in the org.eclipse.viatra.query.examples.cps.xform.m2m.incr.aggr package.

Summary

This transformation has almost the same memory footprint as the batch VIATRA Query transformation. The first transformation time is about the same, however, the time needed to transform the changes in the initial model is half the time needed for the batch VIATRA Query variant.

VIATRA transformation API based QRT M2M transformation

This gives a short introduction on the QRT transformation variant that uses the VIATRA transformation API to define its transformation rules.

Introduction

This transformation variant is closely related to the Query Result Tracebility variant. The basic concept of the transformation and the transformation rules are identical to those of the aforementioned variant, as the VIATRA transformation API basically provides a simplified, more model transformation oriented interface for the Event-driven Virtual Machine (EVM).

How does it work

On the contrary to its sister variant, this method uses the VIATRA transformation API to access the EVM. Similar to the aforementioned QRT method, each transformation step is triggered by an appearing or disappearing VIATRA Query pattern match. The transformation steps are detailed in the listing below.

  • HostInstance

    • Related patterns:

      • hostInstance (Event Trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Create a new DeploymentHost in the deployment model representing the appeared HostInstance. Add trace to traceability.

    • Update: Update the IP address if required.

    • Disappear: Remove the DeploymentHost representing the disappeared HostInstance from the deployment model. Remove trace from traceability.

  • ApplicationInstance

    • Related patterns:

      • applicationInstance (Event Trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Create a new DeploymentApplication in the deployment model representing the appeared ApplicationInstance. Add trace to traceability.

    • Update: Update the id if required.

    • Disappear: Remove the DeploymentApplication representing the disappeared ApplicationInstance from the deployment model. Remove trace from traceability.

  • StateMachine

    • Related patterns:

      • stateMachine (Event Trigger)

      • applicationInstance (Referenced by event trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Create a new DeploymentBehavior in the deployment model representing the appeared StateMachine for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine. Add DeploymentBehavior to proper trace in traceability. If it does not exist, create it.

    • Update: Update the description if required.

    • Disappear: Remove the DeploymentBehaviors representing the disappeared StateMachines from the deployment model. Remove DeploymentBehavior from proper trace in traceability. If no DeploymentBehaviors are left in the trace, remove it.

  • State

    • Related patterns:

      • state (Event Trigger)

      • stateMachine (Referenced by event trigger)

      • applicationInstance (Referenced by event trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Create a new BehaviorState in the deployment model representing the appeared State for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine containing the State. Set the DeploymentBehavior’s current state to the created BehaviorState if the original State was an initial state of it’s state machine. Add BehaviorState to proper trace in traceability. If it does not exist, create it.

    • Update: Update the description and the current state of the state machine if required.

    • Disappear: Remove the BehaviorStates representing the disappeared State from the deployment model. If this BehaviorState was the current state of it’s DeploymentBehavior, set the behavior’s current state to null. Remove BehaviorStates from proper trace in traceability. If no BehaviorStates are left in the trace, remove it.

  • Transition

    • Related patterns:

      • transition (Event Trigger)

      • state (Referenced by event trigger)

      • stateMachine (Referenced by event trigger)

      • applicationInstance (Referenced by event trigger)

      • cps2depTrace (Used in transformation)

      • depBehaviorsStateAndTransitions (Used in transformation)

    • Appear: Create a new BehaviorTransition in the deployment model representing the appeared State for the ApplicationInstance specified by the pattern. This happens for every ApplicationInstance with a type that defines the StateMachine containing the State containing the Transition. Add BehaviorTransition to proper trace in traceability. If it does not exist, create it.

    • Update: Update the description, the source and target states if required.

    • Disappear: Remove the BehaviorTransitions representing the disappeared Transition from the deployment model. Remove BehaviorTransitions from proper trace in traceability. If no BehaviorTransitions are left in the trace, remove it.

  • Trigger

    • Related patterns:

      • triggerPair (Event Trigger)

      • sendTransitionAppSignal (Referenced by event trigger)

      • waitTransitionAppSignal (Referenced by event trigger)

      • appInstanceTransition (Referenced by event trigger)

      • applicationInstance (Referenced by event trigger)

      • applicationInstanceWithHost (Referenced by event trigger)

      • reachableHosts (Referenced by event trigger)

      • hostCommunication (Referenced by event trigger)

      • cps2depTrace (Used in transformation)

    • Appear: Set the trigger between the BehaviorTransitions representing the matched Transitions.

    • Disappear: Remove the trigger between the BehaviorTransitions representing the matched Transitions.

To resolve ordering issues, the events processing order is defined based on priorities as follows: HostInstance > ApplicationInstance > StateMachine > State > Transition > Trigger

(A > B means event A will be processed before event B)

The above order is true for each appear and update event. In the case of disappear events the order is reversed.

Handling of 1-to-n mappings

The 1-to-n mappings are mainly handled inside the event trigger patterns. Each pattern is written in a way so that it will create an event for each applicable ApplicationInstance, e.g. if a new State is added to the CPS model and there are 3 ApplicationInstances of the type that defines the StateMachine, then 3 appeared events will occur, and each of them will add a new BehaviorState to the corresponding DeploymentApplication’s DeploymentBehavior.

Creation of triggers

Detecting new trigger pairs is entirely the job of VIATRA Query using the above specified patterns.

Class of the transformation

The implementation of the transformation can be found in the following class: CPS2DeploymentTransformationViatra.xtend

Summary and comparison

If compared to the QRT variant, while being simpler and easier to maintain than its counterpart due to the simplified, more transformation oriented VIATRA API, this implementation offers the same functionality and performance as well.

CPS to Deployment Unit Tests

The xform.m2m.tests project specifies a high number of test cases that are independent of transformation implementations and are created for allowing Test Driven Development of transformations based on the specification.

The tests are grouped together into classes following the rules found in the specification of the CPS-to-Deployment transformation:

  • HostMappingTest

  • ApplicationMappingTest

  • StateMachineMappingTest

  • StateMappingTest

  • TransitionMappingTest

  • ActionMappingTest

In addition, the TransformationApiTest class ensures that all variants behave the same way for incorrect input parameters, while the WrapperTest class can contain additional tests for specific transformation variant wrappers.

Technical details

Run the tests

Simply right-click on the xform.m2m.tests project and select Run as…​ → JUnit Plugin Test.

Test case structure

All specification related tests extend the CPS2DepTest class, which defines some extension fields:

class CPS2DepTest {
    protected extension Logger logger = Logger.getLogger("cps.xform.CPS2DepTest")
    protected extension CPSTransformationWrapper xform
    protected extension CPSModelBuilderUtil modelBuilder

A simple test case is structured as follows:

@Test
def hostIncremental() {
 val testId = "hostIncremental"
 info("START TEST: " + testId)

 // use model builder to create initial model
 val cps2dep = prepareEmptyModel(testId)

 // use transformation wrapper to initialize (e.g. create rules)
 cps2dep.initializeTransformation
 // use transformation wrapper to execute
 executeTransformation

 // modify model
 val instance = cps2dep.prepareHostInstance
 // re-execute transformation (incremental usually ignores this call)
 executeTransformation

 // check results
 cps2dep.assertHostMapping(instance)

 info("END TEST: " + testId)
}
Test with existing input model

If you would like to test the transformation on your own input CPS model, take a look at the specificInputModel test case in InstanceModelTest.xtend in the <cps>.xform.m2m.tests.integration package.

@Ignore
@Test
def specificInputModel(){
  val testId = "specificInputModel"
  info("START TEST: " + testId)

  val cpsUri = "file://my-cps-git-location/models/org.eclipse.viatra.query.examples.cps.instances/example.cyberphysicalsystem"

  val cps2dep = prepareCPSModel(cpsUri)

  cps2dep.initializeTransformation
  executeTransformation

  info("END TEST: " + testId)
}

Just change the resource URI to a full file path, remove or comment out the @Ignore and run the tests.

Code Generator (Distributed realization - Xtend templates)

The org.eclipse.viatra.query.examples.cps.m2t.distributed.generator project implements a basic model-to-text transformation. It is a basic template based generator written in Xtend .

Deployment realization

The generated Java code realizes a "distributed" Deployment model where Hosts are the base elements of the distribution. Each host is a separated entity which can be run on HostRunner (threads). Hosts can communicate with each other via the CommunicationNetwork shared object.

Code Generator

Hosts and Applications are data objects with states. HostRunner is a simple engine which triggers its hosts to fire available transitions on every applications. The communication is asynchronous and realized with queues.

Code Generator

The public API of the transformation contains four methods.

interface ICPSGenerator {
    def CharSequence generateHostCode(DeploymentHost host) throws CPSGeneratorException
    def CharSequence generateApplicationCode(DeploymentApplication application) throws CPSGeneratorException
    def CharSequence generateBehaviorCode(DeploymentBehavior behavior) throws CPSGeneratorException
    def CharSequence generateDeploymentCode(Deployment deployment) throws CPSGeneratorException
}

This implementation of the code generator is stateless. Each separate model element is generated individually.

Host

The host objects keep references to their own applications.

Generated Code
public class Host152661025 extends BaseHost {

    public Host152661025(CommunicationNetwork network) {
        super(network);
        // Add Applications of Host
        applications = Lists.<Application>newArrayList(
            new AlarmApplication(this),
                        new OtherApplication(this),
        );
    }

}
Application

Applications store their ApplicationID and their current state of the behavior (State machine).

Generated Code
public class AlarmApplication extends BaseApplication<BehaviorAlarmB> {

    protected static final String APP_ID = "Alarm";

    public AlarmApplication(Host host) {
        super(host);

        // Set initial State
        currentState = BehaviorAlarmB.AInit;
    }

    @Override
    public String getAppID() {
        return APP_ID;
    }

}

Behavior

Behavior represents a statemachine of the application. It stores and manages the possible state transitions.

Generated Code
public enum BehaviorAlarmB implements State<BehaviorAlarmB> {
     ///////////
    // States
    AInit {
        @Override
        public List<State<BehaviorAlarmB>> possibleNextStates(Application app) {
            List<State<BehaviorAlarmB>> possibleStates = Lists.newArrayList();

            // Add Neutral Transitions

            // Add Send Transitions
            possibleStates.add(ASent);

            // Add Wait Transitions

            return possibleStates;
        }

        @Override
        public BehaviorAlarmB stepTo(BehaviorAlarmB nextState, Application app) {
            // Send triggers
            if(nextState == ASent){
                app.sendTrigger("152.66.102.5", "Alarm", "ISSReceiving");
                return super.stepTo(nextState, app);
            }

            // Other cases (wait, neutral)
            return super.stepTo(nextState, app);
        }
    },
    ASent {
        @Override
        public List<State<BehaviorAlarmB>> possibleNextStates(Application app) {
            List<State<BehaviorAlarmB>> possibleStates = Lists.newArrayList();

            // Add Neutral Transitions
            possibleStates.add(AInit);

            // Add Send Transitions

            // Add Wait Transitions

            return possibleStates;
        }
    };

    private static Logger logger = Logger.getLogger("cps.proto.distributed.state");

     ////////////
    // Triggers

     /////////////////
    // General part
    @Override
    abstract public List<State<BehaviorAlarmB>> possibleNextStates(Application app);

    @Override
    public BehaviorAlarmB stepTo(BehaviorAlarmB nextState, Application app){
        if(possibleNextStates(app).contains(nextState)){
            logger.info("Step from " + this.name() + " to " + nextState.name());
            return nextState;
        }else{
            logger.info("!!! Warning: Unable to step from " + this.name() + " to " + nextState.name()
                    + " because the target state is not possible state.");
        }
        return this;
    }

}

In addition to the generated code org.eclipse.viatra.query.examples.cps.m2t.proto.distributed project contains the shared part of the working code (general package). Implementation of the CommunicationNetwork, the HostRunner, the BaseApplication, the BaseHost, State and the interfaces are placed there.

Deployment Change Monitor

This component tracks changes in the deployment model and informs the code generator about the changes.

Purpose of the monitor

The code generator produces simulation code for a DeploymentElement given to it. To decide whether a source file for a model element needs to be generated or not is beyond its responsibility. For this reason a DeploymentChangeMonitor is introduced and should be used during the behavior code generation process. This monitor tracks the changes of the model and is able to feed the generator with the DeploymentElements for which source code generation or re-generation is required. This solution will make overall time spent on code generation shorter, because only the changed model parts are considered.

The change monitor aggregates modifications into a delta between checkpoints. The API allows creating a new checkpoint and will provide the delta between the previous and newly created checkpoints, while it also starts to record the delta starting from the new checkpoint. The delta contains a boolean value to signify that the top-level configuration has to be re-generated and three sets of elements:

  • Appeared since the last checkpoint: source code related to these elements has to be generated, clean up not required

  • Disappeared since the last checkpoint: source code related to these elements should be cleaned up

  • Updated since the last breakpoint: source code related to these elements has to be re-generated, clean up may be needed (e.g. file name will change)

How does it work

The implemetation relies on the VIATRA Event-driven Virtual Machine (EVM). There are rules defined for the Deployment, DeploymentHost, DeploymentApplication and DeploymentBehavior types using VIATRA Query patterns. These rules describe the connections and properties of model elements that are to be monitored, and the DeploymentChangeMonitor keeps track of these changes. This is done by separate registered jobs for appear, update and disappear events.

The monitor inside stores three sets separately for appeared, updated and disappeared DeploymentElements, and a boolean flag is the Deployment is changed.

The rules used for monitoring:

  • Deployment is changed iff

    • Lists of host changed OR

    • IP of a contained Host is changed

  • DeploymentHost is changed iff

    • Its list of applications is changed OR

    • Its IP changed

  • DeploymentApplication is changed iff

    • Its ID changed OR

    • The current state of its DeploymentBehavior changed

  • DeploymentBehavior is changed iff

    • The list of its states changed OR

    • The list of its transitions changed OR

    • For any transition the list of triggered transitions are changed

Usage

The implementation class for the monitor is the org.eclipse.viatra.query.examples.cps.xform.m2t.DeploymentChangeMonitor Java class. To use it, an ViatraQueryEngine and a Deployment needed.

engine = ViatraQueryEngine.on(deployment);
monitor = new DeploymentChangeMonitor(deployment,engine);
monitor.startMonitoring();

To get the change detlas a DeploymentChangeDelta DTO is returned by the getDeltaSinceLastCheckpoint() method of the monitor. This DTO also contains the information about the old names/IDs required for identifying the previously generated files that are to be deleted. This is in a map, that can be queried and used like in the code shown below:

String oldId = monitor.deltaSinceLastCheckpoint.oldNamesForDeletion.get(deploymentElement);

To create a checkpoint in order to start collecting deltas to new empty collections the createCheckpoint() method can be used. This also returns a DeploymentChangeDelta containing all changes between the last two checkpoints.

Model Generator

Example Model Generation

You can generate CPS models with SampleModelGenerator class of the org.eclipse.viatra.query.examples.cps.generator.tests project.

How to use it:

  • Remove the @Ignore annotation from the class

  • Run the class as JUnit Plug-in Test

  • Generated files will be in the models folder of the test project

Currently generated example models:

  • DemoCPSConstraints

  • SimpleCPSConstraints

If you need other models you need to add other test cases to the class.

Configurable Model Generation

Since manually creating large instance models requires a lot of effort, we developed a CPS Model Generator that executes a number of generation phases defined in a plan and based on simple configuration can output arbitrarily large CPS models. The model generator is built in Xtend and uses VIATRA Query patterns for gathering elements for complex operations.

The model generator aims to output models that are similar in fine structure but have different number of elements (to generate scaled-up models) and allow some randomization (e.g. to create state machines with different number of states for different application types).

Randomization is controlled by min-max and percentage type parameters and ratio maps:

  • A min-max parameter specifies a range with a minimum and maximum value, while operations depending on the given parameter can obtain a random number that is part of the range (e.g. create statemachine with 5 to 10 states).

  • A percentage parameter specifies the fraction of a total, while operations may use it to decide how to distribute the choices for the possible elements (e.g. 35% of transitions in a state machine should have actions).

  • A ratio map parameter assigns integer values to classes, while operations may use it to distribute choices (e.g. how application instances are allocated to different host class instances).

The fine structure is specified with host and application classes:

  • A host class determines how many host types are created (min-max), how many instances are created for each type in the class (min-max), how many other host instance each host instance communicates with (min-max) and how the communications are distributed among instances of different host classes (ratio map).

  • An application class determines how many application types are created (min-max), how many instances are created for each type in the class (min-max), how many states and transitions should the state machine of each type contain (both min-max), how many of the instances are allocated (percentage), how is the allocation distributed among instances of different host classes (ratio map), how many of the transitions should define actions (percentage) and of those what is the ratio of sends (percentage).

Based on a list of host and application classes as input, the CPS model generator outputs an instance model that satisfies the constraints of the classes. While min-max parameters are always satisfied, percentage and ratio map parameters may not be precisely followed (e.g. allocating 35% of 10 applications may be 3 or 4). However, for larger sizes and in general, the generated model will have the structure specified in the classes.

The model generator component is able to generate CyberPhysicalSystem models with the specified properties. The generator is built on top of the PlanExecutor and implements specific plans, phases, operations, initializer and fragment objects. The generation process is based on pseudo-random actions which means the output is deterministic according to the input parameters.

ModelGenerator

Preferences of the model are declared in ICPSConstraints objects. The following constraints are available:

  • It is able to define Host and Application Classes which specify constraints for Host- and ApplicationTypes. Each HostClass contains the following attributes:

    • Name: Name of the HostClass (important for the ids)

    • HostTypes: Min-Max value of the instantiated HostTypes (the exact value is randomized between the min and max values)

    • HostInstances: Min-Max value of the instantiated HostInstances. (the exact value is randomized separately for each HostTypes of the HostClass, between the min and max values)

    • CommunicationLines: This min-max value specifies the number of accessible HostInstances (communicateWith attribute).

    • CommunicationRatios: The accessible HostInstances are chosen from these HostClasses with the given ratio.

  • ApplicationClass is defined with the following properties:

    • Name: Name of the ApplicationClass (important for the ids)

    • ApplicationTypes: Min-Max value of the instantiated ApplicationTypes (the exact value randomized between the min and max values)

    • ApplicationInstances: Min-Max value of the instantiated ApplicationInstances. (the exact value is randomized separately for each ApplicationTypes of the ApplicationClass, between the min and max values)

    • States: Min-Max value of the instantiated States for each StateMachine of the ApplicationType

    • Transitions: Min-Max value of the instantiated Transitions for each StateMachine of the ApplicationType

    • PercentageOfAllocatedInstances: Probability of application allocation

    • AllocationRatios: Describes the allocation ratio by HostClasses

    • ProbabilityOfActionGeneration: probability of the action generation for Transitions

    • ProbabilityOfSendAction: probability of generating sendSignal action (other is the wiatForSignal)

  • Number of the available signals is specified with Min-Max value

CPS model generation plan

Plan of the CPS model generation

The CPS plan consists of seven phases and eight operations.

  • Prepare: prepare the IncQueryEngine

  • SignalSet: Generate signals

  • Types: Generate Host and Application types (include StateMachines) according to the Classes

  • Instances: Generate Host and Application instances according to the Classes

  • Host Communication: Add communication lines to HostInstances

  • Allocations: Allocate ApplicationInstances to HostInstances

  • Actions: Generate actions to Transitions

Usage example

First, the ICPSConstraints interface shall be implemented.

class SimpleCPSConstraints implements ICPSConstraints {

    override getName() {
        "Simple"
    }

    val hostClass1 = new HostClass(
        "FirstHostClass",
        new MinMaxData(1, 3), // HostTypes
        new MinMaxData(2, 5), // HostInstances
        new MinMaxData(1, 2), // CommLines
        new HashMap // CommRatios
    )
    val hostClass2 = new HostClass(
        "OtherHostClass",
        new MinMaxData(1, 1), // HostTypes
        new MinMaxData(2, 2), // HostInstances
        new MinMaxData(1, 1), // CommLines
        new HashMap // CommRatios
    )

    new() {
        for (class1 : hostClasses) {
            for (class2 : hostClasses) {
                class1.communicationRatios.put(class2, 1)
            }
        }
    }

    override getHostClasses() {
        #[hostClass1, hostClass2];
    }

    override getNumberOfSignals() {
        new MinMaxData(1, 10);
    }

    override getApplicationClasses() {
        val firstAppClassAllocations = new HashMap();
        firstAppClassAllocations.put(hostClass1, 1);
        firstAppClassAllocations.put(hostClass2, 2);

        #[
            new AppClass(
                "FirstAppClass",
                new MinMaxData(1, 3), // AppTypes
                new MinMaxData(1, 2), // AppInstances
                new MinMaxData(2, 4), // States
                new MinMaxData(1, 2), // Transitions
                new Percentage(100), // PercentageOfAllocatedInstances
                firstAppClassAllocations, // allocationRatios
                new Percentage(95), // probabilityOfActionGeneration
                new Percentage(60) // probabilityOfSendAction
            )
        ];
    }
}

This model shall contain least one and maximum three HostTypes of FirstHostClass and exactly one of the OtherHostClass. Each HostType of the FirstHostClass shall be instantiated minimum two and maximum five times and the HostInstances shall communicate with one or two other instances. The OtherHostClass is more stringent, it specifies the exact number of types, instances and communication lines (1,2,1). Instances can communicate with other instances from both HostClasses with equal possibility. Number of the generated signals shall be in range of 1 to 10. The SimpleCPSConstraints specifies only one ApplicationClass, the FirstAppClass. Least one and maximum three ApplicationType shall be created for this class. Each types of FirstAppClass shall be instantiated one or two times and the StateMachine of the types shall contain minimum two and maximum four States with one or two Transactions. Every ApplicationInstance shall be allocated (PercentageOfAllocatedInstances ). Two times more application instances shall be allocated on the instances of the OtherHostClass than the FirstHostClass (allocationRatios). Transitions contain actions with 95% and the probability of the "sendSignal" is 60%.

Then the CPSGeneratorBuilder.buildAndGenerateModel(long seed, ICPSConstraints constraints) : CPSFragment should be called.

Plan Executor

The PlanExecutor is a simple workflow engine which is able to execute plans. The plan is separated by phases which consist of Operations. The other input of the PlanExecutor is one of the Initializer interface implementation. Initializer shall initialize the Fragment object and it is able to store extra information for phases and operations. During the execution operations working on the shared object, called fragment. The output of the process is the fragment.

PlanExecutor
Building blocks
Fragment

The fragment represents the artefact that the executor is operating on. In the CPS model generator, the fragment refers to the CPS instance model that is built. The fragment is introduced as a type parameter to ensure that operations can call the methods in a type-safe way on the fragment object.

Initializer

The initializer is responsible for creating an initial fragment object at the start of the execution. This approach allows the creation of the initializer object without performing possible expensive processing for creating the fragment before it is required.

interface Initializer<FragmentType> {
    def FragmentType getInitialFragment();
}
Operation

Operations are defined for a given fragment type and are executed as part of phases. The same operation implementation may be used in multiple phases. The operation receives the fragment object as a parameter when it is executed.

interface IOperation<FragmentType> {
    def boolean execute(FragmentType fragment);
}
Phase

Phases represent standalone execution steps that define a list of operations on the same fragment type. The phase receives the fragment object as a parameter when assembling the operations, which means that the operation list can be dependent of the current state of the fragment.

interface IPhase<FragmentType> {
    def Iterable<IOperation<FragmentType>> getOperations(FragmentType fragment);
}
Plan

The plan is created by adding phases that were already prepared by the same fragment. During the execution, the list of phases are requested by the executor.

interface IPlan<FragmentType> {
    def void addPhase(IPhase<FragmentType> phase);
    def Iterable<IPhase<FragmentType>> getPhases();
}
Technical details

First step is to create custom implementations of IPlan, IPhase, IOperation, Initializer interfaces and create the Fragment type like in the followings.

MyFragment
class MyFragment {
    SecretStore secretStore = "";

    def addSecretInformation(String info) {
        secretStore.add(info);
    }

    def encryptStore() {
        secretStore.encrypt;
    }

    def print() {
        secretStore.print;
    }
}
MyInitializer
class MyInitializer implements Initializer<MyFragment> {

    override getInitialFragment() {
        return new MyFragment();
    }

}
MyPlan
class MyPlan implements IPlan<MyFragment> {

    List<IPhase<MyFragment>> phases = Lists.newArrayList;

    override addPhase(IPhase<MyFragment> phase) {
        phases.add(phase);
    }

    override getPhases() {
        return phases;
    }

}
MyPhase
class MyPhase implements IPhase<MyFragment>{

    override getOperations(MyFragment fragment) {
        Lists.newArrayList(
                   new AddSecretOperation(),
                   new EncryptStoreOperation(),
                );
    }

}
AddSecretOperation
class AddSecretOperation implements IOperation<MyFragment> {

    override execute(MyFragment fragment) {
        fragment.addSecretInformation("My Secret Information");
        return true;
    }

}
EncryptStoreOperation
class EncryptStoreOperation implements IOperation<MyFragment> {

    override execute(MyFragment fragment) {
        fragment.encryptStore;
        return true;
    }

}
Second step is to build plan and the initializer.
class Example {
    def static void main(String[] args) {
        var MyPlan plan = new MyPlan;
        plan.addPhase(new MyPhase());
        plan.addPhase(new MyOtherPhase());

        var MyInitializer initializer = new MyInitializer;
    }
}
The last step is to instantiate correct PlanExecutor and call the process method.
class Example {
    def static void main(String[] args) {
        var MyPlan plan = new MyPlan;
        plan.addPhase(new MyPhase());
        plan.addPhase(new MyOtherPhase());

        var MyInitializer initializer = new MyInitializer;

        var PlanExecutor<MyFragment, MyInitializer> planExecutor = new PlanExecutor();
        var output = planExecutor.process(plan, initializer);

        output.print;
    }
}

Live Validation

The VIATRA Validation Framework offers a declarative approach for defining complex constraints on instance models that are evaluated incrementally during model editing.

In the CPS demonstrator we defined a set of constraints for Cyber Physical System instance models in the model/validation/rules.eiq file in the cps.queries project. The constraints include the following examples:

  • Host instances must have unique IP addresses

  • The initial state of a state machine must be among the states of the same state machine

  • Transitions must have target states, which must be in the same state machine as the source state

  • Actions of outgoing transitions from a given state must be unique

Definition of constraints

Each constraint is defined using @Constraint annotations on patterns. The annotation has three required parameters:

  • The location identifies which element is the focus of the violation

  • The message is a format string that specifies what will be displayed for each violation

  • The severity specifies the type of the created marker (error or warning)

@Constraint(
    location = state,
    message = "Multiple outgoing transitions of $state.id$ define the same action ($action$)",
    severity = "error"
)
pattern multipleTransitionsWithSameAction(state, action) {
    State.outgoingTransitions(state, transition);
    State.outgoingTransitions(state, otherTransition);
    find actionOfTransition(transition, action);
    find actionOfTransition(otherTransition, action);
    transition != otherTransition;
}

private pattern actionOfTransition(transition, action) {
    Transition.action(transition, action);
}

The VIATRA Query generator fragment generates the required source code and other artefacts automatically when the builder is invoked by saving the query definition file. The code is placed in the cps.queries.validation project.

Usage of live validation

The live validation can be demonstrated in the generated editor for CPS models:

  1. Start a Runtime Eclipse

  2. Open a CPS instance model (e.g. by importing the cps.instances project) in the generated editor

    • Right click on a .cyberphysicalsystem file in the Package explorer, Open with → CyberPhysicalSystem Model Editor

  3. Initialize the validation

    • Right click in the tree editor, VIATRA Validation → Initialize VIATRA Validators on Editor

  4. Violations of constraints are displayed in the Problems view

    • Double clicking the violation will set the selection of the editor to the location element

    • Changes in the model will update problem markers immediately

Incremental Viewers

The VIATRA Viewers Framework is applied to create custom views for the CPS demonstrator.

The views are defined using declarative pattern annotations which specify items and edges in a view. The view may be a graph visualization, but simple UI elements, such as lists or tree views are also supported by the technology. In the CPS demonstrator, we created views using the Zest Graph Visualization framework.

Deployment model viewer

The definition of the views can be found in the cps.queries project in the model/viewer and deployment/viewer packages. Items are defined with @Item annotations, edges are specified with @Edge annotations, while the format (such as colours) is described with @Format annotations.

Viewer example

The following patterns define the following:

  • Create items for each deployment host

  • Create items for each deployment application

  • Create edges between items that correspond to the deployment host and application objects

@Format(color = "#FBFE00")
@Item(item = host, label = "Host $host.ip$")
pattern deploymentHostItem(host) {
    DeploymentHost(host);
}

@Format(color = "#996600")
@Item(item = app, label = "App $app.id$")
pattern deploymentApplicationItem(app) {
    DeploymentApplication(app);
}

@Edge(source = host, target = app, label = "apps")
pattern deploymentHostApplicationEdge(host, app) {
    DeploymentHost.applications(host, app);
}

CPS Application

The CPS Demonstrator application include various features to demonstrate various capabilities of VIATRA using the CPS domain models.

How to start

Start the CPS Application Eclipse instance (download from here).

Starting multiple instances of this application causes Java was started but returned exit code=1 error message caused by both applications opening port 1099 for the VIATRA debugger to connect to. In order to support multiple instances, you have to modify the debug port number in the corresponding eclipse.ini file.

Initializing CPS models

Select File/New/Other and in the CPS Demonstrator category select CPS Demonstrator Example and create an example project.
This project contains an example CPS model (example.cyberphysicalsystem) as the source model of the transformation, an empty target model (example.deployment) and an example.traceability, which connects the source and target models.

Executing the transformation

The CPS Transformations view allows starting or stopping CPS-to-Deployment M2M transformations using different strategies and displays the running transformations.
To open the view press CTRL+3 and type the name of the view.

CPS Transformations view

The view shows the details of the currently running transformations:

  • the name of the resource which contains the model

  • the transformation strategy

Double-click on a transformation to navigate to the model.

Transformation strategies:
In a drop-down list you can select a strategy for the transformation. There are two execution modes batch and incremental.

  • The batch mode clears the destination model and transforms the whole source model then stops.

  • The incremental transformations transform the model, then continue to run and apply changes of the source model to the destination model.

Operations:

  • Run Transformation load query icon : Open the Traceability model and select a CPS To Deployment element. This button starts a new transformation with the selected strategy.

  • Run Transformation with Debugger load xform w debugger icon : This button starts a new transformation on a CPS To Deployment element with the selected strategy. The transformation does not start until a VIATRA Transformation Remote Debugging is connected.

  • Stop Transformation unload icon : Stops a currently running incremental transformation (selected below) and releases its resources.

Advanced

Using the Transformation Debugger

  1. Select a CPS To Deployment element and start a VIATRA transformation with debugger support. Now the transformation is waiting for a debugger to be attached.

  2. Open Debug perspective

  3. In Run/Debug Configurations create a new VIATRA Transformations Remote Debugging

  4. Set the Target Port to 10990 and press Query Port, then the transformation appears in the Target VIATRA Transformation list

  5. The Java class which defines the transformation should be entered into the VIATRA Transformation Class field to associate the breakpoints with it. This time use a new dummy class in a new Java project.

  6. Press Debug

Use Step Over, set breakpoints and Resume the transformation.
The following views help the debugging:

  • Transformation Browser view shows which activation of the transformation rules can be executed. Here you can set breakpoints to suspend if a certain rule or activation is to be executed or a condition is true.

  • Transformation Model Instance Viewer shows the current state of the models during the transformation.

CPS Debug Configuration
Using the same Eclipse instance for debugging an incremental transformation and changing a model causes the program to freeze. Use a different Eclipse instance or run a new Eclipse Application instance from Run/Run Configurations and run the debugger from it.

Find more details on the debugger here.

CPS Model Generator wizard

In addition of initializing a prepared example or manually creating the CPS models, the demonstrator also includes a CPS Model Generator, which can create instances of predefined models and also supports generating arbitrarily large CPS models.

Select File/New/Other and in the CPS Demonstrator category select Generate CPS Model. Select a folder and enter a name for the CPS model.

In contrast to CPS Demonstrator Example project, which generates a source CPS model, a target Deployment model and a connector Traceability model, the CPS Model Generator only generates the CPS model, which must be connected to the other models to use it in a transformation. To do this manually refer this section.
Types of Models in CPS Model Generator

To create a simple model you can choose from a few preset models under the Simple Test Models option.

Some generators use random numbers. The initial value of the seed is time-dependent, so models are very likely to be distinct on each generation. To produce the same models use the same arbitrary number as random seed each time.
Scalable Models

To create arbitrarily large CPS models, which are similar in structure, but have different number of elements, choose a Scalable Model type. Enter a positive a scaling factor, which is proportional to the number of model elements. To generate a model with reasonable size which can be opened in the editor enter a scaling factor from the recommended range.

Opening large models can take a while. Switch off opening if it is not needed.
Model by Detailed Constraints
Detailed Model Generator Constraints

CPS Model Generator uses a detailed configuration during generation phase. (<<Model-Generator#,Here> described in detail.) A simple version of this configuration can be used if you select Model by Detailed Constraints.

Some of the parameters are specified with a min-max range, which is used to obtain a random number of the range to get the exact value of that parameter.
Other parameters are percentage parameters, which is used to decide how to distribute the choices for the possible elements.

For the Hosts you can define how many HostTypes and how many HostInstances for each type exist. For each instance the number of communication lines will fall into the defined range. The number of generated signals can be specified too.
The number of ApplicationTypes and ApplicationInstances can be defined similarly. Also the number of states and transitions in the statemachine of an ApplicationInstance can be defined. The ratio how many ApplicationInstances are allocated to a HostInstance, the ratio of actions in the transitions and the ratio of send action in all the actions can be specified with percentage parameters.

Initializing CPS models manually

  • Create a Deployment Model (File/New/Other and CPS Demonstrator category)

    • Root element shall be Deployment

  • Create a Traceability Model (File/New/Other and CPS Demonstrator category)

    • Root element shall be CPS To Deployment

  • Open the Traceability file

  • In the Traceability editor, load both the existing CPS and the newly created Deployment models with Load Resources... in the context menu

Load necessary resources into the Tracebility Model
  • Set CPS and Deployment references of Traceability model in the properties view

Set the references of the Traceability Model