Model transformation (MT) of very large models (VLMs), with mil- lions of elements, is a challenging cornerstone for applying Model- Driven Engineering (MDE) technology in industry. Recent research efforts that tackle this problem have been directed at distributing MT on the Cloud, either directly, by managing clusters explicitly, or indirectly, via external NoSQL data stores. In this paper, we draw attention back to improving efficiency of model transformations that use EMF natively and that run on non-distributed environments, showing that substantial performance gains can still be reaped on that ground.
We present Yet Another Model Transformation Language (YAMTL), a new internal domain-specific language (DSL) of Xtend for defining declarative MT, and its execution engine. The part of the DSL for defining MT is similar to ATL in terms of expressiveness, including support for advanced modelling contructs, such as multiple rule inheritance and module composition. In addition, YAMTL provides support for specifying execution control strategies. We experimentally demonstrate that the presented transformation engine outper- forms other representative MT engines by using the batch transformation component of the VIATRA CPS benchmark. The improvement is, at least, one order of magnitude over the up-to-now fastest solution in all of the assessed scenarios.
4. Scale UP with…
Yet Another Model Transformation Language !
• Internal DSL of Xtend
• Compiled to Java and excellent interoperability with JVM programs
• High-level API to work with collections
• Succinct syntax to work with lambda expressions
• IDE support: type checker and debugger…
• Focus on
• expressiveness: advanced contructs to model MT using
ATL as reference
• efficiency: MT performance using VIATRA3 as reference
• productivity as a consequence of being an internal DSL
TL
Krikava et al. On the use of an internal DSL for enriching EMF models. OCL and Textual
Modelling. 2012.
Hinkel et al. Using internal domain-specific languages to inherit tool support and modularity for
model transformations. SoSyM. 2017.
6. MTs in YAMTL: ORM Example
name: String
«stereotype»
NamedElt
«stereotype»
Classifier
DataType
Package
isAbstract: Boolean
Class
*
owner
attr
*
type
*super
*
classifiers
name: String
«stereotype»
Named
Type
Database
Column
Table
*
owner
col
*
type
*
types
*
tables
keyOf
key
*
0..1
name = "Item"
1:Class
multiValued: Boolean
Attribute
name = "product"
multiValued=false
2:Attribute
name = "Order"
4:Class
name = "date"
multiValued=false
3:Attribute
name = "items"
multiValued=true
5:Attribute
attr attr attr
1:Class 4:Class
name = "Item"
1:Table
name = "product"
2:Column
name = "Order"
6:Table
name = "date"
3:Column
name = "pk_Order"
7:Column
col
col
col
name =
"pk_Item"
4:Column
col
name = "fk_Item--items-->Order"
5:Column
col
name = "Item"
1:Table
name = "Invoice"
6:Table
typename = "String"
0:DataType
typetype
0:DataType
Source metamodel (class diagrams) Target metamodel (database schemas)
Initial source model
Propagation of delta a (case 4)
Ms MtInitial target model
TL
7. YAMTL Module Declaration
class cd2db extends YAMTLModule {
new () {
header().in('cd', CD).out('db', DB)
ruleStore(
// rule declarations
)
helperStore(
// helper declarations
)
}
val CD = CDPackage.eINSTANCE
val DB = RelationalPackage.eINSTANCE
// other helpers as Xtend methods
}
Façade interface:
loading models,
execution, statistics
MT name
MT signature for
traceable models
inOut()
for in-place MT
TL
8. new Rule('ClassToTable')
.in('c', CD.class_).build()
.out('t', DB.table, [
// environment vbles
val c = 'c'.fetch as Class
val t = 't'.fetch as Table
val pk_col = 'pk_col'.fetch as Column
// bindings
t.name = c.name
t.col += c.attr.fetch as List<Column>
t.col += pk_col
val list = c.incomingReferences
.fetch('ReferenceToFkColumn')
as List<Column>
if (list !== null)
t.col += list
]).build()
.out('pk_col', DB.column, [
// environment vbles
val c = 'c'.fetch as Class
val pk_col = 'pk_col'.fetch as Column
// bindings
pk_col.name = 'pk_' + c.name
]).build()
.build()
YAMTL Rule
rule
• matched | lazy | uniqueLazy
• transient
• filter(EXPR): global constraints
• using(VBLE, EXPR): local variables
• endWith(EXPR): imperative expression
name = "Item"
1:Class
name = "Item"
1:Table
name = "pk_Item"
4:Column
col
TL
9. new Rule('ClassToTable')
.in('c', CD.class_).build()
.out('t', DB.table, [
// environment vbles
val c = 'c'.fetch as Class
val t = 't'.fetch as Table
val pk_col = 'pk_col'.fetch as Column
// bindings
t.name = c.name
t.col += c.attr.fetch as List<Column>
t.col += pk_col
val list = c.incomingReferences
.fetch('ReferenceToFkColumn')
as List<Column>
if (list !== null)
t.col += list
]).build()
.out('pk_col', DB.column, [
// environment vbles
val c = 'c'.fetch as Class
val pk_col = 'pk_col'.fetch as Column
// bindings
pk_col.name = 'pk_' + c.name
]).build()
.build()
YAMTL Rule
input pattern elements
• with(VBLE) dependencies
• filter(EXPR): local constraint (optional)
• derivedWith(EXPR)
name = "Item"
1:Class
name = "Item"
1:Table
name = "pk_Item"
4:Column
col
TL
10. new Rule('ClassToTable')
.in('c', CD.class_).build()
.out('t', DB.table, [
// environment vbles
val c = 'c'.fetch as Class
val t = 't'.fetch as Table
val pk_col = 'pk_col'.fetch as Column
// bindings
t.name = c.name
t.col += c.attr.fetch as List<Column>
t.col += pk_col
val list = c.incomingReferences
.fetch('ReferenceToFkColumn')
as List<Column>
if (list !== null)
t.col += list
]).build()
.out('pk_col', DB.column, [
// environment vbles
val c = 'c'.fetch as Class
val pk_col = 'pk_col'.fetch as Column
// bindings
pk_col.name = 'pk_' + c.name
]).build()
.build()
YAMTL Rule
output pattern elements
• action(EXPR) dependencies
• drop()
name = "Item"
1:Class
name = "Item"
1:Table
name = "pk_Item"
4:Column
col
TL
11. new Rule('ClassToTable')
.in('c', CD.class_).build()
.out('t', DB.table, [
// environment vbles
val c = 'c'.fetch as Class
val t = 't'.fetch as Table
val pk_col = 'pk_col'.fetch as Column
// bindings
t.name = c.name
t.col += c.attr.fetch as List<Column>
t.col += pk_col
val list = c.incomingReferences
.fetch('ReferenceToFkColumn')
as List<Column>
if (list !== null)
t.col += list
]).build()
.out('pk_col', DB.column, [
// environment vbles
val c = 'c'.fetch as Class
val pk_col = 'pk_col'.fetch as Column
// bindings
pk_col.name = 'pk_' + c.name
]).build()
.build()
YAMTL Output Action
fetch
to access execution environment
name = "Item"
1:Class
name = "Item"
1:Table
name = "pk_Item"
4:Column
col
TL
12. new Rule('ClassToTable')
.in('c', CD.class_).build()
.out('t', DB.table, [
// environment vbles
val c = 'c'.fetch as Class
val t = 't'.fetch as Table
val pk_col = 'pk_col'.fetch as Column
// bindings
t.name = c.name
t.col += c.attr.fetch as List<Column>
t.col += pk_col
val list = c.incomingReferences
.fetch('ReferenceToFkColumn')
as List<Column>
if (list !== null)
t.col += list
]).build()
.out('pk_col', DB.column, [
// environment vbles
val c = 'c'.fetch as Class
val pk_col = 'pk_col'.fetch as Column
// bindings
pk_col.name = 'pk_' + c.name
]).build()
.build()
YAMTL Output Action
fetch
to resolve references in…
name = "Item"
1:Class
name = "Item"
1:Table
name = "pk_Item"
4:Column
col
TL
13. new Rule('ClassToTable')
.in('c', CD.class_).build()
.out('t', DB.table, [
// environment vbles
val c = 'c'.fetch as Class
val t = 't'.fetch as Table
val pk_col = 'pk_col'.fetch as Column
// bindings
t.name = c.name
t.col += c.attr.fetch as List<Column>
t.col += pk_col
val list = c.incomingReferences
.fetch('ReferenceToFkColumn')
as List<Column>
if (list !== null)
t.col += list
]).build()
.out('pk_col', DB.column, [
// environment vbles
val c = 'c'.fetch as Class
val pk_col = 'pk_col'.fetch as Column
// bindings
pk_col.name = 'pk_' + c.name
]).build()
.build()
YAMTL Output Action
a) declative rules
new Rule('AttributeToColumn')
.in('att', CD.attribute).filter([ ... ]).build()
.out('col', DB.column, [ ... ]).build()
.build(),
fetch
to resolve references in…
name = "Item"
1:Class
name = "Item"
1:Table
name = "pk_Item"
4:Column
col
TL
14. new Rule('ClassToTable')
.in('c', CD.class_).build()
.out('t', DB.table, [
// environment vbles
val c = 'c'.fetch as Class
val t = 't'.fetch as Table
val pk_col = 'pk_col'.fetch as Column
// bindings
t.name = c.name
t.col += c.attr.fetch as List<Column>
t.col += pk_col
val list = c.incomingReferences
.fetch('ReferenceToFkColumn')
as List<Column>
if (list !== null)
t.col += list
]).build()
.out('pk_col', DB.column, [
// environment vbles
val c = 'c'.fetch as Class
val pk_col = 'pk_col'.fetch as Column
// bindings
pk_col.name = 'pk_' + c.name
]).build()
.build()
YAMTL Output Action
b) lazy rules
new Rule('ReferenceToFkColumn')
.uniqueLazy
.in('ref', CD.attribute).build()
.out('fk_col', DB.column, [ ... ]).build()
.build()
a) declative rules
new Rule('AttributeToColumn')
.in('att', CD.attribute).filter([ ... ]).build()
.out('col', DB.column, [ ... ]).build()
.build(),
fetch
to resolve references in…
name = "Item"
1:Class
name = "Item"
1:Table
name = "pk_Item"
4:Column
col
TL
15. Reuse in YAMTL
• Multiple Rule Inheritance and abstract rules
• Dispatch semantics: leftmost top-down search for most concrete applicable
rule for each object
• Execution semantics of output element actions (inherits/overriding)
• Module composition by class extension
• Inheritance: by default
• Redefinition: when a rule (or a helper) in the extending module have a
compatible interface with one rule (or helper) in the extended module
• Module reuse in other JVM programs using imports
TL
17. VIATRA CPS Benchmark
YAMTL solution:
1. Helper to determine receiving transitions (waitFor)
2. Build the structure of deployment model using rules with high priority
3. Initialize triggers with a transient rule (only updates)
4. Extract CPS traceability model from YAMTL’s internal traceability model
action triggers to be
set after behaviours
are instantiated
behaviours are
instantiated (copy)
traceability model
TL
19. Final Remarks
https://yamtl.github.io/
• YAMTL brings declarative M2M transformations to the Xtend world
• Advanced model transformation constructs
• Support for VLMs/good performance
• Productivity and analysis tools available via Xtend/Java
• Next: Incremental MT - most scalable solution of TTC’18
• Interested in exploring applications
• Thanks to Ábel Hegedüs for integrating YAMTL
solution in official VIATRA CPS Benchmark
Thank you for your attention
Artur Boronat