# medini QVT Relations Tutorial

This page will outline a tutorial of QVT Relations, which was developed together with our friends from the Telematica Instituut, Enschede, Netherlands. This tutorial describes various model transformations in terms of a very simple but effective modelling language called Shapes.

## Shapes metamodel

The Shapes language is a simple syntactical language that has been designed to illustrate model transformation patterns. The Shapes language consists of three different simple shapes: Squares, Circles and Triangles. Furthermore, the Shape language consists of a grouping concepts called Block to express hierarchy. A Block may contain simple shapes and other blocks. Relations between simple shapes and blocks are expressed relations by means of Arrows. Because model transformations are only about structure and syntax no semantics is associated with the Shapes language. The metamodel for the Shapes language is shown below. The metamodel is located in SVN

Below three examples of expressions in the Shapes language are depicted. The first example shows a Square s that is related via an Arrow a to Block B. The Block B contains a Circle C and Triangle T that are unrelated. The second example shows a cyclic reference of a Circle c to itself using Arrow a. The third example demonstrates nesting. It shows a Block B1 containing triangle T and Block B2. T and B2 are related through Arrow a1. Block B2, in turn contains Square s that refers to Block B3 using Arrow a2. Finally, Block B3 contains Circle C.

## The mapping pattern

Goal Establish one-to-one relations between elements from the source model to elements of the target model.

Motivation Mapping is the most common and straightforward transformation problem. It occurs when source and target models use different languages or syntax, but otherwise express more or less the same semantics. This pattern is used in practically every transformation. Typical examples are 1-to-1 model transformation rules. In general there are two cases: mapping of nodes and mapping of relations.

Node mapping The transformation for the node mapping pattern is described below. The transformation specifies to map a node x of type X and node y of type Y in case their respective contexts are related.

```  top relation NodeMapping {
nm: String;
enforce domain left x: X {
context = c1:XContext {},
name = nm
};
enforce domain right y: Y {
context = c2:YContext {},
name = nm
};
when {
ContextMapping(c1,c2);
}
}
```

Relation mapping The transformation for the relation mapping is similar to the transformation of a node mapping but it adds a few additional constraints. Relation a of type A is mapped to relation b of type B in case their names and context can be mapped, and if the associated sources and targets of the relations can be mapped. The specification pattern of a relation mapping is specified below.

```  top relation RelationshipMapping {
nm: String;
enforce domain left a: A {
context = c1 : AContext {},
name = nm,
source = as : AS {},
target = at : AT {}
};
enforce domain right b: B {
context = c2 : BContext {},
name = nm, source = bs : BS {},
target = bt : BT {}
};
when {
ContextMapping(c1,c2);
ElementMapping(as,bs);
ElementMapping(at,bt);
}
}
```

Example A concrete example where the mapping pattern is used is the identity mapping. This mapping, which is called ElementMapping below, maps all elements from the source domain to elements of the target domain thereby preserving structure. ElementMapping makes use of two other relations: RootBlockMapping that maps RootBlock elements, and BlockMapping which maps Block elements that are not RootBlock. The block that are mapped are forced to satisfy the constraints specified in ElementMapping (see the where clause), i.e., their names will be equal. Finally,ElementMapping describes to map all ModelElements (including Blocks) while preserving the element names and their blocks. The condition is specified in the when clause. It indicates to map elements e1 end e2 only if e1 and e2 both have the same RootBlock or the same Block.

```  -- map RootBlock elements
top relation RootBlockMapping {

nm: String;

enforce domain left b1: RootBlock {
name = nm
};
enforce domain right b2: RootBlock {
name = nm
};
}

-- Map Block element that are not RootBlock elements
top relation BlockMapping {

enforce domain left e1: Block {};
enforce domain right e2: Block {};
when {
not(RootBlockMapping(e1,e2));
}
where {
ElementMapping(e1,e2);
}
}

relation ElementMapping {

nm: String;

enforce domain left e1: Shapes::ModelElement {
name = nm,
block = b1 : Block {}
};
enforce domain right e2: Shapes::ModelElement {
name = nm,
block = b2 : Block {}
};
when {
RootBlockMapping(b1,b2) or BlockMapping(b1,b2);
}
}
```

## The flattening pattern

Goal Remove hierarchy from the source model.

Motivation Models are often hierarchically structured. Consider for example package hierarchy in UML, composite states in Statecharts or hierarchical PetriNets. Such hierarchical structuring usually is intended to make the models easier to understand. However, to analyze such models it may be necessary to flatten the model to a model without hierarchy.

Flattening The following transformation outlines how to flatten a composite source model to a target model. It is assumed that the source model and target model are specified by the same metamodel. The idea of the mapping is as follows. All Composites in the source model are related to the RootElement in the target model. The CompositeContext is either the RootElement or another Composite. Thus the CompositeContext c1 should be related to the RootElement r via RootMapping or CompositeFlattening itself. All model elements are mapped from the source model to the target model using instances of the CompositeFlattening transformation.

```top relation CompositeFlattening {
checkonly domain left c: Composite {
context = c1 :CompositeContext {}
};
enforce domain right r: RootElement {};
when {
RootMapping(c1,r) or CompositeFlattening(c1,r);
}
}

relation ElementMapping {
nm: String;
enforce domain left x: Element {
name = nm,
context = c1 :Context {}
};
enforce domain right y: Element {
name = nm,
context = c2 : Context {}
};
when {
RootMapping(c1,c2) or CompositeFlattening(c1,c2);
}
}
```

## Hierarchy refinement pattern

Goal To obtain a more detailed target model by refining a node to a hierarchical node containing sub structures.

Motivation Hierarchy refinement is typically used to zoom in to the structure of a super node thereby revealing the internal structure of a sub node. In behaviour models, hierarchy refinement can be used to zoom in to sub behaviours of a node.

Hierarchy transformation pattern The hierarchy transformation pattern is characterized by a single mapping rule that takes a node in the source domain and maps it a hierarchical structure (calledb_sub in the pattern below) that may contain sub nodes (calledsub_node in the pattern below). The specification of the hierarchy refinement pattern is shown below.

```top relation HierarchyRefinementMapping {
n : String;
enforce domain left node: Node {
name = n,
block = b_left : Block {}
};
enforce domain right b_sub: Block {
name = 'Block(' + n + ')',
block = b_right : Block {}
};
enforce domain right sub_node : Node {
name = 'e',
block = b_sub
};
when {
RootBlockMapping(b_left,b_right) or BlockMapping(b_left,b_right);
}
where {
ElementMapping(node,b_sub);
}
}
```

## Tutorial Code

All transformation rule "specifications" and a corresponding solution is stored in the SVN

You can checkout or export the tutorial and import it into your medini QVT application workspace.