I. Introduction▲
I-A. Concept▲
La création d'éditeurs graphiques (éditeurs UML,
représentation de processus, éditeurs de concepts métier, etc.)
est difficile à intégrer dans un cycle itératif court avec le
client, car coûteuse en temps et nécessitant souvent
l'apprentissage de technologies ou frameworks complexes. Le projet
Eclipse Sirius se propose de faciliter la création d'éditeurs en se
basant sur la représentation d'un DSL au sein d'un modèle EMF
(Eclipse Modeling Framework).
Un DSL, Domain Specific Language, est un langage dédié à un domaine métier avec ses
mots-clés et son formalisme. Ainsi, une recette de cuisine avec des ingrédients et
une série d'actions est un DSL. Les DSL ne sont donc pas limités à
l'informatique. Dans Sirius, à partir d'un modèle EMF, le développeur va pouvoir
spécifier un éditeur de manière complètement déclarative pour le
modèle et observer le résultat en temps réel, sans génération de code.
Dans ce tutoriel, nous allons détailler les différentes étapes depuis la création
du modèle jusqu'à la spécification de l'éditeur avec Sirius, en expliquant
les principaux concepts associés. Nous ne reviendrons pas sur les concepts d'EMF qui sont
expliqués dans ce
tutorielTutoriel sur la création de modèles avec EMF.
I-B. Un peu d'histoire▲
Le projet Sirius a été développé il y a quelques années par la société Obeo, en partenariat avec Thales. Les mécanismes servent notamment de base à l'application propriétaire Obeo Designer. Le projet passe maintenant en Open Source et sera déployé dans sa version 1.0 avec Eclipse Luna dans le « Simultaneous Release Train ». Malgré la numérotation « 1.0 », le projet possède déjà de nombreuses années derrière lui, ce qui garantit donc sa stabilité.
I-C. Prérequis et installation▲
Pour commencer, il vous faut une installation d'Eclipse Juno, Kepler ou
supérieure. Votre distribution doit comporter les outils de création
de modèles EMF. Pour simplifier l'installation, vous pouvez
télécharger la version packagée « Eclipse Modeling
Tools » sur le site de téléchargement officiel. On peut
alors installer Sirius. Actuellement, comme mentionné
précédemment, Sirius n'est pas disponible sur les repositorys,
officiels. Vous trouverez les liens de téléchargement associés
sur la page du projetSirius Update Sites.
Pour ce
tutoriel, nous nous baserons sur la version 1.0.0M5 d'Eclipse
Kepler.
Sélectionnez tous les composants de la catégorie « Sirius ».
Dans la première partie de ce tutoriel, nous verrons comment mettre en place le modèle EMF. Dans les parties suivantes, nous mettrons en place notre éditeur avec Sirius.
II. Création du modèle EMF▲
II-A. Notre DSL▲
Nous allons, dans cet article, créer un DSL très simple qui nous permettra de mettre en œuvre certains mécanismes clés de Sirius. Notre DSL nous servira à représenter les liaisons aériennes qui existent entre différents aéroports. Le modèle contiendra donc un certain nombre d'aéroports définis par un nom, une ville et un pays. Ces aéroports ont un ensemble de portes identifiées par un numéro. Ces portes peuvent référencer une porte d'un autre aéroport, représentant ainsi une liaison entre deux aéroports.
II-B. Création du modèle▲
Créez d'abord un nouveau projet de type « Empty EMF Project », puis créez un fichier « Ecore Diagram » au sein du dossier « model » du nouveau projet , et enfin, créez un nouveau modèle appelé « airports.ecore ».
Créez ensuite chacun des éléments du modèle pour obtenir le diagramme suivant :
II-C. Génération▲
Créez un fichier « .genmodel » à partir de l'assistant « EMF Generator Model » pour notre fichier « airports.ecore » : sur la deuxième page « Select Model importer », sélectionnez « Ecore model », puis sur la page suivante, sélectionnez notre modèle « .ecore » et cliquez sur « Load » :
Sélectionnez ensuite le package « airports » pour la génération :
Une fois le fichier « .genmodel » créé, ouvrez-le et lancez la génération du modèle, du plugin « edit » et du plugin « editor ». Nous obtenons donc trois plugins, « com.abernard.airports », « com.abernard.airports.edit » et « com.abernard.airports.editor ».
III. Création de l'éditeur▲
III-A. Fonctionnement de Sirius▲
La grande force de Sirius est de permettre la spécification des
éditeurs de manière totalement graphique, sans avoir à
écrire de code. Parallèlement à la spécification, le rendu
peut être observé en temps réel à partir de l'instanciation
du modèle que l'on veut représenter. De ce fait, nous allons
travailler dans une instance d'Eclipse qui embarque les plugins que nous avons
générés précédemment, de manière à pouvoir
créer un exemple de notre modèle grâce aux éditeurs par
défaut. Sirius est aussi une énorme avancée dans la construction
d'éditeur de diagrammes dans le sens où la seule alternative
était GMF (Graphical Modeling Framework), extrêmement complexe à
prendre en main et peu intuitif.
La première étape consiste à lancer un Eclipse avec nos plugins. Pour cela, ouvrez
d'abord le panneau « Run configurations » via le menu « Run
> Run configurations », puis créez une nouvelle configuration de type
« Eclipse Application ».
Puis, ajoutez la ligne suivante dans la zone « VM arguments » de l'onglet « Arguments » :
-Xms256m -Xmx1024m -XX:MaxPermSize=256m
Lancez ensuite l'application. C'est uniquement dans cette nouvelle application que nous travaillerons désormais. En effet, Sirius se base sur les plugins EMF que nous avons créés et intégrés dans la nouvelle instance d'Eclipse pour la spécification et le test de l'éditeur.
III-B. Instanciation du modèle▲
Dans l'application, ouvrez la perspective « Sirius ». Cette dernière ouvre une vue appelée « Model Explorer ». Créez ensuite un projet de type « Modeling Project » appelé « com.abernard.airports.example ».
Dans le projet créé, on peut identifier un fichier appelé
« representations.aird ». Ce dernier permettra à
Sirius de stocker l'agencement des éléments dans l'éditeur que
l'on va créer, de manière indépendante du modèle
lui-même. Notez qu'il existe un seul fichier « .aird »
par « Modeling Project », mais chaque fichier peut stocker
plusieurs représentations.
Créez ensuite une instance du modèle grâce au menu « New > Example EMF Model
Creation Wizards > Airports model ». Donnez un nom à votre modèle, puis
sélectionnez comme objet racine, l'objet « World Map ».
Créez ensuite les éléments du modèle à votre convenance, mais avec au moins deux aéroports contenant chacun une porte, les portes sont reliées entre elles. Par exemple, voilà l'instance dont je vais me servir dans le reste de cet article.
III-C. Initialisation de l'éditeur▲
La création des éditeurs de Sirius se fait au travers des projets
que l'on nomme « Viewpoint Specification Project ». Via le
menu « New > Project > Viewpoint Specification Project »,
créez un projet « com.abernard.airports.design ». Afin
de pouvoir le manipuler plus facilement lorsque nous aurons spécifié
l'éditeur dans notre workspace de base, je vous conseille de créer le
projet dans votre workspace de développement plutôt que celui de
runtime. Sur la deuxième page de l'assistant, donnez un nom au fichier
« .odesign » ; ce dernier contient la spécification de
notre éditeur et c'est l'unique fichier que nous allons modifier.
Le fichier s'ouvre, affichant un unique élément « airports ». La
première étape consiste à créer un « Viewpoint ». Comme
son nom l'indique, un viewpoint sert à définir une manière de représenter
un modèle. Cela permet de proposer différents points de vue, selon par exemple le
niveau des utilisateurs. Avec un clic droit sur l'élément
« airports », créez un viewpoint.
Dans la vue « Properties », trois champs sont à remplir : un champ « ID », un champ « Label » et un champ « Model File Extension ». Le champ « ID » est présent sur tous les éléments qui seront définis dans le fichier « odesign » et est obligatoire. D'une version à une autre, si vous modifiez l'ID de vos éléments, la compatibilité ne sera plus assurée avec les fichiers « representations.aird » existants. Le champ « Label » est là pour donner un nom plus compréhensible aux éléments et peut être changé sans perturber les représentations existantes. Il est aussi présent sur la plupart des éléments et sera souvent le texte affiché aux utilisateurs. Dans le champ « Model File Extension », mettez l'extension des fichiers de modèle que vous voulez associer à votre viewpoint.
Nous devons associer ensuite une représentation à notre viewpoint afin d'indiquer à Sirius quel type d'éditeur nous voulons créer. Il est possible de créer des éditeurs sous forme d'arbre, de tableau, de diagramme ou encore de diagramme de séquence.
Dans cet exemple, nous allons créer un diagramme.
Faites un clic droit sur le viewpoint puis sélectionnez « New Representation > Diagram Description ». Dans la vue « Properties », renseignez l'ID, le label et le champ « Domain Class ». Ce champ indique l'objet de base représenté par le diagramme. Par exemple, pour un diagramme de classe, l'élément de base serait sans doute le package ; dans notre cas, c'est l'objet « WorldMap ». Notez que dans ce champ, vous pouvez utiliser l'auto-complétion.
À partir de maintenant, il est possible de visualiser l'éditeur en temps réel au fur et à mesure que nous le spécifions.
III-D. Visualisation en temps réel▲
Pour lancer la visualisation, faites un clic droit sur le projet qui contient le modèle et sélectionnez « Viewpoints Selection ».
Dans la fenêtre qui s'affiche, sélectionnez le Viewpoint que nous venons de créer.
Enfin, dépliez le fichier « example.airports » et faites un clic droit sur l'objet « WorldMap » de notre exemple puis sélectionnez « New Representation » puis « new Airports Diagram » et donnez un nom à la représentation.
Le diagramme s'ouvre. Evidemment il est vide puisque nous n'avions défini aucune représentation pour les éléments de notre modèle. Nous pouvons le laisser ouvert et l'affichage s'adaptera à chaque modification que nous ferons dans le fichier « .odesign », en temps réel.
IV. Spécification des éléments▲
La première étape consiste à spécifier un « layer ». Le layer permettra à l'utilisateur d'afficher ou non certains éléments à la volée grâce au bouton idoine dans la barre d'outils de l'éditeur généré.
Sélectionnez l'élément « Airport Diagram » et dans le menu contextuel, sélectionnez « New Diagram Element > Default Layer Layer ». Comme d'habitude, donnez à cet élément un ID et un label.
IV-A. Spécification des nœuds▲
Nous devons ensuite définir la manière de représenter les éléments de notre modèle. Pour ce faire, vous allez créer des représentations pour les aéroports sous forme de rectangles, puis représenter les différentes portes sur les pourtours de ces rectangles. Pour commencer, grâce au menu contextuel sur le layer créé précédemment, vous créez un nouveau « Node Mapping » (« New Diagram Element » > « Node Mapping »). Donnez-lui un ID, un label, puis définissez dans le champ « Domain Class » la classe du modèle que ce nœud représentera ; dans notre cas, cela correspondra à la classe « Airport ». Le champ « Semantic candidate » vous permet d'indiquer l'expression permettant d'accéder aux éléments à afficher. Cette expression est optionnelle mais si elle n'est pas remplie, tous les objets du modèle correspondant à l'instance seront affichés. Dans l'exemple ci-dessous, l'expression est indiquée mais donne exactement le même résultat que si le champ n'était pas rempli.
Remarquez la manière dont les expressions sont écrites, avec le contenu entre crochets : […/]. Cette syntaxe correspond au langage Acceleo qui permet à Sirius d'interpréter les expressions sur des objets EMF. Pour plus d'informations, reportez-vous au site officielSite Acceleo.
Il faut ensuite définir la représentation du nœud. Pour cela, faites un clic droit sur le « Node mapping » et sélectionnez « New Style > Square Description ». Enregistrez le fichier « .odesign » et observez l'éditeur que nous avions ouvert en regard : il s'est mis à jour et affiche les différents aéroports de notre modèle.
La vue « Propriétés » vous permet de définir le mode d'affichage des nœuds. L'onglet « Label » modifie le mode d'affichage du nom de l'élément : si on doit afficher l'icône, la position du nom et l'expression associée au nom.
L'onglet « Color » règle les couleurs du nœud. Dans l'onglet « Advanced », on peut modifier la taille du nœud et la façon dont elle est calculée. À chaque modification d'une propriété, on peut observer les changements en temps réel dans l'éditeur.
Maintenant que nous avons défini la représentation des aéroports, nous pouvons créer, en bordure des éléments, les représentations de chacune des portes. Cela se fait par un clic droit sur l'élément « Node Mapping » des aéroports via « New Diagram Element > Bordered Node Mapping ».
Puis, comme précédemment, nous pouvons régler les propriétés pour afficher ces éléments, par exemple via « New Style > Lozenge Style Description ». Dans ce cas, l'expression pour définir le label des éléments est « [number/] ». Encore une fois, l'éditeur se met à jour dès la sauvegarde du fichier.
IV-B. Spécification des relations▲
En plus des nœuds qui représentent les objets de notre modèle, Sirius permet de définir la représentation des relations entre les éléments. Pour cela, deux possibilités s'offrent à nous : soit un lien basé sur une relation entre deux objets (association, « containment »…), soit une relation basée sur un objet explicite. Dans notre cas il s'agit d'une relation entre deux objets de type « Gate » qui peut être créée via « New Diagram Element > Relation Based Edge ». L'élément est créé avec un style défini et la page de propriétés permet de définir les critères d'affichage de la relation entre deux éléments. Le champ « Source Mapping » donne le type d'objet source, le champ « Target Mapping » donne le type d'objet cible de la relation et le champ « Target finder expression » donne l'expression utilisée pour trouver l'objet cible depuis l'objet source.
De nouveau, l'éditeur se met à jour et affiche les relations entre les différents éléments de notre modèle.
L'élément « Edge Style Description » permet de modifier la manière dont sont représentées les relations : on peut modifier, par exemple, les connecteurs ou la couleur des liens.
V. Création de la palette▲
Les éléments que nous avons mis en place précédemment permettent de visualiser notre modèle dans un diagramme. Cependant, l'intérêt d'un éditeur reste tout de même de pouvoir éditer le modèle ! Nous allons dans cette section mettre en place la palette d'outils. Cette dernière peut servir à créer deux types d'éléments : d'une part les éléments visibles dans la palette du côté de l'éditeur et d'autre part, les mécanismes qui permettent de modifier les éléments à la volée, comme par exemple le label des éléments. Au niveau du layer de la définition de notre éditeur, créez une « Section » grâce au menu contextuel « New Tool > Section ». Comme d'habitude, donnez à cet élément un label et un ID.
V-A. Outils de création d'éléments▲
V-A-1. Création des nœuds▲
Pour plus de clarté, nous allons grouper dans des sous-sections les outils « visibles » et les outils de manipulation d'éléments. Créez donc une nouvelle section dans celle que nous venons de créer pour les outils de la palette « Palette tools ». Grâce au menu contextuel, sélectionnez « New Element Creation > Node creation Description ». Sur la page de propriétés qui s'affiche, donnez à cet outil un ID et un label, et définissez ensuite quel nœoeud cet outil va créer.
Il faut ensuite indiquer à Sirius comment instancier l'élément et où le placer au sein du modèle. Pour cela, les opérations doivent être décrites dans le nœud « Initial Node Creation Operation » de l'outil. La première chose à faire est de se placer dans le « contexte » adéquat via le menu contextuel « New Operation > Change Context » et définir l'expression afin de se placer dans l'objet « container ». Notez que Sirius, à cet emplacement, vous donne un accès à deux variables qui sont :
- « container » qui correspond à l'élément parent de la création de l'objet au sein de votre modèle (dans notre exemple, c'est directement l'objet « WorldMap ») ;
- et « containerView » qui est l'objet de l'élément « container » au sein du diagramme Sirius.
Créez ensuite une opération de type « Create Instance », puis définissez un nom de variable pour la nouvelle instance, la classe du modèle qui va être instanciée et l'attribut du container qui va faire le lien vers cette nouvelle instance : dans notre cas il s'agit de la liste d'aéroports de la classe « WorldMap », nommée « airports ».
Puis on peut définir des opération de type « Set Value » afin de définir des valeurs par défaut pour les attributs de l'instance que l'on vient de créer, par exemple le nom de l'aéroport ou le pays.
On peut constater que l'outil que nous venons de créer est apparu dans la palette et si l'on crée un nœud sur le diagramme, une nouvelle instance de l'objet « Airport » est créée dans notre modèle avec le nom et le pays par défaut que nous avons défini.
Notez que vous pouvez à tout moment effectuer une validation de votre fichier *.odesign grâce à l'icône « Validate Model ».
De la même manière, vous pouvez définir l'élément de création des objets « Gate » au sein de la palette.
V-A-2. Création des connecteurs▲
Pour définir l'outil de création des liens, faites un clic droit sur la section « Palette » puis choisissez « New Element Creation > Edge Creation Description ». Dans les propriétés, donnez un ID, un label et définissez quel élément du diagramme sera créé.
Comme pour la création des nœuds, Sirius vous donne directement accès à différentes variables représentant la source et la cible dans l'éditeur ainsi que leur correspondance au sein du modèle. Puis, comme pour les nœuds, il s'agit de définir l'enchaînement d'actions qui vont mener à la modification du modèle. La première étape consiste d'abord à se placer dans le contexte « [source/] » grâce à une opération « Change Context ». Puis, grâce à une opération « Set value », on définit la propriété « destination » de l'élément du modèle à « [target/] ».
Après sauvegarde, vous pouvez directement utiliser votre palette pour créer de nouveaux liens entre vos aéroports.
V-B. Outils de modification d'éléments▲
En plus des outils de création d'éléments, Sirius vous permet de définir les différentes actions sur votre diagramme, qui n'apparaissent pas dans la palette, mais permettent d'apporter des modifications à votre modèle. Nous ne verrons dans ce tutoriel que certains de ces outils. Commencez par créer une nouvelle section « Tools » au sein de la section principale « Airports ».
V-B-1. Suppression des éléments▲
Si vous sélectionnez un élément et que vous appuyez sur la touche « Suppr », vous remarquerez que rien ne se passe. Ce comportement est défini grâce à « New Element Edition > Delete Element Description ». Comme d'habitude, donnez un ID et un label à votre action et définissez quels éléments du diagramme vont pouvoir être supprimés avec cette action.
Il est recommandé de se placer dans le contexte de l'élément via une opération « Change Context »et de supprimer l'élément avec une opération « Remove element ».
Vous pouvez ensuite tester dans votre éditeur qu'un appui de la touche « Suppr » lorsqu'un aéroport est sélectionné supprime bien l'élément du modèle.
V-B-2. Modifier les liens entre éléments▲
Une autre opération courante dans un éditeur de type
diagramme est de pouvoir reconfigurer les connexions entre les
différents éléments du diagramme. Là aussi, Sirius
nous propose d'ajouter cette action prédéfinie à notre
palette via « New Element Edition > Reconnect Edge
Description ». Donnez un ID et un label à cet
élément. Vous pouvez aussi définir quel type
d'opération vous voulez gérer : soit
« Reconnect Target » pour seulement autoriser la
reconnexion de la cible de la connexion, soit « Reconnect
Source » pour la reconnexion de la source uniquement, soit
« Reconnect Both » pour gérer les deux cas de
figure. Dans notre cas, nous nous intéresserons à
« Reconnect Target » uniquement. Enfin,
définissez sur quelle connexion cette opération s'applique
dans le champ « Mappings ».
Dans cette action, Sirius donne accès à trois variables :
- « source » : l'instance du modèle qui va être déconnecté ;
- « target » : l'instance du modèle qui va être connecté ;
- « element » : l'instance du modèle derrière la connexion elle-même.
Il faut ensuite définir la suite d'opérations à accomplir pour effectuer la reconnexion. Tout d'abord, on se place dans le contexte de la variable « element ». Puis on effectue une opération « set » sur la feature « destination » du modèle afin d'affecter la nouvelle destination à notre liaison aérienne : la variable « target ».
On peut alors reconnecter la destination des connexions entre éléments.
V-B-3. Renommer les éléments▲
Enfin, Sirius permet de redéfinir à la volée le nom des éléments grâce à l'opération « New Element Edition > Direct Edit Label ». Pour effectuer cette opération, il faut définir sur quel élément graphique elle va s'appliquer (dans notre exemple le nœud « Airport ») en plus des habituels ID et label. Via une opération « Change context », on se place ensuite dans la variable « self » qui représente, dans Sirius, l'instance du modèle sous-jacente à l'élément graphique sélectionné. On peut alors définir une action « Set value » afin de redéfinir le nom de l'aéroport (la feature « name ») avec la valeur donnée par l'utilisateur, « arg0 ». La propriété « Edit Mask Variables » permet de définir une syntaxe pour l'édition des labels permettant d'accéder à plusieurs variables distinctes au sein de la chaîne de caractères entrée par l'utilisateur. Par exemple, nous indiquons dans notre cas le masque « {0} ({1}) » ; ce qui nous permet de récupérer dans la variable « arg0 » le nom de l'aéroport et dans la variable « arg1 » le pays.
L'utilisateur peut alors, en un clic, modifier le nom des aéroports directement au sein du diagramme.
VI. Conclusion et perspectives▲
Et voilà ! Au terme de cet article, vous saurez spécifier un premier éditeur de diagrammes avec Sirius ! Comme vous avez pu le constater, la mise en place, une fois les mécanismes compris, est rapide et ne nécessite aucune ligne de code. Néanmoins, il est possible d'utiliser ses propres « services » développés directement en Java au sein de l'éditeur.
Pour aller plus loin, je vous invite à lire la documentation
complète.
La vue « Propriétés » permet d'éditer les éléments du
diagramme grâce à la vue par défaut d'EMF. Afin d'avoir un rendu plus
agréable et plus ergonomique, l'utilisation d'EEF, « Extended Editing
Framework », permet de créer une vue
« Propriétés » avec des onglets de la même forme que celles
dont on dispose dans la spécification de l'éditeur Sirius. Là encore la
construction se fait de manière déclarative.
Il est intéressant aussi de noter que Sirius a permis de refondre l'éditeur de modèles
Ecore afin de lui donner une nouvelle jeunesse et sera déployé dans Eclipse Luna.
Ci-dessous, deux captures d'écran du même modèle dans l'éditeur actuel et
dans celui basé sur Sirius. Par exemple, on peut y créer directement des interfaces,
classes abstraites, ou des relations symétriques.
VII. Liens▲
VIII. Remerciements▲
Tout d'abord, il serait de bon ton de remercier les personnes ayant contribué au projet et à son passage en Open Source. Je remercie ensuite Mickael BARON, milkoseck et jacques_jean pour leur relecture attentive de cet article.