Skip to main content
Jump to: navigation, search

VIATRA/Transformation/Transformation API

VIATRA2 EMF Transformation API


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

(Batch) Transformation Statements

Name Parameters Description
choose Batch Transformation Rule, (opt: filter) Fires a single activation
forall 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.
until 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

Model Manipulation Primitives

Model manipulation primitives are implemented by instances of IModelManipulations interface. Currently, two implementations are available:

  1. SimpleModelManipulations - uses plain EMF API
  2. 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.

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.until(alwaysFalse)
  // execute AND and OR rules
  andOrRules.until(alwaysFalse)
  // clean orphaned root ORs; and create StateChart root
  finalisationRules.until(alwaysFalse)
}

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.

Back to the top