ObjectModel

authors : Arnaud Thimel
Florian Desbois
contact : eugene-devel@list.nuiton.org ou eugene-users@list.nuiton.org
revision : $Revision$
date : $Date$
Note
Ce document ne considère pas pour le moment les évolutions apportées par la version 2.0 d'EUGene.

TODO : revoir cette documentation

Introduction

Le générateur ObjectModelGenerator est prévu pour lire et analyser des modèles objets puis générer du code à partir de ceux-ci. En UML, un modèle objet est représenté par un diagramme de classe. Cette vision des modèles objet étant très répandue, elle sert de base à l'ObjectModelGenerator (il est à noter cependant que ce n'est pas obligatoire).

Partons donc du principe que l'on dispose d'un modèle (diagramme de classe) créé à l'aide d'un outil de modélisation au format XMI (XML Metadata Interchange).

La génération de code se fait ensuite en trois étapes :

  • Epuration du XMI en un code XML ne conservant que les informations utiles ;
  • Mise en mémoire du modèle simplifié ;
  • Application des templates / génération de code.

Epuration du modèle XMI

La plupart des outils de modélisation décrivent leur modèle en XMI. Or le XMI est trop verbeux pour être compréhensible aisement.

Eugene propose une tranformation XSLT permettant ainsi d'obtenir un XML épuré décrivant le modèle et ne conservant que l'essentiel des informations.

Ce modèle intermédiaire garantit aussi la stabilité et pérennité d'EUGene, puisque qu'on se base toujours sur les modèles d'EUGene et non pas directement sur les modèles extérieurs (XMI) trop variants d'une version à l'autre.

Si on veut supporter une nouvelle version de XMI par exemple, il convient de définir la feuille de style de transformation adéquate.

Parmi les informations extraites, on peut citer :

  • Objets (classes, classes abtraites, interfaces)
  • Attributs (nom, type, visibilité, ...)
  • Relations entre les classes (toutes multiplicités, navigabilité, classes d'association, ...)
  • Opérations (nom, type de retour, noms et types des arguments, exceptions levées, ...)
  • Stéréotypes

A partir du diagramme suivant :

On obtient un ObjectModel tel que :

Modèle mémoire

Une fois le XMI ramené à un XML compréhensible, le modèle est chargé en mémoire afin de subir la génération.

Ainsi, le modèle instancié est basé sur le diagramme de classes (méta-modèle) suivant :

Les interfaces disponibles pour les générateurs sont les suivantes :

ObjectModelGenerator :

Utilisation d'un fichier de consolidation du modèle

Il est possible d'utiliser un fichier supplémmentaire pour injecter au modèle mémoire des tagValues et stéréotypes supplémentaires.

Le fichier doit avoir le ême suffixe que le fichier contenant le modèle.

Par exemple avec un fichier model.zargo, on peut lui associer un fichier model.properties.

Ce fichier est utile quand on ne veut pas ajouter les tagValues dans le modèle zargo (car ensuite impossible d'avoir une vue synthétique de toutes les tagValues ou stéréotypes utilisés dans un modèle).

Ajout de tagValues

Les tagvalues peuvent être ajoutés à différents niveaux :

  • sur le modèle complêt
model.tagValue.version=1.0
  • sur un classifier
org.nuiton.eugene.tutorial.Hotel.tagValue.version=1.0
  • sur un attribut d'un classifier
org.nuiton.eugene.tutorial.Hotel.attribute.room.tagValue.version=1.0
  • sur une opération d'un classifier
org.nuiton.eugene.tutorial.Hotel.operation.enter.tagValue.version=1.0

Ajout de stéréotypes

Les stéréotypes ne peuvent pas être ajoutés au niveau du modèle mais sur :

  • les classifiers
org.nuiton.eugene.tutorial.Hotel.stereotype=unique
  • sur un attribut d'un classifier
org.nuiton.eugene.tutorial.Hotel.attribute.room.stereotype=unique
  • sur une opération d'un classifier
org.nuiton.eugene.tutorial.Hotel.operation.enter.stereotype=unique

TODO Voir comment ajouter plusieurs stéréotypes sur une même cible.

Connaître les tagValues et stéréotypes existants

L'utilisation des ModelPropertiesProvider permet de définir (et donc aussi de valider les tagValues et stéréotypes applicables).

Pour ne savoir plus sur ce concept voir ModelPropertiesProvider

Il suffit alors dans le module maven de génération d'appeler le goal available-data.

Exemple :

$ mvn eugene:available-data

[INFO] --- eugene-maven-plugin:xxx:available-data (default-cli) @ tutti-persistence ---
[INFO] Get datas for data types : [modeltype, writer, modelreader, modeltemplate, tagvalue, stereotype]

Found 2 modeltypes :
 [objectmodel] with implementation 'org.nuiton.eugene.models.object.xml.ObjectModelImpl'
 [statemodel] with implementation 'org.nuiton.eugene.models.state.xml.StateModelImpl'

Found 3 writers :
 [xmi] with implementation 'org.nuiton.eugene.plugin.writer.XmiChainedFileWriter
  inputProtocol             : xmi
  outputProtocol            : model
  defaultIncludes           : **/*.xmi
  defaultInputDirectory     : src/main/xmi
  defaultTestInputDirectory : src/test/xmi'
 [model2Java] with implementation 'org.nuiton.eugene.plugin.writer.ModelChainedFileWriter
  inputProtocol             : model
  outputProtocol            : null
  defaultIncludes           : **/*.*model
  defaultInputDirectory     : src/main/models
  defaultTestInputDirectory : src/test/models'
 [zargo2xmi] with implementation 'org.nuiton.eugene.plugin.writer.ZargoChainedFileWriter
  inputProtocol             : zargo
  outputProtocol            : xmi
  defaultIncludes           : **/*.zargo
  defaultInputDirectory     : src/main/xmi
  defaultTestInputDirectory : src/test/xmi'

Found 2 modelreaders :
 [objectmodel] with implementation 'org.nuiton.eugene.models.object.ObjectModelReader'
 [statemodel] with implementation 'org.nuiton.eugene.models.state.StateModelReader'

Found 5 modeltemplates :
 [org.nuiton.eugene.java.JavaInterfaceTransformer] with implementation 'org.nuiton.eugene.java.JavaInterfaceTransformer'
 [org.nuiton.eugene.java.JavaGenerator] with implementation 'org.nuiton.eugene.java.JavaGenerator'
 [org.nuiton.eugene.java.JavaEnumerationTransformer] with implementation 'org.nuiton.eugene.java.JavaEnumerationTransformer'
 [org.nuiton.eugene.java.SimpleJavaBeanTransformer] with implementation 'org.nuiton.eugene.java.SimpleJavaBeanTransformer'
 [org.nuiton.eugene.java.JavaBeanTransformer] with implementation 'org.nuiton.eugene.java.JavaBeanTransformer'

Found 7 tagvalues in 2 provider(s) : [eugene, java]

Provider [eugene] - Found 5 tagvalues :
 [constantPrefix] targets : 'ObjectModel, ObjectModelClassifier' : Sets the prefix of any constant to be generated for the given class
 [doNotGenerateBooleanGetMethods] targets : 'ObjectModel, ObjectModelClassifier' : To specify to NOT generate getXXX methods for boolean properties
 [documentation] targets : 'ObjectModel, ObjectModelElement' : Sets the documentation of a model or any of his elements
 [i18n] targets : 'ObjectModel, ObjectModelClassifier' : Sets the i18n prefix to use on I18n keys generated
 [version] targets : 'ObjectModel' : To set the version of the model.
Provider [java] - Found 2 tagvalues :
 [beanSuperClass] targets : 'ObjectModel, ObjectModelClassifier' : To specify a super-class to used on generated bean for a class or any class of a model
 [noPCS] targets : 'ObjectModel, ObjectModelClassifier' : To specify to not generate any propertyChange code for a class or any class of a model

Found 4 stereotypes in 2 provider(s) : [eugene, java]

Provider [eugene] - Found 3 stereotypes :
 [indexed] targets : 'ObjectModelAttribute' : To specify that a attribute is indexed
 [ordered] targets : 'ObjectModelAttribute' : To specify that a attribute is ordered
 [skip] targets : 'ObjectModelClassifier' : To specify that a classifier should not been generated.
Provider [java] - Found one stereotype :
 [bean] targets : 'ObjectModelClassifier' : To specify that a class is a JavaBean

Pour plus d'info sur ce goal

Application des templates

Chaque template est à lui seul un générateur qui hérite de ObjectModelGenerator. Toute partie de ce générateur peut donc être surchargée permettant ainsi une forte personnalisation des générateurs. Le rôle de l'ObjectModelGenerator est donc de parcourir le modèle et à chaque élément clé du modèle, (model, classes interfaces, classifier) les méthodes correspondantes sont appelées. Par défaut, ces méthodes décrites dans le générateur de base sont vide, et il n'en ressort donc aucun code généré. Les templates ont donc pour but de surcharger ses méthodes et de décrire le code qui va être généré.

Les templates peuvent être de toutes sortes car elles peuvent générer un fichier différent par modèle, par interface, par classe ou encore par classifier (souche commune aux classes et interfaces). De plus, elles peuvent indifféremment générer du code Java / XML ou encore tout autre type de code (texte ou autre...).