Exprimer et valider des contraintes OCL depuis un modèle EMF

Serge Bachmann

Cet article s'intéresse à l'expressivité et à la validité de contraintes depuis un modèle EMF. Le langage « Object Constraint Language » (OCL) est utilisé pour exprimer de telles contraintes.

Nous allons donc voir comment le langage OCL peut être manipulé par les outils Eclipse. En partant de l'exemple d'un modèle de graphe, nous exprimons une contrainte sur le nombre d'arcs partant d'un nœud.

Pour réagir à cet article, un espace de dialogue vous est proposé sur le forum Commentez .

- Titre : Exprimer et valider des contraintes OCL depuis un modèle EMF

- Auteur : Serge Bachmann

- Parution : 22 août 2012

- Public visé :

- Licence : Le contenu de cet article est rédigé par Serge Bachmann et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Sommaire

- I. Introduction

- I-A. Spécification

- I-B. Lancement de la plate-forme Eclipse

- I-C. Passer en perspective « Ecore »

- II. Installer OCL Tools

- III. Création d'un projet EMF

- IV. Édition du modèle « Ecore »

- V. Aide à la création d'une contrainte

- V-A. Visualisation de la console OCL

- V-B. Création d'une instance dynamique du modèle

- V-B-1. Saisie d'un modèle

- V-C. Expression d'une contrainte

- V-C-1. Mise en place de la contrainte

- V-D. Test du modèle

- VI. Génération éditeur arborescent

- VI-A. Création « EMF Generation Model »

- VI-B. Génération de l'éditeur

- VI-C. Test de l'éditeur généré

- VII. Génération d'un éditeur graphique

- VII-A. Création projet GMF

- VII-B. Sélection du « Domain Model »

- VII-C. Sélection du « Domain Gen Model »

- VII-D. Génération du « Graphical Def Model »

- VII-E. Génération du « Tooling Def Model »

- VII-F. Génération du « Mapping Model »

- VII-F-1. Génération « Diagram Editor Gen Model »

- VII-F-2. Génération de l'éditeur de graphes

- VIII. Test modèles édités

- IX. Conclusions et remerciements

- X. Licence

I - Introduction

I-A - Spécification

Un modèle de graphe développé avec EMF a été proposé précédemment, nous souhaitons pouvoir tester dans un graphe la contrainte suivante : « Pour tout nœud du graphe le nombre d'arcs ayant ce nœud pour origine doit être inférieur ou égal à deux ».

Par exemple, dans le graphe ci-dessous :

Les nœuds « N0 » et « N2 » ne répondent pas à la contrainte.

I-B - Lancement de la plate-forme Eclipse

Double-cliquer : ou le raccourci vers cet exécutable si vous l'avez créé dans le répertoire destiné à recevoir les « workspaces ». La plate-forme « Eclipse » est lancée :

Sélectionner le workspace :

Cliquer sur le bouton « OK » puis fermer la fenêtre « Welcome ».

I-C - Passer en perspective « Ecore »

Faire :

Sélectionner :

II - Installer OCL Tools

Faire :

Sélectionner :

Cliquer sur le bouton « Finish ». Nous obtenons le résultat suivant :

Cliquer sur le bouton « Next > » :

Cliquer sur le bouton « Next > ». Puis accepter la licence :

Cliquer sur le bouton « Finish ». Le logiciel s'installe :

Cliquer sur le bouton « Restart Now » :

Eclipse est relancé, ne pas changer de « Workspace ». Cliquer sur le bouton « OK ».

Après les fermetures de quelques vues, nous obtenons le résultat suivant :

III - Création d'un projet EMF

Faire :

Sélectionner « Eclipse Modeling Framework > Empty EMF Project » :

Cliquer sur le bouton « Next > », nommer le projet :

Cliquer sur le bouton « Finish ».

IV - Édition du modèle « Ecore »

Ouvrir le projet faire un clic droit sur « model » et sélectionner la commande « New > Ecore Diagram » :

Nommer le « Domain File » :

Cliquer sur le bouton « Finish ». Éditer ensuite le modèle et le sauvegarder :

C'est le modèle défini dans les autres documents.

Nous allons créer une référence supplémentaire (Noeud → Graphe) afin de pouvoir accéder au « Graphe » à partir d'un « Nœud » :

Cette référence va être définie comme « EOpposite » de la référence « Graphe → Noeud ».

Pour cela, dans les « properties » de la référence « Noeud → Graphe » cliquer dans le rectangle contenant les trois points :

Dans « Object selection », sélectionner :

Nous obtenons, après quelques modifications de l'aspect du diagramme :

- EReference « graphe » sélectionnée ;

- EReference « listeNoeuds » sélectionnée ;

Si on édite « Graphe.ecore », on obtient :

Remarque : depuis un « Nœud », l'attribut « graphe » permet d'accéder au graphe.Noeud.

V - Aide à la création d'une contrainte

V-A - Visualisation de la console OCL

Un clic droit dans l'éditeur de « Graphe.ecore » fait monter le menu contextuel, faire :

La console OCL interactive comporte deux zones :

V-B - Création d'une instance dynamique du modèle

Sélectionner Graphe puis faire un clic droit sélectionner la commande « CreateDynamicInstance… » :

Ne pas modifier le nom du fichier :

Cliquer sur le bouton « Finish ».

Nous obtenons « Graphe.xmi » :

V-B-1 - Saisie d'un modèle

Afin de faciliter l'écriture de la contrainte, on saisit un modèle expérimental. Le modèle est construit sous « Graphe ». C'est sur ce modèle que nous testerons les expressions OCL.

Pour créer un « Nœud » :

Initialiser les « properties » du « Nœud » (Nom) pour obtenir : (Cliquer dans la zone d'édition) :

Continuer la saisie du modèle :

L'affichage en mode « Texte » (Open With > Text Editor) permet de visualiser le Graphe et les « properties » des Noeuds et des Arcs :

<?xml version="1.0" encoding="ASCII"?>
<graphe:Graphe xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:graphe="http://graphe/1.0" xsi:schemaLocation="http://graphe/1.0 Graphe.ecore">
<listeNoeuds nom="Origine"/>
<listeNoeuds nom="N1"/>
<listeNoeuds nom="N2"/>
<listeNoeuds nom="N3"/>
<listeArcs nom="OrigineToN1" origine="//@listeNoeuds.0" extremite="//@listeNoeuds.1"/>
<listeArcs nom="OrigineToN2" origine="//@listeNoeuds.0" extremite="//@listeNoeuds.2"/>
<listeArcs nom="OrigineToN3" origine="//@listeNoeuds.0" extremite="//@listeNoeuds.3"/>
<listeArcs nom="N1toN2" origine="//@listeNoeuds.1" extremite="//@listeNoeuds.2"/>
<listeArcs nom="N2ToN3" origine="//@listeNoeuds.2" extremite="//@listeNoeuds.3"/>
</graphe:Graphe>

V-C - Expression d'une contrainte

Le modèle édité va nous aider à écrire l'expression « OCL ». Dans ce modèle, le nœud « Origine » est l'« origine » de trois arcs ce qui ne correspond pas à la contrainte que nous nous sommes fixée : « Pour tout nœud du graphe le nombre d'arcs ayant ce nœud pour origine doit être inférieur ou égal à deux ».

Pour écrire l'expression OCL sélectionner le Noeud « Origine » dans « Graphe.xmi ».

Les expressions sont saisies dans la zone « Enrty of queries » de la console.

La vue du métamodèle facilite l'écriture des expressions OCL.

On adopte la disposition ci-dessous des vues :

Les évaluations se font à partir du nœud « Noeud Origine » sélectionné.

Saisir « graphe » dans la zone « Entry of query » (valider la saisie).

L'évaluation s'affiche dans la zone « Results » :

Saisir « graphe.listeArcs » pour obtenir tous les arcs du graphe :

Nous allons considérer pour chaque arc si la condition suivante est remplie : l'origine de l'arc correspond au nœud sélectionné: « Origine » représenté par « self » dans l'expression.

Pour cela nous allons évaluer :

graphe.listeArcs->select(origine=self)

Ce qui donne les trois arcs ayant le nœud « Origine » pour origine :

Finalement nous obtenons l'expression recherchée :

V-C-1 - Mise en place de la contrainte

Fermer « Graphe.xmi » avant toute modification du métamodèle.

Ouvrir « Graphe.ecore » avec l'éditeur OCLinEcore(Ecore) Editor :

Le métamodèle apparaît sous la forme :

module _'Graphe.ecore'
package graphe : graphe = 'http://graphe/1.0'
{
class Graphe
{
property listeNoeuds#graphe : Noeud[*] { ordered composes };
property listeArcs : Arc[*] { ordered composes };
}
class Noeud
{
attribute nom : String[1] { ordered };
property graphe#listeNoeuds : Graphe[1] { ordered };
}
class Arc
{
attribute nom : String[1] { ordered };
property origine : Noeud[1] { ordered };
property extremite : Noeud[1] { ordered };
}
}

On l'édite pour ajouter la contrainte sur les nœuds :

class Noeud
{
invariant toManyOutput:
graphe.listeArcs->select(origine=self)->size()<=2;
attribute name : String[1];
property graphe#listeNoeuds : Graphe[1];
}

Si on réaffiche « Graphe.xmi » avec (Open with > Sample Reflective Ecore Model Editor) :

Nous obtenons :

Où la contrainte « toManyOuput » apparaît.

V-D - Test du modèle

Un clic droit dans la zone d'éditeur de « Graphe.xmi » fait monter le menu contextuel. Sélectionner la commande « Validate » :

Le message suivant s'affiche :

L'arc « Arc OrigineToN3 » est supprimé :

On relance la validation, le modèle maintenant est correct :

VI - Génération éditeur arborescent

VI-A - Création « EMF Generation Model »

Sélectionner « Graphe.ecore » puis faire :

Sélectionner :

Cliquer sur le bouton « Next > ».

On ne modifie pas le nom du modèle :

Cliquer sur le bouton « Next > ».

Sélectionner :

Cliquer sur le bouton « Next > ».

Dans :

Cliquer sur les boutons « Load » et « Next > » :

Cliquer sur le bouton « Finish ».

« Graphe.genmodel » est ouvert en édition.

Sélectionner la racine « Graphe » et initialiser la « property » du « Model » « Operation Reflection » à « true » :

VI-B - Génération de l'éditeur

Dans l'éditeur de « Graphe.genmodel », faire un clic droit et dans le menu contextuel sélectionner « Generate All » :

Après génération trois nouveaux projets sont créés :

VI-C - Test de l'éditeur généré

Créer une nouvelle configuration d'exécution, la nommer et faire « Apply » :

Faire « Run ». Une nouvelle plate-forme « Eclipse » est lancée avec pour « workspace » : « runtime-OCLinEcore ». Fermer la fenêtre « Welcome » et quelques vues pour obtenir :

Créer un nouveau projet :

Sélectionner :

Cliquer sur le bouton « Next > ».

Nommer le projet :

Cliquer le bouton « Finish », le nouveau projet est créé :

Pour créer un modèle faire :

Sélectionner :

Cliquer sur le bouton « Next > ».

Nommer le fichier :

Cliquer sur le bouton « Next > ».

Sélectionner « Graphe » :

Cliquer sur le bouton « Finish ».

Éditer un graphe :

On peut ouvrir le graphe avec un éditeur textuel afin de visualiser les arcs.

On a la correspondance :
N0 → @listeNoeuds.0
N1 → @listeNoeuds.1

<?xml version="1.0" encoding="UTF-8"?>
<graphe:Graphe xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:graphe="http://graphe/1.0">
<listeNoeuds nom="N0"/>
<listeNoeuds nom="N1"/>
<listeNoeuds nom="N2"/>
<listeNoeuds nom="N3"/>
<listeNoeuds nom="N4"/>
<listeArcs nom="N0ToN1" origine="//@listeNoeuds.0" extremite="//@listeNoeuds.1"/>
<listeArcs nom="N0ToN2" origine="//@listeNoeuds.0" extremite="//@listeNoeuds.2"/>
<listeArcs nom="N0ToN3" origine="//@listeNoeuds.0" extremite="//@listeNoeuds.3"/>
<listeArcs nom="N1toN4" origine="//@listeNoeuds.1" extremite="//@listeNoeuds.4"/>
<listeArcs nom="N2ToN4" origine="//@listeNoeuds.2" extremite="//@listeNoeuds.4"/>
<listeArcs nom="N3ToN4" origine="//@listeNoeuds.3" extremite="//@listeNoeuds.4"/>
</graphe:Graphe>

Du nœud N0 partent trois arcs.

Si on demande une validation du graphe, on obtient :

L'erreur est reportée dans la vue « Project Explorer » :

VII - Génération d'un éditeur graphique

Se reporter au document « Génération d'un éditeur graphique ».

VII-A - Création projet GMF

Faire :

Sélectionner :

Cliquer sur le bouton « Next> ».

Nommer le projet :

Cliquer sur le bouton « Next> ».

Sélectionner le « Dashboard » :

Cliquer sur le bouton « Finish ».

Sélectionner le projet « exemple.graphe.gmf » pour obtenir :

VII-B - Sélection du « Domain Model »

Dans le pavé « Domain Model » cliquer « Select » dans :

Sélectionner « Graphe.ecore » :

Cliquer sur le bouton « OK » pour obtenir :

VII-C - Sélection du « Domain Gen Model »

Graphe.genmodel existe déjà dans le projet « exemple.graphe.emf ».

Dans le pavé « Domain Gen Model » cliquer « Select » :

Sélectionner « Graphe.genmodel »:

Cliquer sur le bouton « OK » pour obtenir :

VII-D - Génération du « Graphical Def Model »

Cliquer « Derive » :

Sélectionner le répertoire « model » du projet « exemple.graphe.gmf » :

Cliquer sur le bouton « Next > ».

Faire « Load » et sélectionner « Graphe » :

Cliquer sur le bouton « Next > ».

Ne rien modifier :

Cliquer sur le bouton « Finish ».

Ajout des flèches aux arcs

Dans le projet « exemple.graphe.gmf », éditer le fichier « model > Graphe.gmfgraph » :

Modifier « property » Name de « Polyline Decoration » :

Modifier « property » « Target Decoration » de « Polyline Connection ArcFigure ».

VII-E - Génération du « Tooling Def Model »

Cliquer sur « Derive » :

Sélectionner le répertoire « model » du projet « exemple.graphe.gmf » :

Cliquer sur le bouton « Next > ».

Cliquer sur « Load », sélectionner « Graphe » :

Cliquer sur le bouton « Next > » :

Cliquer sur le bouton « Finish » pour obtenir :

VII-F - Génération du « Mapping Model »

Cliquer sur « Combine » :

Sélectionner le répertoire « model » du projet « exemple.graphe.gmf » :

Cliquer sur le bouton « Next > ».

Cliquer « Load », sélectionner « Graphe » :

Cliquer sur le bouton « Next > ».

Cliquer sur « Load » puis sur le bouton « Next > ».

Cliquer sur le bouton « Load » puis sur « Next > », pour obtenir :

Modifier le « mapping » :

Dans « Links », sélectionner « Arc(<unspecified>;listeArcs) » et cliquer « Change... ».

Éditer les « Properties » :

Cliquer sur le bouton « OK ». Dans « Create GMFMap model - Mapping », cliquer sur le bouton « Finish ».

VII-F-1 - Génération « Diagram Editor Gen Model »

Cliquer sur « Transform », ne pas cocher « RCP ».

On a maintenant dans le répertoire « model » du projet « exemple.graphe.gmf » :

VII-F-2 - Génération de l'éditeur de graphes

Cliquer dans le « GMF Dashboard » : « Generate diagram editor ».

Le projet « exemple.graphe.emf.diagram » est généré.

VIII - Test modèles édités

Faire un clic droit sur le projet : « exemple.graphe.emf.diagram ». Sélectionner la commande « RunAs > Run Configuration ». On retrouve la configuration « OCLinEcore » précédemment créée.

Créer une nouvelle configuration nommée « OCLinEcore », faire « Apply » :

Faire « Run ».

Une nouvelle plateforme Eclipse est lancée. Créer un nouveau projet de type « General > Project » nommé « testGraphe ». Sous le projet créer un graphe de type : « Examples > Graphe Diagram » que l'on nomme « G1.graphe_diagram ». On l'édite et on le sauvegarde.

Valider le graphe :

On sélectionne « G1.graphe » et on utilise le menu contextuel de l'éditeur :

Le message suivant s'affiche :

La première ligne correspond au nombre d'arcs issus du nœud « N1 ».

Les autres lignes indiquent que le métamodèle attend un nom pour chaque arc.

Modifier le modèle :

Seuls les problèmes liés aux noms des arcs sont affichés :

Modifier le modèle en nommant les arcs en utilisant les properties :

La validation donne :

IX - Conclusions et remerciements

La console « Interactive OCL » nous a permis de tester la contrainte appliquée au graphe. Cette contrainte intégrée au modèle EMF est utilisée dans les éditeurs graphiques.

Nous tenons à remercier ClaudeLELOUP pour sa relecture attentive de cet article puis _Max_ et Keulkeul pour la mise au gabarit de l'article original.

X - Licence

La licence « Creative Commons » s'applique à ce document, veuillez vous référer à ce site pour de plus amples informations : http://creativecommons.org/licenses/by-nc-nd/2.0/fr/.