MDA par la pratique

Sébastien Arbogast

Ce document est une traduction aussi fidèle que possible du nouveau « Getting Started with AndroMDA for Java », disponible sur le site officiel d'AndroMDA à cette adresse : https://galaxy.andromda.org/docs/getting-started/java/index.html. Je remercie d'ailleurs chaleureusement son auteur original, Naresh Bhatia, po m'avoir autorisé à réutiliser son travail.

J'ai choisi de traduire ce document, plutôt que d'en écrire un moi-même pour plusieurs raisons ? =

- tout d'abord, le document original est de très grande qualité, comme toutes les productions de la formidable équipe d'AndroMDA, et que par conséquent, j'aurais difficilement pu faire mieux ;

- ensuite, parce qu'en tant qu'ingénieur de profession, je suis un fervent défenseur de l'intégration, de la réutilisation des connaissances, de préférence à une réinvention perpétuelle de la roue. Et dans la mesure où le document original me semblait très bien remplir son office en Anglais, il n'y avait pas de raison qu'il n'y parvienne pas tout aussi bien en Français ;

- enfin parce que pour vous, il sera bien plus facile d'obtenir du support et de l'aide dans la mesure où vous partirez sur les mêmes bases qu'une grande partie de la communauté et que l'application d'exemple sera également la même. Bien sûr, il n'y a pas (encore ?) à l'heure actuelle de communauté francophone autour d'AndroMDA, et si vous voulez poser des questions sur les forums, il vous faudra vous lancer dans la langue de Shakespeare. Mais j'espère au moins qu'une fois que vous aurez lu ce document, vous considérerez que cela en vaut la peine.

J'ai tout de même tenu à y mettre un peu mon grain de sel. En tant qu'utilisateur convaincu d'AndroMDA depuis un peu plus d'un an, et depuis quelques mois dans un cadre professionnel, j'ai ma propre expérience, mon propre regard sur certains aspects de cet outil. J'essaierai de vous faire partager cette vision, lorsque cela sera nécessaire, en incluant par-ci par-là, une note personnelle.

Pour finir cette petite introduction et avant de rentrer dans le vif du sujet, je tiens à insister sur le fait que votre retour d'expérience a beaucoup d'importance pour améliorer la qualité de ce document. Alors si vous avez remarqué des erreurs, des imprécisions de traduction, ou si vous voulez vous-même apporter votre grain de sel, n'hésitez pas à me contacter: sebastien.arbogast@gmail.com.

Ah oui ! Et puis si vous voulez imprimer cet article, vous pouvez aussi télécharger la version PDF.

Et si vous êtes à l'aise avec l'anglais et que vous désirez plus d'informations sur AndroMDA, je vous recommande le site du projet.

Je tiens à remercier tout spécialement Benoît Héricher pour son excellent travail de relecture et de correction de cet article, et pour son retour d'expérience.

- Titre : MDA par la pratique

- Auteur : Sébastien Arbogast

- Parution : 18 mai 2006

- Mise à jour : 29 juin 2020

- Licence : Cette création est mise à disposition sous un contrat Creative Commons.

Sommaire

- I. Introduction à AndroMDA pour Java : concepts d'architecture

- I-A. Architecture des applications

- I-B. L'architecture des applications générées par AndroMDA

- I-C. Propagation des données entre les couches

- I-D. Services et session Hibernate

- I-E. Et maintenant ?

- II. Présentation de l'application d'exemple et installation de l'environnement

- II-A. L'application d'exemple : TimeTracker

- II-B. Préparation de l'environnement de développement

- II-B-1. Installation de Java

- II-B-2. Installation de Maven

- II-B-3. Bilan des variables d'environnement

- II-B-4. Installation du plugin AndroMDA Application pour Maven

- II-B-5. Installation d'un éditeur UML

- Installation de MagicDraw

- II-B-6. Installation d'un système de gestion de bases de données

- II-B-7. Installation d'Eclipse (optionnelle)

- II-C. Création du projet TimeTracker

- II-D. Configurez l'application TimeTracker

- II-E. Configurez la base de données de TimeTracker

- II-E-1. MySQL

- II-E-2. PostgreSQL

- II-E-3. Oracle

- II-F. Téléchargement des dépendances de l'application

- II-G. Et maintenant ?

- III. Concepts de base : modélisation et développement de l'application d'exemple

- III-A. L'entité Person

- III-A-1. Modélisation

- MagicDraw UML

- III-A-2. Génération de code pour l'entité Person

- III-A-3. Création du schéma pour l'entité Person

- III-B. L'objet de valeur PersonVO

- III-B-1. Modélisation de PersonVO

- MagicDraw UML

- III-B-2. Génération de code pour l'objet de valeur PersonVO

- III-C. Le service PeopleService

- III-C-1. Modélisation du service PeopleService

- MagicDraw

- III-C-2. Génération de code pour le service PeopleService

- III-C-3. Implémentation des méthodes du service PeopleService

- handleCreatePerson()

- handleGetPerson()

- handleGetAllPeople()

- Imports

- III-D. Création de l'application console

- III-E. Bilan intermédiaire

- IV. Concepts avancés : finalisation de l'application

- IV-A. Création d'associations

- IV-A-1. Modélisation

- MagicDraw UML

- IV-A-2. Génération de code

- IV-B. Complétion du modèle de TimeTracker

- IV-B-1. Ajout des entités manquantes

- MagicDraw UML

- IV-B-2. Ajout de comportements personnalisés aux entités

- IV-B-3. Ajout des objets de valeur manquants

- IV-B-4. Ajout du service TimeTrackerService

- IV-B-5. Création du schéma

- V. Trucs et astuces : finition du client console

- V-A. Création des tâches

- V-B. Création de fiches de temps

- V-C. La suite des évènements

- VI. Ma conclusion

I - Introduction à AndroMDA pour Java : concepts d'architecture

Comprendre de nouveaux outils et de nouvelles technologies peut être une tâche effrayante. AndroMDA n'est pas une exception. Ce tutoriel vise donc à être une présentation en douceur de la puissance d'AndroMDA. Nous allons vous guider pas à pas dans l'installation de votre environnement de développement et bâtir une première application Java. Au lieu de passer mécaniquement à travers une série d'étapes, nous allons nous concentrer sur les idées et les concepts. Avec cette connaissance, vous serez prêt à affronter les défis du monde réel. Alors n'hésitez pas à mettre de côté une demi-journée ininterrompue de concentration pour comprendre les bases d'AndroMDA, parce qu'il y a beaucoup à apprendre. Et puis préparez-vous une bonne tasse de café avant de plonger avec nous dans le monde merveilleux de l'architecture pilotée par le modèle.

Vous allez découvrir beaucoup de choses au cours de ce voyage, beaucoup de concepts assez abstraits et d'éléments qui dépassent de loin les considérations de langages ou les détails d'implémentation. C'est d'ailleurs une chose qui effraie souvent ceux qui découvrent MDA pour la première fois : on se demande comment cela peut servir concrètement à quelque chose. C'est là que je vous demande de me faire confiance : encore une fois, j'utilise AndroMDA quotidiennement, sur mes projets personnels et professionnels, parce qu'il me permet de gagner du temps, tout en concevant des logiciels de meilleure qualité. Ça ne sera pas évident tout de suite, alors un peu de patience et à la fin, soit vous vous demanderez comment vous avez pu programmer avant, soit vous rejetterez tout en bloc. Mais au moins, dans le deuxième cas, ça sera en toute connaissance de cause. Quand les auteurs vous conseillent de vous réserver une demi-journée et de prendre un bon café, c'est pour évoquer cette patience et cette concentration du début : apprendre AndroMDA, c'est beaucoup plus court que d'apprendre un langage ou un framework, mais cela demande un peu plus de concentration et surtout d'ouverture d'esprit, parce que le but est de développer différemment. Alors en voiture… !

Commençons donc par passer en revue quelques concepts fondamentaux qui forment la base des applications d'entreprises moderne. Après avoir évoqué ces concepts, nous verrons comment AndroMDA les implémente dans les applications qu'il génère.

I-A - Architecture des applications

Les applications d'entreprises modernes sont communément basées sur l'utilisation de plusieurs composants, chacun fournissant une fonctionnalité particulière. Les composants qui fournissent des services similaires sont généralement regroupés en couches, eux-mêmes organisés en une pile dans laquelle les composants d'une couche donnée utilisent les services des composants de la couche en dessous (ou ceux des composants de la même couche).

Pour ceux qui seraient familiers avec la théorie des réseaux, vous connaissez certainement le modèle OSI (« Open Systems Interconnection »), ou alors vous aurez peut-être entendu parler de la « pile TCP/IP » ? Et bien l'architecture applicative en couches est basée sur les mêmes principes. Mais si vous n'en avez jamais entendu parler, peut-être comprendrez-vous mieux le principe avec les schémas ci-dessous.

Le diagramme ci-dessous illustre une structure en couches très populaire pour une application d'entreprise :

Architecture des applications d'entreprise

- La couche de présentation contient les composants qui doivent interagir avec l'utilisateur de l'application, comme les pages Web, les formulaires, ainsi que tout ce qui régit le comportement de l'interface utilisateur.

- La couche métier intègre les fonctionnalités et les traitements propres à l'application. Les fonctionnalités simples peuvent être implémentées avec des composants sans états, alors que les transactions complexes et longues peuvent utiliser des composants d'ordonnancement avec états. Les composants métier sont généralement dissimulés derrière une sous-couche d'interface de service qui agit comme une façade afin de dissimuler la complexité de l'implémentation. Cela participe de ce que l'on appelle communément une architecture orientée par les services (SOA = « Service-Oriented Architecture »).

- La couche d'accès aux données fournit une interface simple pour accéder aux données et les manipuler. Les composants de cette couche abstraient la sémantique de la couche de données sous-jacente, permettant ainsi à la couche métier de ce concentrer sur la logique applicative. Chaque composant fournit typiquement des méthodes pour créer, lire, mettre à jour et effacer (CRUD = « Create, Read, Update, Delete ») des entités de données.

- La couche de stockage des données comprend l'ensemble des sources de données de l'application d'entreprise. Les deux types les plus communs de sources de données sont les bases de données et les systèmes de fichiers.

Il est important de noter que ces couches ne sont que des regroupements logiques de composants qui constituent une application. La façon dont ces couches sont matérialisées dans un environnement matériel et logiciel réel peut varier de façon importante en fonction de plusieurs facteurs. Dans un scénario très simple, toutes ces couches peuvent résider sur une seule et même machine. Dans un autre un peu plus complexe (mais assez commun), la couche de présentation peut se trouver par exemple sur la station de travail de l'utilisateur final, les couches métier et d'accès aux données sur un serveur d'applications, et les bases de données sur un serveur dédié à cet usage.

Un argument que l'on entend souvent contre l'utilisation d'MDA en tant que concept est le fait qu'il s'adapte à très peu d'applications réelles, ce qui rend du même coup l'investissement en temps nécessaire à son apprentissage relativement peu utile. Pourtant, l'architecture d'application exposée ci-dessous est extrêmement courante : on parle souvent d'architecture n-tier pour la désigner, chaque tier correspondant à une couche. Et vous allez voir dans la suite de cet article comment MDA en tant que méthode, et AndroMDA en tant qu'outil, s'adaptent particulièrement dans cette situation courante et vous font gagner un temps précieux par rapport à une façon de faire plus traditionnelle, et même par rapport à l'utilisation de générateurs de code classiques.

I-B - L'architecture des applications générées par AndroMDA

Maintenant que nous avons évoqué les concepts de base derrière les applications d'entreprise modernes, voyons ensemble comment AndroMDA implémente ces concepts.

AndroMDA prend en entrée un modèle métier spécifié en UML (« Unified Modeling Language ») et génère des parties importantes des couches nécessaires pour construire une application Java. La faculté d'AndroMDA à traduire automatiquement des spécifications métier haut niveau en un code de qualité permet un gain de temps significatif dans l'implémentation d'applications Java.

En fait, l'idée qui se cache derrière MDA en tant que méthode, et donc derrière AndroMDA en tant qu'outil, c'est de se dire que la plus grande partie d'une application doit pouvoir être conçue indépendamment de la technologie utilisée pour l'implémenter. Le résultat de cet effort de conception, ce sont des modèles qui peuvent être spécifiées dans un langage standard, et lui aussi indépendant de la technologie d'implémentation : UML. Ensuite, la démarche la plus simpliste est de partir de ces modèles pour les traduire manuellement en leur implémentation en fonction de la technologie utilisée, ce qui est souvent très long et très facilement source d'erreurs inutiles et d'incohérences. Il se trouve justement qu'avec l'expérience, on a pu identifier des schémas de conception (plus connus dans leur dénomination anglophone de « design patterns ») génériques, qui permettaient de résoudre des problèmes classiques, de proposer une solution éprouvée qu'il suffisait de réutiliser. On s'est aussi rend compte que l'implémentation de ces modèles dans une technologie donnée était automatisable dans une certaine mesure. C'est ce que fait AndroMDA : il extrait toutes les informations qu'il peut d'un modèle UML, y applique un ensemble de modèles de conception et de paramètres de configuration pour produire tout le code générique d'une application, ne laissant au développeur qu'à boucher les trous en implémentant les parties qui n'ont pas pu être spécifiées dans le modèle, notamment parce qu'elles dépendaient de la technologie d'implémentation choisie. La part de code généré dans le code intégral de votre application dépend donc de deux facteurs : le niveau de détail de votre modèle et sa conformité avec les attentes d'AndroMDA d'une part, et le nombre et la qualité des modules de génération mis en œuvre par AndroMDA d'autre part. Ça peut encore vous paraître très abstrait, mais vous allez voir : c'est réellement bluffant, d'autant qu'on s'attend souvent à ce qu'un générateur de code produise un code assez « sale », parsemé de variables numérotées et autres commentaires codés. Mais avec AndroMDA, ce n'est pas du tout le cas grâce à ses importantes possibilités de configuration et à l'utilisation de modèles de conception standards.

Le diagramme ci-dessous met en correspondance les différentes couches applicatives identifiées précédemment avec les technologies Java supportées par AndroMDA.

Architecture des applications d'entreprise - Implémentation

- Couche de présentation : AndroMDA offre actuellement un choix entre deux technologies pour implémenter des couches de présentation web : Struts (plus d'infos ici et là, ou encore ici) et JSF. Il accepte en entrée des diagrammes d'activité UML pour spécifier les enchaînements de pages, et génère des composants pour les frameworks Struts ou JSF.

- Couche métier : la couche métier générée par AndroMDA est principalement consituée de services configurés en utilisant le framework Spring (plus d'infos ici). AndroMDA crée des méthodes vides dans les classes d'implémentation où la logique métier peut être ajoutée. Les services générés peuvent éventuellement être interfacés avec des EJB. Dans ce scénario, les services doivent être déployés dans un conteneur d'EJB comme JBoss AS. Les services peuvent également être exposés comme des WebServices, fournissant une interface indépendante de la plateforme aux clients qui souhaitent accéder à leurs fonctionnalités. AndroMDA peut aussi générer des processus et des ordonnancements métier pour le moteur d'ordonnancement jBPM (qui fait partie de la famille de produits JBoss).

- Couche d'accès aux données : AndroMDA s'appuie sur le très populaire outil de mapping objet relationnel Hibernate pour la génération de la couche d'accès aux données des applications. Il produit des objets d'accès aux données (DAO pour « Data Access Objects ») pour les entités définies dans le modèle UML. Ces objets d'accès aux données utilisent l'interface de programmation d'Hibernate pour convertir les champs de bases de données en objets et vice-versa.

- Bases de données : puisque les applications générées par AndroMDA utilisent Hibernate pour accéder aux données, vous pouvez utiliser n'importe quelle base de données supportée par Hibernate.

Deux choses importantes à ajouter après ce paragraphe. D'abord, puisqu’AndroMDA est totalement modulaire, il est fondamentalement extensible et il y a de très nombreuses possibilités d'ajout de modules qui génèreront une implémentation pour des technologies propres à votre environnement. Et comme AndroMDA est développé selon un modèle ouvert, la seule limite réelle c'est votre imagination. Bien sûr, développer certains plugins peut être une tâche ardue, mais tout est une question de rentabilité de l'investissement. D'ailleurs, l'équipe d'AndroMDA a créé récemment une nouvelle initiative pour coordonner et encourager la création de modules additionnels. Sachez par exemple qu'un effort important est en cours pour finaliser une pile de modules pour .NET, qui devrait à terme vous permettre de générer à votre convenance une application Java et/ou .NET à partir des mêmes modèles. Vous commencez à entrevoir l'intérêt ? Enfin, il est important de remarquer que, contrairement à certains générateurs de code classiques, AndroMDA ne se contente pas de générer des fichiers de classes Java : il génère également les fichiers de configuration XML traditionnellement nécessaires dans la plupart des frameworks Java, comme les fichiers de mapping d'Hibernate, les fichiers de description de beans de Spring ou encore les fichiers de configuration d'Axis. En fait, ce qui est étonnant, c'est qu'alors même que vous n'avez pas encore bouché les trous d'implémentation, simplement avec votre modèle, AndroMDA génère une application qui compile et peut déjà être déployée sans erreur dans un serveur d'applications ! Bien sûr il manque des fonctionnalités, mais toute l'infrastructure est prête.

I-C - Propagation des données entre les couches

Au-delà des concepts évoqués jusqu'à maintenant, il est important de comprendre comment les données se propagent entre les différentes couches d'une application. Commençons du plus bas niveau pour remonter.

Comme vous le savez sans doute, les bases de données relationnelles stockent les données comme des champs dans des tables. La couche d'accès aux données récupère ces champs depuis la base de données et les transforme en objets qui représentent les entités du domaine métier. C'est pourquoi on appelle ces objets des entités métier. La couche d'accès aux données passe les entités métier à la couche métier qui exécute sa logique sur ces entités.

Concernant la communication entre la couche métier et la couche présentation, il y a véritablement deux écoles de pensée. Certains recommandent que la couche de présentation puisse avoir un accès direct aux entités métier, tandis que d'autres préconisent l'inverse : les entités métier devraient être totalement isolées de la couche de présentation et la couche métier devrait encapsuler les données dans ce que l'on appelle des objets de valeur (« value objects ») avant de les transmettre à la couche de présentation. Essayons de comprendre les avantages et les inconvénients de ces deux approches.

La première approche (que des entités, pas d'objets de valeur) est plus simple à implémenter. Vous n'avez pas besoin de créer des objets de valeur ou d'écrire aucun code pour transférer l'information depuis les entités vers les objets de valeur. En fait, pour de petites applications simples où la couche de présentation et la couche métier s'exécutent sur la même machine, cette approche fonctionnera très bien. Mais pour des applications plus grandes et plus complexes, cette approche s'adapte mal, notamment pour les raisons suivantes :

- la logique métier n'est plus contenue exclusivement dans la couche métier. Il est alors tentant de manipuler directement les entités depuis la couche de présentation, et de disperser du même coup la logique métier dans des endroits différents, ce qui peut rapidement devenir un cauchemar en termes de maintenabilité. Et dans le cas où il y a plusieurs interfaces de présentation pour un service (par exemple une interface web, un client riche et un client mobile), la logique métier doit alors être dupliquée dans tous ces clients. De plus, il n'y a rien qui empêche les clients de corrompre les entités, intentionnellement ou pas ;

- lorsque la couche de présentation s'exécute sur une machine différente (par exemple dans le cas d'un client riche), il est complètement absurde de sérialiser tout un réseau d'entités pour l'envoyer au client. Prenons l'exemple de la présentation à l'utilisateur d'une liste de commandes. Dans ce scénario, nous n'avons pas besoin de transmettre tous les détails de chaque commande à l'application cliente. Tout ce dont le client a besoin, c'est d'un numéro de commande, d'une date et d'un montant total pour chaque commande. Ensuite, si l'utilisateur souhaite voir les détails d'une commande en particulier, nous pouvons toujours lui transmettre cette commande en entier ;

- passer des entités réelles au client peut poser un risque de sécurité. Voulez-vous que l'application cliente puisse toujours accéder au salaire dans une entité « Employé » ou à votre marge de profit dans une entité « Commande » ?

Les objets de valeur fournissent une solution pour tous ces problèmes. D'accord, il faut écrire un peu de code en plus, mais en échange vous obtenez une couche métier d'une solidité à toute épreuve qui communique efficacement avec la couche présentation. On peut voir les objets de valeur comme une vision contrôlée cohérente avec les besoins de votre application cliente. Notez d'ailleurs qu'AndroMDA fournit un support de base pour la transformation d'entités en objets de valeur (et vice-versa), comme vous allez le voir dans le tutoriel, un support qui va d'ailleurs encore une fois vous faire gagner beaucoup de temps.

I-D - Services et session Hibernate

Un autre concept-clé à propos des applications générées par AndroMDA est la relation forte entre les méthodes de services (c'est-à-dire les opérations exposées par un service) et les sessions Hibernate. Mais avant d'introduire ce concept, nous devons poser quelques bases.

Une session Hibernate est un objet construit à l'exécution de l'application qui permet à cette dernière de créer, lire, mettre à jour et supprimer des entités dans la base de données. Tant que cette session est ouverte, ces entités sont « attachées » à la session et vous pouvez naviguer de l'une à l'autre en utilisant les relations entre elles. Si au cours de cette navigation, vous faites référence à une entité qui n'est pas encore chargée en mémoire, Hibernate va automatiquement la charger pour vous : c'est ce que l'on appelle le chargement paresseux, ou « lazy loading ». Cependant, dès que vous fermez la session Hibernate, les entités en mémoire sont considérées comme « détachées », c'est-à-dire qu'Hibernate n'en a plus aucune connaissance. Vous êtes libre de garder des références vers de telles entités, mais Hibernate ne maintiendra plus le lien entre ces entités et la base de données, et en particulier il ne chargera pas les entités reliées en cas de besoin. Si vous essayez d'accéder à une telle entité accidentellement, vous obtiendrez d'ailleurs une exception « LazyInitializationException ».

Dans ce contexte, parlons de la relation entre une méthode de service et une session Hibernate. Quand une application client appelle une méthode de service, une nouvelle session Hibernate est automatiquement ouverte. Vous n'avez besoin d'écrire aucun code pour ça. De la même façon, lorsque la méthode de service est terminée, la session Hibernate associée est automatiquement fermée. En d'autres termes, la durée de vie d'une session Hibernate correspond exactement au temps d'exécution d'une méthode de service. En conséquence, les entités sont attachées à la session Hibernate pendant toute la durée de l'exécution de la méthode de service, mais pas au-delà. Donc si votre méthode de service retourne des entités, l'application client doit faire extrêmement attention à ne pas accéder à des entités reliées qui ne seraient pas déjà en mémoire. De toute façon, vous pouvez éviter tout cela en suivant la recommandation évoquée précédemment, c'est-à-dire en encapsulant toute l'information nécessaire dans des objets de valeur tant que la session est encore ouverte et passer ces objets de valeur à l'appelant comme valeur de retour. Autrement dit, considérez une méthode de service comme une frontière transactionnelle logique, et faites tout ce que vous avez besoin de faire à l'intérieur de la méthode de service avant de retourner les résultats comme des objets de valeur.

Une autre implication de la relation forte entre une méthode de service et une session Hibernate est que les applications clients ne devraient pas essayer de court-circuiter la couche de service et d'interagir directement avec les couches inférieures. Vous pourrez toujours vous débrouiller pour passer en force et accéder directement aux composants d'accès aux données, mais tôt ou tard vous aurez des problèmes.

I-E - Et maintenant ?

Maintenant que vous comprenez la théorie de base d'AndroMDA, le prochain article de cette série sera consacré à la description de l'application que nous allons implémenter dans ce tutoriel.

II - Présentation de l'application d'exemple et installation de l'environnement

II-A - L'application d'exemple : TimeTracker

Choisir un système de timetracking comme exemple est un peu délicat, parce que c'est une notion assez culturelle. Les pratiques de gestion des ressources humaines en termes de travail varient énormément en fonction des professions, des cultures d'entreprises et des pays. Pointeuse logicielle, TimeSheet, Timecard, ou parfois même pas de surveillance du tout. Alors pour ceux qui ne seraient pas familiers de ce concept, sachez qu'il est assez fréquent dans les métiers du développement logiciel (entre autres), les horaires de travail n'étant pas fixes, que les entreprises tiennent un décompte des heures de leurs employés. L'application d'exemple de ce tutoriel utilise justement le concept de fiche horaire hebdomadaire, l'employé remplissant chaque semaine une fiche qui indique de quelle heure à quelle heure il a travaillé et sur quelle(s) tâche(s). Moi-même, en tant que consultant, je dois remplir une timesheet papier (avec seulement un décompte des jours travaillés par client) tous les mois pour ma société, et une fiche horaire mensuelle pour mon client grâce à un logiciel interne. Tout ça pour vous dire que même si ça peut ne rien vous évoquer, c'est un exemple très concret. Et peut-être qu'un jour, la société qui vous emploie sera rachetée par un grand groupe américain qui décidera de mettre en place un tel système, et que vous pourrez alors brandir fièrement votre première application construite avec MDA :oP

La société « Tartempion SA » utilise un système papier pour la gestion du temps de travail de ses employés. Ce procédé est complètement inefficace et par conséquent, votre supérieur vous a demandé de créer un système de gestion du temps en ligne appelé TimeTracker. Malheureusement, il veut que le système lui soit livré avant la semaine prochaine et si vous ne pouvez pas remplir cet objectif, il confiera cette tâche à quelqu'un d'autre. Tout d'un coup vous vous souvenez d'une conversation avec un ami qui ne tarissait pas d'éloges à propos de cet outil, AndroMDA, capable de générer des parties importantes d'une application à partir des spécifications fonctionnelles. Alors là vous vous dites « Si c'est vrai, cela devrait m'aider à atteindre mes objectifs. Allez, faisons un essai avec AndroMDA. » Alors vous acceptez l'offre de votre directeur et vous mettez au travail.

Votre première étape consiste à rencontrer la directrice des ressources humaines. Vous lui demandez de vous décrire le procédé de gestion du temps actuel, et elle vous dit ceci :

« Au début de chaque semaine, chaque employé prend une nouvelle fiche dans la salle des fournitures. Comme ils travaillent sur des tâches différentes, ils marquent leurs heures de début et de fin de travail sur cette fiche. Chaque tâche est munie d'un identifiant unique répertorié dans le manuel de l'employé. À la fin de la semaine, les gens soumettent leur fiche à leur supérieur pour vérification et approbation. Un directeur peut soit approuver, soit rejeter la fiche. S’il choisit de la rejeter, il doit laisser un commentaire sur la fiche indiquant la raison de ce rejet. L'employé qui a soumis la fiche en question doit alors apporter les corrections nécessaires et la soumettre à nouveau. »

Vous demandez alors poliment à la directrice qu'elle vous fournisse une copie d'une fiche typique, et voici ce qu'elle vous remet :

Copie d'une fiche de pointage typique

Oui, je sais, là aussi ça fait un choc : travailler la nuit et enchaîner 19h avec simplement une pause d'une heure après 15 heures de travail acharné… ça fait réfléchir. J'ai pourtant recopié exactement la fiche du document original. Rappelons pour l'anecdote que le 20 janvier 2006 était un vendredi et que le sieur John Smith/Alain Durand aura eu une fin de projet mouvementée. Ce qui fait peur, c'est que vous avez demandé à votre DRH une « fiche typique »…

Armé de cette connaissance, vous avez hâte de vous atteler à la tâche alors vous vous précipitez à votre bureau : il est temps maintenant d'installer l'environnement de développement nécessaire.

II-B - Préparation de l'environnement de développement

Avant de pouvoir commencer à développer avec AndroMDA, il va vous falloir installer votre environnement de développement en suivant les instructions ci-dessous. Nous partons du principe que vous travaillez sur une plateforme Windows.

Si ce n'est pas le cas, les auteurs ont sans doute estimé qu'en tant qu'utilisateur de Linux, de MacOSX ou d'un autre système encore plus exotique, vous disposiez des connaissances suffisantes pour adapter ces instructions à votre environnement. Pour ma part, travaillant sur Windows principalement, ma connaissance des autres systèmes est relativement limitée. Néanmoins j'essaierai de vous donner des indications complémentaires lorsque je l'estimerai utile et que ça reste dans mes compétences.

II-B-1 - Installation de Java

Téléchargez et installer le JDK 5.0 depuis cette adresse: http://java.sun.com/j2se/1.5.0/download.jsp. Il s'agit de la version recommandée, mais AndroMDA supporte également le JDK 1.4. Si vous préférez cette version, vous pouvez la télécharger à cette adresse: http://java.sun.com/j2se/1.4.2/download.html

Si vous n'avez aucune raison particulière pour vous limiter à la version 1.4 du JDK, je vous recommande vivement de vous lancer avec la version 5.0. Néanmoins, considérez bien l'ensemble de votre infrastructure de développement et posez-vous notamment les questions suivantes: est-ce que l'outil de modélisation que je compte utiliser est compatible avec le JDK5 (sachant que la plupart de ces outils sont eux-mêmes programmés en Java)? Est-ce que le serveur d'applications sur lequel vous comptez déployer votre application s'exécute sur une machine virtuelle Java 5 (qu'il s'agisse de JBoss, ou alors de Tomcat, sachant que Tomcat 5.5 par exemple est prévu pour Java 5 mais nécessite un plugin pour s'exécuter sur le JDK 1.4) ? Bien sûr, il est toujours possible de configurer tous ces outils pour s'accommoder des différentes versions, mais par expérience, il est préférable de choisir la configuration optimale pour assurer une bonne stabilité.

Une fois le JDK installé, assurez-vous que la variable d'environnement JAVA_HOME pointe bien vers le répertoire racine de votre installation du JDK. Il est possible que cette variable ait déjà été initialisée lors de l'installation du JDK. Mais voici comment vous assurer qu'elle l'est correctement :

1. Rendez-vous dans le panneau de configuration et cliquez sur l'icône « Système ». Si vous utilisez Windows XP il est possible que vous ayez à cliquer sur l'icône « Performance et maintenance » avant de voir l'icône Système ;

2. Cliquez sur l'onglet « Avancé » et cliquez sur le bouton « Variables d'environnement » ;

3. Assurez-vous que la variable apparait bien dans la section « Variables utilisateur pour… » et qu'elle pointe bien vers le répertoire racine du JDK. Sinon, ajoutez ou modifiez la variable pour lui donner la bonne valeur. Par défaut, le JDK est installé dans « C:\Program Files\Java\jdk1.5.0 ». Vous pouvez ajouter la variable soit à la section utilisateur, soit aux variables système.

Par défaut MacOSX Tiger 10.4.X est livré avec la version 1.4.2 du JDK, mais le JDK 5 est disponible en téléchargement manuel à l'adresse suivante: http://www.apple.com/support/downloads/java2se50release3.html. Pour plus de détails concernant Java sur MacOSX, voici une adresse utile: http://developer.apple.com/java/. Pour ce qui est de l'environnement Linux, il y a un guide d'installation complet à cette adresse: http://java.sun.com/j2se/1.5.0/install-linux.html. L'affectation de la variable d'environnement JAVA_HOME est semble-t-il spécifique à votre distribution et au shell que vous utilisez. Je vous laisse requérir à vous sources d'informations habituelles pour trouver cette information.

II-B-2 - Installation de Maven

Maven est un outil de gestion et d'intégration de projets logiciels. Il s'appuie sur le concept de modèle objet de projet (POM) pour gérer la construction, les rapports et la documentation d'un projet à partir d'une source d'informations unique. Nous allons maintenant installer Maven et le configurer pour télécharger les dépendances depuis le serveur d'AndroMDA quand le moment sera venu.

Maven (http://maven.apache.org/) traverse actuellement une période de transition très importante: la version 1.0.2 est la dernière version stable de Maven 1, qui a depuis été complètement réécrit pour donner naissance à Maven 2. Le problème, c'est que Maven 2 comporte des changements tellement importants (pour le meilleur, croyez-moi) qu'il n'est pas compatible avec les versions précédentes. En particulier, les plugins développés pour Maven 1 ne sont plus compatibles avec Maven 2 et doivent eux aussi être adaptés, voire réécrits. C'est notamment le cas des plugins AndroMDA pour Maven qui sont en cours d'adaptation pour Maven 2, et qui devraient être disponibles dans la version 3.2 d'AndroMDA. Dès que ce sera le cas, j'essaierai de mettre ce tutoriel à jour.

1. Téléchargez Maven 1.0.2 depuis ce site: http://maven.apache.org/maven-1.x/start/download.html. Notez bien que les versions ultérieures de Maven ne sont pas encore supportées par AndroMDA.

2. Installez la librairie téléchargée. Nous supposerons que vous l'avez installée dans « C:/Program Files/Apache Software Foundation/Maven 1.0.2 ».

3. Si l'assistant d'installation se plaint que la variable d'environnement JAVA_HOME n'existe pas, alors assurez-vous que vous l'avez correctement initialisée.

Sur les machines Linux, ainsi que très vraisemblablement sur le système MacOSX, l'installation de Maven implique 3 étapes: d'abord il vous faudra extraire l'archive téléchargée dans le dossier d'installation de votre choix. Ensuite vous devrez initialiser la variable d'environnement MAVEN_HOME et la faire pointer sur ce dossier. Enfin, il vous faudra créer le référentiel local en exécutant la commande suivante: $MAVEN_HOME/bin/install_repo.sh $HOME/.maven/repository. Pour vérifier que l'installation de Maven fonctionne correctement, il vous suffit d'exécuter la commande suivante: maven -v

II-B-3 - Bilan des variables d'environnement

À l'issue de l'installation de Java et de Maven, voici les variables d'environnement qui doivent être initialisées:

Propriété

Valeur

Requise?

JAVA_HOME

Répertoire d'installation de Java. Par exemple: C:\Program Files\Java\jdk1.5.0

Oui

MAVEN_HOME

Répertoire d'installation de Maven. Par défaut: C:\Program Files\Apache Software Foundation\Maven 1.0.2. Cette variable a pu être déjà initialisée par l'installeur.

Oui

MAVEN_OPTS

Paramètres à transmettre à la machine virtuelle Java lorsqu'il exécute Maven. Affectez la valeur suivante à cette variable: -XX:MaxPermSize=128m -Xmx512m (requis pour compiler les gros projets Maven et notamment AndroMDA)

Non

PATH

Nécessaire pour que le système retrouve les exécutables en ligne de commandes. Normalement, cette variable d'environnement système existe déjà et il vous suffit d'y ajouter ceci: %JAVA_HOME%/bin;%MAVEN_HOME%/bin;

Oui

II-B-4 - Installation du plugin AndroMDA Application pour Maven

Nous allons maintenant télécharger et installer le plugin AndroMDA Application dans le référentiel local de Maven. Ce module permet la création de squelettes de projet Java utilisant AndroMDA. C'est le seul élément d'AndroMDA que nous aurons besoin d'installer explicitement. Tous les autres artefacts, comme les cartridges AndroMDA, seront automatiquement téléchargés grâce aux scripts Maven générés par ce plugin.

Avant de pouvoir installer les plugins Maven pour AndroMDA, nous devons lui indiquer où trouver le référentiel d'AndroMDA. Pour ce faire :

- rendez-vous dans votre dossier personnel. Si votre nom d'utilisateur est « foo », ce dossier se trouve dans « C:\Documents and Settings\foo ».

- créez-y un fichier appelé « build.properties » et ajoutez-y la ligne suivante. Cette ligne indique à Maven d'aller chercher les artefacts sur le serveur d'AndroMDA en plus du référentiel standard sur ibiblio:

maven.repo.remote=http://www.ibiblio.org/maven,http://team.andromda.org/maven

Pour installer le plugin AndroMDA Application, ouvrez une fenêtre de console et exécutez la commande suivante. Assurez-vous d'obtenir un message « BUILD SUCCESSFUL » à la fin de l'exécution.

maven plugin:download -DgroupId=andromda -DartifactId=maven-andromdapp-plugin -Dversion=3.2-RC1

Notez que maven-andromdapp-plugin-3.2-RC1.jar est maintenant installé dans MAVEN_HOME/plugins (C:\Program Files\Apache Software Foundation\Maven 1.0.2\plugins dans notre exemple).

Il est important de noter que le cycle de publication d'AndroMDA s'appuie sur le principe de distribution, c'est-à-dire que tous les composants d'AndroMDA évoluent en parallèle avec le même numéro de version. Il est d'ailleurs intéressant de faire tout de suite un point sur la politique de versions d'AndroMDA. Le numéro de version d'AndroMDA respecte un schéma à 2 chiffres séparés par un point: majeure.mineure. La dernière version stable publiée est la version 3.2-RC1, RC signifiant Release Candidate. La prochaine version publiée sera la version 3.2. Pendant la période de développement actif, ce numéro de version est complété par un SNAPSHOT signifiant que la distribution évolue de jour en jour. Vous vous rendrez vite compte qu'AndroMDA évolue de façon relativement dynamique, même s'il est vrai que la version 3.1 commence à prendre un peu d'âge. En ce moment, les défis sont nombreux pour l'équipe de développement, avec l'intégration du support des nouvelles versions d'UML (UML2), de Maven (Maven 2) et de Java (Java 5), sans parler du fait qu'AndroMDA 4.0 est déjà en cours de conception pour intégrer des nouveautés majeures telles que la modélisation agile ou encore les transformations de modèle à modèle. Pour finir, il est important de signaler que l'équipe de développement d'AndroMDA a adopté un processus d'intégration continue qui fait que toutes les versions SNAPSHOT sont testées et validées en permanence, ce qui les rend relativement stables et encourage de nombreux utilisateurs à travailler directement avec la dernière SNAPSHOT. Cependant, par expérience, j'ai tendance à éviter cette pratique dans la mesure où les soubresauts ne sont pas inexistants. Dans un cadre personnel, rien ne vous empêche d'utiliser la dernière SNAPSHOT, mais dans un cadre professionnel, je vous recommande de vous en tenir à la dernière version stable, d'autant que les nouvelles fonctionnalités de la SNAPSHOT ne sont pas toujours documentées au fur et à mesure.

II-B-5 - Installation d'un éditeur UML

Nous allons maintenant installer un outil qui va nous permettre de modéliser nos applications en UML et d'exporter ces modèles dans un format qu'AndroMDA peut comprendre. AndroMDA supporte actuellement UML 1.4 et le format d'exportation XMI 1.2. Suivez les instructions d'un des paragraphes ci-dessous pour installer l'outil de votre choix. (Nous invitons les éditeurs d'outils et les projets Open Source à tester leurs outils avec AndroMDA et à fournir les instructions d'installation pour être incluses dans cette section).

À ce stade, vous vous demandez probablement quel outil installer. Dans les faits, AndroMDA travaille avec des modèle UML1.4 exportés en XMI 1.2 STANDARD. Je me permets d'insister sur le mot « STANDARD », car de nombreux outils de modélisation UML parmi les plus populaires proposent une option d'exportation en XMI, mais dans une version complètement non standard, faite pour vous obliger plus ou moins à ne pas pouvoir travailler sur votre modèle avec d'autres outils que le leur. Dans les faits donc, les éditeurs UML qui exportent en XMI standard sont assez rares. Dans la pratique, AndroMDA est développé avec MagicDraw, un produit commercial de la société No Magic. Pour en avoir testé de nombreux, je peux vous assurer que MagicDraw est de loin l'outil qui s'intègre A CE JOUR le plus harmonieusement avec AndroMDA, sans parler du fait qu'il propose une ergonomie relativement simple, mais redoutable pour être vraiment productif. Heureusement, dernièrement le projet Open Source ArgoUML a connu un regain d'activité, doublé d'un intérêt marqué pour une intégration poussée avec AndroMDA. ArgoUML pourrait donc devenir un jour l'outil Open Source qui manquait à la boîte à outils ouverts gravitant autour d'AndroMDA. Mais dans les faits, cette intégration n'est pas encore finalisée, ce qui me pousse à vous recommander fortement de préférer MagicDraw, au moins dans une première phase d'approche, d'autant que puisqu'une très large majorité de la communauté utilise cet outil, il vous sera plus facile d'obtenir du support concernant son utilisation avec AndroMDA.

À l'origine, le tutoriel prévoyait des explications sur la modélisation avec ArgoUML, une alternative Open Source à MagicDraw UML. Malheureusement, à un moment donné, un bug est notoire est apparu dans la dernière version stable pour l'ajout de valeurs balisées. Par conséquent, j'ai supprimé toutes les sections concernant ArgoUML pour l'instant. Je les réintègrerai dès qu'une nouvelle version d'ArgoUML aura résolu ce bug.

Installation de MagicDraw

Ce paragraphe vous indique comment télécharger et installer MagicDraw 9.5, un outil pour créer des modèles UML. n'oubliez pas que la version 10 de MagicDraw permet de créer des modèles respectant le standard UML 2.0 exportés en XMI2.1. Ces versions ne sont pas encore supportées par AndroMDA.

Veuillez noter que MagicDraw est un produit commercial, mais une édition gratuite « communauté » (Community Edition) est disponible. La version « communauté » n'est pas Open Source. Voici un extrait du fichier lisez-moi de la « community edition »: « MagicDraw édition communauté est une version gratuite pour les développeurs travaillant sur les projets non commerciaux. » À noter également que le projet AndroMDA n'est en aucun cas affilié avec MagicDraw.

Voici les instructions pour installer MagicDraw UML 9.5 Community Edition (avec Service Pack 1) :

1. Rendez-vous sur le site FTP de MagicDraw: ftp://ftp.magicdraw.com/pub/MagicDraw/community_edition/9.5_sp1/ [ftp://ftp.magicdraw.com/pub/MagicDraw/community_edition/9.5_sp1/];

2. Téléchargez et installez l'installeur qui convient à votre machine :

1. MD_UML_95_sp1_CE_win.exe est destinée aux machines sous Windows.

2. MD_UML_95_sp1_CE_unix.sh est la version recommandée pour une installation sur Unix et Linux,

3. MD_UML_95_sp1_CE_mac.dmg est la version pour MacOS,

4. MD_UML_95_sp1_CE_no_install.zip est adaptée à toutes les plateformes (il suffit de décompresser l'archive) ;

3. Suivez simplement les instructions de l'installeur automatique.

MagicDraw a de nombreux avantages, comme le fait qu'il est traduit en Français, qu'il dispose d'une interface que je trouve personnellement très claire et efficace (mais bon en même temps les goûts et les couleurs) et ce malgré le fait qu'il implémente UML 1.4 avec une rigueur et un sens du détail qui pousse à l'insolence. Mais malheureusement c'est vrai, le version Communauté est assez limitée, notamment au niveau des diagrammes de cas d'utilisation et d'activité, utilisés abondamment par les cartridges BPM4Struts et JSF. Pour une utilisation avancée d'AndroMDA, vous vous rendrez donc vite compte que cette version est assez restreinte. Deux choix s'offriront alors à vous: soit vous migrez vers ArgoUML, complètement Open Source et donc illimité (malgré quelques maladresses dans l'implémentation d'UML), soit vous faites l'acquisition d'une licence personnelle pour la modique somme de 125€ pour l'Union européenne (ou alors même d'une licence académique pour 42€ si vous êtes étudiant). Entendons-nous bien, je ne fais absolument pas de publicité ici, je n'ai aucun intérêt chez No Magic et je ne touche pas de commission. Je vous donne uniquement ces informations à titre… informatif! Pour plus de détails, n'hésitez pas à consulter http://www.magicdraw.com.

II-B-6 - Installation d'un système de gestion de bases de données

Nous allons maintenant installer un système de bases de données supporté par Hibernate. Pour connaître la liste des systèmes supportés, il suffit de vous rendre à cette adresse: http://www.hibernate.org/260.html. À partir de maintenant, nous partirons de l'hypothèse que vous avez installé un des systèmes suivants. Si ce n'est pas le cas, il vous faudra modifier les fichiers de configuration d'AndroMDA en fonction de votre installation.

- MySQL 5.0 : MySQL est un système de gestion de bases de données (SGBD) Open Source. Vous pouvez le télécharger à l'adresse suivante: http://dev.mysql.com/downloads/mysql/5.0.html. Nous vous recommandons de télécharger la version intégrale, et pas seulement les « Essentials ». Par la même occasion, n'hésitez pas à télécharger et à installer MySQL Administrator (http://dev.mysql.com/downloads/administrator/1.1.html) et MySQL Query Browser (http://dev.mysql.com/downloads/query-browser/1.1.html). Il s'agit d'interfaces graphiques qui vous faciliteront grandement la gestion de vos bases de données. Enfin téléchargez et décompressez MySQL Connector/J (le pilote JDBC pour MySQL, disponible ici: http://dev.mysql.com/downloads/connector/j/3.1.html). Dans le répertoire de votre choix. Dans la suite, nous supposerons que vous avez installé ce pilote dans C:\Program Files\MySQL\mysql-connector-java-3.1.12

- PostgreSQL 8.1 : PostgreSQL est un SGBD Open Source. Vous pouvez le télécharger à cette adresse: http://www.postgresql.org/ftp/binary/v8.1.2/win32/. L'installation de Postgres comprend une interface graphique d'administration appelée pgAdmin III. Les pilotes JDBC font également partie de l'installation.

- Oracle 9i : Oracle 9i est un SGBD commercial de la société Oracle. Nous supposons que vous disposez des supports de distributions nécessaires à son installation. Oracle 9i intègre un outil administratif graphique appelé Enterprise Manager. Les pilotes JDBC sont également inclus dans l'installation.

Pour ma part, et puisque je me suis donné comme mission de vous aider à choisir, je ne peux que vous recommander de choisir entre les deux options suivantes: si vous avez l'intention de travailler sur des projets Open Source en priorité, vous serez très satisfait par MySQL 5 qui rattrape définitivement son retard par rapport à ses concurrents commerciaux et qui est très facile à utiliser. Si vous envisagez d'utiliser AndroMDA dans un cadre plus professionnel, la très grande pénétration d'Oracle dans ce domaine me pousse à vous orienter vers un système Oracle. Malheureusement, Oracle 9i est un enfer à installer (et encore bien pire à désinstaller), et se trouve être d'une lourdeur qui mettront vite à genoux votre petit portable. Heureusement, Oracle a lui aussi cherché à combler son retard dans le domaine des bases de données faciles à installer et à utiliser, en proposant Oracle 10i Express Edition. Pour la télécharger, rendez-vous à cette adresse http://www.oracle.com/technology/software/products/database/oracle10g/index.html et téléchargez puis installer « Oracle Database 10g Express Edition ». Cette version d'Oracle est beaucoup plus simple à installer et à utiliser que les versions professionnelles, sans vraiment sacrifier les fonctionnalités. De plus, elle est livrée avec une interface web d'administration très efficace. Et combinée avec l'excellent client graphique SQLDeveloper (http://www.oracle.com/technology/software/products/sql/index.html), vous obtenez un excellent environnement de travail qui vous permettra de vous familiariser en douceur avec Oracle avant de déployer votre application dans votre entreprise. Là encore, je n'ai aucun lien avec la société Oracle, et je ne vous parle de ces produits que parce qu'ils sont gratuits, nouveaux, puissants et que relativement peu de monde est au courant de ces nouvelles versions qui mettent Oracle, traditionnellement réputé pour être un système lourd et difficile à déployer et à administrer, à la portée du développeur indépendant, voire débutant. Pour ma part j'utilise Oracle 9i pour mes projets professionnels, et MySQL pour mes projets personnels.

II-B-7 - Installation d'Eclipse (optionnelle)

Eclipse est un environnement de développement intégré (EDI) populaire qui s'avère très utile pour le développement d'applications Java. AndroMDA ne requiert pas l'utilisation d'Eclipse. Néanmoins,nous vous en recommandons l'utilisation pour le développement dans la mesure où il vous aide à améliorer votre productivité. Vous pouvez télécharger Eclipse à cette adresse: http://www.eclipse.org/downloads/. Il vous suffit de double-cliquer sur le fichier téléchargé pour démarrer l'installation.

Eclipse est devenu un standard de facto dans la communauté des développeurs Java, notamment de par le fait que puisqu'il n'est pas qu'un EDI Java, il permet de développer en fait dans de très nombreux langages. Et la possibilité de développer des plugins rend ses possibilités quasi illimitées. De fait, au moment où j'écris ces lignes, un des développeurs d'AndroMDA est en train de travailler au développement du plugin Android/Eclipse, qui vise à intégrer AndroMDA dans Eclipse. Pour ma part, je ne fais pas partie des enthousiastes d'Eclipse dans la mesure où je fais partie des 5% de gens chez qui il plante sans arrêt (et dommage pour la productivité). C'est pourquoi je ne peux que vous recommander de jeter un œil, encore une fois à titre purement informatif, sur IntelliJ Idea (http://www.jetbrains.com/idea/), un produit commercial de la société JetBrains, qui vaut son pesant de cacahuètes (499$ pour une licence individuelle, 99$ pour une licence académique), mais qui bénéficie d'une version d'essai complète de 30 jours pour vous faire une idée, et éventuellement une licence Open Source gratuite si vous avez votre propre projet Open Source. Enfin voilà, je sais, « payant! cher! pas bien! », mais bon essayez-le et vous comprendrez ce que c'est un vrai « gain de productivité » :oP

II-C - Création du projet TimeTracker

Nous allons maintenant pouvoir créer un squelette d'application en utilisant le plugin AndroMDA. Plus tard, nous ferons évoluer cette application de base pour ajouter de façon incrémentale les fonctionnalités de pointage. Notez que l'application TimeTracker complète est disponible dans les distributions sources et binaires, sous /samples/time-tracker-java. Nous vous recommandons de garder l'application complète sous la main au cas où vous ressentiriez le besoin de réparer votre propre version.

Quelques petites choses avant de commencer :

- faites attention à bien suivre les instructions de ce tutoriel très précisément. Ne prenez AUCUN raccourci, faute de quoi vous risquez juste de perdre du temps. Il y a une raison à chaque étape dans le tutoriel. Vous ne trouverez rien de superflu ici ;

- il est recommandé que vous utilisiez Firefox ou Internet Explorer 7 pour parcourir ce tutoriel. Internet Explorer 6 ne permet pas de sélectionner du texte correctement dans les pages de tutoriel ce qui complique la copie de code.

Bien entendu, cette dernière remarque n'est pas d'actualité pour la version française du tutoriel, à cause de la plateforme technique de documentation. La version anglaise utilise les capacités de génération de documentation de Maven, alors que cette version utilise le mécanisme maison de Developpez.com. Donc, normalement ça ne devrait pas poser de problème pour faire des copier-coller depuis Internet Explorer 6. Par contre, je ne pouvais pas m'empêcher de laisser cette remarque, ne serait-ce que pour vous encourager à utiliser Firefox si vous ne le faites pas déjà. Croyez-moi, je ne suis pas un de ces fanatiques néo-réac qui vous diront que tout ce qui n'est pas Microsoft est forcément mieux. Mais dans les faits, surtout pour un développeur, Firefox est de loin le meilleur navigateur qui existe à l'heure actuelle. Et puisque c'est gratuit, vous n'avez rien à perdre à l'essayer, alors: http://www.mozilla-europe.org/fr/products/firefox/. Un autre outil qui pourrait vraiment vous être utile si vous travaillez en ligne de commandes sous windows: « Open Command Window Here Powertoy for Windows XP » est un petit plugin pour Windows XP signé Microsoft qui ajoute une commande au menu contextuel et qui vous permet d'ouvrir un interpréteur de commandes qui pointe directement sur un dossier de votre choix. Ça évite beaucoup d'appels nostalgiques aux vieilles commandes DOS (cd et dir pour ne pas les nommer). Vous le trouverez à cette adresse: http://download.microsoft.com/download/whistler/Install/2/WXP/EN-US/CmdHerePowertoySetup.exe.

Allez, nous sommes maintenant prêts à démarrer. Créez l'application de départ en suivant les étapes suivantes :

1. Ouvrez un interpréteur de commandes et rendez-vous dans le dossier où vous désirez créer le dossier de l'application. Dans cet exemple, nous avons choisi le répertoire C:\. L'application sera créée dans le dossier C:\timetracker ;

2. Maintenant, exécutez la commande suivante pour générer le squelette d'application. Répondez aux questions exactement de la manière indiquée dans la saisie d'écran suivante. La seule chose que vous pouvez modifier est votre propre nom en réponse à la première question :-).

C:\>maven andromdapp:generate
__  __
|  \/  |__ _Apache__ ___
| |\/| / _` \ V / -_) ' \  ~ intelligent projects ~
|_|  |_\__,_|\_/\___|_||_|  v. 1.0.2

Please enter your first and last name (i.e. Chad Brandon):
Sebastien Arbogast
Please enter the name of your J2EE project (i.e. Animal Quiz):
TimeTracker
Please enter the id for your J2EE project (i.e. animalquiz):
timetracker
Please enter a version for your project (i.e. 1.0-SNAPSHOT):
1.0-SNAPSHOT
Please enter the base package name for your J2EE project (i.e. org.andromda.samples):
org.andromda.timetracker
Would you like an EAR or standalone WAR (enter 'ear' or 'war')?
ear
Please enter the type of transactional/persistence cartridge to use (enter 'hibernate', 'ejb', or 'spring'):
spring
Would you like to use the jBpm workflow engine, it uses Hibernate3 (enter 'yes' or 'no')?
no
Please enter the hibernate version number  (enter '2' for 2.1.x or '3' for 3.0.x):
3
Would you like a web application? (enter 'yes' or 'no'):
yes
Would you like your web tier to use JSF or Struts? (enter 'jsf' or 'struts'):
struts
Would you like to be able to expose your services as web services? (enter 'yes' or 'no'):
no
build:start:

andromdapp:init:

andromdapp:generate:
[echo] +---------------------------------------------------------------------+
[echo] |   G E N E R A T I N G   A n d r o M D A   J 2 E E   P R O J E C T   |
[echo] +---------------------------------------------------------------------+
[mkdir] Created dir: C:\timetracker
[copy] Copying 1 file to C:\timetracker
andromdapp:init:

andromdapp:generate-app-subproject:
andromdapp:generate-module:
[mkdir] Created dir: C:\timetracker\app
[copy] Copying 2 files to C:\timetracker\app

[mkdir] Created dir: C:\timetracker\app\src\META-INF

andromdapp:init:

andromdapp:generate-spring-subproject:
[mkdir] Created dir: C:\timetracker\core
andromdapp:init:

andromdapp:generate-core-subproject:
andromdapp:generate-module:

[mkdir] Created dir: C:\timetracker\core\src\java
[mkdir] Created dir: C:\timetracker\core\target\src

andromdapp:init:

andromdapp:generate-common-subproject:
andromdapp:generate-module:
[mkdir] Created dir: C:\timetracker\common

[mkdir] Created dir: C:\timetracker\common\src\java
[mkdir] Created dir: C:\timetracker\common\target\src

andromdapp:init:

andromdapp:generate-mda-subproject:
[mkdir] Created dir: C:\timetracker\mda\src\uml
[copy] Copying 1 file to C:\timetracker\mda\src\uml
[mkdir] Created dir: C:\timetracker\mda\conf
[copy] Copying 1 file to C:\timetracker\mda
[mkdir] Created dir: C:\timetracker\mda\conf\mappings

andromdapp:init:

andromdapp:generate-web-subproject:
andromdapp:generate-module:
[mkdir] Created dir: C:\timetracker\web

[mkdir] Created dir: C:\timetracker\web\src\java
[mkdir] Created dir: C:\timetracker\web\target\src

[echo] |
[echo] |  New J2EE project generated to: 'C:\/timetracker'
[echo] |
[echo] |  For more information on how to proceed from here read 'C:\/timetracker/readme.txt'
[echo] |
BUILD SUCCESSFUL
Total time: 7 minutes 10 seconds
Finished at: Sat Apr 08 14:34:40 CEST 2006

C:\>

Examinez les différents dossiers et fichiers créés par le plugin andromdapp. Vous remarquerez l'existence de fichiers appelés project.xml, maven.xml et project.properties dans différents dossiers sous timetracker. Ces fichiers correspondent à plusieurs projets Maven. En fait, le répertoire timetracker contient une hiérarchie de projets Maven comme ceci:

timetracker
|
|-- mda
|
|-- common
|
|-- core
|
|-- web
|
+-- app

- Timetracker : Il s'agit du projet principal qui contrôle le processus de construction et les propriétés génériques.

- Mda : Le projet mda est le sous-projet le plus important de l'application. Il comprend le modèle UML de TimeTracker, enregistré dans le répertoire src/uml. C'est également dans le projet mda qu'AndroMDA est configuré pour générer les fichiers nécessaires à l'assemblage de l'application.

- Common : Le sous-projet common rassemble les ressources et les classes qui sont partagées par plusieurs autres sous-projets. Cela inclut notamment les objets de valeur et les énumérations.

- Core : Le sous-projet core contient les ressources et les classes qui utilisent le framework Spring, et éventuellement Hibernate et/ou des EJB. Il s'agit notamment des classes d'entités, des objets d'accès aux données, des fichiers de mappage Hibernate et des fabriques de composants Spring.

- Web : Le sous-projet web comprend les ressources et les classes qui constituent la couche de présentation.

- App : Le sous-projet app englobe les ressources et les classes requises pour construire l'archive .ear.

À ce stade, vous pourriez avoir peur devant le nombre impressionnant de sous-projets impliqués. Et encore nous n'avons pas activé les WebServices ou encore la gestion des processus métier. Pour autant, par expérience, seul le sous-projet core va faire l'objet d'une attention toute particulière. En effet, les éléments générés dans le sous-projet common n'ont généralement besoin d'aucune personnalisation, le dossier app ne servira qu'à personnaliser la configuration du paquetage pour Jboss, ce qui est inutile dans la plupart des cas. Le sous-projet web ne sera utile que lorsque nous utiliserons la cartouche Bpm4Struts, ce qui n'est pas prévu dans ce tutoriel, mais dans un prochain. Quant au dossier mda, il ne sera utile qu'à deux choses: éditer le modèle UML et personnaliser la configuration d'AndroMDA. Ne vous laissez donc pas distraire: dans ce tutoriel, tout va essentiellement se passer dans le sous-projet core. Il est enfin intéressant de remarquer que cette organisation en multiprojet vous permet d'avoir un projet modulaire. Par exemple, lorsque vous désirerez mettre vos services à disposition en Web Services, il vous suffira de rajouter ce module qui pourra réutiliser le module core, sans avoir à redévelopper toute la logique métier de votre application.

Vous pourrez trouver plus de détails sur le contenu du projet TimeTracker dans le fichier readme.txt, à la racine du dossier timetracker. Ce fichier contient également une description des cibles Maven utiles pour le projet.

Dans la mesure où MDA est une démarche originale dans le monde du développement en général, il est fort probable que si votre projet est amené à être manipulé par d'autres personnes, celles-ci ne soient pas formées aux subtilités d'AndroMDA comme vous allez l'être grâce à ce tutoriel. Par conséquent, ces personnes risquent très bien de vouloir aller modifier directement des fichiers sources générés, ou encore de réarranger l'organisation du projet à leur sauce, sans tenir compte de la configuration d'AndroMDA. Dans ce contexte, le fichier readme.txt est une base de documentation minimale qui permettra à n'importe qui de compiler et d'utiliser votre projet. Pensez-y avant de l'effacer ;o)

II-D - Configurez l'application TimeTracker

Nous allons apporter une légère adaptation de configuration pour simplifier l'implémentation de TimeTracker. Au lieu d'une couche de présentation utilisant une interface Web qui passe par les EJB pour communiquer avec la couche de services, nous allons d'abord créer un client en ligne de commande qui communique directement avec la couche de services. Voici les étapes à suivre pour désactiver les EJB.

1. Éditez le fichier de configuration d'AndroMDA qui se trouve dans le dossier timetracker\mda\conf\andromda.xml.

2. Dans l'espace de nommage (ou « namespace ») spring, commentez les propriétés appelées « dataSource » et « session-ejbs ».

Voici la section correspondante dans le fichier andromda.xml une fois modifié :

<namespace name="spring">
<properties>
<!--<property name="dataSource">${dataSource}</property>-->
<property name="username">${dataSource.user}</property>
<property name="password">${dataSource.password}</property>
<property name="driver">${dataSource.driver.class}</property>
<property name="connectionUrl">${dataSource.url}</property>
<property name="hibernateDialect">${hibernate.db.dialect}</property>
<property name="hibernateShowSql">${hibernate.db.showSql}</property>
<property name="hibernateQueryUseNamedParameters">true</property>
<property name="sessionFactory">org.springframework.orm.hibernate3.LocalSessionFactoryBean</property>
<property name="localTransactionManager">org.springframework.orm.hibernate3.HibernateTransactionManager</property>
<property name="hibernateCacheProvider">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernateQueryCacheFactory">org.hibernate.cache.StandardQueryCacheFactory</property>
<property name="hibernateInheritanceStrategy">${hibernate.inheritance.strategy}</property>
<property name="springTypesPackage">${application.package}</property>
<property name="daos">${maven.andromda.core.generated.dir}</property>
<property name="dao-impls">${maven.andromda.core.manual.dir}</property>
<property name="spring-configuration">${maven.andromda.core.generated.dir}</property>
<property name="services">${maven.andromda.core.generated.dir}</property>
<property name="service-impls">${maven.andromda.core.manual.dir}</property>
<property name="enableSpringTransactionsWhenEjbsEnabled">true</property>
<!-- to remove any dependency on EJB, comment the following property -->
<!--<property name="session-ejbs">${maven.andromda.core.generated.dir}</property>-->
<!-- uncomment to enable EJB security
<property name="securityRealm">${application.id}</property>
-->
</properties>
</namespace>

Voilà qui nous donne l'occasion d'une petite introduction au fichier de configuration d'AndroMDA, ainsi qu'à la façon dont AndroMDA est construit. AndroMDA étant le fruit d'une équipe d'expérience, qui utilise AndroMDA dans un cadre professionnel, le concepteur même d'AndroMDA, Matthias Bohlen étant lui-même un architecte logiciel expérimenté, vous vous rendrez rapidement compte qu'AndroMDA est construit selon les mêmes principes intelligents qu'il préconise pour vos projets. L'aspect le plus marquant de cela, c'est qu'AndroMDA est fondamentalement modulaire et extensible. À chaque module fonctionnel d'AndroMDA correspond notamment un espace de nommage, ou « namespace ». Ces modules fonctionnels se présentent sous plusieurs formes, qui sont autant de possibilités d'extensions et de personnalisation. Le type de plugin le plus important est ce qu'on appelle les cartouches (ou « cartridges »). Chaque cartouche génère une partie de votre application pour une ou plusieurs technologies cibles données. Ainsi par exemple la cartouche Spring va pouvoir générer à partir de votre modèle UML l'ensemble des classes et des fichiers de configuration nécessaires au déploiement de votre application sur un serveur utilisant Spring pour la couche métier et Hibernate pour la couche de persistance des données (couple très populaire). Les cartouches Bpm4Struts et JSF quant à elles utilisent le même modèle de base pour générer la couche de présentation, mais pour des technologies cibles différentes (en l'occurrence respectivement Struts et Hibernate). Et bien entendu, ce ne sont pas les seules extensions possibles, puisqu'il est possible également de changer le moteur de génération (AndroMDA utilise Velocity par défaut), de développer de nouvelles métafaçades (certainement une des parties les plus avancées du développement d'AndroMDA: il s'agit des métamodèles UML utilisés par les cartouches), ou encore les librairies de traduction (pour pouvoir traduire les requêtes en OCL de votre modèle vers HQL ou EJB-QL par exemple). Je ne vous cache pas que le développement de ces différents composants additionnels requiert une connaissance approfondie d'AndroMDA et de son architecture, mais les développeurs du projet encouragent de plus en plus les utilisateurs à développer et à proposer leurs propres composants, notamment s'il s'agit de cartouches. Ils ont lancé pour cela le projet AndroMDA-Plugins sur SourceForge, et ils ont récemment publié une documentation en 10 étapes pour créer une nouvelle cartouche (http://www.andromda.org/index.php?option=com_content&task=blogcategory&id=35&Itemid=77). La communauté est donc très dynamique et en pleine expansion, ce qui laisse présager de choses très intéressantes pour l'avenir. Et pour en revenir au fichier de configuration, chaque cartouche est associée à un namespace, qui comprend lui-même une série de propriétés que l'on configure dans andromda.xml. Enfin pour être plus précis, l'usage veut que ce fichier contienne en fait des références vers des variables qui sont initialisées dans les fichiers project.properties. Il s'agit là à la fois d'une convention historique et d'une commodité visant à rassembler en un même lieu accessible et lisible depuis un simple éditeur de texte, à la fois les propriétés de Maven et celles d'AndroMDA. Bien sûr, avec la disparition des project.properties dans Maven2 il y a fort à parier que cette pratique va bientôt évoluer.

Nous allons encore appliquer une modification supplémentaire pour réduire la verbosité des messages de log de l'application.

1. Éditez le fichier C:/timetracker/mda/project.properties.

2. Changez la valeur de la propriété hibernate.db.showSql de true à false.

II-E - Configurez la base de données de TimeTracker

Configurons maintenant la base de données que vous avez choisie.

Créez un schéma et un utilisateur pour l'application TimeTracker en suivant les étapes ci-dessous. Dans ce tutoriel, nous supposerons que votre schéma s'appelle timetracker et que l'utilisateur timetracker y a accès. Toutefois vous êtes libre d'utiliser d'autres noms ou schémas préexistants dans votre base de données MySQL. Mais souvenez-vous de les adapter dans vos copier-coller sauvages ;o)

Si vous connaissez déjà votre système de bases de données et/ou que vous avez l'habitude d'utiliser votre propre outil d'administration ou même tout simplement la ligne de commande, la procédure générique est assez simple: il va vous falloir dans l'ordre créer un schéma timetracker, créer un utilisateur appelé timetracker avec pour mot de passe timetracker, lui affecter tous les droits sur le schéma timetracker, et enfin adapter le fichier timetracker\project.properties afin qu'elles reflètent votre environnement. Faites attention à ne pas vous tromper dans ces propriétés, notamment en ce qui concerne l'emplacement du driver JDBC, car la moindre erreur peut aboutir à des bugs systématiques de votre application qui n'arrivera pas à se connecter à votre base de données. Si vous n'êtes pas sûr de ce que vous faites, je vous recommande de bien recopier la section correspondant à votre environnement dans les paragraphes suivants.

II-E-1 - MySQL

1. Lancez MySQL Administrator et connectez-vous comme l'utilisateur root.

2. Cliquez sur « Catalogs » dans la barre de navigation à gauche.

3. Cliquez droit dans le panneau en bas à gauche (appelé « Schemadata ») et sélectionnez « Create New Schema ».

4. Saisissez le nom du schéma, par exemple timetracker, et cliquez sur OK.

5. Cliquez sur « User Administration » dans la barre de navigation à gauche.

6. Cliquez sur le bouton « New User » et ajoutez un nouvel utilisateur appelé « timetracker » et avec pour mot de passe « timetracker ».

7. Sélectionnez l'onglet « Schema Privileges » et cliquez sur le schéma timetracker.

8. Cliquez sur le bouton « << » pour conférer tous les privilèges à l'utilisateur timetracker sur le schéma du même nom, et cliquer sur le bouton « Apply Changes ».

9. Vous pouvez maintenant quitter MySQL Administrator si vous le souhaitez.

Éditez le fichier timetracker\project.properties et modifiez les valeurs des propriétés de base de données afin qu'elles correspondent à votre environnement. Un fichier project.properties figure ci-dessous pour l'exemple:

# set this to true will deploy the ear exploded
deployExploded=false

# The datasource for the application
dataSource.name=TimeTrackerDS
dataSource=java:/${dataSource.name}

# Properties for management of the database schema,
# ignore if you setup/drop your schema manually
dataSource.driver.jar=C:/Program Files/MySQL/mysql-connector-java-3.1.12/mysql-connector-java-3.1.12-bin.jar
dataSource.driver.class=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://127.0.0.1:3306/timetracker
dataSource.user=timetracker
dataSource.password=timetracker
dataSource.sql.init=core/target/schema-create.sql
dataSource.sql.drop=core/target/schema-drop.sql
dataSource.sql.load=core/target/db/create-dummy-load.sql
# What schema related goals should do when an error occurs.
dataSource.sql.onError=continue

# Change this to generate to the correct MDA database mappings
# For MySql use: MySQL
# For Hypersonic use: HypersonicSql
# For Oracle9i use: Oracle9i
sql.mappings=MySQL

# For MySql use: org.hibernate.dialect.MySQLDialect
# For Hypersonic use: org.hibernate.dialect.HSQLDialect
# For Oracle9i use: org.hibernate.dialect.Oracle9Dialect
hibernate.db.dialect=org.hibernate.dialect.MySQLDialect

II-E-2 - PostgreSQL

1. Lancez l'application pgAdmin III.

2. Double-cliquez sur « PostgreSQL Database Server 8.1 » pour vous connecter au serveur. Si cela vous est demandé, saisissez le mot de passe pour l'utilisateur postgres.

3. Cliquez droit sur « Login Roles » dans le panneau de gauche et sélectionnez « New Login Role ».

4. Saisissez timetracker comme nom de rôle et comme mot de passe.

5. Cochez la case appelée « Can create database objects ».

6. Cliquez sur OK pour créer l'utilisateur.

7. Cliquez droit sur « Databases » dans le panneau de gauche et sélectionnez « New Database ».

8. Saisissez timetracker comme nom de la base de données.

9. Sélectionnez timetracker comme propriétaire (« owner »).

10. Cliquez sur OK pour créer la base de données.

11. Vous pouvez maintenant quitter l'application pgAdmin si vous le souhaitez.

Voici le fichier timetracker\project.properties tel qu'il doit être adapté pour votre environnement.

# set this to true will deploy the ear exploded
deployExploded=false

# The datasource for the application
dataSource.name=TimeTrackerDS
dataSource=java:/${dataSource.name}

# Properties for management of the database schema,
# ignore if you setup/drop your schema manually
dataSource.driver.jar=C:/Program Files/PostgreSQL/8.1/jdbc/postgresql-8.1-404.jdbc3.jar
dataSource.driver.class=org.postgresql.Driver
dataSource.url=jdbc:postgresql://localhost:5432/timetracker
dataSource.user=timetracker
dataSource.password=timetracker
dataSource.sql.init=core/target/schema-create.sql
dataSource.sql.drop=core/target/schema-drop.sql
dataSource.sql.load=core/target/db/create-dummy-load.sql
# What schema related goals should do when an error occurs.
dataSource.sql.onError=continue

# Change this to generate to the correct MDA database mappings
# For MySql use: MySQL
# For Hypersonic use: HypersonicSql
# For Oracle9i use: Oracle9i
sql.mappings=PostgreSQL

# For MySql use: org.hibernate.dialect.MySQLDialect
# For Hypersonic use: org.hibernate.dialect.HSQLDialect
# For Oracle9i use: org.hibernate.dialect.Oracle9Dialect
hibernate.db.dialect=org.hibernate.dialect.PostgreSQLDialect

II-E-3 - Oracle

Notez que, dans le cas particulier d'Oracle, un schéma appelé timetracker sera automatiquement créé quand l'utilisateur timetracker commence à créer des objets de base de données dans votre instance de base de données.

1. Ouvrez « Enterprise Manager Console et connectez-vous en tant que »system".

2. Déployez votre instance de base de données dans le panneau de gauche.

3. Cliquez droit sur le nœud « Users » sous « Security » et sélectionnez « Create… ».

4. Saisissez timetracker comme nom d'utilisateur ainsi que comme mot de passe.

5. Sélectionnez l'onglet « Role » et donnez les privilèges CONNECT et RESOURCES à cet utilisateur.

6. Cliquez sur « Create » pour créer l'utilisateur.

7. Vous pouvez maintenant quitter Enterprise Manager si vous le souhaitez.

Voici le fichier timetracker\project.properties tel qu'il doit être adapté pour votre environnement.

# set this to true will deploy the ear exploded
deployExploded=false

# The datasource for the application
dataSource.name=TimeTrackerDS
dataSource=java:/${dataSource.name}

# Properties for management of the database schema,
# ignore if you setup/drop your schema manually
dataSource.driver.jar=C:/oracle/ora92/jdbc/lib/ojdbc14.jar
dataSource.driver.class=oracle.jdbc.OracleDriver
dataSource.url=jdbc:oracle:thin:@localhost:1521:nbdb1
dataSource.user=timetracker
dataSource.password=timetracker
dataSource.sql.init=core/target/schema-create.sql
dataSource.sql.drop=core/target/schema-drop.sql
dataSource.sql.load=core/target/db/create-dummy-load.sql
# What schema related goals should do when an error occurs.
dataSource.sql.onError=continue

# Change this to generate to the correct MDA database mappings
# For MySql use: MySQL
# For Hypersonic use: HypersonicSql
# For Oracle9i use: Oracle9i
sql.mappings=Oracle9i

# For MySql use: org.hibernate.dialect.MySQLDialect
# For Hypersonic use: org.hibernate.dialect.HSQLDialect
# For Oracle9i use: org.hibernate.dialect.Oracle9Dialect
hibernate.db.dialect=org.hibernate.dialect.Oracle9Dialect

II-F - Téléchargement des dépendances de l'application

Vous vous souvenez certainement que pour l'instant, nous n'avons téléchargé qu'un seul artefact d'AndroMDA. Il s'agissait du plugin AndroMDA Application. Et bien il est maintenant temps de se procurer les éléments restants. Nous allons le faire automatiquement en exécutant les scripts Maven générés plus haut. Ces scripts spécifient toutes les dépendances que l'application a vis-à-vis d'AndroMDA. Donc si nous les exécutons sur notre modèle vide, toutes les dépendances nécessaires seront rapatriées dans notre référentiel Maven. Bien sûr, puisque le modèle est blanc, aucun code ne sera généré. Toutefois, récupérer les dépendances maintenant est important puisque nous en aurons besoin très bientôt. Suivez les étapes ci-dessous pour télécharger les dépendances nécessaires.

1. Ouvrez une fenêtre de commandes et rendez-vous dans le répertoire C:\timetracker.

2. Exécutez la commande « maven install ». Vous verrez des messages sur votre écran vous indiquant que les artefacts sont en cours de téléchargement. Assurez-vous que vous obtenez un message « BUILD SUCCESSFUL » quand le script Maven se termine.

Voici un extrait de la sortie correspondant à l'exécution de cette commande:

C:/timetracker>maven install
__  __
|  \/  |__ _Apache__ ___
| |\/| / _` \ V / -_) ' \  ~ intelligent projects ~
|_|  |_\__,_|\_/\___|_||_|  v. 1.0.2

build:start:

install:
multiproject:install:
multiproject:projects-init:
[echo] Gathering project list
Starting the reactor...
...
+----------------------------------------
| Executing multiproject:install-callback TimeTracker MDA
| Memory: 4M/5M
+----------------------------------------
Attempting to download andromda-profile-3.2-RC1.xml.zip.
15K downloaded
Attempting to download andromda-profile-datatype-3.2-RC1.xml.zip.
18K downloaded
Attempting to download andromda-profile-webservice-3.2-RC1.xml.zip.
12K downloaded
Attempting to download andromda-profile-service-3.2-RC1.xml.zip.
13K downloaded
...
INFO  [App] BUILD SUCCESSFUL
INFO  [App] Total time: 2 minutes 48 seconds
INFO  [App] Finished at: Sat Jan 28 18:52:31 EST 2006
INFO  [App]
C:/timetracker>

Notez que la recherche et le téléchargement de toutes les dépendances depuis des référentiels distants vers votre machine peuvent prendre un certain temps. Toutefois, ce processus n'est pas requis à chaque fois que vous construisez le projet. Une fois que toutes les dépendances ont été téléchargées, nous utiliserons l'option -o de Maven pour les constructions à venir. Cette option demande à Maven de s'exécuter en mode hors-ligne, en utilisant les librairies du référentiel local. Ces constructions seront beaucoup plus rapides.

II-G - Et maintenant ?

Maintenant que nous avons créé l'application de base, il est temps de commencer à modéliser.

III - Concepts de base : modélisation et développement de l'application d'exemple

III-A - L'entité Person

III-A-1 - Modélisation

Dans cette section, vous allez créer votre toute première entité en utilisant AndroMDA. Puisque les gens sont au cœur de TimeTracker, nous allons commencer par modéliser une entité « Person ». Person a trois attributs: « username » (nom d'utilisateur), « firstName » (prénom) et lastName (nom de famille). Le modèle pour l'entité Person figure ci-dessous.

L'entité Person

Notez que nous avons marqué la classe Person avec le stéréotype « Entity ». Cela indique à AndroMDA que Person est une entité, et non pas un autre type d'éléments de modèle comme Enumeration ou Service. Les stéréotypes déterminent quel type de code AndroMDA génèrera pour un élément de modèle. Plus précisément, ils déterminent quels calques de génération de code AndroMDA seront utilisés.

Les stéréotypes et les valeurs balisées sont deux mécanismes de métadonnées prévus par la norme UML. AndroMDA les utilise abondamment et avec des rôles bien précis. Les stéréotypes sont utilisés pour préciser la nature des classes dans un modèle, alors que les valeurs balisées permettent de spécifier des informations propres à la technologie d'implémentation ciblée. Sans les stéréotypes et les valeurs balisées, les capacités d'AndroMDA ne dépasseraient pas celles d'un générateur de code classique. Mais ces mécanismes permettent de donner à AndroMDA des informations de haut niveau sur la nature des éléments modélisés, des informations qui ne sont pas disponibles par défaut dans le langage UML.

Les trois attributs sont de type String. Attention à ne pas confondre ce type avec le type java.lang.String. En architecture pilotée par le modèle, le modèle doit rester indépendant de la technologie d'implémentation et donc tous les éléments de modèle sont définis en termes de types indépendants de la plateforme. Donc « String » dans ce contexte est un type indépendant de la plateforme. Quand nous exécuterons AndroMDA pour générer le code, il traduira les types indépendants de la plateforme en types spécifiques à la plateforme comme java.lang.String. Si nous devions utiliser le même modèle pour générer une application .NET, AndroMDA traduirait String en System.String. Comme vous pouvez le voir, un avantage-clé de l'approche pilotée par le modèle est que votre investissement dans les modèles métier est préservé même lorsque les technologies d'implémentation changent.

Maintenant, intégrons l'entité Person dans le modèle vide créé par le plugin AndroMDA Application. Si vous vous souvenez, ce modèle a été créé dans timetracker\mda\src\uml\TimeTrackerModel.xmi. Les sections qui suivent détaillent les procédures de modélisation suivant l'outil UML de votre choix.

MagicDraw UML

Cette section fournit les instructions pour créer l'entité Person en utilisant MagicDraw. Le modèle apparait ci-dessous pour votre référence.

Diagramme de l'entité Person

1. Démarrez MagicDraw.

2. Sélectionnez Fichier > Ouvrir Projet… et ouvrez le fichier C:\TimeTracker\mda\src\uml\TimeTrackerModel.xmi.

3. Si vous obtenez un message d'avertissement vous signalant « Module andromda-profile-3.2-RC1.xml.zip non trouvé. », cliquez simplement sur OK. Une boîte de dialogue de recherche de fichier apparait pour vous permettre de localiser andromda-profile-3.2-RC1.xml.zip. Pour cela, rendez-vous dans votre référentiel local Maven, qui se trouve par défaut dans C:\Documents and Settings\<votre nom d'utilisateur>\.maven\repository. Vous trouverez andromda-profile-3.2-RC1.xml.zip dans ce référentiel, dans le répertoire andromda\xml.zips. Sélectionnez ce fichier et cliquez sur « Ouvrir ».

4. Le modèle de TimeTracker va maintenant s'ouvrir en affichant le seul diagramme de classes présent dans ce modèle. Le titre de ce diagramme est « DataTypes[datatype] ». Ce diagramme contient les types indépendants de la plate-forme destinés à être utilisés dans votre modèle UML.

5. Dans l'Arbre de Confinement sur la gauche, cliquez droit sur l'élément racine appelé Data et sélectionnez Nouvel Elément > Modèle. Un nouveau modèle est alors créé sous l'élément racine avec une boîte d'édition. Entrez-y TimeTracker comme nom pour ce modèle. MagicDraw intègre le concept de hiérarchie de modèles. Chaque modèle dans une hiérarchie peut être sauvegardé dans un fichier séparé. Cela permet à plusieurs développeur de travailler en parallèle sur des parties différentes d'un même modèle.

6. Maintenant, cliquez droit sur le modèle TimeTracker que vous venez juste de créer et sélectionnez Nouvel Elément > Paquet. Un nouveau paquet est alors créé sous le modèle TimeTracker avec une boîte d'édition. Entrez-y org.andromda.timetracker comme nom pour ce paquet. AndroMDA fera correspondre à ce paquet un package Java avec le même nom. Attention: vérifiez que le nom de paquet est exactement org.andromda.timetracker, sans aucun espace devant ou derrière. Nous avons découvert que certains navigateurs introduisent un espace avant dans le nom de paquet si vous le copiez depuis cette page!

7. Créez maintenant un paquet nommé « domain » sous « org.andromda.timetracker ». Nous créerons nos entités et les classes correspondantes dans ce paquet. À noter qu'AndroMDA n'impose absolument pas cette structure de paquets. Nous suggérons simplement cette organisation pour séparer les classes du domaine métier des autres classes comme les objets de valeurs, etc.

8. Dans l'Arbre de Confinement sur la gauche, cliquez droit sur le paquet « domain » et sélectionnez « Nouveau Diagramme > Diagramme de Classes ». Une boîte de dialogue « Diagramme de Classes Spécification » apparait. Saisissez « Objets du Domaine » comme nom pour ce diagramme et cliquez sur OK. Le diagramme est créé et ouvert dans une nouvelle fenêtre.

9. Dans la barre d'outils sur la gauche du diagramme de classes, cliquez sur l'icône « Classe » (sixième en partant du haut). Maintenant, cliquez n'importe où dans le diagramme. Une nouvelle classe est créée. Cette classe est automatiquement sélectionnée comme l'indiquent les quatre poignées aux coins. Si vous désélectionnez cette classe, il suffit de recliquer dessus pour la sélectionner à nouveau. Tapez maintenant « Person ». Ce mot est saisi comme étant le nom de la classe.

10. Ajoutons de la documentation à la classe Person. C'est toujours une bonne idée de documenter votre modèle. La documentation ajoutée aux éléments de modèles comme les classes, les attributs et les opérations seront transférés dans les commentaires du code généré. Double-cliquez sur la classe Person pour afficher la boîte de dialogue « Classe Spécification ». Ajoutez la phrase suivante dans le champ « Documentation » et cliquez sur OK: « Cette classe représentation toute personne donc le temps doit être surveillé. »

11. Maintenant, ajoutez le stéréotype « Entity » à la classe Person. Pour ce faire, cliquez droit sur la classe et sélectionnez « Editer stéréotype », puis cochez « Entity » et enfin cliquez sur « Appliquer ». La classe Person a maintenant le stéréotype Entity.

12. Ajoutons maintenant un attribut username à Person. Cliquez droit sur la classe Person et sélectionnez « Insérer Nouvel Attribut ». Un nouvel attribut est inséré avec la spécification « -sans nom1 ». Remplacez cette spécification par celle-ci: « +username : String » (faites bien attention à effacer le signe moins devant le nom). N'appuyez pas sur Entrée après avoir saisi cet attribut, car cela créerait un autre attribut. Cliquez plutôt en dehors de la classe pour terminer la saisie de l'attribut. Notez bien que les attributs sont toujours générés comme des membres privés d'une classe. Toutefois les visibilités des getter et setter associés sont déterminés par la visibilité de la spécification d'attribut. Ici nous avons spécifié une visibilité publique (en utilisant le signe plus) et donc l'accesseur et le mutateur de username seront publics.

13. Ajoutez maintenant deux attributs supplémentaires appelés firstName et lastName à la classe Person. Affectez-leur le type String.

14. Assurez-vous que votre diagramme correspond exactement à celui affiché ci-dessus. C'est normal si un compartiment opérations vide apparait dans votre classe. Il peut être caché très facilement.

15. Sauvegardez votre modèle TimeTracker en sélectionnant Fichier > Sauvegarder.

Félicitations! Vous venez de modéliser l'entité Person pour l'application TimeTracker. Nous sommes maintenant prêts à générer du code. Passez maintenant à la section 3.1.2.

III-A-2 - Génération de code pour l'entité Person

Suivez les étapes ci-dessous pour générer le code.

1. Ouvrez une fenêtre de commandes et rendez-vous dans le répertoire C:\timetracker.

2. Exécutez la commande « maven -o install ». Comme nous en avons parlé plus tôt, l'option -o demande à Maven de s'exécuter en mode « hors-ligne », en utilisant les librairies disponibles dans le référentiel local. Cela permet à la construction de s'exécuter beaucoup plus rapidement. Assurez-vous que vous obtenez un message BUILD SUCCESSFUL quand Maven termine son exécution.

Ouvrez le dossier C:\timetracker\core\target\src\org\andromda\timetracker\domain dans l'explorateur Windows. Vous pouvez constater qu'il y a 6 fichiers générés dans ce dossier, résultant de la création de la seule entité Person dans le modèle de l'application.

1. Person.java: Il s'agit de la classe abstraite de base qui implémente l'entité Person. Elle contient les 3 attributs du modèle ainsi que leurs accesseurs et mutateurs respectifs. AndroMDA ajoute automatiquement un attribut « id » qui représente l'identificateur unique pour les instances de Person dans la base de données. De plus, AndroMDA génère les méthodes equals() et hashCode() pour l'entité. Notez que la classe Person est abstraite, et que donc on ne peut pas l'instancier. La classe PersonImpl décrite ci-dessous est une classe concrète qui hérite de Person. Elle peut être instanciée en utilisant les méthodes de fabrique de la classe Person.

2. PersonImpl.java: Comment mentionné ci-dessus, PersonImpl est une implémentation concrète de la class Person. Elle est destinée à contenir tout le code personnalisé que les développeurs aimeraient ajouter à l'entité Person.

3. PersonDao.java: Pour n'importe quelle entité, les objets d'accès aux données sont générés comme un trio de classes: une interface, une classe de base abstraite et une implémentation concrète. PersonDao est l'interface pour l'objet d'accès aux données de l'entité Person. Elle spécifie les méthodes CRUD pour le DAO.

4. PersonDaoBase.java: PersonDaoBase implémente toutes les méthodes CRUD spécifiées dans l'interface PersonDao.

5. PersonDaoImpl.java: PersonDaoImpl est une extension concrète de la classe PersonDaoBase. Elle doit contenir tout le code personnalisé que les développeurs pourraient vouloir ajouter à l'object d'accès aux données de l'entité Person. C'est notamment dans cette classe que figureront plus tard les méthodes de transformation entre entité et objets de valeurs.

6. Person.hbm.xml: Il s'agit du fichier de mapping d'Hibernate qui fait correspondre l'entité Person à sa représentation dans une base de données relationnelle.

Il est important de remarquer que ces 6 fichiers sont générés dans le dossier target du projet core. Le dossier target n'est destiné qu'aux fichiers générés automatiquement. Aucun des fichiers dans ce dossier ne devrait être modifié manuellement, car la génération de code les écrasera complètement, annulant du même coup toutes vos modifications. Il est également recommandé de ne pas intégrer ce code dans votre gestionnaire de versions. Laissez plutôt votre script de construction le générer à la volée.

À présent, vous devez vous demander où ajouter du code personnalisé. Nous avons évoqué plus haut la possibilité pour les développeurs d'ajouter du code personnalisé dans PersonImpl.java et dans PersonDaoImpl.java. Mais pourquoi ces classes sont-elles générées dans le dossier target alors? Et bien cela vient du fait qu'AndroMDA est assez intelligent pour remarquer que vous ne lui avez donné aucune indication comme quoi vous vouliez écrire du code personnalisé. Aussi longtemps que cela sera vrai, il continuera à générer les classes d'implémentation dans le dossier target. Néanmoins, aussitôt que vous indiquerez à AndroMDA que vous désirez écrire du code personnalisé dans ces classes, il les génèrera dans le dossier src du projet core. Vous serez alors libre de modifier les classes d'implémentation et d'y ajouter n'importe quel code. À noter que dans ce cas, elles ne seront générées qu'une seule fois pour vous servir de base de travail. Plus tard dans ce tutoriel, nous vous montrerons comment écrire du code personnalisé.

III-A-3 - Création du schéma pour l'entité Person

En plus des classes d'entités et de DAO évoquées ci-dessus, AndroMDA génère automatiquement le script DDL pour créer les tables dans votre base de données. Ce script DDL est situé dans C:\timetracker\core\target\schema-create.sql. Ouvrez ce fichier et vérifiez son contenu. Vous devriez y voir le code SQL nécessaire pour créer la table PERSON. Suivez les étapes ci-dessous pour créer cette table dans votre base de données.

Notez que PostgreSQL n'aime pas trop la première instruction dans schema-create.sql (drop sequence hibernate_sequence). Il est conseillé de la commenter pour ce système.

1. Ouvrez une fenêtre de commandes et rendez-vous dans le dossier C:\timetracker.

2. Exécutez la commande « maven -o create-schema », qui va créer la table PERSON dans votre base de données. Utilisez vos outils de gestion de base de données pour vérifier que la table a effectivement été créée.

III-B - L'objet de valeur PersonVO

III-B-1 - Modélisation de PersonVO

Dans cette section nous allons créer l'objet de valeur PersonVO. Nous allons faire simple et garder une correspondance exacte entre l'objet de valeur et l'entité Person. Dans la suite de ce tutoriel, nous modéliserons des objets de valeur plus complexes qui correspondront à plusieurs entités.

Notez que nous avons ajouté une dépendance depuis Person vers PersonVO. Cette dépendance va générer du code utilitaire dans PersonDAO pour permettre la transformation entre entités Person et objet de valeur PersonVO. De plus, nous avons modélisé un nouveau type appelé PersonVO[]. Ce type sera utilisé comme valeur de retour dans nos méthodes de service.

Vous allez maintenant ajouter PersonVO et PersonVO[] à votre modèle. Pour ce faire, suivez les instructions du paragraphe correspondant à votre outil de modélisation.

MagicDraw UML

Cette page présente la marche à suivre pour créer PersonVO en utilisant MagicDraw. Le modèle apparait ci-dessous pour référence.

L'objet de valeur PersonVO dans MagicDraw

1. Dans le modèle TimeTracker, créez un paquet appelé « vo » sous « org.andromda.timetracker ». Nous allons créer tous nos objets de valeur dans ce paquet.

2. Dans l'arbre de confinement à gauche, cliquez droit sur le paquet « vo » et sélectionnez Nouveau Diagramme > Digramme de Classes. Entrez « Objets de Valeur » comme nom pour ce diagramme et cliquez sur OK. Le diagramme est créé et ouvert dans un nouvel onglet.

3. Depuis l'arbre de confinement sur la gauche, faites glisser la classe Person vers le diagramme. Attention, il est important de réutiliser la classe Person existante dans le paquet « domain ». NE CRÉEZ PAS UNE NOUVELLE CLASSE PERSON dans ce diagramme, faute de quoi vous créeriez une nouvelle classe Person dans le paquet vo, ce qui n'est pas notre intention. Tout ce dont nous avons besoin, c'est une référence vers la classe Person du paquet « domain ».

4. Ajoutez une nouvelle classe au diagramme et appelez-la PersonVO.

5. Ajoutez le stéréotype « ValueObject » à PersonVO.

6. Ajoutez 4 attributs à PersonVO comme indiqué dans le diagramme ci-dessus.

7. Sélectionnez l'icône « Dépendance » dans la barre d'outils latérale gauche (12e icône en partant du haut) ou appuyez sur la lettre « D » de votre clavier. Maintenant cliquez gauche sur la classe Person et faites glisser la flèche jusqu'à la classe PersonVO puis validez la destination de la flèche en cliquant gauche à nouveau lorsque la classe PersonVO est encadrée de bleu. Une relation de dépendance est alors créée entre les deux classes.

8. Ajoutez une nouvelle classe au diagramme et appelez-la PersonVO[].

9. Assurez-vous que votre diagramme correspond à celui qui apparait ci-dessus.

10. Enregistrez le modèle au moyen du raccourci clavier Ctrl+S

Nous sommes maintenant prêts à générer le code pour l'objet de valeur PersonVO. Pour cela, rendez-vous à la section 3.2.2.

III-B-2 - Génération de code pour l'objet de valeur PersonVO

Suivez les étapes ci-dessous pour générer le code.

1. Ouvrez une fenêtre de commandes et rendez-vous dans le répertoire C:\timetracker.

2. Exécutez la commande « maven -o clean install ». La cible « clean » nous permet de nettoyer les dossiers target avant de régénérer le code. Assurez-vous que vous obtenez un message BUILD SUCCESSFUL quand Maven termine son exécution.

Ouvrez le dossier C:\timetracker\common\target\src\org\andromda\timetracker\vo dans l'explorateur Windows. Vous pouvez constater que la classe PersonVO est générée ici. Ouvrez-la et vérifiez son contenu.

Ouvrez maintenant le dossier C:\timetracker-magicdraw\core\target\src\org\andromda\timetracker\domain dans l'explorateur Windows. Vous vous souvenez que ce dossier contenait 6 fichiers générés automatiquement après la dernière construction. Cette fois-ci il n'y en a que 5, PersonDaoImpl.java manque à l'appel! Mais que se passe-t-il ? En fait, cette classe a cette fois été générée dans le dossier src au lieu du dossier target, parce que nous avons ajouté une dépendance depuis Person vers PersonVO. Cette dépendance est une indication pour AndroMDA afin qu'il ajoute du code utilitaire dans PersonDaoBase.java et PersonDaoImpl.java pour la conversion entre Person et PersonVO. La plus grande partie de ce code se trouve dans la classe autogénérée PersonDaoBase. Cependant, si l'on désire modifier le mécanisme de traduction par défaut, il est possible de surcharger ces méthodes dans la classe PersonDaoImpl. De plus, cette dernière est déplacée dans l'arbre des sources à un endroit où elle peut être modifiée en toute sécurité (voir C:\timetracker\core\src\java\org\andromda\timetracker\domain). Vérifiez les classes PersonDaoBase et PersonDaoImpl pour comprendre ce mécanisme de conversion.

Maintenant que nous avons modélisé l'objet de valeur PersonVO, il est temps de créer un service qui l'utilise: PeopleService.

III-C - Le service PeopleService

III-C-1 - Modélisation du service PeopleService

Dans cette section nous allons créer le service PeopleService. Ce service expose 3 méthodes pour gérer l'information à propos des personnes travaillant chez Northwind.

Nous allons également modéliser une dépendance de PeopleSevice vers l'entité Person afin de s'assurer que le service a accès a PersonDao.

Pour ajouter le service à votre modèle, il vous suffit de suivre les instructions du paragraphe correspondant à votre outil de modélisation.

MagicDraw

Ce paragraphe fournit les instructions nécessaires à la modélisation du service PeopleService avec MagicDraw. Le modèle figure ci-dessous pour référence.

Le service PeopleService dans MagicDraw UML

1. Dans le modèle TimeTracker, créez un paquet appelé « service » sous org.andromda.timetracker. Nous allons créer tous nos services dans ce paquet.

2. Dans l'arbre de confinement sur la gauche, cliquez droit sur le paquet « service » et sélectionnez Nouveau Diagramme > Diagramme de Classe. Saisissez « Services » comme nom pour ce diagramme et cliquez sur OK. Le diagramme est créé et ouvert dans un nouvel onglet.

3. Ajoutez une nouvelle classe dans le diagramme et appelez-la PeopleService.

4. Ajoutez le stéréotype <<Service>> à la classe PeopleService.

5. Ajoutez trois méthodes à la classe PeopleService comme dans le diagramme ci-dessus. Faites attention au type de retour de la dernière méthode. Il ne sera pas interprété comme PersonVO[] si vous l'entrez dans le diagramme. Double-cliquez sur la méthode et choisissez le bon type dans la boîte de dialogue de spécification de l'opération. Dans cette boîte de dialogue, faites également attention à bien vider le champ « Modificateur du type de retour ».

6. Depuis l'arbre de confinement à gauche, faites glisser la classe Person vers le diagramme.

7. Créez une dépendance depuis PeoplePerson vers Person (pour indiquer que le service PeopleService va manipuler des Person).

8. Assurez-vous que votre diagramme correspond à celui qui figure ci-dessus.

9. Sauvegardez votre modèle.

Nous avons déjà ajouté des services, des objets de valeurs, et des entités à notre modèle. Et il arrivera très fréquemment que ces différents éléments se côtoient dans les mêmes diagrammes avec pour seul moyen de les distinguer leur stéréotype. Or dans MagicDraw, il est possible de modifier la couleur des éléments. Il peut donc être très utile de se choisir une couleur standard pour chaque stéréotype. C'est une perte de temps relative à la modélisation, d'autant qu'on aimerait pouvoir faire cela automatiquement, mais à l'usage, la lisibilité des diagrammes y gagne énormément. Pour modifier la couleur de remplissage d'une classe dans MagicDraw, ou plus précisément du symbole qui représente une classe, il vous suffit de cliquer droit sur l'élément puis de sélectionner « Éditer symbole… ». Vous avez alors accès à la boîte de dialogue des propriétés du symbole et vous pouvez modifier tout un tas de choses donc la couleur de remplissage. Autre astuce, dans les diagrammes où vous n'avez pas besoin de voir les membres des entités, ce qui est souvent le cas dans les diagrammes qui se concentrent sur les services par exemple, vous pouvez cacher à la fois les membres et les opérations de l'entité pour la faire ressembler au symbole que vous pouvez voir plus haut. Cela vous permet également d'améliorer la lisibilité de vos diagrammes.

Nous sommes maintenant prêts à générer le code pour PeopleService. Pour ce faire, rendez-vous à la section 3.3.2.

III-C-2 - Génération de code pour le service PeopleService

Suivez les étapes ci-dessous pour générer le code.

1. Ouvrez une fenêtre de commandes et rendez-vous dans le répertoire C:\timetracker .

2. Exécutez la commande « maven -o clean install ». Assurez-vous que vous obtenez un message BUILD SUCCESSFUL quand Maven termine son exécution.

À ce stade, après l'exécution de maven, j'ai personnellement rencontré un problème qui aboutissait à un message BUILD FAILED. Le problème, c'était que l'interface PeopleService.java n'était pas générée du tout à cause d'une ligne manquante dans le fichier de configuration d'AndroMDA généré par le plugin AndroMDApp. Si vous vous trouvez dans une situation similaire, vérifiez que la ligne suivante figure bien dans le namespace spring, dans le fichier C:\timetracker\mda\conf\andromda.xml: <property name=« service-interfaces »>${maven.andromda.common.generated.dir}</property>

Tout comme pour les objets d'accès aux données, un service est généré sous la forme d'un trio de classes: une interface, une classe abstraite de base et une implémentation concrète. Voici les 3 classes générées pour PeopleService:

- PeopleService.java : PeopleService est l'interface qui spécifie les méthodes de service. Puisque les applications clientes ont besoin de cette interface comme de son implémentation, elle est générée dans la branche target du projet « common ».

- PeopleServiceBase.java : PeopleServiceBase implémente les méthodes spécifiées par l'interface PeopleService. Ces méthodes servent avant tout à effectuer quelques vérifications sur les paramètres, après quoi elles délèguent la véritable fonctionnalité métier à des méthodes « handle ». Les méthodes « handle » doivent être implémentées manuellement dans la classe PeopleServiceImpl. PeopleServiceBase contient également les références aux DAO dont le service a besoin. PeopleServiceBase est générée dans la branche target du projet core.

- PeopleServiceImpl.java : PeopleServiceImpl est une extension concrète de la classe PeopleServiceBase. C'est dans cette classe que les développeurs doivent coder la logique métier pour les méthodes de service. PeopleServiceImpl.java est générée dans la branche src du projet core.

III-C-3 - Implémentation des méthodes du service PeopleService

Cette section vous indique comment implémenter les 3 méthodes « handle » dans PeopleServiceImpl. Ouvrez le fichier C:\timetracker-argouml\core\src\java\org\andromda\timetracker\service\PeopleServiceImpl.java et suivez les instructions ci-dessous.

handleCreatePerson()

Cette méthode de service prend en entrée un PersonVO et crée l'entité Person correspondante dans la base de données. Elle retourne l'identificateur de la personne nouvellement créée. Remplissez l'implémentation de cette méthode comme indiqué ci-dessous.

protected java.lang.Long handleCreatePerson(org.andromda.timetracker.vo.PersonVO personVO)
throws java.lang.Exception
{
Person person = Person.Factory.newInstance();
getPersonDao().personVOToEntity(personVO, person, true);
getPersonDao().create(person);
return person.getId();
}

Nous créons d'abord une nouvelle instance de Person en mémoire en utilisant la fabrique de Person. Nous initialisons ensuite la Person avec les données de l'objet de valeur -- l'implémentation par défaut de personVOToEntity() fonctionne parfaitement pour cela. Ensuite, nous demandons à PersonDao de persister la Person dans la base de données. Enfin nous retournons l'identificateur de la personne nouvellement créée à l'appelant.

Attention, cette implémentation est propre à la version 3.2 d'AndroMDA. J'ai moi-même été très surpris par cet algorithme au premier coup d'œil. Mais force est de constater que la nouvelle implémentation par défaut des méthodes de transformation (il n'y en avait aucune auparavant) rend les choses beaucoup plus propres. Je me permets enfin d'insister sur l'importance de passer par la fabrique de Person, et non pas d'appeler directement le constructeur de PersonImpl, ce qui serait contraire aux principes du Design Pattern implémenté par AndroMDA.

handleGetPerson()

Cette méthode de service prend en entrée un identificateur de Person et retourne l'objet de valeur PersonVO correspondant. Elle est implémentée en utilisant un appel direct au DAO qui retrouve la Person, le transforme en PersonVO et le retourne.

protected org.andromda.timetracker.vo.PersonVO handleGetPerson(java.lang.Long id)
throws java.lang.Exception
{
return (PersonVO) getPersonDao().load(PersonDao.TRANSFORM_PERSONVO, id);
}

handleGetAllPeople()

Cette méthode de service retourne toutes les personnes dans la base de données de l'application comme un tableau d'instances de PersonVO. Elle est implémentée grâce à un simple appel à PersonDao.loadAll(), qui retourne une collection d'objets PersonVO. Cette collection est transformée en un tableau et retournée à l'appelant.

protected org.andromda.timetracker.vo.PersonVO[] handleGetAllPeople()
throws java.lang.Exception {
Collection people = getPersonDao().loadAll(PersonDao.TRANSFORM_PERSONVO);
return (PersonVO[]) people.toArray(new PersonVO[people.size()]);
}

Imports

Ajoutez les instructions d'importation requises au fichier après l'instruction package comme indiqué ci-dessous.

package org.andromda.timetracker.service;

import org.andromda.timetracker.domain.Person;
import org.andromda.timetracker.domain.PersonDao;
import org.andromda.timetracker.vo.PersonVO;
import java.util.Collection;

Après avoir implémenté le code qui figure ci-dessus, enregistrez le fichier et compilez l'application.

1. Ouvrez une fenêtre de commandes et rendez-vous dans le répertoire C:\timetracker .

2. Exécutez la commande maven -o install. Assurez-vous d'obtenir un message BUILD SUCCESSFUL.

Est-ce que vous commencez à sentir la puissance de la chose ? Est-ce que vous commencez à vous émerveiller devant la magnificence de l'outil qui vous génère un squelette en implémentant des Design Patterns bien propres et vous laissant uniquement le code métier à produire ? Personnellement, je n'arrête jamais d'être épaté :oP

III-D - Création de l'application console

Dans cette section, nous allons essayer le service PeopleService en utilisant une simple application en ligne de commandes.

- Téléchargez le projet d'application (http://galaxy.andromda.org/docs/getting-started/java/resources/sample-code/timetracker/console1.zip) console et dézippez-la dans le dossier timetracker (C:\timetracker). Vous obtenez alors un nouveau répertoire appelé C:\timetracker\console. Ce répertoire contient trois fichiers - project.xml, maven.xml (les fichiers de projet de Maven) et TimeTrackerConsole.java (l'application console, dans src\java\org\andromda\timetracker\console).

- Ajoutez deux nouvelles cibles dans C:\timetracker\maven.xml: ces cibles vous permettent de construire et d'exécuter l'application console depuis le répertoire C:\timetracker. Les deux nouvelles cibles sont ttconsole et run. Copiez-collez ces cibles après la cible mda comme indiqué ci-dessous:

<!-- ==================================================================
Builds the Console component
================================================================== -->
<goal name="ttconsole" >
<maven:maven descriptor="console/project.xml" goals="jar:install"/>
</goal>

<!-- ==================================================================
Runs the Console component
================================================================== -->
<goal name="run">
<maven:maven descriptor="console/project.xml" goals="run"/>
</goal>

- Vérifiez l'application console dans TimeTrackerConsole.java. Les méthodes clés de cette application sont reproduites ci-dessous:

public static void main(String[] args) {
// Get services
serviceLocator = ServiceLocator.instance();
peopleService = serviceLocator.getPeopleService();

// Create people
PersonVO naresh = createPerson("nbhatia", "Naresh", "Bhatia");
PersonVO louis = createPerson("lcoude", "Louis", "Coude");
PersonVO john = createPerson("jsmith", "John", "Smith");

// Fetch and show all objects created above
PersonVO[] people = peopleService.getAllPeople();
showPeople(people);
}

private static PersonVO createPerson(String username, String firstName, String lastName) {
PersonVO person = new PersonVO(null, username, firstName, lastName);
person.setId(peopleService.createPerson(person));
System.out.println("Person " + person.getId() + " created - " + person.getUsername());
return person;
}

Comme vous pouvez le voir, la logique de l'application console est très simple. Nous avons d'abord besoin d'obtenir une référence à PeopleService, ce que nous faisons en utilisant le ServiceLocator, une classe utilitaire générée par AndroMDA qui utilise le framework Spring pour localiser les services. Ensuite, nous créons trois personnes dans la base de données en utilisant PeopleService. Pour finir, nous chargeons toutes les personnes qui existent dans la base de données, toujours en utilisant PeopleService, et nous les affichons.

- Construisez l'application console en exécutant la cible ttconsole comme suit: maven -o ttconsole.

- Exécutez l'application en exécutant la cible run comme suit: maven -o run. La sortie de la console figure ci-dessous.

C:/timetracker>maven -o run
...
[java] Person 1 created - nbhatia
[java] Person 2 created - lcoude
[java] Person 3 created - jsmith
[java] People:
[java] 1: nbhatia - Naresh Bhatia
[java] 2: lcoude - Louis Coude
[java] 3: jsmith - John Smith
[java]
BUILD SUCCESSFUL
Total time: 8 seconds
Finished at: Thu Apr 20 21:57:16 CEST 2006
C:/timetracker>

- Effacez le schéma de base de données en préparation des prochaines sections du tutoriel où nous allons ajouter plus de tables à notre base de données timetracker. Pour ce faire, exécutez la cible drop-schema comme suit: maven -o drop-schema.

III-E - Bilan intermédiaire

À ce stade, vous venez de terminer votre première application fonctionnelle avec AndroMDA. La fonctionnalité est assez simple, mais vous allez voir dans la suite de cette série que toute la puissance d'AndroMDA réside justement dans l'évolutivité qu'il permet. En fait, nous venons de terminer le premier cycle d'un processus de développement itératif qui va nous mener petit à petit vers une application complète.

Sur un plan méthodologique justement, l'expérience montre que la démarche MDA s'intègre parfaitement dans un processus de développement à base de cycles itératifs cours :

- on modélise une fonctionnalité précise ;

- le modèle est validé et compilé par AndroMDA pour générer le code générique de cette fonctionnalité ;

- pour faire les choses correctement, c'est MAINTENANT que l'on écrit les tests unitaires dans C:\timetracker\core\src\test ;

- On « bouche les trous » laissés par AndroMDA (que l'on repère facilement grâce aux commentaires TODO).

- on compile l'application et on corrige les éventuelles erreurs ;

- on utilise éventuellement l'application console pour faire des tests fonctionnels ;

- on recommence le cycle au départ.

Typiquement, ce cycle dure de l'ordre de 1 à plusieurs jours et permet de construire l'application par agrégation. Cette démarche se rapproche beaucoup d'une méthodologie de développement qui gagne en popularité: le processus unifié.

Dans les prochaines parties, nous allons faire évoluer cette application pour explorer les nombreuses autres possibilités d'AndroMDA. Eh oui : ce n'est que le début !

IV - Concepts avancés : finalisation de l'application

IV-A - Création d'associations

IV-A-1 - Modélisation

Dans cette section nous allons apprendre comment créer des associations entre les entités. Nous allons commencer par modéliser une entité Timecard (une fiche de pointage) et nous créerons ensuite deux associations entre Timecard et Person. Le modèle complet ressemblera à ceci :

Création d'associations entre Timecard et Entity

L'entité Timecard a trois attributs :

1. status : une énumération avec quatre valeurs possibles ;

2. begDate : la date de début de la fiche, qui devrait tomber au début de la semaine ;

3. comments : les commentaires ajoutés par la personne qui soumet la fiche et/ou celle qui contresigne la fiche.

L'entité Timecard a également deux associations avec Person :

1. submitter : la personne qui a soumis la fiche ;

2. approver : la personne qui approuvera la fiche.

Les flèches sur les deux associations indiquent qu'elles sont navigables depuis Timecard vers Person, ce qui signifie que la fiche référence à la fois la personne qui l'a remplie et celle qui l'approuve. Attention: une navigabilité dans les deux sens est représentée par une association sans aucune flèche. Le « 1 » et le « * » à chaque bout de l'association indiquent leur multiplicité. L'assocation du haut signifie qu'une personne peut soumettre plusieurs (signifié par « * ») fiches. De la même façon, l'association du bas signifie qu'une même personne peut contresigner plusieurs fiches.

Voilà qui illustre parfaitement l'originalité de l'utilisation d'UML dans le cadre d'une approche MDA. En effet, si vous avez déjà utilisé UML dans un contexte de conception traditionnel, vous remarquerez que nous ajoutons à ces associations beaucoup plus d'informations ici. En fait, il faut bien voir que les noms donnés aux extrémités navigables (submitter et approver) vont servir de nom aux variables correspondantes dans la classe Timecard générée, que le signe « + » qui précède ces identifiants va faire que ces variables seront publiques, et que le fait que la multiplicité de ce côté soit de 1 va générer une référence unique au lieu d'une collection. Et même l'information de multiplicité du côté non navigable est utile, car elle va permettre au générateur de configurer correctement le fichier de mapping Hibernate et par extension de générer un script DDL cohérent. Tout ça pour vous faire remarquer que nous commençons mine de rien à utiliser UML de façon beaucoup plus détaillée pour nous rapprocher progressivement du code généré. Rassurez-vous, bien souvent, si le générateur manque d'informations pour générer son code, le validateur de modèle vous en préviendra avec un message très significatif. Tiens, c'est étrange! Comme un compilateur le ferait avec du code… Un compilateur de modèle! Oh my god ! ;o)

Nous sommes maintenant prêts à ajouter ces éléments à notre modèle TimeTracker. Pour ce faire, suivez les instructions de la section correspondant à votre outil de modélisation UML.

MagicDraw UML

Cette section vous fournira toutes les instructions dont vous aurez besoin pour créer l'entité Timecard ainsi que ces associations avec l'entité Person, grâce à Magicdraw UML. Voici le modèle que nous voulons obtenir à la fin de ce processus:

Modélisation de l'entité Timecard et de ses associations avec Person

- Dans le modèle TimeTracker, ouvrez le diagramme « Objets du domaine ». Ce diagramme contient déjà l'entité Person.

- Ajoutez maintenant la classe Timecard au diagramme et affectez-lui le stéréotype Entity.

- Ensuite, nous ajoutons l'attribut status à Timecard. Remarquez que status est de type TimecardStatus, qui s'avère être une énumération. Nous devons donc d'abord définir TimecardStatus. Donc, créez une classe appelée TimecardStatus et donnez-lui le stéréotype « Enumeration ». Ajoutez quatre attributs à celle-ci. Ils représentent les valeurs de l'énumération. Maintenant que nous avons défini TimecardStatus, nous pouvons ajouter l'attribut status à Timecard comme montré ci-dessus.

À ce stade, pour peu que vous ayez appris à apprécier les énumérations type-safe apparues dans Java 5, je sens la colère monter en vous. Qu'est-ce que c'est que cette classe pour modéliser une énumération, et ces variables membres pour simuler les littéraux? En plus il existe un stéréotype « enumeration » standard dans UML! Et vous serez encore plus choqué d'apprendre qu'on ne peut même pas modéliser des opérations dans cette énumération. Mais qu'est-ce que…? On se calme, et on n'oublie pas qu'AndroMDA ne génère pas encore de code qui utilise à fond les possibilités de Java 5. Et dans l'ancien temps, pour implémenter des énumérations en Java, on utilisait un design pattern qui servait à les émuler avec des classes. Et bien devinez quoi, c'est justement ce modèle de conception qui est mis en œuvre par AndroMDA! C'est dingue, non? Notez enfin qu'il est toujours recommandé que les variables membres qui servent à émuler les littéraux d'une énumération soient de type String. Ensuite libre à vous de leur donner une valeur explicite. Si vous ne le faites pas, la valeur sera égale au nom du littéral.

- Ajoutez ensuite les attributs begDate et comments à Timecard.

- Nous devons maintenant modéliser une première association entre Timecard et Person. Pour ce faire, cliquez sur l'icône association dans la barre d'outils (13e en partant du haut). Cliquez sur la classe Timecard, faites glisser jusqu'à la classe Person et relâchez la souris. Une nouvelle association est alors créée.

- Cliquez droit sur l'extrémité de l'association du côté de Timecard et décochez « Navigable ». Ainsi l'association sera à sens unique depuis Timecard vers Person.

- Cliquez droit sur l'extrémité de l'association du côté de Person et sélectionnez la multiplicité 1. De la même manière, définissez la multiplicité de l'extrémité côté Timcard à plusieurs (*).

- Cliquez droit sur l'extrémité de l'association du côté de Person et sélectionnez « Éditer Nom ». Entrez la spécification suivante: « +submitter ». L'autre bout de l'association n'a pas besoin d'être nommé puisqu'il n'est pas navigable. Voilà qui termine l'association submitter depuis Timecard vers Person.

- Sur le même modèle, ajoutez une association approver depuis Timecard vers Person. Déplacez les associations vers le haut ou vers le bas de façon à ce qu'elles ne se chevauchent pas.

- Assurez-vous que votre diagramme de classes ressemble à celui qui apparaît ci-dessus.

- Enregistrez le projet.

Nous allons maintenant pouvoir générer le code pour Timecard. Pour ce faire, rendez-vous au paragraphe 4.1.2.

IV-A-2 - Génération de code

Suivez les instructions suivantes pour générer le code.

1. Ouvrez une fenêtre de commandes et rendez-vous dans le répertoire C:\timetracker .

2. Exécutez la commande « maven -o clean install ». La cible « clean » nous permet de nettoyer les dossiers target avant de régénérer le code. Assurez-vous que vous obtenez un message BUILD SUCCESSFUL quand Maven termine son exécution.

Ouvrez le dossier C:/timetracker/core/target/src/org/andromda/timetracker/domain dans l'explorateur Windows. Vous remarquerez la présence de 7 nouveaux fichiers dans ce dossier qui sont tous reliés à l'entité Timecard. Passez ces fichiers en revue. Remarquez que la classe Timecard contient deux références à la classe Person, mais que la classe Person ne contient aucune référence à la classe Timecard. Cela vient du fait que les deux associations sont à sens unique depuis Timecard vers Person.

Nous avons maintenant couvert les bases de la modélisation pour AndroMDA. Dans la prochaine section, nous allons ajouter les fonctionnalités restantes au modèle de TimeTracker.

IV-B - Complétion du modèle de TimeTracker

Dans cette section nous allons ajouter les fonctionnalités restantes au modèle de TimeTracker. Maintenant que vous comprenez la plupart des concepts importants de modélisation, nous ne vous donnerons des instructions détaillées que lorsque cela sera nécessaire. Alors, remontez vos manches et allons-y.

IV-B-1 - Ajout des entités manquantes

Ouvrez le diagramme « Objets du Domaine » et ajoutez les détails manquants comme indiqué ci-dessous.

Modèle de données complet

- TimeAllocation représente la période pendant laquelle une personne a travaillé sur une tâche donnée. Cette période est spécifiée en utilisant une « valeur imbriquée » de type TimePeriod. Une valeur imbriquée est spécifiée en marquant la classe avec le stéréotype EmbeddedValue. Contrairement aux entités, les valeurs imbriquées n'ont pas d'identité séparée dans la base de données. Elles sont imbriquées dans les tables d'entité et sont considérées comme faisant partie intégrante de l'entité. Remarquez que vous devez créer la valeur imbriquée TimePeriod avant de pouvoir l'utiliser comme type dans la classe TimeAllocation.

- Chaque Timecard peut contenir plusieurs TimeAllocations. Une tâche peut également être associée avec plusieurs TimeAllocations.

- Dans la première association, l'extrémité du côté de Timecard est marquée comme étant composite. Cela signifie qu'une TimeAllocation ne peut exister sans une Timecard.

- Puisque TimeAllocation est connecté si étroitement avec Timecard, nous voudrions utiliser cette observation pour simplifier notre code. Lorsqu'une Timecard est enregistrée, toutes les allocations associées devraient être sauvegardées automatiquement. De la même façon, lorsqu'une allocation est supprimée d'une timecard, elle devrait être supprimée automatiquement de la base de données. Ceci est spécifié en affectant « all-delete-orphan » à la valeur balisée andromda.hibernate.cascade. Pour savoir comment modifier cette valeur, rendez-vous dans le paragraphe correspondant à votre outil de modélisation UML.

MagicDraw UML

1. Cliquez droit sur la fin d'association appelée « allocations » et sélectionnez Spécification. Une boîte de dialogie de spécification de fin d'association s'ouvre.

2. Sélectionnez l'onglet « Valeurs balisées ».

3. Sélectionnez la balise andromda.hibernate.cascade dans le panneau de gauche et cliquez sur « Ajouter valeur ».

4. Dans la zone de texte à droite, saisissez la valeur « all-delete-orphan » (sans les guillemets, à la place de la valeur par défaut « none ») et cliquez sur OK. La nouvelle valeur balisée s'affiche dans le diagramme.

IV-B-2 - Ajout de comportements personnalisés aux entités

Jusqu'ici, nous nous sommes limités au comportement par défaut généré par AndroMDA pour les entités. Chaque entité est générée sous la forme d'un « Plain Old Java Object » (POJO) associé à un objet d'accès aux données (DAO). Ces deux objets bénéficient de comportements par défaut implémentés par des méthodes générées automatiquement. Voyons maintenant comment nous pouvons demander à AndroMDA de nous fournir des points d'entrée pour injecter des comportements personnalisés.

Créez un nouveau diagramme de classes sous le package « domain » et appelez-le « Objets de Domaine - Comportement ». Il est préférable d'ajouter les détails comportementaux des classes dans un diagramme séparé. De cette façon, les diagrammes qui représentent les détails purement structurels, tels que le diagramme figurant ci-dessous, restent simples et faciles à comprendre. Ajoutez ensuite les méthodes affichées ci-dessous dans le nouveau diagramme que vous venez de créer. Puisque les entités Person et Timecard existent déjà dans votre modèle, elles ne doivent pas être recréées, mais vous devez les faire glisser depuis l'explorateur de modèle (ou l'arbre de confinement) vers la fenêtre de diagramme. Ajoutez ensuite les méthodes aux deux entités.

Aspects comportementaux des entités

- La méthode findByUsername() retrouve une personne par son nom. Le signe « @ » devant la méthode indique qu'il s'agit d'une requête. Les méthodes de requête sont utilisables lorsque vous essayez de trouver une ou plusieurs entités à partir de leurs attributs. La bonne nouvelle, c'est qu'AndroMDA est capable d'implémenter intégralement les méthodes de requêtes sans votre concours. Il va générer la requête Hibernate adéquate et renvoyer le résultat sous forme d'un objet ou d'une collection en fonction du type de retour que vous spécifiez.

- Comme vous le savez, l'association entre Timecard et TimeAllocation est navigable dans les deux sens. Donc chaque objet doit maintenir une référence à l'autre. addTimeAllocation() est une méthode utilitaire qui fait exactement cela en un seul endroit. AndroMDA va générer une implémentation vide de cette méthode dans TimecardImpl. Et nous complèterons les détails.

MagicDraw permet de saisir les mêmes informations de façons différentes: boîtes de dialogues, panneaux de l'interface, mais aussi ce que j'appelle la syntaxe en ligne. Par exemple, pour spécifier une opération dans une classe, vous pouvez soit passer par l'arbre de confinement, soit par la boîte de spécification de la classe, mais vous pouvez aussi rédiger la spécification en ligne dans la classe, en saisissant ce que verrez une fois l'opération terminée. Par exemple, pour spécifier une opération « test » qui prend un paramètre « truc » de type String qui retourne un « void », il vous suffit de cliquer sur la classe, d'utiliser la séquence Ctrl+Alt+O sur le clavier pour ajouter une méthode, et de saisir la chaîne suivante: « test(truc:String):void ». MagicDraw se charge ensuite d'interpréter cette chaîne et de placer les informations au bon endroit dans le modèle. Bien que très puissante, cette méthode est limitée aux cas simples. Ainsi, si vous essayez de saisir une méthode de type requête de cette manière, vous vous rendrez vous compte que le « @ » en tête de méthode est mal interprété et que la méthode n'est pas identifiée comme une requête. Mon conseil: méfiez-vous de cette méthode pour les cas avancés, et ne vous fiez qu'aux boîtes de dialogue de spécification.

À présent, générez le code à partir de ce nouveau modèle en exécutant la commande « maven -o clean mda ». Ouvrez le fichier PersonDaoBase.java sous core/target/src/org/andromda/timetracker/domain. Vous y trouverez la méthode findByUsername() complètement implémentée par AndroMDA. La requête Hibernate générée apparaît ci-dessous.

public Object findByUsername(final int transform, final java.lang.String username)
{
return this.findByUsername(
transform,
"from org.andromda.timetracker.domain.Person as person where person.username = :username",
username
);
}

Maintenant complétons l'implémentation de la méthode addTimeAllocation(). Ouvrez le fichier TimecardImpl.java sous core/src/java/org/andromda/timetracker/domain. Localisez l'implémentation par défaut de addTimeAllocation(), qui lance une UnsupportedOperationException pour l'instant, avec une balise @todo pour vous faciliter le repérage des méthodes à implémenter. Remplacez l'implémentation générée par celle qui figure ci-dessous. Celle-ci s'assure que Timecard et TimeAllocation ont toujours une référence l'une vers l'autre.

public void addTimeAllocation(org.andromda.timetracker.domain.TimeAllocation timeAllocation)
{
getAllocations().add(timeAllocation);
timeAllocation.setTimecard(this);
}

Assurez-vous que votre code compile. Tout ce que vous avez besoin de faire, c'est de construire le module core. Pour ce faire, exécutez simplement la commande « maven -o core ».

IV-B-3 - Ajout des objets de valeur manquants

Ouvrez le diagramme « Objets de valeur » et ajoutez les détails restants pour arriver au résultat qui figure ci-dessous.

Ajout des objets de valeur manquants

Il n'y a rien de vraiment nouveau ici, excepté le fait que nous fournissons deux vues de l'entité Timecard. TimecardSummaryVO est très légère et peut être utilisée pour afficher des listes de timecards. Quant à TimecardVO, elle est un peu plus lourde puisqu'elle inclut les TimeAllocations en plus des attributs de TimecardSummaryVO. Cet objet de valeur sera utilisé lorsque nous voudrons afficher les détails d'une timecard particulière. Notez que TimecardVO hérite de TimecardSummaryVO, héritant du même coup de tous ses attributs.

À présent vous pouvez générer le code pour votre modèle modifié en exécutant la commande « maven -o clean install ». Assurez-vous que vous obtenez un message « BUILD SUCCESSFUL » à la fin de la construction.

IV-B-4 - Ajout du service TimeTrackerService

Nous allons maintenant ajouter au modèle le service TimeTrackerService. Ce service fournit toutes les opérations de suivi du temps qui pourraient être utilisées par une interface utilisateur. Ouvrez le diagramme « Services » et ajoutez-y TimeTrackerService pour obtenir le modèle qui figure ci-dessous.

Le service TimeTrackerService

À présent, générez le code pour le modèle modifié en exécutant la commande « maven -o clean install ». Assurez-vous d'obtenir un message « BUILD SUCCESSFUL ».

IV-B-5 - Création du schéma

Maintenant que la structure de nos entités est pratiquement finalisée, nous pouvons créer le schéma correspondant dans la base de données. Vous vous en souvenez peut-être, AndroMDA génère automatiquement le script de création de la base de données. Celui-ci se trouve dans C:/timetracker/core/target/schema-create.sql. Ouvrez ce fichier et passez son contenu en revue. Vous y trouverez les instructions SQL pour créer toutes les tables et les contraintes nécessaires. Pour créer le schéma, exécutez la commande "maven -o create-schema.

Notez que PostgreSQL n'apprécie pas spécialement la première instruction dans schema-create.sql (« drop sequence hibernate_sequence »). Nous vous recommandons donc de commenter cette ligne pour PostgreSQL.

V - Trucs et astuces : finition du client console

Dans cette section, nous allons enrichir l'application console pour créer et lire des fiches de temps en utilisant le service TimeTrackingService. Nous allons devoir ajouter du code personnalisé aux couches métier et d'accès aux données afin de faire fonctionner l'application.

- Téléchargez l'application console à cette adresse (http://galaxy.andromda.org/docs/getting-started/java/resources/sample-code/timetracker/TimeTrackerConsole.java) et remplacez la copie existante de TimeTrackerConsole.java dans C:/timetracker/console/src/java/org/andromda/timetracker/console par le fichier que vous venez de télécharger.

- Passez en revue la méthode main dans le nouveau TimeTrackerConsole.java.

public static void main(String[] args) {
// Get services
serviceLocator = ServiceLocator.instance();
peopleService = serviceLocator.getPeopleService();
timeTrackingService = serviceLocator.getTimeTrackingService();

// Create people
PersonVO naresh = createPerson("nbhatia", "Naresh", "Bhatia");
PersonVO louis = createPerson("lcoude", "Louis", "Coude");
PersonVO john = createPerson("jsmith", "John", "Smith");

// Create tasks
TaskVO research = createTask("Research");
TaskVO development = createTask("Development");

// Create timecards
TimecardVO timecard1 = createTimecard(naresh, john);
TimecardVO timecard2 = createTimecard(naresh, john);
TimecardVO timecard3 = createTimecard(louis, john);
TimecardVO timecard4 = createTimecard(louis, john);

// Fetch and show all objects created above
PersonVO[] people = peopleService.getAllPeople();
showPeople(people);
TaskVO[] tasks = timeTrackingService.getAllTasks();
showTasks(tasks);
TimecardSummaryVO[] timecards = timeTrackingService.getAllTimecardSummaries();
showTimecardSummaries(timecards);

// Fetch and show timecard1 details
System.out.println("Timecard " + timecard1.getId() + " Details:");
TimecardVO timecard1FromDB = timeTrackingService.getTimecard(timecard1.getId());
showTimecard(timecard1FromDB);
}

Comme vous pouvez le voir, nous pouvons maintenant créer des tâches et des fiches en plus des personnes. Les méthodes createTask() et createTimecard() appellent le service TimeTrackingService pour réaliser ces opérations. Ensuite nous récupérons toutes les personnes, toutes les tâches et toutes les fiches de temps qui existent dans la base de données, et nous les affichons.

Assurez-vous que l'application console compile en exécutant la cible ttconsole comme suit: maven -o ttconsole. Bien sûr, il n'y a aucun espoir de pouvoir exécuter cette application avec succès pour l'instant puisque la plus grande partie de la couche métier n'a pas encore été implémentée (en particulier les méthodes de TimeTrackingService que nous avons modélisées à l'étape précédente). Nous allons maintenant essayer de rendre l'application exécutable, mais une étape à la fois.

V-A - Création des tâches

La méthode createTask() de TimeTrackerConsole appelle simplement la méthode createTask() de TimeTrackingService, que nous n'avons pas encore implémentée. Alors implémentons cette méthode pour commencer. Ouvrez le fichier TimeTrackingServiceImpl.java et remplissez la méthode handleCreateTask() comme suit:

protected java.lang.Long handleCreateTask(org.andromda.timetracker.vo.TaskVO taskVO)
throws java.lang.Exception
{
Task task = Task.Factory.newInstance();
getTaskDao().taskVOToEntity(taskVO, task, true);
getTaskDao().create(task);
return task.getId();
}

Vérifiez l'implémentation par défaut de taskVOToEntity dans TaskDaoBase.java. Cette implémentation devrait fonctionner parfaitement.

Ajoutez maintenant les instructions import ci-dessous dans TimeTrackingServiceImpl.java (juste en dessous de l'instruction package):

package org.andromda.timetracker.service;

import java.util.Collection;
import org.andromda.timetracker.domain.*;
import org.andromda.timetracker.vo.*;

Nous devrions pouvoir créer des tâches maintenant. Compilez le module code en exécutant la commande « maven -o core », puis exécutez l'application grâce à la commande « maven -o run ». La sortie correspondante est recopiée ci-dessous.

C:/timetracker>maven -o run
...
[java] Person 1 created - nbhatia
[java] Person 2 created - lcoude
[java] Person 3 created - jsmith
[java] Task 1 created - Research
[java] Task 2 created - Development
[java] Exception in thread "main" java.lang.NullPointerException
[java]      at org.andromda.timetracker.console.TimeTrackerConsole.createTimecard(TimeTrackerConsole.java:94)
[java]      at org.andromda.timetracker.console.TimeTrackerConsole.main(TimeTrackerConsole.java:42)
[java] [ERROR] Java Result: 1

Notez que les tâches sont bien créées avec succès. Vous pouvez le vérifier en jetant un œil à votre base de données. Toutefois, nous obtenons une NullPointerException dans TimeTrackerConsole.java. Après avoir regardé dans le code à la ligne spécifiée, il est clair que timeTrackingService.getAllTasks() retourne null. Et cela est tout à fait normal puisque cette méthode n'a pas encore été implémentée. Implémentez cette méthode comme indiqué ci-dessous en appelant TaskDao.loadAll():

protected org.andromda.timetracker.vo.TaskVO[] handleGetAllTasks()
throws java.lang.Exception
{
Collection tasks = getTaskDao().loadAll(TaskDao.TRANSFORM_TASKVO);
return (TaskVO[])tasks.toArray(new TaskVO[tasks.size()]);
}

Compilez le module core en exécutant la commande « maven -o core ». Avant que nous ne puissions exécuter l'application à nouveau, nous devons réinitialiser la base de données en supprimant le schéma et en le recréant. Exécutez la commande « maven -o drop-schema create-schema » pour démarrer avec une nouvelle base de données. Ensuite, exécutez l'application grâce à la commande « maven -o run ». La sortie correspondante est reproduite ci-dessous.

C:/timetracker>maven -o run
...
[java] Person 1 created - nbhatia
[java] Person 2 created - lcoude
[java] Person 3 created - jsmith
[java] Task 1 created - Research
[java] Task 2 created - Development
[java] Timecard null created with 3 allocations
[java] Timecard null created with 1 allocations
[java] Timecard null created with 1 allocations
[java] Timecard null created with 1 allocations
...

Beaucoup mieux! Il semble que les tâches soient bien créées à présent. Le prochain obstacle à franchir est la création de fiches de temps.

V-B - Création de fiches de temps

En analysant le code dans TimeTrackerConsole.createTimecard(), il est clair que timeTrackingService.createTimecard() retourne null. Cela vient bien sûr du fait que createTimecard() n'a pas été implémentée dans TimeTrackingService. Il va donc vous falloir ouvrir TimeTrackingServiceImpl.java sous C:/timetracker/core/src/java/org/andromda/timetracker/service et implémenter handleCreateTimecard() comme suit:

protected java.lang.Long handleCreateTimecard(org.andromda.timetracker.vo.TimecardVO timecardVO)
throws java.lang.Exception
{
// Create new timecard from timecardVO

Timecard timecard = Timecard.Factory.newInstance();
getTimecardDao().timecardVOToEntity(timecardVO, timecard, true);

// Set submitter and approver associations
timecard.setSubmitter(getPersonDao().findByUsername(timecardVO.getSubmitterName()));
timecard.setApprover(getPersonDao().findByUsername(timecardVO.getApproverName()));
// Set allocations
TimeAllocationVO allocations[] = timecardVO.getAllocations();
for(int i=0; i<allocations.length; i++) {
// Create TimeAllocation from TimeAllocationVO
TimeAllocationVO allocationVO = allocations[i];
TimeAllocation allocation = TimeAllocation.Factory.newInstance();
getTimeAllocationDao().timeAllocationVOToEntity(allocationVO, allocation, true);

// Connect to timecard
timecard.addTimeAllocation(allocation);
// Connect to task
allocation.setTask(getTaskDao().load(allocationVO.getTaskId()));
}
// Create the timecard
getTimecardDao().create(timecard);
return timecard.getId();
}

En analysant TimeAllocationDaoBase.java, il est clair qu'AndroMDA ne gère pas la conversion de valeurs imbriquées lorsqu'il génère les méthodes de conversion d'objets de valeurs en entités, et vice-versa. Nous allons donc devoir ajouter du code dans TimeAllocationDaoImpl.java pour effectuer cette conversion. Ce fichier est généré dans le répertoire C:/timetracker/core/src/java/org/andromda/timetracker/domain. Apportez les modifications suivantes au fichier :

- ajoutez les instructions import suivantes après l'instruction package.

package org.andromda.timetracker.domain;

import org.andromda.timetracker.vo.TimeAllocationVO;
import org.andromda.timetracker.vo.TimePeriodVO;

- implémentez les deux méthodes toTimeAllocationVO() comme suit:

public void toTimeAllocationVO(org.andromda.timetracker.domain.TimeAllocation sourceEntity, org.andromda.timetracker.vo.TimeAllocationVO targetVO)
{
super.toTimeAllocationVO(sourceEntity, targetVO);
TimePeriod timePeriod = sourceEntity.getTimePeriod();
targetVO.setTimePeriodVO(new TimePeriodVO(timePeriod.getStartTime(), timePeriod.getEndTime()));
targetVO.setTaskId(sourceEntity.getTask().getId());
}

public org.andromda.timetracker.vo.TimeAllocationVO toTimeAllocationVO(final org.andromda.timetracker.domain.TimeAllocation entity)
{
TimeAllocationVO targetVO = new TimeAllocationVO();
toTimeAllocationVO(entity, targetVO);
return targetVO;
}

- implémentez la méthode timeAllocationVOToEntity() comme suit (attention à implémenter la bonne méthode, c'est-à-dire celle qui prend un paramètre copyIfNull):

public void timeAllocationVOToEntity(
org.andromda.timetracker.vo.TimeAllocationVO sourceVO,
org.andromda.timetracker.domain.TimeAllocation targetEntity,
boolean copyIfNull)
{
super.timeAllocationVOToEntity(sourceVO, targetEntity, copyIfNull);
TimePeriodVO timePeriodVO = sourceVO.getTimePeriodVO();
targetEntity.setTimePeriod(TimePeriod.newInstance(timePeriodVO.getStartTime(), timePeriodVO.getEndTime()));
}

Nous devons apporter des changements similaires à la classe TimecardDaoImpl :

- ajoutez les instructions import suivantes après l'instruction package.

package org.andromda.timetracker.domain;

import java.util.ArrayList;
import java.util.Collection;

import org.andromda.timetracker.ServiceLocator;
import org.andromda.timetracker.vo.TimeAllocationVO;
import org.andromda.timetracker.vo.TimecardSummaryVO;
import org.andromda.timetracker.vo.TimecardVO;

- implémentez les deux méthodes toTimecardSummaryVO() comme suit:

public void toTimecardVO(
org.andromda.timetracker.domain.Timecard sourceEntity,
org.andromda.timetracker.vo.TimecardVO targetVO)
{
toTimecardSummaryVO(sourceEntity, targetVO);
// Create allocations
Collection allocations = new ArrayList(sourceEntity.getAllocations());
((TimeAllocationDao)ServiceLocator.instance().getService("timeAllocationDao")).toTimeAllocationVOCollection(allocations);
targetVO.setAllocations((TimeAllocationVO[])allocations.toArray(new TimeAllocationVO[allocations.size()]));
}

public org.andromda.timetracker.vo.TimecardVO toTimecardVO(final org.andromda.timetracker.domain.Timecard entity)
{
TimecardVO targetVO = new TimecardVO();
toTimecardVO(entity, targetVO);
return targetVO;
}

Nous allons enfin implémenter deux méthodes dans TimeTrackingServiceImpl.java de façon à ce que les timecards puissent être retrouvées pour être affichées. Voici ces deux méthodes:

protected org.andromda.timetracker.vo.TimecardVO handleGetTimecard(java.lang.Long id)
throws java.lang.Exception
{
return (TimecardVO)getTimecardDao().load(TimecardDao.TRANSFORM_TIMECARDVO, id);
}

protected org.andromda.timetracker.vo.TimecardSummaryVO[] handleGetAllTimecardSummaries()
throws java.lang.Exception
{
Collection timecards = getTimecardDao().loadAll(TimecardDao.TRANSFORM_TIMECARDSUMMARYVO);
return (TimecardSummaryVO[])timecards.toArray(new TimecardSummaryVO[timecards.size()]);
}

Compilez l'application en exécutant la commande « maven -o clean install ». Avant de pouvoir exécuter l'application à nouveau, nous devons encore effacer la base de données et recréer le schéma. Exécutez la commande « maven -o drop-schema create-schema » pour démarrer avec une base de données vide. Ensuite, exécutez l'application grâce à la commande « maven -o run ». L'application s'exécute avec succès jusqu'au bout! La sortie est reproduite ci-dessous.

[java] Person 1 created - nbhatia
[java] Person 2 created - lcoude
[java] Person 3 created - jsmith
[java] Task 1 created - Research
[java] Task 2 created - Development
[java] Timecard 1 created with 3 allocations
[java] Timecard 2 created with 1 allocations
[java] Timecard 3 created with 2 allocations
[java] Timecard 4 created with 2 allocations
[java] People:
[java] 1: nbhatia - Naresh Bhatia
[java] 2: lcoude - Louis Coude
[java] 3: jsmith - John Smith
[java]
[java] Tasks:
[java] 1: Research
[java] 2: Development
[java]
[java] Timecards:
[java] 1: status=DRAFT, begin date=2006-02-01 04:23:33.0, comments=On track!, submitter=nbhatia, approver=jsmith
[java] 2: status=DRAFT, begin date=2006-02-01 04:23:33.0, comments=On track!, submitter=nbhatia, approver=jsmith
[java] 3: status=DRAFT, begin date=2006-02-01 04:23:34.0, comments=On track!, submitter=lcoude, approver=jsmith
[java] 4: status=DRAFT, begin date=2006-02-01 04:23:34.0, comments=On track!, submitter=lcoude, approver=jsmith
[java]
[java] Timecard 1 Details:
[java] 1: status=DRAFT, begin date=2006-02-01 04:23:33.0, comments=On track!, submitter=nbhatia, approver=jsmith
[java]     1: start time=2006-02-03 04:23:33.0, end time=2006-02-04 04:23:33.0, task id=2
[java]     2: start time=2006-02-02 04:23:33.0, end time=2006-02-03 04:23:33.0, task id=1
[java]     3: start time=2006-02-01 04:23:33.0, end time=2006-02-02 04:23:33.0, task id=1

V-C - La suite des évènements

Dans ce tutoriel, nous nous sommes assurés d'avoir tout l'environnement installé pour pouvoir démarrer l'écriture de projets MDA en utilisant AndroMDA, mais ce n'est que le début. Il y a plusieurs cartridges différentes que vous pouvez utiliser, ou peut-être, si vous n'en trouvez aucune qui correspond à vos besoins, pourrez-vous en écrire une vous-même et la proposer à l'intégration dans le projet AndroMDA.

Une autre chose que vous pourrez essayer sera de construire une interface graphique utilisateur pour l'application TimeTracker. Vous pouvez vous référer aux guides pratiques (http://galaxy.andromda.org/docs/howto-guides.html) pour en savoir plus sur la cartridge Bpm4Struts qui peut être utilisée pour développer des interfaces web.

Quoi qu'il en soit, vous devrez en apprendre plus sur UML, MDA, les techniques et les meilleures pratiques de modélisation. Une bonne idée pourrait être également de jeter un œil aux exemples compris dans la distribution binaire, et notamment au modèle inclus dans chacun d'entre eux. Cette distribution peut être téléchargée depuis la page du projet AndroMDA: http://sourceforge.net/project/showfiles.php?group_id=73047. Notez toutefois que les exemples de la distribution doivent être construits si vous désirez voir les sources générées ou avant de les déployer. Pour ce faire, rendez-vous dans le dossier de l'exemple et invoquez maven, c'est tout.

VI - Ma conclusion

Je vous sens un peu sur votre faim. Parce que vous avez certainement remarqué qu'il reste encore des méthodes non implémentées dans TimeTrackingService. Et que toutes ces méthodes ne sont pas mises en œuvre dans TimeTrackerConsole. Considérez cela comme un exercice qui vous permettra de vous faire la main.

À l'heure où je termine cet article, j'ai pour projet de prolonger ce tutoriel en implémentant une interface web avec Struts ou avec JSF. Comme un tel projet de tutoriel est déjà dans le pipeline de l'équipe d'AndroMDA, j'attends d'avoir un peu plus de nouvelles de ce côté pour éviter la redondance. Et à plus long terme, je réfléchis déjà à un troisième volet sur la sécurisation d'une application avec Acegi, et sur le développement d'un client de type RIA (Rich Internet Application) avec OpenLaszlo.

En attendant, je vous invite vraiment à me faire partager vos impressions sur ce tutoriel, à me faire parvenir vos questions et vos remarques à sebastien.arbogast.at.gmail.com: tous les retours sont les bienvenus et sont susceptibles d'améliorer ce document.

De mon côté, j'essaierai de mettre ce document à jour en fonction de votre feedback et des évolutions d'AndroMDA. La suite au prochain épisode…