M1 to M2: promotion,
M2 to M1: demotion,
M3 to M1, M3 to M2, etc.
The present courseware has been elaborated in the context of the MODELWARE European IST FP6 project (http://www.modelware-ist.org/).
Co-funded by the European Commission, the MODELWARE project involves 19 partners from 8 European countries. MODELWARE aims to improve software productivity by capitalizing on techniques known as Model-Driven Development (MDD).
To achieve the goal of large-scale adoption of these MDD techniques, MODELWARE promotes the idea of a collaborative development of courseware dedicated to this domain.
The MDD courseware provided here with the status of open source software is produced under the EPL 1.0 license.
Model Driven Engineering (MDE)
The role of model transformations in MDE
UML
OCL
MOF
Basic programming concepts
Introduction
Description of ATL
Example: Class to Relational
Additional considerations
Conclusion
Introduction
Definitions
Operational context
Description of ATL
Example: Class to Relational
Additional considerations
Conclusion
A model transformation is the automatic creation of target models from source models.
M1 to M2: promotion,
M2 to M1: demotion,
M3 to M1, M3 to M2, etc.
Introduction
Description of ATL
Overview
Source pattern
Target pattern
Execution order
Example: Class to Relational
Additional considerations
Conclusion
Source models are read-only (they can only be navigated, not modified),
Target models are write-only (they cannot be navigated).
In ATL, transformations are organized in modules.
A module contains 4 parts:
A header.
An optional import section.
A set of helpers.
A set of rules.
module RedGreen2PinkBlue;
create OUT : PinkBlue from IN : RedGreen;
By convention, the module name follows the format source-language2target-language
.
Source and target models are typed: here PinkBlue
and RedGreen
.
Models must respect their types (languages/metamodels).
uses strings; -- imports the strings library
The optional import section enables to declare which ATL libraries are imported.
helper context Integer def : double() : Integer = self * 2;
helper def : sqrt(x: Real): Real = x ∗ x;
Helpers are auxiliary functions.
A helper is composed of: - a name, a context (type), a return type, and an optional set of parameters, identified by pairs name/type.
a body, in the form of an ATL expression that represents the code of the ATL helper.
There are two kinds of rules: called or matched.
Called rules are equivalent to procedures in imperative programming, they are called by other rules.
Matched rules are declarative, they are automatically executed by ATL.
rule newGreen (name: String) {
to
p : RedGreen!Green (
name <- name
)
}
Unlike helpers, called rules create elements in the target model.
rule newGreen (name: String) {
to
p : RedGreen!Green (
name <- name
)
}
It is called by its name,
It may take arguments,
It can contain:
A declarative target pattern,
An action block (i.e. a sequence of statements),
Both.
rule red2blue {
from
red : RedGreen!Red
to
blue : BluePink!Blue (
name <- red.name
)
}
Matched rules are the core of ATL transformations.
They allow to specify:
for which kinds of source elements target elements must be generated,
the way the generated target elements have to be initialized.
rule red2blue {
from
red : RedGreen!Red
to
blue : BluePink!Blue (
name <- red.name
)
}
a source pattern to be matched in the source models,
a target pattern to be created in the target models for each match during rule application.
rules that are applied once for each match: a given set of elements may only be matched by one standard rule,
rules that are applied as many times for each match as it is referred to from other rules (possibly never for some matches)
lazy rules that are applied at most once for each match and only if it is referred to from other rules.
rule red2blue {
from
red : RedGreen!Red(red.name->size() > 0)
-- (...)
The source pattern is composed of:
A labeled set of types coming from the source metamodels,
A guard (Boolean expression) used to filter matches.
A match corresponds to a set of elements coming from the source models that:
Are of the types specified in the source pattern (one element for each type),
Satisfy the guard.
rule red2blue {
-- (...)
to
blue : BluePink!Blue (
name <- red.name
)
A labeled set of types coming from the target metamodels,
For each element of this set, a set of bindings.
A binding specifies the initialization of a property of a target element using an expression.
rule red2blue {
-- (...)
to
blue : BluePink!Blue (
name <- red.name
)
Elements are created in the target models (one for each type of the target pattern),
Target elements are initialized by executing the bindings:
First evaluating their value,
Then assigning this value to the corresponding property.
The order in which rules are matched and applied is not specified.
Remark: the match of a lazy or unique lazy rules must be referred to before the rule is applied.
The order in which bindings are applied is not specified.
The execution of declarative rules can however be kept deterministic:
The execution of a rule cannot change source models
It cannot change a match,
Target elements are not navigable
The execution of a binding cannot change the value of another.
Introduction
Description of ATL
Example: Class to Relational
Overview
Source metamodel
Target metamodel
Rule Class2Table
Rule SingleValuedAttribute2Column
Rule MultiValuedAttribute2Column
Additional considerations
Conclusion
The source metamodel Class is a simplification of class diagrams.
The target metamodel Relational is a simplification of the relational model.
ATL declaration of the transformation:
module Class2Relational;
create Mout : Relational from Min : Class;
The transformation excerpts used in this presentation come from: http://www.eclipse.org/atl/atlTransformations/#Class2Relational
package Class
abstract class NamedElt {
String name
}
abstract class Classifier extends NamedElt {
}
class DataType extends Classifier {
}
class ^Class extends Classifier {
refers ^Class[] ^super
contains Attribute[] attributes opposite owner
boolean isAbstract
}
class Attribute extends NamedElt {
boolean multiValued
refers Classifier ^type
container ^Class owner opposite attributes
}
package Relational
abstract class Named {
String name
}
class Table extends Named {
contains Column[] col opposite owner
refers Column[] ^keys opposite keyOf
}
class Column extends Named {
container Table owner opposite col
refers Table[0..1] keyOf opposite ^keys
refers Type ^type
}
class Type extends Named {
}
Class2Table:
A table is created from each class,
The columns of the table correspond to the single-valued attributes of the class,
A column corresponding to the key of the table is created.
SingleValuedAttribute2Column:
A column is created from each single-valued attribute.
MultiValuedAttribute2Column:
A table with two columns is created from each multi-valued attribute,
One column refers to the key of the table created from the owner class of the attribute,
The second column contains the value of the attribute.
A Table is created for each Class:
rule Class2Table {
from -- source pattern
c : Class!Class
to -- target pattern
t : Relational!Table
}
The name of the Table is the name of the Class:
rule Class2Table {
from
c : Class!Class
to
t : Relational!Table (
name <- c.name -- a simple binding
)
}
The columns of the table correspond to the single-valued attributes of the class:
rule Class2Table {
from
c : Class!Class
to
t : Relational!Table (
name <- c.name,
col <- c.attr->select(e | -- a binding
not e.multiValued)-- using complex navigation
)
}
Remark: attributes are automatically resolved into columns by automatic traceability support.
Each Table owns a key containing a unique identifier:
rule Class2Table {
from
c : Class!Class
to
t : Relational!Table (
name <- c.name,
col <- c.attr->select(e |
not e.multiValued
)->union(Sequence {key}),
key <- Set {key}
),
key : Relational!Column ( -- another target
name <- ‘Id’-- pattern element
) -- for the key
}
A Column is created for each single-valued Attribute:
rule SingleValuedAttribute2Column {
from -- the guard is used for selection
a : Class!Attribute (not a.multiValued)
to
c : Relational!Column (
name <- a.name
)
}
A Table is created for each multi-valued Attribute, which contains two columns:
The identifier of the table created from the class owner of the Attribute
The value.
rule MultiValuedAttribute2Column {
from
a : Class!Attribute (a.multiValued)
to
t : Relational!Table (
name <- a.owner.name + ‘_’ + a.name,
col <- Sequence {id, value}
),
id : Relational!Column (
name <- ‘Id’
),
value : Relational!Column (
name <- a.name
)
}
Introduction
Description of ATL
Example: Class to Relational
Additional considerations
Other ATL features
ATL in use
Conclusion
Rule inheritance, to help structure transformations and reuse rules and patterns:
A child rule matches a subset of what its parent rule matches,
All the bindings of the parent still make sense for the child,
A child rule specializes target elements of its parent rule:
Initialization of existing elements may be improved or changed,
New elements may be created.
abstract rule R1 {
-- ...
}
rule R2 extends R1 {
-- ...
}
query <query_name> = <atl_exp>;
In short, a query is a model to primitive type value transformation.
A query is composed of:
A name.
A type.
A ATL expression that expresses the calculated value.
Since source models are read-only target models must be created from scratch,
This can be done by writing copy rules for each elements that are not transformed,
This is not very elegant.
In refining mode, the ATL engine automatically copies unmatched elements.
The developer only specifies what changes.
ATL semantics is respected: source models are still read-only.
An (optimized) engine may modify source models in-place but only commit the changes in the end.
Syntax: replace from
by refining
module A2A; create OUT : MMA refining IN : MMA;
ATL has been used in a large number of application domains.
A library of transformations is available at
More than 40 scenarios,
More than 100 single transformations.
About 100 sites use ATL for various purpose:
Teaching,
Research,
Industrial development,
Etc.
ATL tools and documentation are available at: https://eclipse.org/atl/
Execution engine:
Virtual machine,
ATL to bytecode compiler,
Integrated Development Environment (IDE) for:
Editor with syntax highlighting and outline,
Execution support with launch configurations,
Source-level debugger.
Documentation:
Starter’s guide, User manual, Installation guide, etc.
Introduction
Description of ATL
Example: Class to Relational
Additional considerations
Conclusion
ATL has a simple declarative syntax:
Simple problems are generally solved simply.
ATL supports advanced features:
Complex OCL navigation, lazy rules, refining mode, rule inheritance, etc.
Many complex problems can be handled declaratively.
ATL has an imperative part:
Any problem can be handled.
Questions?
Comments?
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.