Tutoriel : surcharger proprement le code EMF généré

Olivier PROUVOST

Si vous utilisez EMF, vous avez sûrement déjà dû être confronté à la gestion du code surchargé. Cet article présente une solution propre et un outil permettant de générer une structure saine et indépendante pour tout le code modifié par le développeur. Pour réagir au contenu de cet article, un espace de dialogue vous est proposé sur le forum : Commentez

- Titre : Tutoriel : surcharger proprement le code EMF généré

- Auteur : Olivier PROUVOST

- Parution : 28 mars 2015

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2015 Olivier PROUVOST. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Les étapes de travail

- II-A. Règles de nommage

- II-B. Paramétrage du genmodel

- II-C. Création d'un répertoire 'src'

- II-D. Définition de la factory surchargée

- II-E. Implémentation de la factory surchargée

- II-F. Point d'extension 'factory_override'

- II-G. Utilisation de la factory dans le code

- II-H. Surcharge du code des interfaces

- II-I. Surcharge du code des classes

- III. Générer le code durant le build, dans Eclipse

- IV. Le plug-in 'genModelAddon'

- IV-A. Installer le plug-in

- IV-B. Utilisation du plug-in

- IV-C. Contribution au plug-in

- V. Conclusion

- VI. Remerciements

I - Introduction

EMF permet de générer le code Java à partir d'un modèle Ecore. En paramétrant un fichier .genmodel, on peut ainsi générer les trois couches de code : « model », « edit » et « editor », qui contiennent les sources Java permettant d'exploiter le modèle métier défini. La couche « model » contient toutes les interfaces et les implémentations correspondant au modèle métier. C'est uniquement de cette couche logicielle dont cet article va parler. En effet, c'est la couche la plus utilisée et la plus représentative du modèle. Les autres couches (« edit » et « editor ») sont utilisées pour obtenir des éditeurs graphiques ou arborescents et ont également leur manière d'être surchargées. Elles feront probablement l'objet d'un autre article.
Pour surcharger ces trois couches logicielles, la préconisation est d'utiliser la méthode consistant à modifier directement le code généré en ajoutant un « NOT » derrière les balises « @generated ».
Le plug-in « mint » (dans EMFTool) (1) , permet de distinguer les méthodes surchargées (en rouge), les méthodes ajoutées (en noir) et les méthodes générées (en bleu) :

Plugin Mint

Cette méthode peut être acceptable si peu de code est modifié, mais dans le cas de projets où beaucoup de code métier doit être ajouté, il est préférable de :

- séparer clairement le code généré du code développé ;

- générer le code automatiquement dès le process de build ;

- retirer le code généré de la gestion de configuration (CVS, SVN, GIT…) et le régénérer lors de la livraison.

EMF et Eclipse proposent des solutions simples pour répondre à ce besoin.

II - Les étapes de travail

La séparation du code généré et du code développé doit être préparée dès le début du projet. Elle consiste en 6 étapes :

- paramétrer le genmodel pour générer le code dans 'src-gen' et nommer correctement les classes et interfaces dans le code généré ;

- créer un répertoire de code source 'src' ;

- créer une nouvelle factory dans le répertoire 'src' ;

- déclarer cette factory en utilisant une extension de 'factory_override' ;

- étendre les classes et les interfaces générées selon les besoins ;

- instancier les nouvelles classes dans la nouvelle factory.

Les cinq dernières étapes sont réalisées par l'outil 'genModelAddon' présenté en fin de cet article qui analyse le fichier « .genmodel » et génère la structure de code attendue. Cet outil est expliqué dans la seconde partie de cet article.

II-A - Règles de nommage

Dans l'exemple décrit ci-dessous, nous utiliserons les nommages suivants, où {0} représente le nom de la EClass en cours de génération.

- M{0} : interface générée par EMF ;

- M{0}Impl : implémentation générée par EMF ;

- {0} : interface modifiée par le développeur (étend M{0}) ;

- {0}Impl : implémentation modifiée par le développeur.

II-B - Paramétrage du genmodel

Pour travailler proprement, il faut prendre des mesures d'étanchéité, en séparant clairement le répertoire du code généré de celui du code surchargé. Pour ce faire, on paramètre le genmodel de la manière suivante :

Paramétrage du genmodel

II-C - Création d'un répertoire 'src'

On crée ensuite un répertoire 'src' (source folder), dédié à la surcharge dans le projet. Le code généré étant stocké dans le 'src-gen' on peut dériver les classes et les interfaces dans le répertoire 'src'. On obtient alors l'organisation suivante :

Organisation des sources

II-D - Définition de la factory surchargée

Ce nouveau répertoire de source va contenir la nouvelle factory EMF pour créer les instances des classes surchargées. Cette factory dérive de la factory générée et propose des créations d'objets avec les nouvelles interfaces :

Factory surchargée

Afin de faciliter l'écriture du code, on surcharge également l'initialisation de l'eINSTANCE pour récupérer l'instance correcte de la factory. On complétera les méthodes de cette factory au fur et à mesure que l'on surchargera les classes du modèle généré.

II-E - Implémentation de la factory surchargée

L'implémentation de la factory est alors simplement :

Implémentation de la factory

II-F - Point d'extension 'factory_override'

Il ne reste plus qu'à relier cette nouvelle factory à EMF, en utilisant le point d'extension 'factory_override' :

Extension 'factory_override'

Pour finir, il faut ajouter le code d'initialisation dans l'implémentation de la factory afin d'appeler la prise en compte de cette extension (les méthodes de création des objets, décrites précédemment, ont été condensées pour l'affichage) :

Initialisation de la factory

II-G - Utilisation de la factory dans le code

Lorsqu'on utilise une factory EMF, l'usage veut qu'on appelle « MProjectFactory.eINSTANCE ». Cette instance sera initialisée correctement avec la nouvelle instance de factory, grâce à l'extension de factory_override. Toutefois, il sera nécessaire de caster cette instance dans le type ProjectFactory afin de travailler sur les nouveaux objets dérivés.
On utilisera donc la nouvelle instance initialisée correctement en appelant : ProjectFactory.eINSTANCE. On remplacera ainsi les appels à « MProjectFactory.eINSTANCE » par « ProjectFactory.eINSTANCE ».

II-H - Surcharge du code des interfaces

Les interfaces dérivant du code généré par EMF peuvent maintenant contenir des méthodes de confort (add, remove) :

Surcharge des interfaces

II-I - Surcharge du code des classes

On peut alors définir les méthodes de confort et les opérations au même endroit :

Surcharge des classes

III - Générer le code durant le build, dans Eclipse

Si on sépare totalement le code généré du code surchargé, il peut être intéressant d'automatiser la génération du code à partir du modèle. EMF nous propose une tâche Ant (emf.Ecore2Java) permettant de générer le code à partir d'un genmodel. Le fichier Ant à écrire est trivial :

Script Ant

Pour l'exécuter, il faudra faire attention d'utiliser le JRE du workspace (paramètre dans le lancement du build, dans l'onglet JRE). Ce fichier ant peut alors être intégré au builder du projet en le mettant en première position pour être sûr que le code généré sera présent pour la compilation :

Paramétrage du build

IV - Le plug-in 'genModelAddon'

La mise en œuvre des conseils de cet article peut être fastidieuse à effectuer, car elle est répétitive et doit s'appliquer à chaque classe du modèle. Le plug-in genModelAddon permet de générer toute la structure du code attendu instantanément.

IV-A - Installer le plug-in

Les sources du plug-in sont disponibles sur github à l'adresse :
https://github.com/opcoach/genModelAddon

Pour installer plus simplement le plug-in, un update site à jour est disponible sur la page de développement du site d'OPCoach :
http://www.opcoach.com/developpement-eclipse/travaux-de-developpement/

Il faut télécharger ce zip et l'installer comme tout update site zippé en sélectionnant 'Help->Install New Software?' puis 'Add update Site', 'Archive' et sélection du zip :

Installation de genModelAddon

IV-B - Utilisation du plug-in

Le plug-in ajoute un menu contextuel lorsque le fichier « *.genmodel » est ouvert. Pour l'afficher, il faut faire un clic droit sur l'élément racine du fichier (i.e. le genModel) :

Menu contextuel de génération

Remarque : il se peut que, dans certains cas, le menu n'apparaisse pas la première fois. Dans ce cas, il faut faire un clic droit sur le Epackage (en dessous), puis refaire un clic droit sur le genModel. Pour générer la structure, il faut donc :

- générer le code dans src-gen en utilisant la commande EMF 'Generate Model Code' ;

- puis générer le code dans src en utilisant la commande 'Generate Derived Source Folder' dans le menu OPCoach.

La commande de génération ouvre un dialogue rappelant les paramètres utilisés dans le genModel ainsi que les paramètres de nommage à utiliser dans le répertoire src. Des tooltips rappellent à l'utilisateur le sens de chaque paramètre :

Paramètres de génération

L'outil ayant pour but de régénérer les squelettes de code dans le répertoire src, il gère également la surcharge des fichiers en proposant à l'utilisateur la sélection des fichiers à générer s'ils existent déjà et en rappelant le code qui sera généré dans le tooltip associé :

Surcharge des fichiers

En cas de régénération, il est bien sûr conseillé de commiter le code avant, au cas où un fichier serait écrasé suite à un oubli dans le dialogue ci-dessus.

IV-C - Contribution au plug-in

Le projet étant hébergé sur github, il est possible d'y contribuer en créant des issues ou en proposant des pull requests :

- la page d'accueil du projet : http://opcoach.github.io/genModelAddon

- la page d'accueil sur github : https://github.com/opcoach/genModelAddon

- le fichier 'pom.xml' pour reconstruire le repository p2 se trouve dans le projet build/com.opcoach.genmodeladdon.repository

Vous pouvez également contacter l'auteur de cet article pour toute remarque ou question en utilisant le mail suivant : olivier.prouvost[at]opcoach[dot]com.

V - Conclusion

Dans cet article, nous avons étudié une bonne pratique pour la surcharge du code EMF généré. Nous avons aussi découvert un outil extrêmement pratique pour effectuer cette surcharge de manière automatisée et réduire encore le code écrit à la main et le risque d'erreur.

VI - Remerciements

Cet article a été publié avec l'aimable autorisation de la société OPCoach qui remercie également Alain BERNARD pour sa relecture et ses remarques. Merci aussi à ced pour sa relecture orthographique.

(1)Mint n'est plus mis à jour mais il fonctionne toujours. L'update site : Mint update-site