I. Installation et préparation▲
I-A. Présentation▲
Cet article présente l'utilisation du générateur de code Acceleo de concert avec les modeleurs spécifiques. On peut considérer qu'il s'agit de la suite logique du tutoriel de démarrage du projet GMF qui traite de la création d'un modeleur spécifique : un outil de « MindMapping ». Ce modeleur permet la formalisation d'idées que l'on peut mettre en relation.
Dans cet article nous détaillerons la réalisation d'un générateur de code pour cet outil de « MindMapping ». Il s'agit de générer des slides (en XHTML) à partir d'une carte mentale, les idées principales représentent autant de slides et les idées annexes des points à aborder au sein d'un slide.
Vous pouvez d'ores et déjà consulter un exemple de slides générés via le lien suivant. De plus tous les projets réalisés le long de cet article sont disponibles en téléchargement.
I-B. Installation d'Acceleo▲
Il faut dans un premier temps installer Acceleo, ses dépendances ainsi que GMF qui permet l'utilisation de modeleurs spécifiques. Un bundle est disponible sur le site d'Acceleo, ce dernier (bundle-emf-uml2-gmf-acceleo-1.1.0) permet l'installation simultanée d'Acceleo et de GMF.
Page de téléchargement d'Acceleo 1.1
Pour de plus amples informations concernant l'installation d'Acceleo, reportez-vous aux instructions disponibles sur le site d'Acceleo.
Si tout s'est bien déroulé, une nouvelle perspective « Acceleo » doit être disponible au sein d'Eclipse.
I-C. Installation du modeleur de MindMap▲
Cet article repose également sur un plugin produit grâce au projet GMF. Ce plugin contient le modeleur de MindMap.
Le projet GMF propose un article détaillant la réalisation de ce modeleur, vous êtes invité à le consulter si vous souhaitez réaliser votre propre modeleur spécifique. Nous montrons ici comment l'exploiter. Nous avons compilé ce plugin réalisé à partir du même métamodèle, téléchargez-le puis décompressez-le dans le répertoire d'installation de votre Eclipse.
Si le plugin n'est pas pris en compte dans votre environnement Eclipse, il peut être nécessaire de fermer Eclipse, d'effacer les répertoires contenus dans « configuration » de votre installation Eclipse puis de redémarrer ce dernier.
Tutorial GMF :réalisation d'un outil de MindMapping.
Vous pouvez vérifier la bonne installation de l'outil MindMapping en créant un projet vide puis en choisissant « File », « New » puis « Other » dans Eclipse. Une catégorie « Obeo Domain Specific Modeler » doit être disponible, elle permet la création d'une nouvelle carte mentale.
II. Mise en place de l'environnement▲
II-A. Présentation▲
Le principe général de la génération est le suivant : Acceleo utilise un template pour générer du code (ou texte) à partir d'un modèle. Ici le modèle est la carte mentale, le code généré est un ensemble de fichiers XHTML qui correspondent aux slides que l'on obtient.
Ici nous allons générer un fichier par idée (« Topic ») de la carte et un fichier supplémentaire pour la page de titre.
Nous adoptons une démarche de type « bottom-up » pour la création d'un générateur. Il s'agit dans un premier temps de réaliser un modèle d'exemple (ici une carte mentale) puis de coder manuellement les slides correspondants (on parle de « prototype »).
Une fois ces deux premières tâches réalisées, on va « industrialiser » et par conséquent réaliser les templates de génération permettant d'obtenir, à partir du modèle de départ, un résultat similaire au prototype. C'est cette phase que nous allons détailler, bien sûr nous allons générer ici du XHTML, mais nous pouvons en utilisant la même méthode générer du code (C + +, C, Python, Java…).
Une fois la première phase d'industrialisation réalisée, il s'agit de vérifier le bon fonctionnement du générateur sur d'autres modèles afin de le valider et éventuellement de l'ajuster.
Les projets que nous allons développer dans le cadre de cet article peuvent être téléchargés, ils contiennent un modèle d'exemple et le générateur XHTML complet.
II-B. Projets▲
Nous divisons notre environnement de travail en deux projets distincts, le premier (free.demo.mindmap) contiendra notre carte mentale ainsi que le code généré. Le second (free.demo.mindmap.gen.xhtml) contient les templates de génération correspondants.
Le projet free.demo.mindmap est un projet de type simple que l'on peut créer au sein d'Eclipse en choisissant « General » dans l'assistant de création de projets.
Nous organisons le projet de la façon suivante : le répertoire model contient notre carte mentale correspondante au prototype. Ce dernier sera disponible dans prototype et nous aidera à mettre au point notre générateur tandis que le répertoire slides contiendra lui, le code généré.
Le projet free.demo.mindmap.gen.xhtml est un module de génération, il faut choisir « Acceleo generator » pour le créer au sein de l'environnement.
Ce projet accueillera tous les templates de génération nécessaires, ils seront placés dans le répertoire src.
Trois templates de génération ont été développés (les fichiers .mt), nous les détaillerons plus loin.
II-C. Modélisation▲
Nous l'avons indiqué auparavant, nous adoptons une démarche de type « bottom-up » pour la création des générateurs. Ainsi il faut dans un premier temps réaliser une carte mentale et le code correspondant.
Plaçez-vous dans le répertoire model du projet free.demo.mindmap. Vous pouvez alors créer une nouvelle carte mentale en choisissant new puis other dans le menu contextuel.
Vous pouvez ainsi créer votre carte mentale. Remplissez-la avec différentes idées que vous pouvez relier entre elles.
Cette carte représentera notre base de travail pour la réalisation du prototype.
II-D. Prototype▲
Dans notre cas le prototype est donc un ensemble de slides réalisés en XHTML. Sa création permet de mettre en place le contenu d'un fichier type ainsi que les feuilles de style nécessaires.
Dans le cadre de cet article nous ne réalisons que deux fichiers : le premier présente la page de titre (index.html) tandis que le second un exemple de slide.
III. Un générateur pour MindMap▲
III-A. Un premier template▲
Nous allons tout d'abord rapidement présenter le fonctionnement d'Acceleo et la syntaxe de ses templates de génération.
Un template de génération est un patron qui se doit de délimiter de façon claire le texte statique généré et les éléments variables. Dans Acceleo cette limite est claire et facilite la lecture des scripts par une tierce personne. Le texte variable commence par <% et fini par %>.
Voici un exemple de template de génération. On y distingue plusieurs parties.
La zone en entête définit sur quel métamodèle ce template s'applique. Ici l'adresse correspond à celle de notre métamodèle de carte mentale, mais elle pourrait aussi bien être UML par exemple. Dans cette zone sont également réalisés des imports (pour appeler d'autres scripts ou du code Java).
Ensuite le template est divisé en un certain nombre de scripts. Le script est l'unité élémentaire d'un template. Il évalue un élément pour produire du texte. Chaque script s'exécute sur un type d'éléments donnés. Ainsi dans notre cas on va avoir des scripts s'exécutant sur Topic (qui correspond à une idée) tandis que d'autres concerneront toute la carte mentale (le type Map).
Nous allons dans un premier temps réaliser un template très simple. Ce dernier génère un fichier pour chaque Topic d'une carte mentale.
Pour créer un nouveau template, cliquez sur New puis Empty Generator.
Ici nous voulons réaliser un template pour « MindMap ». Il convient donc de sélectionner l'URI correspondante. L'URI permet d'identifier clairement les types de modèles que l'on va exploiter, ici il s'agit de http://www.obeo.fr/dsl/mindmap, mais si l'on souhaite générer du code à partir d'UML par exemple on choisira l'URI http://www.eclipse.org/uml2/2.0.0/UML.
La liste déroulante Types values permet d'indiquer sur quel type d'objet on souhaite générer un fichier.
Ici on souhaite générer un fichier par Topic présent dans le modèle, on choisit donc le type Topic.
L'assistant crée alors un template de génération vide.
La syntaxe d'Acceleo est extrêmement simple. Tous les caractères représentés en noir dans l'éditeur sont des zones statiques, elles seront recopiées telles quelles au sein du fichier généré. Les zones entourées des balises <% et %> sont des zones variables qui correspondent à l'évaluation de l'expression sur l'objet courant.
Autrement dit dans le fichier suivant l'expression <%title%> est automatiquement remplacée par le titre du Topic courant.
Vous pouvez d'ores et déjà expérimenter la réalisation de template, l'éditeur fourni avec Acceleo supporte la complétion syntaxique et la détection d'erreurs ce qui aide considérablement à la réalisation de templates de génération.
III-B. Prévisualisation du code généré▲
Maintenant que nous avons réalisé notre premier template, il est très pratique de voir le résultat d'une génération. En plus de l'éditeur de fichiers .mt Acceleo offre un outil extrêmement pratique pour la mise au point de templates de génération : l'éditeur réflectif.
Vous pouvez l'ouvrir en cliquant avec le bouton droit sur le fichier contenant la carte mentale (d'extension .mindmap) et en choisissant Open as->Acceleo XMI.
L'éditeur réflectif est associé par défaut aux fichiers d'extension « xmi », « ecore », « uml » et « uml2 ». Dans le cas où votre modèle utilise une autre extension vous pouvez l'ouvrir avec l'éditeur réflectif en utilisant le menu « Open As -> Acceleo ».
Le modèle est alors représenté sous une forme arborescente. On y retrouve la carte mentale, les Topic et les Relationship liant les topics entre eux.
L'éditeur réflectif permet la prévisualisation en temps réel du code généré. Une fois le modèle ouvert dans l'éditeur réflectif il faut lui associer le template créé précédemment. Cliquez sur « Acceleo » -> « Select Template » dans l'éditeur réflectif et choisissez le template de génération que nous avons réalisé.
Une fois le template sélectionné, des marqueurs apparaissent dans la vue « Outline » de l'éditeur réflectif.
Ces marqueurs signifient que le template peut générer un fichier pour chacun des objets marqués.
Lorsque l'on sélectionne un Topic disposant de ce marqueur l'éditeur réflectif affiche une prévisualisation du code généré dans l'onglet « source » (sur la gauche).
Modifiez le template de génération, choisissez dans l'éditeur réflectif Acceleo -> Reload Template et l'onglet source sera mis à jour.
En itérant de cette manière vous pouvez affiner le contenu des fichiers générés. Nous allons maintenant détailler de manière plus précise la syntaxe des expressions entre balises <%%>.
La syntaxe des expressions est une notation pointée extrêmement simple. Elle est contextuelle au type de l'objet courant. Ainsi l'expression suivante évaluée sur un objet de type Map
ownedTopics
fournit la liste de tous les Topics contenus dans la carte mentale.
L'expression suivante :
ownedTopics.title
renvoie la liste des titres des topics contenus dans la carte mentale.
La figure suivante détaille un cas concret d'utilisation : on souhaite générer le contenu des Topic (sous la forme de paragraphes). Ainsi on itère sur la liste des Thread contenus dans le Topic.
Pour chacune des itérations, on génère une division qui contiendra autant de paragraphes que le Thread contient de ThreadItem.
Ensuite dans le script content, on traite le cas où le Topic possède un certain nombre d'autres sous-topics. Ils apparaissent alors sur ce slide sous la forme de divisions.
La ligne
subTopics.target.itemTopic
déclenche l'appel d'un sous-script : « itemTopic » pour chacun des subTopic du Topic courant.
La figure suivante montre un exemple de code généré via ces deux scripts.
III-C. Notation pointée et navigation dans le modèle▲
Nous allons désormais détailler un peu plus précisément le fonctionnement de cette syntaxe.
Par cette notation pointée, nous pouvons donc indifféremment accéder à des attributs des objets (récupérer le titre d'un Topic) ou accéder à d'autres objets liés au premier.
Ainsi dans l'exemple suivant le template
ownedTopics.topic2Xhtml
renvoie le code généré depuis tous les Topics par le script topic2Xhtml.
Il est également possible d'appeler de la même façon des services codés en Java. Un certain nombre de services utiles pour une navigation aisée dans le modèle sont fournis avec Acceleo. Il est également possible de coder ses propres services très simplement, nous en verrons un exemple plus loin.
ownedTopics.nFirst.topic2Xhtml
renvoie le code généré à partir du premier Topic par le script topic2Xhtml.
eAllContents("ThreadItem")
renvoie la totalité des objets de type ThreadItem contenus dans la descendance de l'objet courant.
Il est également possible de sélectionner certains éléments en fonction de critères par le biais du service select. Ainsi :
eAllContents("Topic").select("ownedThreads.nSize > 0")
sélectionne tous les descendants de type Topic contenant au moins un Thread.
Pour plus d'informations et pour avoir une liste détaillée des services fournis avec Acceleo, reportez-vous à la documentation de référence et aux projets d'exemple.
Documentation de référence Acceleo
Nous n'exposerons volontairement pas dans le détail la totalité des templates de génération ici. Vous êtes invité à faire vos propres templates en prenant exemple sur les projets de démonstration fournis.
IV. Notions avancées▲
IV-A. Génération massive des slides▲
Nous allons maintenant mettre en place la génération massive de fichiers. Notre générateur est constitué de trois templates :
slide.mt : génère pour chaque Topic le fichier XHTML correspondant au slide.
index.mt : génère pour chaque carte une page de titre des slides.
common.mt : définit des scripts communs utilisés par les deux templates précédents.
Il est possible d'importer des scripts au sein d'autres scripts par le biais de l'instruction import que l'on peut positionner dans l'entête du template.
Il est temps désormais de lancer une génération qui créera réellement les fichiers. Chaque script conduisant à la création d'un fichier possède un attribut file. Cet attribut est une expression évaluée sur l'objet courant.
Il est possible de lancer la génération sans avoir besoin de l'éditeur réflectif par le biais d'une chaîne de lancement (fichier .chain).
Créez une chaîne de lancement via le menu New->chain. Exécutez l'assistant, à la fin de ce dernier un fichier est créé, il permet l'enchainement de générations. Pour ajouter une opération de génération, il faut d'abord ajouter le template correspondant dans le repository du fichier.chain puis ajouter une nouvelle action de génération.
Modifiez le fichier afin d'obtenir un résultat similaire à la figure suivante.
Une fois le fichier .chain complété, vous pouvez cliquer avec le bouton droit dessus et choisir Launch. Ceci va déclencher le lancement de la génération et les fichiers vont apparaitre dans le répertoire slides.
Ainsi vous pouvez maintenant tester l'enchainement des différents slides et effectuer les ajustements nécessaires dans les templates.
IV-B. Génération incrémentale▲
Acceleo permet la génération incrémentale. Cela signifie qu'il est possible de compléter le code généré (ici du XHTML), puis de régénérer sans perdre les modifications apportées auparavant.
Le code pouvant être modifié par les développeurs est entouré de balises utilisateur. Ces balises ne polluent pas le code cible, car elles se présentent sous la forme de commentaires explicites. À la génération suivante, tout ce qui sera entre les deux balises sera conservé.
Nous allons ici définir une telle zone pour chaque slide afin que l'utilisateur puisse ajouter, par exemple, une illustration au sein d'un slide.
Relancez la génération. Modifiez le code généré entre ces deux balises. Régénérez, vous constatez que le code utilisateur n'est pas perdu.
IV-C. Ajustements▲
Nous allons maintenant réaliser quelques ajustements à notre génération. Le premier consiste est l'insertion de la date de génération dans les slides, ceci passe par la réalisation d'un service Java.
Pour créer un service Java, il suffit de placer un fichier .java dans le répertoire src du générateur.
Créez un nouveau package, nous le nommons ici « services ». Créez ensuite une nouvelle classe au sein de ce package.
Les méthodes de cette classe représentent autant de services qui peuvent être utilisés pendant la génération.
Le premier paramètre de la méthode représente l'objet sur lequel le service est disponible. Ainsi si l'on spécifie un type String, on ne pourra appeler le service que sur des chaînes de caractères.
La figure suivante détaille le service now(). Ce dernier renvoie une chaîne de caractères correspondant à la date courante.
Ce service est défini sur le type ENode. Cela signifie que l'on peut l'appliquer sur n'importe quel type d'objet. Le second service : « noSpecials » enlève tous les caractères spéciaux d'une chaîne. Ce dernier s'applique sur le type String.
Vous pouvez désormais importer ce service au sein du template par le biais de l'instruction import.
Le service now() est alors disponible.
IV-D. Résultat▲
Nous avons désormais un générateur de slides XHTML depuis une carte mentale. Vous pouvez vous faire une idée de la génération obtenue en consultant l'exemple de slides mis en ligne.
Cet exemple a pour but principal de faciliter la compréhension du fonctionnement d'Acceleo et de la mise en place de template de génération.
Nous avons ici généré du XHTML à partir d'un modeleur de carte à idées, le processus est exactement le même pour générer du code (Java, Python ou autre…). Des projets d'exemples sont disponibles sur le site d'Acceleo, ils contiennent des générateurs de code Java (DTO, DAO, Jsp) et présentent une utilisation plus poussée des templates et des services Java.
V. Conclusion▲
V-A. Industrialisation du développement et génération de code▲
L'utilisation de cette approche a de nombreux avantages. Elle apporte tout d'abord une certaine indépendance vis-à-vis de la plateforme technologique. Ainsi si nous souhaitons migrer nos slides vers une autre technologie (SVG par exemple) il suffit de réaliser un générateur pour SVG et l'on pourra indifféremment générer du XHTML ou du SVG.
De plus l'utilisation de templates de génération fait que le code généré est cadré et respecte donc les standards que l'on souhaite établir (tant d'un point de vue du formatage que de l'architecture).
Il est également important de noter que les templates permettent la capitalisation du savoir technique. En effet une personne sans connaissance particulière de XHTML sait désormais générer des slides via cette technologie en utilisant un générateur.
De plus la maintenance est facilitée, on obtient une vraie synchronisation entre le code et le modèle. Ce dernier passe du statut de modèle documentaire à celui de modèle productif.
Enfin cette approche couplée aux modeleurs spécifiques permet de définir son propre modeleur constitué d'un nombre réduit de concepts, juste assez riche pour permettre une génération intéressante et juste assez léger pour ne pas remplacer le code.
Ces modeleurs permettent d'avoir une vision plus proche des besoins fonctionnels, Acceleo permet l'exploitation et la valorisation de ces informations.