3.4 Système de types de Kermeta
4.2.3 Conception et implantation en Kermeta
Comme pour le développement de tout composant logiciel, la première étape de
dé-veloppement est la conception. Le fait d’utiliser un langage généraliste comme Kermeta
plutôt qu’un langage dédié à la transformation de modèle impose de porter un soin
par-ticulier à la conception. En effet, les langages dédiés à la transformation fournissent des
constructions et des structures adaptées à la définition de transformations de modèles
alors qu’une transformation écrite en Kermeta n’est qu’un programme orienté-objets
qui manipule des éléments de modèles.
Conception
La transformation CLS2RDB consiste à créer des tables pour chaque classe
mar-quée comme persistante dans le modèle source. Pour chaque attribut ou association
des classes persistantes, des colonnes ou clés étrangères sont ajoutées dans les tables
correspondantes. En pratique, cette transformation peut s’implanter par trois étapes
successives :
1. Création des tables. Création d’une table dans le modèle de sortie pour chaque
classe marquée persistante dans le modèle d’entrée.
2. Création des colonnes. Création d’un attribut pour chaque attribut ou référence
des classes persistantes dans le modèle d’entrée. Les colonnes correspondants aux
clés étrangères ne peuvent pas être créées lors de cette étape car toutes les clés
primaires des tables ne sont pas encore créées.
3. Mise-à-jour des clés étrangères. Dans cette troisième phase, les clés primaires de
toutes les tables sont à jour et il est donc possible de créer l’ensemble des colonnes
correspondant aux clés étrangères.
Entre les deux premières phases de la transformation il est nécessaire de garder
une information de traçabilité entre les éléments du modèle source et les éléments du
modèle résultat. En effet, afin d’ajouter les colonnes dans les tables appropriées lors de
la seconde phase, il est nécessaire de conserver un lien entre les classes persistantes et
les tables qui leur correspondent lors de la première phase. Ce besoin de stocker des
informations de traçabilité n’est pas propre à la transformation CLS2RDB mais est
observé de façon récurrente pour l’écriture de transformations de modèles.
En Kermeta plusieurs possibilités existent pour stocker les informations de
traça-bilité. La solution la plus simple est d’utiliser une structure de donnée disponible dans
le framework de Kermeta tel qu’une table de hachage par exemple. Cependant, étant
donné qu’il s’agit d’un problème récurrent il peut être avantageux de concevoir un
so-lution réutilisable sous la forme d’un framework de traçabilité. Le fait que Kermeta soit
un langage orienté-objets généraliste fait que son application à un domaine particulier
tel que l’écriture de transformations de modèles passe par la création de frameworks
spécialisés qui encapsulent les constructions du domaine.
La figure 4.17 présente l’implantation Kermeta d’une classe générique permettant
de stocker la correspondance entre deux types d’objets. L’utilisation des variables de
types génériques SRC et T GT permet de rendre la classe Trace réutilisable dans un
contexte de typage statique fort. L’implantation proposée est très simple et permet de
stocker des correspondances "un-un" unidirectionnelles entre deux ensembles d’objets.
Ce système de trace très simple est suffisant pour la transformation CLS2RDB mais
mériterait d’être enrichi en offrant par exemple la possibilité de stocker des traces
bi-directionnelles ou des correspondances mettant en jeu plus de deux objets.
La conception d’une transformation en Kermeta se fait comme la conception de
n’importe quel programme orienté-objets : conception de classes, création de
frame-works, utilisation de patrons de conceptions, etc. Une des particularités de Kermeta
pour la transformation de modèles est la possibilité d’encapsuler une partie du code
de la transformation dans le méta-modèle d’entrée et de sortie de la transformation.
Afin d’illustrer cette possibilité nous avons choisi d’intégrer au méta-modèle de base de
données l’étape 3 de la transformation qui consiste a créer les colonnes correspondant
aux clés étrangères. En effet, ce traitement est utile à la transformation CLS2RDB
Transformation de modèles 119
1 package trace ;
2 require kermeta
3 using kermeta :: utils
4
5 /* *
6 * This class represents a simple one to one
7 * unidirectional mapping
8 */
9 c l a s s Trace < SRC , TGT >
10 {
11 /* * Mapping between source and target objects */
12 reference src2tgt : Hashtable < SRC , TGT >
13
14 operation create () i s do
15 src2tgt := Hashtable < SRC , TGT >. new
16 end
17
18 /* * get a target element */
19 operation getTargetElem ( src : SRC ) : TGT i s do
20 r e s u l t := src2tgt . getValue ( src )
21 end
22
23 /* * Store a trace */
24 operation storeTrace ( src : SRC , tgt : TGT ) i s do
25 src2tgt . put ( src , tgt )
26 end
27 }
mais peut être également être utile à tout programme ou transformation qui utilise le
méta-modèle de base de données et qui crée des clés étrangères.
Pour ce qui est de la transformation elle-même et des traitements correspondant
aux étapes un et deux, nous avons choisi d’utiliser simplement une classe nommée
Class2RDBMS.
Implantation
La figure 4.18 présente le listing Kermeta contenant la classeClass2RDBMS, ses
pro-priétés et la méthodetransform qui constitue le point d’entrée de la transformation. La
première ligne du listing précise dans quel package est définie la classeClass2RDBMS.
Les lignes de 3 à 6 permettent d’importer les éléments qui sont utilisés dans la
trans-formation : le framework de base de Kermeta, le framework de trace que l’on a définit
précédemment et enfin les deux méta-modèles. On remarque que le méta-modèle de
classes est directement importé dans le format ECore (ligne 5) alors que pour le
méta-modèle de base de données, c’est la version Kermeta qui est utilisée (ligne 6).
La classe Class2RDBMS comporte deux références définies respectivement aux
lignes 13 et 15. La première, appeléeclass2table qui est utilisée pour stocker les
corres-pondances entre classes et tables entre les deux premières phases de la transformation
en utilisant la classe génériqueTrace définie précédemment. La seconde, nomméefkeys
permet de stocker l’ensemble des clés étrangères crées au cours de la transformation
afin de créer les colonnes correspondantes lors de la dernière phase. Pour représenter
cette collection, on a utilisé la classe génériqueCollection du framework de Kermeta.
L’opérationtransformest le point d’entrée de la transformation. On retrouve dans le
corps de cette méthode, un bloc d’initialisation suivi des trois phases de la
transforma-tion. Le bloc d’initialisation (lignes 18 à 22) permet de créer les structures de données
utilisées et d’initialiser le modèle résultat. La première phase de transformation assure
la création des tables correspondant aux classes marquées persistantes (ligne 23 à 29).
Pour chacune des classes marquées comme persistantes, une nouvelle table est créée,
ajoutée au modèle de sortie, et l’information de trace entre la classe et la nouvelle table
est stockée.
La seconde phase consiste à créer les colonnes correspondant à chaque table. Pour
cela on a défini une opération createColumns dont l’implantation est détaillée sur le
listing de la figure 4.19. Le code de cette opération est simple : il consiste tout d’abord
à ajouter l’ensemble des colonnes correspondant aux attributs (appel à l’opération
createColumnsForAttribute) de la classe puis à ajouter les colonnes correspondant aux
associations (appel à l’opérationcreateColumnsForAssociation).
L’opération createcolumnsForAttribute permet la création des colonnes
correspon-dant à un attribut. Trois cas doivent être pris en compte :
– Si le type de l’attribut est simple alors une seule colonne doit être créée.
– Si le type de l’attribut est une classe persistante alors une clé étrangère doit être
créée. Les colonnes correspondantes ne seront ajoutées dans la table que lors de
la troisième étape de la transformation.
Transformation de modèles 121
1 package Class2RDBMS ;
2
3 require kermeta // The kermerta standard library
4 require " trace . kmt " // The trace framework
5 require " ../ metamodels / ClassMM . ecore " // Input metamodel in ecore
6 require " ../ metamodels / RDBMSMM . kmt " // Output metamodel in kermeta
7
8 [...]
9
10 c l a s s Class2RDBMS
11 {
12 /* * The trace of the transformation */
13 reference class2table : Trace < Class , Table >
14 /* * Set of keys of the output model */
15 reference fkeys : Collection < FKey >
16
17 operation transform ( inModel : ClassModel ) : RDBMSModel i s do
18 // Initialize the trace
19 class2table := Trace < Class , Table >. new
20 class2table . create
21 fkeys := Set < FKey >. new
22 r e s u l t := RDBMSModel . new
23 // Create tables
24 getAllClasses ( inModel ). select { c | c. is_persistent }. each { c |
25 var table : Table i n i t Table . new
26 table . name := c. name
27 class2table . storeTrace (c , table )
28 r e s u l t. table . add ( table )
29 }
30 // Create columns
31 getAllClasses ( inModel ). select { c | c. is_persistent }. each { c |
32 createColumns ( class2table . getTargetElem ( c ) , c , " ")
33 }
34 // Create foreign keys
35 fkeys . each { k | k . createFKeyColumns }
36 end
37
38 [...]
39 }
1 operation createColumns ( table : Table , cls : Class , prefix : String ) i s
2 do
3 // add all attributes
4 getAllAttributes ( cls ). each { att |
5 createColumnsForAttribute ( table , att , prefix )
6 }
7 // add all associations
8 getAllAssociation ( cls ) . each { asso |
9 createColumnsForAssociation ( table , asso , prefix )
10 }
11 end
12
13 operation createColumnsForAttribute ( table : Table ,
14 att : Attribute ,
15 prefix : String ) i s
16 do
17 // The type is primitive : create a simple column
18 i f PrimitiveDataType . isInstance ( att . type ) then
19 var c : Column i n i t Column . new
20 c. name := prefix + att . name
21 c. type := att . type . name
22 table . cols . add (c)
23 i f att . is_primary then table . pkey . add ( c ) end
24 e l s e
25 var type : Class type ?= att . type
26 // The type is persitant
27 i f isPersistentClass ( type ) then
28 // Create a FKey
29 var fk : FKey i n i t FKey . new
30 fk . prefix := prefix + att . name
31 table . fkeys . add ( fk )
32 fk . references :=
33 class2table . getTargetElem ( getPersistentClass ( type ))
34 fkeys . add ( fk )
35 e l s e
36 // Recusively add all attrs and asso of the non persistent table
37 createColumns ( table , type , prefix + att . name )
38 end
39 end
40 end
Transformation de modèles 123
correspondant aux attributs de cette classe doit être créé. Cela est fait par un
appel récursif à l’opérationcreateColumns.
De la même manière, l’opération createcolumnsForAssociation permet la création des
colonnes correspondant à une association. Nous ne détaillons pas ici son implantation
car elle est très similaire à l’opérationcreatecolumnsForAttribute à l’exception près que
le type cible d’une association ne peut pas être un type simple.
1 c l a s s FKey
2 {
3 reference references : Table
4 reference cols : Column [1..*]
5
6 /* *
7 * prefix for the name of the columns
8 * used by the createFKeyColumns method
9 */
10 attribute prefix : String
11
12 /* *
13 * Create the FKey columns in the table
14 */
15 operation createFKeyColumns () i s do
16 var src_table : Table
17 src_table ?= container
18 // add columns
19 references . pkey . each { k |
20 var c : Column i n i t Column . new
21 c. name := prefix + k. name
22 c. type := k . type
23 s e l f. cols . add ( c)
24 src_table . cols . add ( c)
25 }
26 end
27 }
Fig.4.20 – Implantation de l’opérationcreateFKeyColumnsdans la classeFKeydu méta-modèle de
base de données.
Enfin, la figure 4.20 présente l’implantation de la troisième étape de la
transforma-tion, c’est-à-dire la création des colonnes correspondant à une clé étrangère. Comme
nous l’avons évoqué précédemment, l’opération permettant la création de ces colonnes
a été directement intégrée dans la classeFKey du méta-modèle de base de donnée. En
plus de l’opération createFKeyColumns nous avons ajouté un attribut prefix dans la
classeFKeyafin de stocker le préfixe à utiliser pour les noms des colonnes correspondant
à la clé étrangère.
4.2.4 Conclusion
Cette étude sur l’utilisation de Kermeta pour l’implantation de transformations de
modèles montre que, bien que le langage Kermeta ne soit pas dédié à la transformation
il présente des qualités intéressantes pour la réalisation de transfomations.
La première de ces qualités est de permettre la conception de code réutilisable dans
plusieurs transformations. Dans l’exemple de la transformation Class2RDBMS nous
avons, par exemple, intégré des opérations dans le méta-modèle de base de données. Ce
code, indispensable à la transformationClass2RDBMS, peut être réutilisé dans d’autre
transformations ou programmes qui manipulent des modèles de base de données. Nous
avons également créé un framework de traçabilité générique qui peut être réutilisé dans
toute application ayant besoin de garder une correspondance entre deux types d’objets.
Un autre avantage de Kermeta est la grande liberté de conception offerte par le
paradigme orienté-objets. Dans le contexte du workshop MTIP, Kermeta a permis
d’implanter aussi bien les transformations très structurelles comme la transformation
Class2RDBMS que les transformations plus algorithmiques comme la déterminisation
ou la minimisation d’automates. Les approches dédiées à la transformation ciblent
géné-ralement des type de transformation particuliers. Par exemple, les approches purement
déclaratives [LS05] ont de grandes qualités pour exprimer des transformations
structu-relles mais sont peu adaptées, bien que théoriquement utilisables, pour l’implantation
de transformation plus algorithmiques.
Dans le document
Langage et méthode pour une ingénierie des modèles fiable
(Page 120-127)