Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
VIATRA/Transformation/Transformation API
Contents
VIATRA2 EMF Transformation API
- Based on EVM
- Relies on Xtend features such as extension methods and closures to be
- Language concepts (for requirements overview)
- Documentation for API in org.eclipse.viatra2.emf.git (browse, stats, fork on OrionHub)
Batch Transformation API
Three extension classes used for transformations:
- BatchTransformation - hides IncQueryEngine and RuleEngine; manages group initialization of rules - instead of an extension method, this can also be used as a base class
- TransformationStatements - control structure
- ModelManipulation - generic model manipulation primitives; hides details of EditingDomains (if necessary); implementation not batch transformation specific
Batch Transformation Rules
- Special rule type
- Precondition + action
- Life cycle:
- Stateless
- rule does not maintain state whether an activation has fired or not
- Lifecycle: firing: active -> active
- Stateful
- rule maintains whether an an activation has fired or not
- Lifecycle: firing: active -> fired
- Stateless
(Batch) Transformation Statements
Name | Parameters | Description |
---|---|---|
fireOne | Batch Transformation Rule, (opt: filter) | Fires a single activation |
fireAllCurrent | Batch Transformation Rule, (opt: filter) | Fires all current activations. If the firings change the set of activations, it won't change the set of fired activations. |
fireWhilePossible | Batch Transformation Rule, (opt: filter) | Fires the activations one by one. Useful for iterate-choose scenarios. Break conditions are implemented using Match Predicates - functions that receive Match instances as parameters. |
fireUntil | Batch Transformation Rule, break condition, (opt: filter) | After firing the first activation, it checks whether the break condition became true; if yes, exits, if not, it restarts. It does not store the initial set of activations. Useful for iterate-choose scenarios. Break conditions are implemented using Match Predicates - functions that receive Match instances as parameters. |
find | IQuerySpecification, (opt: filter) | Returns a match of a selected query |
Incremental Transformation API
TBA asd
Model Manipulation Primitives
Model manipulation primitives are implemented by instances of IModelManipulations interface. Currently, two implementations are available:
- SimpleModelManipulations - uses plain EMF API
- ModelManipulationsWithEditingDomain - uses EMF Edit commands on EditingDomain instances
If some transformation needs specific primitives (e.g. transaction support), new instances can introduce extra methods as required.
Name | Parameters | Description |
---|---|---|
create | Resource; EClass | Creates an object with the corresponding EClass type, and puts it into the root of the selected resource |
createChild | EObject (container); EReference; EClass | Creates an object with the corresponding EClass type, and puts it into the selected reference; the reference must be of containment type |
addTo | EObject (container); EStructuralFeature; Object | Adds an existing object to the corresponding container with a reference; if using a reference it must *not* be of containment type |
remove | EObject | Removes the EObject from the model |
remove | EObject (container); EStructuralFeature; Object | Removes an object from the selected container; when using a containment EReference, also removes it from the resource set |
remove | EObject (container); EStructuralFeature | Removes all objects from a multivalued feature; when using a containment EReference, also removes them from the resource set |
set | EObject (container); EStructuralFeature; Object | Sets the value of a single-valued feature |
move | EObject(s), EObject (new container), EStructuralFeature | Moves elements to a new container, and removes them from an old one. 'Remark': The implementation here is specific, as it relies on features of the index. |
Examples
A (not very well tested) example transformation is available by implementing the Petri net to State Charts case of the Transformation Tool Contest 2013.
- Case description: http://planet-sl.org/community/index.php?option=com_community&view=groups&task=viewgroup&groupid=26&Itemid=387&lang=en
- Implementation: https://github.com/izsob/TTC13-PN2SC-EIQ (look for the branch viatra-api)
- The following snippets are taken from this repository
Setting up a transformation
class Pn2ScJobs { /* Transformation-related extension API */ extension BatchTransformationRuleFactory ruleFactory = new BatchTransformationRuleFactory extension BatchTransformation transformation extension TransformationStatements statements extension IModelManipulations manipulation /* Makes available the Literals of the EPackage for the manipulation API */ extension StatechartsPackage chartPackage = StatechartsPackage.eINSTANCE Statechart stateChart Resource resource new(Resource resource) { /Storing transformation-specific input elements this.resource = resource this.stateChart = resource.contents.head as Statechart /* Extensions are initialized as normal fields in Xtend */ transformation = new BatchTransformation(resource.resourceSet) statements = new TransformationStatements(transformation) manipulation = new SimpleModelManipulations(transformation.iqEngine) } ... }
Defining rules, rulegroups
Rules can be created using the factory methods of the BatchTransformation class; its actions can be described by an Xtend closure.
If required, it is possible to extend BatchTransformationRule manually - both implementations are interchangeable.
/** * Map a PetriNet place to a base state in the StateChart with an "or" container. */ val createMapPlaceRuleSpecification = createRule(PlaceMatcher::querySpecification) [ // create base b with b.name=p.name; and the state or, where or.contains={b} var or = stateChartResource.create(OR) as OR var basic = or.createChild(compound_Contains, basic) as Basic basic.set(state_Name, p.name)///name = p.name // create trace from place to or createTrace(p, or) ] /** * Map a PetriNet transition to a hyperedge state in the StateChart without an "or" container. */ val createMapTransitionRuleSpecification = createRule(TransitionMatcher::querySpecification) [ // create hyperEdge h with h.name=t.name (without an or container) var hyperEdge = stateChartResource.create(hyperEdge) as HyperEdge hyperEdge.name = t.name // create trace from transition to hyperEdge createTrace(t, hyperEdge) ] /** * Create "next" edges in the StateChart between elements connected in the PetriNet. */ val createNextStateRuleSpecification = createRule(NextStateMatcher::querySpecification) [ state1.addTo(state_Next, state2) ] /** * Get rules for performing initial mapping */ def getInitialisationRules() { new TransformationRuleGroup( createMapPlaceRuleSpecification, createMapTransitionRuleSpecification, createNextStateRuleSpecification ) }
Executing rules, rule groups
The primitives ask for a rule and filter
- A filter is expressed by a collection of name-value pairs (available names come from the precondition pattern)
- Parameter names not mentioned are unconstrained
val moveChildrenRule = createRule(EquivContainsMatcher::querySpecification) [ state.moveTo(newP, compound_Contains) ] // add children elements to OR of the StateChart moveChildrenRule.forall("namedElement" -> q)
The following snippet shows that primitives also work with rule groups with the exact same syntax. The idea here is that the engine decides which rule of the group to execute (based on the ConflictResolver).
def transformPn2Sc() { // place->OR mapping initialisationRules.fireWhilePossible // execute AND and OR rules andOrRules.fireWhilePossible // clean orphaned root ORs; and create StateChart root finalisationRules.fireWhilePossible }
Further ideas to evaluate
- "Strict" API vs "relaxed" API
- Everything presented here is a strict API
- Useful for research goals (e.g. analysis)
- Might be too strict for Java/EMF programmers
- It might make sense to support transformation with bring-your-own-code style
- Currently almost all elements are optional in API: statements and model manipulations commands need not to be used -> simple Java/Xtend replacements possible
- Some simple wrappers might be needed to create RecordingCommands, etc.
- Everything presented here is a strict API