• Aucun résultat trouvé

Intégration d’un support des contraintes dans Kermeta

5.2 Développements pour la définition, la qualification et

5.2.2 Intégration d’un support des contraintes dans Kermeta

Dans cette sous-section, nous détaillons notre contribution que constitue l’intégration d’un système de contraintes à Kermeta. Il s’agit d’une phase de développement qui a concerné plusieurs parties du langage et de son framework. Cela a nécessité, entre autre, l’ajout de mots clefs dans la syntaxe concrète, de concepts dans le méta-modèle du langage (la syntaxe abstraite), le codage du comportement des contraintes en Java et Kermeta. Ce développement et son test ont duré plus de deux mois et ont nécessité l’écriture d’environ 5000 lignes de code.

package simpleUML_MM; require " simpleClassConstraints.kmt" using kermeta using kermeta::standard @aspect "true" class Class{

// Operational semantic of the method allParents

operation allParents() : Class[0..*] is do result := getParents ( self.container.asType(ClassModel).classifier .select{clr | Class.isInstance(clr)}.size) end operation getParents(nbmaxRecurs:Integer):Class[0..*] is do result := OrderedSet<Class>.new if(self.parent != void) then result.add(self.parent) if(nbmax_recursion > 0)

then nbmax_recursion := nbmaxRecurs-1

result.addAll(self.parent.getParentsRecursive(nbmax_recursion))

end end

end }

Figure 5-7 - Implémentation d’une opération du méta-modèle de classe

a- Motivations

Les contraintes sont utilisées pour exprimer des propriétés sur des modèles. Dans le domaine de l’IDM, nous les employons de différentes manières:

ƒ Directement dans les travaux de cette thèse, les contraintes permettent l’élaboration d’oracles de test de transformations. Nous avons montré au précédent chapitre qu’il s’agit d’une solution envisageable, en particulier sous la forme d'assertions dédiées à un modèle de sortie donné.

ƒ Avec un support des contraintes, il est possible de développer des programmes Kermeta (de toutes formes) en suivant une méthodologie design-by-contract. Dans ce chapitre, nous montrons également que transcrire la spécification de la transformation avec des contrats permet de définir des composants autotestables,

ƒ Au-delà des travaux de cette thèse, les contraintes sont utilisées dans les activités de méta-modélisation. Elles peuvent être définies au niveau des méta-modèles pour contraindre leurs modèles. Le Meta-Object Facility (MOF) [OMG'04] est le langage standard de l’Object Management Group (OMG) pour la définition de méta-modèles. Le

121 Développements pour la définition, la qualification et l’amélioration de

composants de confiance

MOF permet de définir des méta-modèles qui sont des modèles exprimant des propriétés structurelles. Par exemple ils spécifient les relations entre concepts et leurs cardinalités. Mais des langages comme le MOF, ou les diagrammes de classes d’UML, ont un pouvoir d’expression limité. Ils ne fournissent pas de moyen de spécifier toute la sémantique statique de méta-modèles, ce qui nécessite l’emploi de contraintes.

Les contraintes que nous considérons sont de trois types: les pré-conditions, les post- conditions, et les invariants. Elles sont définies telles que dans le design-by-contract. Leur support est une fonctionnalité majeure de Kermeta, ce qui lui confère un quatrième aspect (le rond de droite de la figure 5-6) déterminant pour en faire une plate-forme complète pour le développement dirigé par les modèles. Les contraintes dans Kermeta sont utilisées dans différents projets de recherche nationaux ou internationaux, comme par exemple : Speeds, DiVA, Mopcom, Domino.

b- Mise en œuvre

La figure 5-8 représente une partie du méta-modèle de Kermeta qui permet de définir les contraintes. Elles sont représentées par la classe Constraint et peuvent être de trois types : des invariants, des pré-conditions, ou des post-conditions. Les invariants sont contenus par une définition de classe (ClassDefinition). Les pré-conditions et post-conditions sont contenues par des opérations.

Constraint stereotype : ConstraintType Object checkInvariants() checkAllInvariants() NamedElement name : String ClassDefinition Expression « enumeration » ConstraintType inv : 0 pre : 0 post : 0 Operation 1 body post * pre * inv * CallExpression name : String CallVariable isAtpre : boolean CallFeature isAtpre : boolean parameters 0..* pre 0..1

Figure 5-8 - Intégration des contraintes dans le méta-modèle de Kermeta

L’opération checkInvariant définie dans la classe Object permet d’appeler la vérification des invariants d’un objet. L’opération checkAllInvariant appelle en plus la vérification des invariants de tous les objets contenus. Elle permet de vérifier à partir de la racine d’un modèle les invariants de toutes ses classes. Ces opérations renvoient true si tous les invariants sont respectés et lèvent une exception dans le cas contraire. Ces exceptions peuvent être récupérées, elles fournissent des informations sur les invariants violés. Dans l’environnement Kermeta, les

opérations check(All)Invariant. Cela permet de modulariser ces vérifications. Une stratégie respectant la méthodologie de design-by-contract [Meyer'92a] peut être appliquée : les invariants sont appelés avant et après chaque opération ainsi qu’après la création de chaque instance d’une classe. Mais pendant une transformation de modèles, il peut être utile d’employer une autre stratégie. Par exemple, les concepteurs peuvent laisser les modèles prendre des états non-conformes pendant qu’une partie de la transformation est réalisée.

Les pré et post-conditions sont vérifiées automatiquement par l’interpréteur de Kermeta. Elles peuvent toutefois être activées et désactivées au lancement d’un programme Kermeta pour augmenter les performances.

L’ensemble des expressions Kermeta peut être librement utilisé dans les contraintes. Il appartient à l’utilisateur de s’assurer que les expressions contenues dans les contraintes n’ont pas d’effet de bord. Dans le futur, nous envisageons d’implémenter des vérifications statiques pour interdire les constructions avec des effets de bord. Cependant, dans le cas général, ce problème n’est pas décidable car les contraintes Kermeta permettent l’appel à des fonctions arbitraires.

Les contraintes Kermeta peuvent appeler n’importe quelle expression Kermeta. Elles bénéficient du pouvoir d’expressivité du langage. De cette façon, il est possible d’appeler une opération dont seule la signature est définie dans le méta-modèle. Il suffit alors d’implémenter son comportement en Kermeta. De la sorte, il est possible de construire des méta-modèles complets disposant d’une structure (définie en Ecore ou directement en Kermeta), du comportement du méta-modèle (définie en Kermeta), et des contraintes (définies en Kermeta, ou comme nous le verrons au point 5.2.2c- en OCL).

En plus des expressions Kermeta, l’opérateur spécifique @pre peut être utilisé dans les post- conditions afin de faire référence à un état avant l’exécution de l’opération. Cet opérateur correspond à celui d’OCL et à l’opérateur old du langage Eiffel. Il peut être appliqué pour exprimer les changements d’états de propriétés (CallFeature) ou de variables (CallVariable) Kermeta.

Nous avons également considéré l’héritage dans cette intégration. Tout d’abord les invariants d’une classe sont hérités et vérifiés dans une classe fille. Les pré-conditions et les post-conditions d’une opération sont également héritées par la redéfinition de l’opération. Il conviendra d’assurer que les pré-conditions de l’opération fille soient assouplies et que les post- conditions soient renforcées.

Finalement, nous avons également modifié la syntaxe concrète du langage Kermeta pour intégrer tous les mots clefs relatifs aux contraintes et définir la manière d’écrire des contraintes dans un programme. Les exemples de la figure 5-9 et de la figure 5-10 illustrent l’emploi de différentes contraintes. Nous remarquons que l’invariant de la classe Class appelle l’opération

123 Développements pour la définition, la qualification et l’amélioration de

composants de confiance package simpleUML_MM; require kermeta require " simpleUML_MM.ecore" using kermeta::standard @aspect "true" class ClassModel{ inv invariant1 is self.classifier.select{clr|Class.instances(clr)} .forAllCpl{ c1, c2 | c1.name.equals(c2.name).equals(c1.equals(c2))} } @aspect "true" class Class{ inv invariant2 is self.allParents.includes(self).~not }

Figure 5-9 – Exemple d’invariants dans le fichier simpleClassConstraints.kmt

c- Support d’OCL dans Kermeta

OCL (Object Constraint Language) [Warmer'03, OMG'03] est un standard largement adopté pour l’expression de contraintes dans l’IDM. Il est donc nécessaire de le supporter dans la plate- forme Kermeta et dans la définition des contraintes utilisées dans notre approche du test de transformations de modèles.

Figure 5-10 -Syntaxe Kermeta pour définir des pré et post-conditions

Avec le support d’OCL par Kermeta, il est possible de définir des contraintes OCL que Kermeta permet d’exploiter automatiquement. Ces contraintes OCL sont transformées en contraintes Kermeta. Cette transformation exogène a pu été réalisée car tous les concepts d’OCL sont dans le langage de contraintes de Kermeta ou peuvent être transcrits en expressions Kermeta. Cette transformation est automatique et a été écrite en Kermeta, elle est appliquée après une phase de parsing du code OCL (figure 5-11).

Le concepteur fournit uniquement son méta-modèle en un fichier « .ecore » et ses contraintes OCL dans un fichier « .ocl ». Puis les contraintes OCL sont transformées en contraintes Kermeta. Finalement elles sont automatiquement tissées avec les méta-modèles qui les emploient.

contraintes OCL dans un fichier texte (.ocl) contraintes Kermeta (.km) Parser OCL Méta-modèle de Kermeta

modèle des contraintes OCL dans un fichier xmi (.xmi)

Méta-modèle de OCL 2.0

transformation OCL->KM

Figure 5-11 - Processus de transformation des contraintes OCL en Kermeta

Par exemple les invariants OCL de la figure 5-12 deviennent les invariants Kermeta de la figure 5-9. Nous remarquons l’instruction « require simpleUML_MM.ecore » qui réalise le tissage des contraintes avec le méta-modèle.

La mise en œuvre d’OCL bénéficie directement de l’intégration de notre système de contraintes à Kermeta. Les qualités des contraintes Kermeta bénéficient directement au support d’OCL. Par exemple, il est possible d’étendre la logique du premier ordre d’OCL en appelant n’importe quelle opération déclarée dans le méta-modèle. En implémentant cette opération en Kermeta, cela permet l’évaluation de la contrainte et lui offre une plus grande expressivité. Il devient alors possible d’appeler des fonctions mathématiques, de définir facilement des récursivités et la clôture transitive.

Figure 5-12 - Contraintes sur le méta-modèle de classe dans le fichier simpleClass.ocl

Le support d’OCL permet à Kermeta d’être moins invasif dans les contraintes qui ne sont plus nécessairement écrites elles-mêmes en Kermeta. Le concepteur peut publier son méta- modèle et les contraintes associées dans des formats standards : Ecore et OCL sans dépendance avec Kermeta. Dans ce cas, seul le comportement d’opérations nécessaires aux contraintes ou à la simulation est réalisé en Kermeta. Le concepteur des méta-modèles qui utilise déjà Kermeta bénéficie de la compatibilité des standards existants et de la possibilité d’intégrer des contraintes OCL dans ses méta-modèles Ecore ou ses transformations.