Méta-modélisation Olivier Barais kezaqo (Univ. Rennes 1 & INRIA) Triskell Team @ IRISA Campus de Beaulieu F-35042 Rennes Cedex Tel : +33 299 842 541 Fax : +33 299 847 171 e-mail : barais@irisa.fr D’après le cours de Jean-Marc Jézéquel et le cours de Sebastien Mosser
Objects have failed ! [R. Gabriel, OOPSLA'02] The object-oriented approach does not adequately address the computing requirements of the future. Object-oriented languages have lost the simplicity -some would say purity that made them special and which were the source of their expressive and development power. Objects promised reuse, and we have not seen much success.
Plan de la présentation Modèles / Méta-Modèles Définition EMF Conclusion Sémantique statique OCL Sémantique opérationnelle Kermeta
Vision Objet versus Vision MDE Write once, run everywhere
Vision Objet versus Vision MDE Write once, generate everywhere
Mon premier métamodèle . . . (niveau CE1) Une phrase contient un sujet, un verbe et un complément
Mon premier métamodèle . . . (niveau CE1) Lien Concept Une phrase contient un sujet, un verbe et un complément Cardinalité
Mon premier métametamodèle . . . (niveau CM1) Concept Sujet Verbe Une phrase contient un sujet, un verbe et un complément Phrase
L'IDM : une (méta) façon de penser Méta : du grec μετα Au delà de . . . (Métaphysique, Métalinguistique, . . . ) Métadonnées Systèmes de fichiers, ID3/MP3, Web Sémantique . . . Métalangage Grammaires eBNF, UML, XML, . . . Modèles, Métamodèles & Transformations Un modèle est une représentation du domaine d'application Un modèle est conforme à un métamodèle On passe d'un modèle à un autre par transformation Un métamodèle est un modèle (métamétamodèles)
Meta-Models as Shared Knowledge Definition of an Abstract Syntax in E-MOF Repository of models with EMF Reflexive Editor in Eclipse JMI for accessing models from Java XML serialization for model exchanges Applied in more and more projects
Exemple avec une Machine à états Model Meta-Model
Eclipse Modeling Framework
Acronymes & Vocabulaire MOF : Meta Object Facility (OMG) BNF ) Grammaires, MOF ) Métamodèles Il existe différentes variantes du MOF : eMOF, cMOF, sMOF Standard ISO/IEC19502:2005 EMF : Eclipse Modeling Framework (IBM) Totalement intégré dans Eclipse Plus ou moins aligné sur EMOF XMI, format standard interopérable Échange de modèles : Encodage XMI Sérialisation XML conforme au métamodèle.
EMF & UML [F. Chauvel] eMOF (alignement vis à vis d'EMF) Construit sur un noyau refléxif Un ensemble de concepts pour décrire des métamodèles C'est un métamodèle de métamodèle (métamétamodèle) ! Il en existe différentes implémentations (ECore, RubyMOF, . . . ) Et le diagramme de classe UML dans tout ça ? On en réutilise la syntaxe graphique Restriction sémantique (small is beautiful) Moins expressif (visibilité absente, . . . ) Trop limité ?
Implantation d'ECore . . . en ECore ! Expression du métamodèle ECore dans un métamodèle Rappel : ECore est un métamodèle de métamodèle . . . On l'implante au même titre qu'un autre métamodèle $ECLIPSE/plugins/org.eclipse.emf.ecore_XXX.jar Dans le sous-répertoire models : Ecore.ecore L'approche est dfinitivement méta : On considère la modélisation comme un domaine métier Définition des métaoutils pour travailler sur ce domaine Validation naturelle des concepts Conséquence : Si EMF l'a fait, on peut aussi le faire ! Tout dans EMF utilise une approche dirigée par les modèles !
Outillage fourni par EMF
Intégration d'ECore dans EMF : Manipulation & Génération Outils de manipulation : On dispose . . . D'un éditeur arborescent proche de l'éditeur XML D'un éditeur graphique proche d'un modeleur UML D'une récupération de code Java par annotation javadoc La spécficité Eclipse : .genmodel Les outils de génération ne travaillent pas sur le .ecore Eclipse définit un fichier .genmodel en parallèle : New/ Other/ Eclipse Modeling Framework/ EMF Model L'IDE se charge du maintien de la cohérence
Générateurs de code Action disponibles sur le métamodèle : Generate Model Code : Classes Java reposant sur EMF Generate Edit Code : Plugin supportant l'édition Generate Editor Code : Plugin d'édition arborescente Generate Test Code : Plugin de test unitaire
Générateur d'éditeur graphique dirigé par les modèles Définir un éditeur graphique revient à définir : Un modèle de ce que l'on veut représenter Un modèle de représentation à l'écran Un modèle d'action accessibles à l'utilisateur Un modèle de liaison, et un modèle de création ! GMF : Graphical Modeling Framework Métier : Graph.ecore, Graph.gmfgraph, Graph.gmftool Technique : Graph.gmfmap & Graph.gmfgen => Génération d'un plugin Eclipse
Workflow GMF de A à Z
Conclusion sur les méta-modèles
Conclusions sur les méta-modèles L'approche métamodèle . . . est finalement naturelle permet de se focaliser sur son métier EMF est un canevas logiciel Basé sur eMOF (standard ISO), Open Source, intégré à Eclipse De nombreux outils l'utilisent, pas si complexe qu'il en à l'air ! Fournit de nombreuses fonctionnalités out of the box. . . . mais . . . Un manque de maturité reste visible L'approche tout modèle laisse parfois perplexe
Questions ouverte : Multiplicité technologique ?
Questions ouverte : Interopérabilité des outils ?
Questions ouverte : Pragmatisme de la démarche ?
Questions ouverte : Coût d'un développement IDM?
Example with StateMachines Model Meta-Model
Zoom: UML2 comments
UML2 Generalizations
What is missing? Express e.g. that no two states may have the same name Static Semantics with OCL Transformations/code generation Model transformation à la MDA Get a simulator Dynamic (operational) Semantics Integrating all of this: Kermeta
Un langage pour modéliser précisément OCL Un langage pour modéliser précisément
Static Semantics with OCL Complementing a meta-model with Well-Formedness Rules, aka Contracts e.g.; ModelElement has a unique name in a Namespace no cycle in a UML2 inheritance graph… Expressed with the OCL (Object Constraint Language) The OCL is a language of typed expressions. A constraint is a valid OCL expression of type Boolean. A constraint is a restriction on one or more values of (part of) an object-oriented model or system.
OCL Can be used at both Let’s overview it with M1 level exemples M1 level (constraints on Models) aka Design-by-Contract (Meyer) M2 level (constraints on Meta-Models) aka Static semantics Let’s overview it with M1 level exemples
Motivations Diagrammes exprimant certaines contraintes graphiquement contraintes structurelles (e.g. un attribut dans une classe) contraintes de types (e.g. sous-typage) contraintes diverses (e.g. composition, cardinalité, etc.) via des propriétés prédéfinies sur des classes (e.g. {abstract}) sur des rôles (e.g. {ordered}) Les diagrammes UML manquent parfois de précision. Le langage naturel est souvent ambigu.
Illusions partagées … ou non Compte 1..4 0..* Attention aux contraintes supposées être évidentes ou vérifiée "naturellement" Client numéro solde dMax titulaires 1 signataire 1 0..* CarteBleue * c1 : Compte c2 : Compte paul : Client pierre : Client marie : Client c3 : Compte titulaires : CarteBleue signataire jean : Client Le signataire d'une carte bleue est titulaire de ce compte.
Expression des contraintes en langue naturelle Simple à mettre en oeuvre utilisation des notes en UML + texte libre compréhensible par tous Indispensable ! documenter les contraintes est essentiel détecter les problèmes le plus tôt possible Problèmes ambigu, imprécis difficile d ’exprimer clairement des contraintes complexes difficile de lier le texte aux éléments du modèle
Conception par contrats avec UML Ajout de contraintes à des éléments de modélisation. {context Personne inv : self.epouse ->notEmpty() implies self .epouse.mari = self and self.mari -> notEmpty() implies self .mari.epouse = self}
Exemple Client 1..4 0..* Consortium Compte numéro solde dMax * 1 1..* titulaires Consortium Compte numéro solde dMax * 1 1..* signataire CarteBleue code retraitMax Distributeur Banque
Exemple Client 1..4 0..* titulaires Consortium Compte numéro solde dMax * 1 1..* signataire CarteBleue code retraitMax Distributeur Banque (1) Le solde d'un compte ne doit pas être inférieur au découvert maximum autorisé (2) Le signataire d'une carte bleue associée à un compte est le titulaire de ce compte. (3) Une carte bleue est acceptée dans tous les distributeurs des consortiums de la banque. (4) Les clients d'une banque non affiliée à un consortium ne peuvent pas avoir de carte bleues.
Exemple context c : Compte inv: solde > dMax context Compte 1..4 0..* 1..* 1 Banque 1..* Client numéro solde dMax numéro solde dMax titulaires numéro 1 signataire 0..* 1 Consortium CarteBleue 0..* * 1 code retraitMax 0..* Distributeur * 1..* -- (1) Le solde d'un compte ne doit pas être inférieur au découvert maximum autorisé context c : Compte inv: solde > dMax context Compte inv: dMax >= 0 inv: solde > dMax
Exemple .titulaires .signataire = self.Compte context CarteBleue inv: 1..4 0..* 1..* 1 Banque 1..* Client numéro solde dMax titulaires .titulaires titulaires numéro signataire .signataire 1 signataire 0..* Compte = self.Compte 1 Consortium context CarteBleue inv: CarteBleue 0..* * 1 code retraitMax 0..* Distributeur * 1..* -- (2) Le signataire d'une carte bleue associée à un compte est le titulaire de ce compte. self
Exemple context CarteBleue Compte 1..4 0..* 1..* 1 Banque 1..* Client numéro solde dMax titulaires titulaires numéro 1 signataire 0..* signataire 1 Compte Consortium CarteBleue 0..* * 1 code retraitMax 0..* Distributeur * 1..* -- (2) Le signataire d'une carte bleue associée à un compte est l'un des titulaires de ce compte. context CarteBleue inv: self.Compte.titulaires->includes(self.signataire)
Exemple .Banque .Consortium self.Compte context CarteBleue inv: self Client 1..4 0..* titulaires Consortium Compte numéro solde dMax * 1 1..* signataire CarteBleue code retraitMax Distributeur Banque .Banque .Consortium self.Compte context CarteBleue inv: self .Distributeur .Distributeur -- (3) Une carte bleue est acceptée dans tous les distributeurs des consortiums de la banque. = ->asSet
/ distributeursPossibles Exemple Client 1..4 0..* titulaires Consortium Compte numéro solde dMax * 1 1..* signataire CarteBleue code retraitMax Distributeur Banque / distributeursPossibles context CarteBleue::distributeursPossibles : set(Distributeur) derive: self.Compte.Banque.Consortium.Distributeur->asSet
OCL : Object Contraint Language OCL = Object Constraint Language Relativement simple à écrire et à comprendre context Vol inv: nbPlacesPotentiellementLibres = avion.nbPlaces - reservations->select(estConfirmée).nbPassager->sum() Syntaxe purement textuelle sans symboles "étranges" inv: estDéfini implies reservations->forAll( estConfirmée implies estPayée)
L'une des bases d'UML et du MDA Sémantique d'UML écrite en OCL OCL est en pleine expansion Nouvelle version avec UML2.0 Essentiel pour avoir des modèles suffisemment précis Largement utilisé pour la description des méta-models Fondamental pour le MDA De plus en plus d'outils édition, vérification génération (partielle) de code …
Caractéristiques d’OCL Langage d'expressions (fonctionnel) Valeurs, expressions, types Fortement typé Pas d'effets de bords Langage de spécification, pas de programmation Haut niveau d'abstraction Pas forcément exécutable Permet de trouver des erreurs beaucoup plus tôt dans le cycle de vie
Caractéristiques d’OCL Points faibles Pas aussi rigoureux que VDM, Z ou B => pas de preuves possibles Puissance d'expression limitée Points forts Relativement simple à écrire et à comprendre Très bien intégré à UML Bon compromis entre simplicité et puissance d'expression Passage vers différentes plateformes technologiques
Contexte d'une contrainte Contrainte toujours associée à un élément de modèle : le contexte de la contrainte. Deux techniques pour spécifier le contexte : context Compte inv: dmax >=0 inv: solde > -dMax context CarteBleue inv: Compte.titulaires->includes(self.signataire) inv: code>0 and code<=9999 inv: retraitMax>10 context Compte::solde : integer init: floor(depotInitial * 10 / 100) Client 1..4 0..* titulaires Compte numéro solde dMax * 1 signataire CarteBleue code retraitMax { init: 0 } { inv: dMax >= 0 inv: solde > -dMax } { inv: Compte.titulaires->includes(self.signataire)}
Où utiliser OCL OCL peut être utilisé pour décrire des prédicats inv: invariants de classes inv: solde < decouvertMax pre: pré-conditions d ’opérations pre: montantARetirer > 0 post: post-conditions d ’opérations post: solde > solde@pre OCL peut également être utilisé pour décrire des expressions def: déclarer des attributs ou des opérations def: nbEnfants:Integer init: spécifier la valeur initiale des attributs init: enfants->size() body: exprimer le corps de méthodes {query} body: enfants->select(age< a ) derive: définir des élements dérivés (/) derive: age<18
OCL Utilisation avancée
Types Types de bases Types énumérés Types construits Integer Real Boolean String Types énumérés Types construits TupleType( x : T, y : T … ) Set(T) OrderedSet(T) Sequence(T) Bag(T) Collection(T) Types provenant d ’UML classes associations … Méta-types OclType OclAny OclState OclExpression
Syntaxe des expressions OCL est un langage simple d ’expressions constantes identificateur self expr op expr exprobjet . propobjet exprobjet . propobjet ( parametres ) exprcollection -> propcollection ( parametres ) package::package::element if cond then expr else expr endif let var : type = expr in expr
Exemples self.salaire- 100 self.enfants->isEmpty() parents 0..2 Personne self.salaire- 100 self.enfants->isEmpty() self.enfants->forall(age>20) self.impôts(1998) / self.enfants->size() self.enfants->select( sexe = Sexe::masculin ) self.enfants->collect(salaire)->sum() self.enfants.salaire->sum() self.enfants->union(self.parents)->collect(age) sexe salaire age * enfants impots
A retenir . permet d ’accéder à une propriété d ’un objet -> permet d ’accéder à une propriété d ’une collection :: permet d ’accéder à un élément d ’un paquetage, d'une classe, … Règles pour mixer collections et objets self.impôts(1998) / self.enfants->size() objet objet collection
Integer et Real Integer Real valeurs : 1, -5, 34, 24343, ... opérations : +, -, *, div, mod, abs, max, min Real valeurs : 1.5, 1.34, ... opérations : +, -, *, /, floor, round, max, min Le type Integer est « conforme » au type Real
Boolean Boolean L ’évaluation des opérateurs or, and, if est partielle valeur : true, false opérations : not, and, or, xor, implies, if-then-else-endif L ’évaluation des opérateurs or, and, if est partielle true or x est toujours vrai, même si x est indéfini false and x est toujours faux, même si x est indéfini (age<40 implies salaire>1000) and (age>=40 implies salaire>2000) if age<40 then salaire > 1000 else salaire > 2000 endif salaire > (if age<40 then 1000 else 2000 endif)
String valeur : ‘ ’, ‘ une phrase ’ opérations : = s.size(), s1.concat(s2), s1.substring(i1,i2) s.toUpper(), s.toLower(), nom= nom.substring(1,1).toUpper().concat( nom.substring(2,nom.size()).toLower()) Les chaînes ne sont pas des séquences de caractères :-( String <> Sequence(character) car le type character n'existe pas
<<enumeration>> Jour Enumération Utilisation d ’une valeur d ’un type énuméré Jour::Mardi (notation avant UML2.0: #Mardi ) Opérations =, <> Pas de relation d'ordre <<enumeration>> Jour Lundi Mardi Mercredi Jeudi Vendredi Samedi Dimanche
<<enumeration>> Sexe Exemples épouse <<enumeration>> Sexe 0..1 Personne Masculin Feminin sexe : Sexe 0..1 époux épouse->notEmpty() implies épouse.sexe = Sexe::Feminin épouse.sexe < sexe Pas de relation d'ordre Pas toujours défini
Element vs. singleton Dans tout langage typé il faut distinguer un élément e du singleton contenant cet élément Set{e} Conversion implicite élement => singleton lorsqu ’une opération sur une collection est appliquée à un élement isolé elem -> prop Set{elem}->prop self->size() = 1 not 0->isEmpty()
Collections Type général Collection( T ) Set(T ) Bag(T ) {unique} {nonunique} Set(T ) Bag(T ) {unordered} OrderedSet(T ) {ordered} Sequence(T ) Type général Collection( T )
Utilisation lors de la navigation objet . nomderole à pour type : X 1 ou 0..1 X X * Set(X) X {ordered} * OrderedSet(X) X * {nonunique} Bag(X) X {ordered, nonunique} * Sequence(X)
Expressions de type collection Exemples Set { 'lundi', 'mercredi', 'mardi' } Bag { 'lundi', 'lundi', 'mardi', 'lundi' } OrderedSet { 10, 20, 5 } Sequence { 'lundi', 'lundi', 'mardi', 'lundi' } Notation .. pour spécifier des intervalles Sequence { 1..5, 2..4 } Utile pour réaliser des itérations Sequence { 0 .. nbétages-1 } -> forall( i | possèdeArrêt(i) )
Opérations traditionnelles sur les collections Cardinalité : coll -> size() : Integer Vide : coll -> isEmpty() : Boolean Non vide : coll -> nonEmpty() : Boolean Nombre d ’occurrences : coll -> count(elem) : Integer Appartenance : coll -> includes( elem ) : Boolean Non appartenance : coll -> excludes( elem ) : Boolean Inclusion : coll -> includesAll(coll) : Boolean Exclusion : coll -> excludesAll(coll) : Boolean Somme des élements coll -> sum() : G
Exemples Set { 3, 5, 2, 45, 5 }->size() Sequence { 1, 2, 45, 9, 3, 9 } ->count(9) Sequence { 1, 2, 45, 2, 3, 9 } ->includes(45) Bag { 1, 9, 9, 1 } -> count(9) c->asSet()->size() = c->size() c->count(x) = 0 Bag { 1, 9, 0, 1, 2, 9, 1 } -> includesAll( Bag{ 9,1,9} )
Opérations sur les ensembles Union ens -> union( ens ) : Collection Intersection ens -> intersection( ens ) : Collection Difference ens1 - ens2 : Collection Ajout d ’un élément ens -> including(elem):Collection Suppression d ’un élément ens -> excluding(elem):Collection Conversion vers une liste ens -> asSequence() :Sequence Conversion vers un sac ens -> asBag():Bag Conv.vers un ens. Ord. ens -> asOrderedSet():OrderedSet
Filtrage : select, reject et any coll -> select( cond ) retient les éléments vérifiant la condition (extension d ’un prédicat sur un ensemble) coll -> reject( cond ) reject élimine ces élements coll -> any( cond ) any sélectionne l'un des éléments vérifiant la condition opération non déterministe utile lors de collection ne contenant qu'un élément retourne la valeur indéfinie si l'ensemble est vide
Exemples self.enfants ->select( age>10 and sexe = Sexe::Masculin) self.enfants ->reject(e : Personne | e.enfants->isEmpty())->notEmpty() membres->any(titre='président') membres Association1901 Personne 0..2 parents * sexe : Sexe age : integer titre : string * enfants
Filtrage : autres syntaxes Possibilité de nommer la variable et d'expliciter son type self.employés->select(age > 50) self.employés->select( p | p.age>50 ) self.employés->select( p : Personne | p.age>50) self.employés->reject( p : Personne | p.age<=50) employés Société Personne * age : integer
Quantificateurs : forAll, exists, one coll -> forAll( cond ) : Boolean coll -> exists( cond ) : Boolean coll -> one( cond ) : G self.enfants->forall(age<10) self.enfants->exists(sexe=Sexe::Masculin) self.enfants->one(age>=18) Personne 0..2 parents sexe : Sexe age : integer titre : string * enfants
Attention à l'inversion p enfants . p.age < 10 enfants->forall( p : Personne | p.age<10)
Quantificateurs : autres syntaxes Il est possible de nommer la variable d ’expliciter son type de parcourir plusieurs variables à la fois self.enfants->forall( age < self.age ) self.enfants->forall( e | e.age < self.age - 7) self.enfants->forall( e : Personne | e.age < self.age - 7) self.enfants->exists( e1,e2 | e1.age = e2.age ) self.enfants->exists( e1,e2 | e1.age = e2.age and e1<>e2 ) self.enfants->forall( e1,e2 : Personne | e1 <> e2 implies e1.prénom <> e2.prénom) Personne age prénom * enfants
Unicité coll -> isUnique ( expr ) : Boolean Retourne vrai si pour chaque valeur de la collection, l ’expression retourne une valeur différente self.enfants -> isUnique ( prénom ) à la place de self.enfants->forall( e1,e2 : Personne | e1 <> e2 implies e1.prénom <> e2.prénom) Pratique pour définir la notion de clé importée et de clé Personne age prénom * enfants
Image d’une expression : collect coll -> collect( expr ) : Bag<G> Correspond à l ’image d ’une fonction (map, apply, ...) L ’expression est évaluée pour chaque élément Le résultat est un sac, si l'opération est appliqué à un ensemble ou un sac une séquence, si l'opération est appliqué à une séquence ou un ens. Ord. self.enfants->collect(age) = Bag{10,5,10,7} self.employés->collect(salaire/10)->sum() employés Personne Société Employé enfants age * * salaire
Collect : syntaxe simplifiée Collect est une opération de navigation courante Equivallence pour simplifier self.enfants->collect(age) <=> self.enfants.age Opérateur . utilisé avec une collection <=> collect Personne age enfants *
Attention aux doublons Rappel : le résultat est un sac ou une séquence à cause des doublons Si l ’on souhaite obtenir un ensemble : self.enfants.age->asSet() Permet de naviguer self.enfants.enfants.voitures voitures Personne Voitures * * age enfants *
Collections ordonnées vs. triées Sequence OrderedSet … mais pas forcément triées Sequence { 12, 23, 5, 5, 12 } Sequence { 5, 5, 12, 12, 23 } OrderedSet { 10, 4, 20 } OrderedSet { 4, 10, 20 } Sequence{1..s->size()-1} -> forall(i | s.at(i) < s.at(i+1) )
Collections ordonnées 4 types de collections Ensembles : Set(T) pas de répétition, pas d ’ordre Set { 1, 5, 10, 3 } = Set {1,5,5,1,10,3} Set { 1, 5, 10, 3 } = Set {1,10,5,3} Sacs : Bag(T) répétitions possibles, pas d ’ordre Bag { 1, 5, 10, 3 } <> Bag {1,5,5,1,10,3} Bag { 1, 5, 5, 10, 3, 1} = Bag {5,1,10,3,1,5} Ensembles ordonnés : OrderedSet(T) pas de répétition, ordre entre les élements OrderedSet { 1, 5, 10, 3 } <> OrderedSet{1,10,5,3} Listes : Sequence(T) répétitions possibles, ordre entre les éléments Sequence { 1, 5, 5, 10, 3, 1 } <> Sequence {5,1,10,3,1,5}
Tri d'une collection coll -> sortedBy( expr ) : Collection L'opération < doit être définie sur le type correspond à expr Tri toujours par ordre croissant Permet de trier une collection en fonction d'une expression enfants->sortedBy( age ) Le résultat est de type OrderedSet si l'opération est appliquée sur un Set Sequence si l'opération est appliquée sur un Bag
Exemples enfants->sortedBy( age ) enfants->sortedBy( -age ) enfants->sortedBy( enfants->size() )->last() enfants->sortedBy( e: Personne | e.enfants->size() )->last() let ages = enfants.age->sortedBy(a | a) in ages.last() - ages.first()
Iterateur général : Iterate L'itérateur le plus général Autres itérateurs (forall, exist, select, etc.) : cas particulier coll -> iterate( élém : Type ; accumulateur : Type2 = <valeur initiale> | <expr> ) Exemple enfants -> iterate( e : Enfant ; acc : Integer = 0 | acc+e.age ) Equivalent en pseudo code à acc : Integer = 0 ; foreach e:Enfant in enfants acc := acc+e.age return acc
Exemples enfants.salaire -> iterate( s :Integer ; somme : Integer = 0 | somme+s) enfants -> iterate( e : Enfant ; tousmineur : Boolean = true | tousmineur and e.age<18 ) enfants -> iterate( e : Enfant ; mineurs : Set(Personne) = Set{} | if e.age<18 then mineurs->including(e) else mineurs endif )
Ré-écriture des iterateurs dérivés c->exists( iterators | body ) = c->iterate( iterators ; result : Boolean = false | result or body ) c->forall( iterators | body ) = c->iterate( iterators ; result : Boolean = true | result and body ) c->isUnique( iterators | body ) = c->collect( iterators | body )->forAll( x,y | x<>y ) c->any( iterator | body ) = c->select( iterator | body )->asSequence()->first() c->one( iterator | body ) = c->select(iterator | body )->size() = 1 c->collect( iterators | body ) = c->collectedNested(iterators | body )->flatten()
Tuples A partir de UML 2.0 Champs nommés, pas d'ordre entre les champs Définition de types tuples TupleType( x : real, y : real ) TupleType( y : real, x : real ) TupleType( nom : string, prénom : string, age : integer ) Tuples (valeurs) Tuple{ x=-1.5 , y=12.6 } Tuple{ y=12.6 , x=-1.5 } Tuple{ y:real=12.6, x:real=-1.5 } Tuple{ nom = 'dupont', prénom='léon', age=43 }
Opérations sur les tuples Sélection d'un champ Tuple{ x=-1.5 , y=12.6 }.x adresse.ville enfants.adresse.ville
Collections imbriquées Jusqu'à UML 2.0 pas de collections de collections! argument : peu utilisé et plus complexe à comprendre mise à plat intuitive lors de la navigation self.parents.parents mise à plat par default lié à l'opération implicite collect A partir de UML 2.0 imbrications arbitraires des constructeurs de types Set( Set(Personne) ) Sequence( OrderedSet(Jour) ) Très utile pour spécifier des structures non triviales Rapports Documents XML, etc.
CollectNested L'opération collect met à plat les collections (utile pour naviger) CollectNested permet de conserver l'imbrication enfants.enfants.prénom = enfants->collect(enfants)->collect(prénom) = Bag{ 'pierre', 'paul', 'marie', 'paul' } enfants->collectNested(enfants.prénom) = Bag { Bag{'pierre','paul'}, Bag{'marie','paul'} }
Synthèse OCL = langage de contraintes + de requêtes Parfaitement intégré à UML Langage de spécification avec un sous-ensemble exécutable Complément essentiel des diagrammes de classes … mais aussi en UML 2.0 … Diagrammes de séquences, de collaborations Diagrammes de composants, de deploiement, Diagrammes d'états, diagrammes d'activités ... mais aussi dans des outils MDA
OCL for M2: Examples of WFR ModelElement has a unique name in a Namespace Context ModelElement inv : namespace.ownedElement->collect(name)->count(self.name)=1 …
Sémantique opérationnelle avec Kermeta
Example A model Its metamodel a/b x/y b/a y/x A model Its metamodel Adding Operational Semantics to OO Metamodels
From Metamodels to Languages How do these things relate? MOF EMOF ECore Infra Etc. Generic Syntax (HUTN) Abstract Syntax Semantic Specification Concrete Syntax Concrete Syntax Concrete Syntax Semantics The language I want to build
Metadata languages (E)MOF => Only data structures classes, properties, associations, ... operations : only signatures Not sufficient to operate on models Constraints Actions Transformations ...
Typical example (excerpted from MOF spec) Operation isInstance(element : Element) : Boolean “Returns true if the element is an instance of this type or a subclass of this type. Returns false if the element is null”. A natural language specification operation isInstance (element : Element) : Boolean is do // false if the element is null if element == void then result := false else // true if the element is an instance of this type // or a subclass of this type result := element.getMetaClass == self or element.getMetaClass.allSuperClasses.contains(self) end An operational specification
What is “meta”-executability? Basic CRUD Operations Merge, Composition… M M-1 Definition Execution Simply an (object-oriented) program that manipulates model elements “Program = Data Structure + Algorithm”, Niklaus Wirth Meta-Data Meta-Actions Meta- Executability = +
Kermeta Rationale Model, meta-model, meta-metamodel, DSLs… Meta-bla-bla too complex for the normal engineer On the other hand, engineers are familiars with OO programming languages (Java,C#,C++,..) UML (at least class diagram) May have heard of Design-by-Contract Kermeta leverages this familiarity to make Meta-modeling easy for the masses
Breathing life into Meta-Models // MyKermetaProgram.kmt // An E-MOF metamodel is an OO program that does nothing require "StateMachine.ecore" // to import it in Kermeta // Kermeta lets you weave in aspects // Contracts (OCL WFR) require “StaticSemantics.ocl” // Method bodies (Dynamic semantics) require “DynamicSemantics.kmt” // Transformations Context FSM inv: ownedState->forAll(s1,s2| s1.name=s2.name implies s1=s2) aspect class FSM { operation reset() : Void { currentState := initialState }} class Minimizer { operation minimize (source: FSM):FSM {…} }
Kermeta: a Kernel metamodeling language Strict EMOF extension Statically Typed Generics, Function types (for OCL-like iterators) Object-Oriented Multiple inheritance / dynamic binding / reflection Model-Oriented Associations / Compositions Model are first class citizens, notion of model type Aspect-Oriented Simple syntax for static introduction Arbitrary complex aspect weaving as a framework Still “kernel” language Seamless import of Java classes in Kermeta for GUI/IO etc.
Kermeta, a Kernel to Meta Actions Constraints Transformations Metadata
Types & opérateurs usuels Types scalaires très restreints Integer, String, Boolean Opérateurs : Affectation : := (naïve), ?= (cast) Arithmétique : +,-,/,* Comparaison : ==, !=, <, <=,>,>= Logique : and, or, not Collections : fondées sur la définition d'OCL
Définition de classes, opérations, méthodes Déclaration de classes à la Java (class C { }) Classes abstraites (abstract), généricité (class A<T>) Héritage (inherits), multiple ou non Constructions : pas de constructeur ! (MyClass.new) Variables de classes : Attributs & Référence attribute a: String ⇒ a est contenue par composition () reference r: String ⇒ r est référencée self représente l'instance courante Absence de visibilité : tout est public Méthode d'instance : Opérations & Méthodes operation name(arg1: T): OutputType is do ... end Redéfinition par héritage : operation → method Variable locale : var tmp: String init String.new Retour : pas de return ! On utilise la variable result Pas de surcharge dans le langage (simplification)
EMOF Kermeta class State{ reference owningFSM : FSM[1..1]#ownedState attribute name : String attribute outgoingTransition : Transition[0..*]#source reference incomingTransition : Transition#target operation step(c : String) : kermeta::standard::~Void is do end } class Transition{ reference source : State[1..1]#outgoingTransition reference target : State[1..1]#incomingTransition attribute input : String attribute output : String operation fire() : String is do class FSM { attribute ownedState : State[0..*]#owningFSM reference initialState : State[1..1] reference currentState : State operation run() : kermeta::standard::~Void is do end operation reset() : kermeta::standard::~Void is do }
Assignment semantics Composition Association Before Before After After
Fermetures & λ-fonctions pour l'itération Effectuer une action ∀e ∈ C each f.each{ n | stdio.write( n.toString + " ") } Vérifier une condition ∀e ∈ C forAll var b: Boolean init f.forAll{ n | n < 250 } Sélection d'un sous-ensemble (filter) select var f2: Sequence<Integer> init f.select{n | n < 100} Exclusion d'un sous-ensemble reject var f3: Sequence<Integer> init f.reject{n | n < 100} Mapping de fonction collect var f4: Sequence<Integer> init fib.collect{n | n + 1} Détection d'un élément detect var x: Integer init fib.detect{n | n > 47} Existence d'un élément exists var b2: Boolean init fib.exists{n | n > 47 }
Example operation fire() : String source.owningFSM.currentState := target result := output
operation step(c : String) : String // Get the valid transitions var validTransitions : Collection<Transition> validTransitions := outgoingTransition.select { t | t.input.equals(c) } // Check if there is one and only one valid transition if validTransitions.empty then raise NoTransition.new end if validTransitions.size > 1 then raise NonDeterminism.new end // fire the transition result := validTransitions.one.fire operation step(c : String) : String
operation run() : Void from var str : String until str == "exit" loop stdio.writeln("current state is " + currentState.name) str := stdio.read("Enter an input string or 'exit' to exit simulation : ") stdio.writeln(str) if str != "exit" then do stdio.writeln("Output string : " + currentState.step(str)) rescue (ex : FSMException) stdio.writeln("ERROR : " + ex.toString) end stdio.writeln("* END OF SIMULATION *") operation run() : Void
/** * Load a sample FSM from a xmi2 file */ operation loadFSM() : FSM is do var repository : EMFRepository init EMFRepository.new var resource : EMFResource resource ?= repository.createResource("../models/fsm_sample1.xmi", "../metamodels/fsm.ecore") resource.load // Load the fsm (we get the main instance) result ?= resource.instances.one end
Kermeta workbench snapshot
Using aspect-composition to reflectively build Kermeta
The action metamodel CRUD operation Control structures Operation call Close to the OCL CRUD operation Control structures Operation call Variables and assignment Exceptions handling Functions (OCL-like iterators) Kermeta design
KerMeta Metamodel
Current Status Latest version (1.2.0) Under development / test Parser, type checker, interpreter, debugger Eclipse plug-in: Textual Editor, Browser, Launcher EMF Ecore metamodel Import / Export EMF model Import / Export Constraints (Kermeta or OCL) Graphical Editor (generated with Topcased) Documentation and Examples Under development / test Seamless import of Java classes in Kermeta Compiler
Home page Development page http://www.kermeta.org Smoothly interoperates with Eclipse/EMF Open Source Download it now! Home page http://www.kermeta.org Development page http://kermeta.gforge.inria.fr/ A statically typed object-oriented executable meta-language