Maven Guide FR
Maven Guide FR
xv 1.1. Changes in Edition 0.7.2 ........................................................................... xv 1.2. Changes in Edition 0.7.1 .......................................................................... xix 1.3. Modifications de l'Edition 0.7 .................................................................... xx 1.4. Modifications de l'Edition 0.6 ................................................................... xxi 1.5. Modifications de l'Edition 0.5 ................................................................... xxi 1.6. Modifications de l'Edition 0.4 .................................................................. xxii Prface ....................................................................................................................... xxv 1. Comment utiliser ce livre ................................................................................... xxv 2. Vos Retours ................................................................................................... xxvi 3. Conventions de Police ...................................................................................... xxvi 4. Conventions d'criture Maven ........................................................................... xxvii 5. Remerciements ............................................................................................... xxvii 6. Remerciements des traducteurs ......................................................................... xxviii 1. Introduction Apache Maven ........................................................................................ 1 1.1. Maven... De quoi s'agit-il ? ................................................................................. 1 1.2. Convention plutt que configuration ..................................................................... 1 1.3. Une Interface Commune ..................................................................................... 2 1.4. Rutilisation universelle grce aux plugins Maven ................................................... 3 1.5. Le Modle conceptuel d'un "Projet" ...................................................................... 4 1.6. Maven est-il une alternative XYZ ? .................................................................... 5 1.7. Comparaison de Maven et de Ant ........................................................................ 6 2. Installation de Maven ................................................................................................. 11 2.1. Vrifier votre installation de Java ....................................................................... 11 2.2. Tlchargement de Maven ................................................................................ 11 2.3. Installer Maven ............................................................................................... 12 2.3.1. Installer Maven sur Mac OSX ................................................................. 12 2.3.2. Installer Maven sur Microsoft Windows .................................................... 13 2.3.3. Installer Maven sur GNU/Linux ............................................................... 14 2.3.4. Installer Maven sur FreeBSD ou OpenBSD ................................................ 14 2.4. Tester une installation Maven ............................................................................ 14 2.5. Dtails de l'installation de Maven ....................................................................... 14 2.5.1. Configuration et dpt spcifiques l'utilisateur .......................................... 15 2.5.2. Mettre jour une installation de Maven .................................................... 16 2.5.3. Migrer de Maven 1.x Maven 2.x ........................................................... 16 2.6. Dsinstaller Maven .......................................................................................... 17 2.7. Obtenir de l'aide avec Maven ............................................................................ 17 2.8. propos de l'Apache Software License ............................................................... 18 I. Maven par l'exemple ................................................................................................... 21 3. Mon premier projet avec Maven ........................................................................... 23
3.1. Introduction ............................................................................................ 3.1.1. Tlcharger l'exemple de ce chapitre ................................................. 3.2. Cration du projet Simple ......................................................................... 3.3. Construire le projet Simple ........................................................................ 3.4. Modle Objet du projet Simple .................................................................. 3.5. Les concepts principaux ............................................................................ 3.5.1. Plugins Maven et Goals ................................................................. 3.5.2. Cycle de vie de Maven .................................................................. 3.5.3. Les coordonnes Maven ................................................................. 3.5.4. Les dpts Maven ......................................................................... 3.5.5. La gestion des dpendances de Maven .............................................. 3.5.6. Rapports et production du site ......................................................... 3.6. En rsum .............................................................................................. 4. Personnalisation d'un projet Maven ....................................................................... 4.1. Introduction ............................................................................................ 4.1.1. Tlcharger l'exemple de ce chapitre ................................................. 4.2. Prsantation du projet Simple Weather ........................................................ 4.2.1. Yahoo! Mto RSS ....................................................................... 4.3. Crer le Projet Simple Weather .................................................................. 4.4. Personnaliser les informations du projet ....................................................... 4.5. Ajout de nouvelles dpendances ................................................................. 4.6. Code source de Simple Weather ................................................................. 4.7. Ajouter des Ressources ............................................................................. 4.8. Excuter le programme Simple Weather ...................................................... 4.8.1. Le plugin Maven Exec ................................................................... 4.8.2. Explorer les dpendances de votre projet ........................................... 4.9. Ecrire des tests unitaires ........................................................................... 4.10. Ajouter des dpendances dans le scope test .............................................. 4.11. Ajouter des ressources pour les tests unitaires .............................................. 4.12. Excuter les test unitaires ........................................................................ 4.12.1. Ignorer les tests en chec .............................................................. 4.12.2. Court-circuiter les tests unitaires ..................................................... 4.13. Construire une application package et excutable en ligne de commande .......... 4.13.1. Rattacher le goal Assembly la phase Package ................................. 5. Une simple application web ................................................................................. 5.1. Introduction ............................................................................................ 5.1.1. Tlcharger l'exemple de ce chapitre ................................................. 5.2. Dfinition de l'application web simple-webapp .............................................. 5.3. Cration du projet web simple-web ............................................................. 5.4. Configurer le plugin Jetty ......................................................................... 5.5. Ajouter une simple servlet ......................................................................... 5.6. Ajouter les dpendances J2EE ................................................................... 5.7. Conclusion .............................................................................................
23 23 23 26 27 28 28 30 33 36 37 39 39 41 41 41 41 42 42 44 45 46 52 53 54 55 57 59 60 62 62 63 64 66 69 69 69 69 69 72 73 75 77
iv
6. Un projet multimodule ........................................................................................ 79 6.1. Introduction ............................................................................................ 79 6.1.1. Tlcharger l'exemple de ce chapitre ................................................. 79 6.2. Le projet parent ...................................................................................... 79 6.3. Le module simple-weather ........................................................................ 81 6.4. Le module simple-web ............................................................................. 83 6.5. Construction du projet multimodule ............................................................ 85 6.6. Excution de l'application web ................................................................... 87 7. Un projet multimodule d'entreprise ........................................................................ 89 7.1. Introduction ............................................................................................ 89 7.1.1. Tlcharger les sources de ce chapitre ............................................... 89 7.1.2. Projet multimodule d'entreprise ........................................................ 89 7.1.3. Technologies utilises dans cet exemple ............................................ 92 7.2. Le projet simple-parent ............................................................................. 92 7.3. Le module simple-model .......................................................................... 94 7.4. Le module simple-weather ........................................................................ 98 7.5. Le module simple-persist ........................................................................ 101 7.6. Le module simple-webapp ....................................................................... 108 7.7. Excution de l'application web ................................................................. 118 7.8. Le module de ligne de commande ............................................................. 119 7.9. Excution de l'application en ligne de commande ......................................... 125 7.10. Conclusion .......................................................................................... 127 7.10.1. Programmation avec des projets API ............................................. 128 8. Optimiser et remanier les POMs ......................................................................... 131 8.1. Introduction .......................................................................................... 131 8.2. Nettoyer le POM ................................................................................... 132 8.3. Optimiser les dpendances ....................................................................... 132 8.4. Optimiser les plugins .............................................................................. 136 8.5. Optimisation avec le plugin Maven Dependency .......................................... 138 8.6. Les POMs finaux ................................................................................... 141 8.7. Conclusion ........................................................................................... 149 II. Maven - La Reference .............................................................................................. 151 9. Le Modle Objet de Projet ................................................................................. 153 9.1. Introduction .......................................................................................... 153 9.2. Le POM ............................................................................................... 153 9.2.1. Le Super POM ........................................................................... 155 9.2.2. Le POM le plus simple possible ..................................................... 158 9.2.3. Le POM effectif .......................................................................... 159 9.2.4. Vritables POMs ......................................................................... 159 9.3. Syntaxe de POM ................................................................................... 160 9.3.1. Les versions d'un projet ................................................................ 160 9.3.2. Rfrence une proprit ............................................................. 162 9.4. Dpendances d'un projet .......................................................................... 163
9.4.1. Scope de dpendance ................................................................... 9.4.2. Dpendances optionnelles ............................................................. 9.4.3. Intervalle de versions pour une dpendance ...................................... 9.4.4. Dpendances transitives ................................................................ 9.4.5. Rsolution des conflits ................................................................. 9.4.6. Gestion des dpendances .............................................................. 9.5. Relations entre projets ............................................................................ 9.5.1. Au sujet des coordonnes .............................................................. 9.5.2. Projets multimodules .................................................................... 9.5.3. Hritage de projet ........................................................................ 9.6. Les bonnes pratiques du POM .................................................................. 9.6.1. Regrouper les dpendances ............................................................ 9.6.2. Multimodule ou hritage ............................................................... 10. Cycle de vie du build ...................................................................................... 10.1. Introduction ......................................................................................... 10.1.1. Cycle de vie Clean (clean) ........................................................... 10.1.2. Cycle de vie par dfaut (default) ................................................... 10.1.3. Cycle de vie Site (site) ............................................................... 10.2. Cycles de vie spcifiques par type de package ........................................... 10.2.1. JAR ......................................................................................... 10.2.2. POM ....................................................................................... 10.2.3. Plugin Maven ............................................................................ 10.2.4. EJB ......................................................................................... 10.2.5. WAR ....................................................................................... 10.2.6. EAR ........................................................................................ 10.2.7. Autres types de packaging ........................................................... 10.3. Goals communs aux cycles de vie ........................................................... 10.3.1. Traiter les resources ................................................................... 10.3.2. Compilation .............................................................................. 10.3.3. Traiter les ressources des tests ...................................................... 10.3.4. Compilation des tests .................................................................. 10.3.5. Tester ...................................................................................... 10.3.6. Installer l'artefact ....................................................................... 10.3.7. Dploiement ............................................................................. 11. Profils de Build .............................................................................................. 11.1. quoi servent-ils ? .............................................................................. 11.1.1. Qu'est ce que la Portabilit du Build ? ............................................ 11.1.2. Choisir le bon niveau de portabilit ............................................... 11.2. Portabilit grce aux profils Maven ......................................................... 11.2.1. Surcharger un POM ................................................................... 11.3. Activation de profil .............................................................................. 11.3.1. Configuration de l'activation ........................................................ 11.3.2. Activation par l'absence d'une proprit ..........................................
164 165 167 168 169 171 172 173 174 175 178 178 180 185 185 185 188 190 190 191 191 191 192 192 193 193 194 195 198 199 199 200 201 201 203 203 203 204 205 207 208 210 211
vi
11.4. Lister les profils actifs .......................................................................... 11.5. Trucs et Astuces .................................................................................. 11.5.1. Environnements communs ........................................................... 11.5.2. Protger les mots de passe ........................................................... 11.5.3. Classifieurs de plateforme ........................................................... 11.6. En rsum ........................................................................................... 12. Excuter Maven ............................................................................................. 12.1. Options de ligne de commande Maven ..................................................... 12.1.1. Dfinition de proprit ................................................................ 12.1.2. Obtenir de l'aide ........................................................................ 12.1.3. Utilisation de profils de build ....................................................... 12.1.4. Afficher les informations relatives la version ................................ 12.1.5. Travailler en mode dconnect ..................................................... 12.1.6. Utiliser le POM et le fichier settings de votre choix .......................... 12.1.7. Chiffrer les mots de passe ........................................................... 12.1.8. Gestion des erreurs .................................................................... 12.1.9. Contrle de la verbosit de Maven ................................................ 12.1.10. Excution de Maven en mode batch ............................................. 12.1.11. Tlchargement et vrification des dpendances ............................. 12.1.12. Contrle de la mise jour des plugins .......................................... 12.1.13. Builds non-rcursifs .................................................................. 12.2. Utilisation des options avances du Reactor ............................................... 12.2.1. Reprise de build ........................................................................ 12.2.2. Spcifier un sous ensemble de projets ............................................ 12.2.3. Construire des sous-ensembles ..................................................... 12.2.4. Modifier simple-weather et vrifier que nous n'avons rien cass grce --also-make-dependents ...................................................................... 12.2.5. Reprise d'un build "make" ........................................................... 12.3. Usage du plugin Maven Help ................................................................. 12.3.1. Dcrire un plugin Maven ............................................................ 13. Configuration Maven ....................................................................................... 13.1. Configuration des plugins Maven ............................................................ 13.1.1. Paramtres du plugin Configuration ............................................... 13.1.2. Ajouter des dpendances un plugin ............................................. 13.1.3. Configurer les paramtres globaux d'un plugin ................................. 13.1.4. Modifier les paramtres spcifiques une excution ......................... 13.1.5. Configuration des paramtres par dfaut pour une excution en ligne de commande ...................................................................................... 13.1.6. Configuration des paramtres pour les goals rattachs au cycle de vie par dfaut ........................................................................................... 14. Maven Assemblies .......................................................................................... 14.1. Introduction ......................................................................................... 14.2. Les bases du plugin Assembly ................................................................
211 212 212 214 215 217 219 219 219 219 221 221 221 222 222 222 223 223 223 224 224 225 225 225 226 226 226 227 227 231 231 231 234 235 235 236 236 239 239 239
vii
14.2.1. Les descripteurs Assembly prdfinis ............................................ 14.2.2. Construire un Assembly .............................................................. 14.2.3. Utilisation des assemblies comme dpendances ................................ 14.2.4. Construction d'assemblies partir d'assemblies dpendances ............... 14.3. Vue d'ensemble du descripteur d'assembly ................................................ 14.4. Le descripteur d'assembly ...................................................................... 14.4.1. Rfrence de proprit dans un descripteur d'assembly ...................... 14.4.2. Informations obligatoires pour un assembly .................................... 14.5. Choisir les contenus d'un assembly .......................................................... 14.5.1. Section files .......................................................................... 14.5.2. Section fileSets ..................................................................... 14.5.3. Patterns d'exclusion par dfaut pour la balise fileSets .................... 14.5.4. Section dependencySets ........................................................... 14.5.5. La balise moduleSets ............................................................... 14.5.6. Balise repositories ................................................................ 14.5.7. Gestion du rpertoire racine de l'assembly ...................................... 14.5.8. componentDescriptors et containerDescriptorHandlers ....... 14.6. Best Practices ...................................................................................... 14.6.1. Descripteurs d'assembly standards et rutilisables ............................. 14.6.2. Assembly de distribution (agrgation) ............................................ 14.7. En rsum ........................................................................................... 15. Proprits et filtrage des ressources .................................................................... 15.1. Introduction ......................................................................................... 15.2. Proprits Maven ................................................................................. 15.2.1. Proprits d'un projet Maven ........................................................ 15.2.2. Proprits des Settings Maven ...................................................... 15.2.3. Proprits des variables d'environnement ........................................ 15.2.4. Proprits systme Java .............................................................. 15.2.5. Proprits dfinies par l'utilisateur ................................................. 15.3. Filtrage des ressources .......................................................................... 16. Gnration du Site .......................................................................................... 16.1. Introduction ......................................................................................... 16.2. Contruire le site d'un projet avec Maven ................................................... 16.3. Personnaliser le descripteur de site .......................................................... 16.3.1. Personnaliser les images des en-ttes du site ................................... 16.3.2. Personnaliser le menu navigation .................................................. 16.4. Structure de rpertoire d'un site ............................................................... 16.5. crire la documentation d'un projet .......................................................... 16.5.1. Exemple de fichier APT .............................................................. 16.5.2. Exemple de fichier FML ............................................................. 16.6. Dployez le site de votre projet .............................................................. 16.6.1. Configurer l'authentification de votre serveur .................................. 16.6.2. Configurer les permissions des fichiers et dossiers ............................
240 241 244 244 248 249 249 249 251 251 252 254 255 265 271 272 273 273 274 277 281 283 283 283 284 286 286 286 287 289 293 293 293 295 296 297 298 299 299 300 301 302 302
viii
16.7. Personnaliser l'apparence de votre site ...................................................... 16.7.1. Personnaliser la CSS du site ........................................................ 16.7.2. Crer un modle de site personnalis ............................................. 16.7.3. Rutilisation des skins ................................................................ 16.7.4. Cration d'un thme CSS personnalis ........................................... 16.8. Trucs et Astuces .................................................................................. 16.8.1. Intecter du XHTML dans le HEAD ............................................... 16.8.2. Ajouter des liens sous le logo de votre site ...................................... 16.8.3. Ajouter un chemin de navigation votre site ................................... 16.8.4. Ajouter la version de votre projet .................................................. 16.8.5. Modifier le format et l'emplacement de la date de publication ............. 16.8.6. Utiliser des macros Doxia ........................................................... 17. Cration de Plugins ......................................................................................... 17.1. Introduction ......................................................................................... 17.2. Programmation Maven .......................................................................... 17.2.1. Qu'est ce que l'inversion de contrle ? ............................................ 17.2.2. Introduction Plexus .................................................................. 17.2.3. Pourquoi Plexus ? ...................................................................... 17.2.4. Qu'est ce qu'un Plugin ? .............................................................. 17.3. Descripteur de Plugin ............................................................................ 17.3.1. lments haut-niveau du descripteur de plugin ................................ 17.3.2. Configuration du Mojo ............................................................... 17.3.3. Dpendances d'un Plugin ............................................................. 17.4. crire un plugin personnalis ................................................................. 17.4.1. Cration d'un projet Plugin .......................................................... 17.4.2. Un simple Mojo Java ................................................................. 17.4.3. Configuration d'un prfixe de Plugin ............................................. 17.4.4. Les traces d'un plugin ................................................................. 17.4.5. Annotations de Mojo .................................................................. 17.4.6. Lorsque un Mojo choue ............................................................. 17.5. Paramtres d'un Mojo ........................................................................... 17.5.1. Affecter des valeurs aux paramtres de Mojo .................................. 17.5.2. Paramtres de Mojo multi-valeurs ................................................. 17.5.3. Dpendre de composants Plexus ................................................... 17.5.4. Paramtres des annotations d'un Mojo ............................................ 17.6. Plugins et le cycle de vie Maven ............................................................. 17.6.1. Excution dans un cycle de vie parallle ........................................ 17.6.2. Cration d'un cycle de vie personnalis .......................................... 17.6.3. Surcharge du cycle de vie par dfaut ............................................. 18. Utilisation des archetypes Maven ....................................................................... 18.1. Introduction aux archetypes Maven ......................................................... 18.2. Utilisation des archtypes ...................................................................... 18.2.1. Utilisation d'un archtype partir de la ligne de commande ................
303 303 304 308 309 311 311 311 312 312 313 314 317 317 317 317 318 319 320 320 322 323 325 326 326 327 328 331 332 333 334 334 336 338 339 340 340 341 342 345 345 345 345
ix
18.2.2. Utilisation du goal Generate en mode interactif ................................ 18.2.3. Utilisation d'un archtype partir du plugin Eclipse m2eclipse ............ 18.3. Archtypes disponibles .......................................................................... 18.3.1. Archtypes Maven communs ....................................................... 18.3.2. Archtypes tiers notables ............................................................. 18.4. Publication d'archtypes ........................................................................ 19. Dveloppement avec Flexmojos ........................................................................ 19.1. Introduction ......................................................................................... 19.2. Configuration de l'environnement de build pour Flexmojos ........................... 19.2.1. Faire rfrence un dpt contenant le Framework Flex .................... 19.2.2. Configuration de l'environnement pour les tests Flex Unit .................. 19.2.3. Ajouter FlexMojos aux groupes de plugins de votre configuration Maven .............................................................................................. 19.3. Cration d'un projet FlexMojos partir d'un archtype ................................. 19.3.1. Cration d'une bibliothque Flex ................................................... 19.3.2. Cration d'une application Flex ..................................................... 19.3.3. Creation d'un projet multimodule : Une application web avec une dpendance Flex .................................................................................. 19.4. Le cycle de vie de FlexMojos ................................................................. 19.4.1. Le cycle de vie SWC ................................................................. 19.4.2. Le cycle de vie SWF .................................................................. 19.5. Les goals du plugin FlexMojos ............................................................... 19.5.1. Gnration de la documentation ActionScript .................................. 19.5.2. Compilation des sources Flex ....................................................... 19.5.3. Gnration des fichiers de projet Flex Builder ................................. 19.6. Rapports du plugin FlexMojos ................................................................ 19.6.1. Produire le rapport de documentation ActionScript ........................... 19.7. Dveloppement et personnalisation de Flexmojos ....................................... 19.7.1. Obtenir le code source Flexmojos ................................................ A. Annexe : dtails des settings ...................................................................................... A.1. Aperu rapide ............................................................................................... A.2. Dtails des settings ........................................................................................ A.2.1. Valeurs simples .................................................................................. A.2.2. Balise servers ................................................................................. A.2.3. Balise mirrors ................................................................................. A.2.4. Balise proxies ................................................................................. A.2.5. Balise profiles ................................................................................ A.2.6. Balise activation ............................................................................ A.2.7. Balise properties ............................................................................ A.2.8. Balise repositories ......................................................................... A.2.9. Balise pluginRepositories .............................................................. A.2.10. Balise activeProfiles ................................................................... A.2.11. Chiffrement des mots de passe dans les Settings Maven ............................
346 348 349 349 350 353 355 355 355 355 360 362 362 363 367 370 375 376 377 378 379 379 381 381 381 382 383 385 385 385 385 386 387 388 389 389 390 391 393 394 394
xi
Copyright
Copyright 2009 Sonatype, Inc. Online version published by Sonatype, Inc., 654 High Street, Suite 220, Palo Alto, CA, 94301. Print version published by O'Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. Nutshell Handbook, the Nutshell Handbook logo, and the O'Reilly logo are registered trademarks of O'Reilly Media, Inc. The Developer's Notebook series designations, the look of a laboratory notebook, and related trade dress are trademarks of O'Reilly Media, Inc. Java(TM) and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc., in the United States and other countries. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and Sonatype, Inc. was aware of a trademark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and authors assume no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.
<a rel="cc:attributionURL" property="cc:attributionName" href="[Link] Inc.</a> / <a rel="license" href="[Link] CC BY-NC-ND 3.0</a> </div>
When downloaded or distributed in a jurisdiction other than the United States of America, this work shall be covered by the appropriate ported version of Creative Commons Attribution-NoncommercialNo Derivative Works 3.0 license for the specific jurisdiction. If the Creative Commons AttributionNoncommercial-No Derivative Works version 3.0 license is not available for a specific jurisdiction, this work shall be covered under the Creative Commons Attribution-Noncommercial-No Derivate Works version 2.5 license for the jurisdiction in which the work was downloaded or distributed. A comprehensive list of jurisdictions for which a Creative Commons license is available can be found on the Creative Commons International web site at [Link] If no ported version of the Creative Commons license exists for a particular jurisdiction, this work shall be covered by the generic, unported Creative Commons Attribution-Noncommercial-No Derivative Works version 3.0 license available from [Link]
xiv
1. Historique de Modifications
De nombreux lecteurs nous ont demand de tracer les modifications que nous apportons au contenu du livre, la section suivante les liste par ordre retro-chronologique depuis la version 0.9-SNAPSHOT.
[Link] [Link]
Fixed a spelling related typo on Page 7 in Section 1.7, Comparaison de Maven et de Ant . (MVNDEF-2899) Split a sentence on Page 5 in Section 1.6, Maven est-il une alternative XYZ ? . (MVNDEF-30210) Fixed a sentence structure issues on Page 48 in Section 4.6, Code source de Simple Weather . (MVNDEF-30411) Fixed a spelling typo on Page 39 in Section 3.5.5, La gestion des dpendances de Maven . (MVNDEF-31012) Added missing punctuation on Page 360 in Section A.2.1, Valeurs simples . (MVNDEF-31313) Fixed a grammar error on Page 356 in Section 19.7.1, Obtenir le code source Flexmojos . (MVNDEF-31414) Fixed a wording issues on Page 353 in Section 19.5.2, Compilation des sources Flex . (MVNDEF-31515) Fixed a spelling problem on Page 324 in Section [Link], Plugins Confluence et JIRA . (MVNDEF-31716) Fixed a spelling problem on Page 320 in Section 18.2.2, Utilisation du goal Generate en mode interactif . (MVNDEF-31817) Fixed two sentence structure issue on Page 312 in Section 17.6.1, Excution dans un cycle de vie parallle . (MVNDEF-32018) Fixed a spelling issue on Page 311 in Section 17.5.4, Paramtres des annotations d'un Mojo . (MVNDEF-32119) Fixed several sentence structure issues on Page 30 in Section 3.5.1, Plugins Maven et Goals . (MVNDEF-32320) Fixed a tense issue on Page 298 in Section 17.4.1, Cration d'un projet Plugin . (MVNDEF-32421) Capitalized "Java" on Page 296 in Section 17.3.2, Configuration du Mojo . Changed the note for executionStrategy. Added a missing question mark. (MVNDEF-32522) Fixed some sentence structure issues on Page 294 in Section 17.3.1, lments haut-niveau du descripteur de plugin . (MVNDEF-32623)
xvi
Fixed some sentence structure issues on Page 290 in Section 17.2.1, Qu'est ce que l'inversion de contrle ? . (MVNDEF-32724) Fixed some wording issues on Page 282 in ???. (MVNDEF-32825) Added a missing word on Page 281 in Section 16.7.4, Cration d'un thme CSS personnalis . (MVNDEF-32926) Fixed a wording issue on Page 273 in Section 16.6, Dployez le site de votre projet . (MVNDEF-33027) Fixed a spelling issue on Page 244 in Section 14.5.6, Balise repositories . (MVNDEF-33128) Fixed wording issues on Page 229 in Section 14.5.4, Section dependencySets . (MVNDEF-33229) Modified sentence structure in Section 11.2, Portabilit grce aux profils Maven . (MVNDEF-33730) Removed unnecessary comma from Page 168 in Section 9.5.2, Projets multimodules . (MVNDEF-33931) Fixed sentence structure on Page 166 in Section 9.5.1, Au sujet des coordonnes . (MVNDEF-34032) Fixed various spelling and grammar typos on Page 155 in Section 9.3, Syntaxe de POM . (MVNDEF-34133) Fixed punctuation issues on Page 149 in Section 9.2.1, Le Super POM . (MVNDEF-34234) Fixed some spelling and wording issues on Page 119 in Section 7.8, Le module de ligne de commande . (MVNDEF-34435) Fixed some punctuation issues on Page 110 in Section 7.6, Le module simple-webapp . (MVNDEF-34536) Responding to Grant Birchmeier's proofread of the Preface material from GetSatisfaction. (MVNDEF-34637, MVNDEF-34738) Split sentence in second paragraph of Section 1, Comment utiliser ce livre . (MVNDEF-34939) Fixed mismatch between contact address and footnote in first paragraph of Section 2, Vos Retours . (MVNDEF-35040) Making sure that the Italic is really italic in the font conventions section. (MVNDEF-35141)
xvii
Adopted the proposed language for the "plugin" bullet point. (MVNDEF-35242) Added a missing article to the first sentence of the first paragraph of Section 1.3, Une Interface Commune . (MVNDEF-35343) Rearranged a long, ungrammatical sentence at the start of the last paragraph in Section 1.4, Rutilisation universelle grce aux plugins Maven . (MVNDEF-35444) Added a missing preposition to first bullet in Section 1.5, Le Modle conceptuel d'un "Projet" . (MVNDEF-35545) Reworded the universal reuse bullet item in Section 1.5, Le Modle conceptuel d'un "Projet" . (MVNDEF-35646) Removed final sentence in Section 1.5, Le Modle conceptuel d'un "Projet" . (MVNDEF-35747) Removed the last sentence of Section 1.6, Maven est-il une alternative XYZ ? . (MVNDEF-35848) Removed a superfluous "the" from the first paragraph of Section 1.7, Comparaison de Maven et de Ant . (MVNDEF-35949) Rewrote the first paragraph of Section 1.7, Comparaison de Maven et de Ant . (MVNDEF-36050) Rewrote second and third sentence fragments in the sixth paragraph of Section 1.7, Comparaison de Maven et de Ant . (MVNDEF-36251) Made sure that the comparison bullet points used consistent tense. Fixed a number of sentence fragment issues in the comparison bullet points. (MVNDEF-36352, MVNEF-36453, MVNDEF-36554, and MVNDEF-36655) Addressed a few grammar errors in the third to last paragraph of Section 1.7, Comparaison de Maven et de Ant . (MVNDEF-36756) Combined the first two sentences of Section 2.5.2, Mettre jour une installation de Maven . (MVNDEF-36957) Italicized a book title in Section 2.5.3, Migrer de Maven 1.x Maven 2.x . (MVNDEF-37158) Separating URLs with a colon twice in Section 2.8, propos de l'Apache Software License . (MVNDEF-37259)
xviii
Fixed an incorrect reference to Part II in the third paragraph of Partie I, Maven par l'exemple . (MVNDEF-37360)
xix
Verified that examples can be compiled without the need for Sonatype repositories in response to a reader question. (MVNDEF-7270) Minor formatting typo fixed in Section 14.2.2, Construire un Assembly . (MVNDEF-4271) Resized all Vector Images to fit within Print Margins. Resized PDF to Royal Quatro sizing for print-on-demand. Automated generation of print figures. PDF now bundles fonts to satisfy pre-print requirements.
xx
Correction de fautes de frappe mineures dans Section 11.5.3, Classifieurs de plateforme . ( MVNDEF-124 87) Correction de la faute de frappe [Link] instead au lieu de [Link]. Erreurs corriges dans Chapitre 19, Dveloppement avec Flexmojos. ( MVNDEF-129 88)
xxi
MVNDEF-102 99 - Mise jour du livre pour rfrencer la version 3.2.0 de FlexMojos MVNDEF-94 100 - Documentation des goals test-compile et test-run. - ??? MVNDEF-89 101 - Documentation du goal flexbuilder - Section 19.5.3, Gnration des fichiers de projet Flex Builder MVNDEF-87 102 - Documentation des goals compile-swc et compile-swf - Section 19.5.2, Compilation des sources Flex MVNDEF-86 103 - Documentation du goal et du rapport Actionscript Documentation Section 19.5.1, Gnration de la documentation ActionScript et Section 19.6, Rapports du plugin FlexMojos
xxii
MVNDEF-39 112 - Le prefixe du goal du plugin Compiler est "compiler" et non "compile" comme il tait prcdemment crit dans Section 17.3.1, lments haut-niveau du descripteur de plugin
xxiii
Prface
Maven est un outil de "build", de gestion de projet, un conteneur abstrait o s'excutent les diffrentes tapes de construction du projet. C'est un outil qui s'est rvl indispensable pour les projets qui deviennent complexes et qui ont besoin de construire et de grer de manire cohrente de nombreux modules et bibliothques interdpendants, eux-mme utilisant des dizaines voir des centaines de composants tiers. C'est un outil qui a fortement allg le fardeau quotidien de la gestion des dpendances vers les bibliothques tierces pour des millions d'ingnieurs, et a permis de nombreuses organisations de se sortir de l'ornire de la gestion du build de projet pour atteindre un monde o l'effort requis pour construire et maintenir un logiciel n'est plus le facteur limitant dans sa conception. Ce travail est la premire tentative d'un livre complet sur Maven. Il se base sur les expriences et le travail combins des auteurs des livres prcdents sur Maven, aussi vous ne devez pas le voir comme une tape finale mais comme la premire dition d'une longue liste de mises jour. Alors que Maven n'a que quelques annes d'existence, les auteurs de ce livre pensent qu'il a juste commenc remplir les audacieuses promesses faites. Les auteurs, et l'entreprise derrire ce livre, Sonatype1, pensent que la publication de ce livre marque le dbut d'une nouvelle phase d'innovation et de dveloppement de Maven et de son cosystme environnant.
[Link]
sujet particulier. Vous pouvez sauter certaines parties du livre, la Partie I, Maven par l'exemple n'est en aucune sorte un pr-requis pour la Partie II, Maven - La Reference , mais vous pourrez mieux apprcier la Partie II, Maven - La Reference si vous avez lu la Partie I, Maven par l'exemple . Maven s'apprend mieux par l'exemple, mais une fois ceux-ci faits, vous aurez besoin d'lments de rfrence pour commencer adapter Maven votre environnement.
2. Vos Retours
Nous n'avons pas crit ce livre afin de produire un document Word que nous enverrions notre maison d'dition avant d'aller en fter le lancement en nous autocongratulant pour un travail termin. Ce livre n'est pas "termin" ; en fait, ce livre ne le sera jamais compltement. Le sujet qu'il couvre est en perptuelle volution et expansion, aussi nous considrons ce travail comme une discussion vivante avec la communaut. Publier ce livre signifie juste que le vritable travail vient de commencer, et vous, notre lecteur, vous avez un rle essentiel pour nous aider maintenir et amliorer ce livre. Si vous voyez une erreur quelconque dans ce livre, une faute d'orthographe, du code de mauvaise qualit, un mensonge hont, envoyez-nous un e-mail : book@sonatype.com2. C'est grce vous et vos retours que ce livre restera pertinent. Nous voulons savoir ce qui marche et ce qui ne marche pas. Nous voulons savoir s'il existe des points qui restent obscurs. Notamment, nous voulons savoir si vous trouvez ce livre affreux. Les commentaires positifs ou ngatifs sont les bienvenus. Bien sr nous nous rservons le droit de ne pas tre d'accord avec vous, mais toute remarque sera rcompense par une jolie rponse.
3. Conventions de Police
Ce livre respecte certaines conventions quant l'utilisation des polices de caractre. Comprendre ces conventions ds le dbut facilite l'utilisation de ce livre.
Italic
Utilise pour les fichiers, les extensions, les URLs, les noms des applications, la mise en valeur, et les termes nouveaux lors de leur premire utilisation.
Largeur Fixe
Utilise pour les classes, les mthodes, les variables Java, les proprits, les lments en relation avec les bases de donnes, et les extraits de code qui apparaissent dans le texte.
Largeur Fixe Gras
Utilise pour les commandes que vous devez taper sur une ligne de commande et pour mettre en valeur un nouvel lment de code introduit dans un exemple qui fonctionne.
Largeur fixe italique
[Link]
xxvi
Les noms de goal sont affichs avec une police largeur fixe. plugin Alors que la relle orthographe "plug-in" (avec un tiret) est probablement plus rpandue, ce livre utiliser le terme "plugin" pour deux raisons : il est plus facile lire et crire et c'est devenu le standard pour la communaut Maven. Cycle de vie Maven, Structure Standard Maven des Rpertoires, Plugin Maven, Modle Objet de Projet (Project Object Model) Les concepts fondamentaux de Maven commencent par des majuscules lorsqu'il y est fait rfrence dans le texte.
goalParameter
Le paramtre d'un goal Maven est affich avec une police largeur fixe.
compile phase
Les phases du cycle de vie de Maven sont affiches avec une police largeur fixe.
5. Remerciements
Sonatype souhaite remercier les contributeurs suivants. Les personnes cites ci-dessous ont fourni des retours qui ont permis l'amlioration de la qualit de cet ouvrage. Merci donc Raymond Toal, Steve Daly, Paul Strack, Paul Reinerfelt, Chad Gorshing, Marcus Biel, Brian Dols, Mangalaganesh Balasubramanian, Marius Kruger et Mark Stewart. Et plus spcifiquement, merci Joel Costigliola pour son aide dbogger et corriger le chapitre sur Spring web. Stan Guillory tait pratiquement un contributeur au vu du nombre de corrections qu'il a post sur le site Get Satisfaction pour ce livre. Merci Stan. Un grand merci Richard Coasby de Bamboo pour son rle de consultant en grammaire. Merci tous nos auteurs contributeurs, y compris Eric Redmond. Merci aux contributeurs suivants qui nous ont signal des erreurs soit par courriel soit par le site Get Satisfaction: Paco Sobern, Ray Krueger, Steinar Cook, Henning Saul, Anders Hammar, "george_007", "ksangani", Niko Mahle, Arun Kumar, Harold Shinsato, "mimil", "-thrawn-", Matt Gumbley. Si vous voyez votre pseudo Get Satisfaction dans cette liste, et que vous souhaitiez le voir remplac par votre vritable nom, envoyez nous un courriel book@sonatype.com3.
3
[Link]
xxvii
xxviii
[Link] [Link]
spcifications initiales EJB 2.1. On retrouve une illustration de ce principe au travers de la persistance EJB3 : pour rendre une classe persistante tout ce que vous avez faire est de l'annoter avec @Entity. Le framework va considrer que les noms de la table et des colonnes seront ceux de la classe et de ses attributs. Si le besoin s'en ressent, vous pouvez surcharger ces noms prdfinis, mais la plupart du temps, l'usage de ces conventions implicites du framework procurera un gain de temps apprciable au projet. Maven intgre ce concept en ayant un comportement logique par dfaut. Sans configuration spcifique, le code source est suppos se trouver dans ${basedir}/src/main/java et les diffrentes ressources dans ${basedir}/src/main/resources. Les tests, eux, sont supposs tre dans ${basedir}/ src/test, et un projet est suppos produire un fichier JAR. Maven suppose que vous voulez compiler en bytecode dans ${basedir}/target/classes et ensuite crer votre fichier JAR distribuable dans ${basedir}/target. Mme si tout cela peut sembler trivial, n'oubliez pas que pour la plupart des scripts Ant vous devez dfinir les emplacements de ces diffrents rpertoires. Ant n'a pas la moindre ide d'o se trouve le code source et les diffrentes ressources, vous devez le lui indiquer. L'adoption par Maven de ce principe de "convention plutt que configuration" va plus loin que les rpertoires, les plugins au cur de Maven appliquent un ensemble de conventions pour compiler le code source, packager les lments distribuer, produire des sites web, et bien d'autres traitements. La force de Maven vient de ses "convictions", il a un cycle de vie bien dfini et un ensemble de plugins de base pour construire et assembler un logiciel. Si vous suivez les conventions, Maven ne va vous demander quasiment aucun effort - vous n'avez qu' mettre votre code source dans le bon rpertoire et Maven s'occupe du reste. Une des consquences des systmes respectant le principe de "convention plutt que configuration" est que leurs utilisateurs peuvent se sentir contraints de suivre une certaine mthodologie. S'il est vrai que Maven a fait certains choix qui ne doivent pas tre remis en cause, la plupart des valeurs par dfaut peuvent tre adaptes. Par exemple, il est tout fait possible de modifier l'emplacement du code source et des ressources pour un projet, de redfinir les noms des fichiers JAR, et il est possible d'adapter presque tous les comportements aux spcificits de votre projet par le dveloppement de plugins spcifiques. Si vous ne souhaitez pas suivre les conventions, Maven vous permettra de changer les valeurs par dfaut selon vos propres besoins.
[Link] [Link]
Cette poque se caractrisait par des discussions sans fin sur les outils et les procdures pour construire un logiciel. Le monde d'avant Maven tait un monde inefficace, l'ge de "l'Ingnieur du Build". Aujourd'hui, la plupart des dveloppeurs du libre ont utilis ou utilisent Maven pour grer leurs nouveaux projets logiciels. Cette transition n'est pas le simple passage d'un outil de build un autre, mais l'adoption d'une interface commune de construction de projet. Pendant que les logiciels devenaient modulaires, les systmes de build devenaient de plus en plus complexes et le nombre de projets a crev le plafond. Avant Maven, lorsque vous vouliez rcuprer le code source de projets comme Apache ActiveMQ5 ou Apache ServiceMix6 depuis Subversion et le construire partir de ses sources, vous deviez passer plus d'une heure essayer de comprendre comment fonctionnait le systme de build de chacun de ces projets. De quoi a t'on besoin pour construire ce projet ? Quelles bibliothques dois-je tlcharger ? Ensuite, o dois-je les mettre ? Quelles tches dois-je excuter dans le build ? Dans le meilleur des cas, il fallait quelques minutes pour comprendre comment construire un logiciel, dans le pire (par exemple l'antique implmentation de l'API Servlet du projet Jakarta), construire le logiciel tait si complexe qu'il fallait plusieurs heures un nouveau contributeur pour pouvoir modifier le code source et compiler le projet. De nos jours, il suffit de rcuprer le source et d'excuter la commande mvn install. Mme si Maven fournit tout un ensemble d'avantages, dont la gestion des dpendances et la rutilisation de comportements communs de build par ses plugins, la raison principale de son succs vient de la cration d'une interface unifie pour construire un logiciel. Si vous voyez qu'un projet comme Apache Wicket7 utilise Maven, vous pouvez supposer qu'aprs avoir rcupr son code source, la commande mvn install vous permettra de le construire sans trop de problmes. Vous savez o insrer la clef de contact, que la pdale d'acclrateur se trouve droite et le frein gauche.
Maven rcupre les dpendances et les plugins depuis des dpts distants que vous pouvez rutiliser une logique de build universelle. Le plugin Maven Surefire est le plugin qui a en charge l'excution des tests unitaires. un moment donn, entre la version 1.0 et la version utilise actuellement quelqu'un a dcid d'apporter le support du framework de tests unitaires TestNG en plus de celui de JUnit. Cette mise jour s'est faite sans casser la compatibilit ascendante. Si vous utilisez le plugin Surefire pour compiler et excuter vos tests unitaires JUnit 3, et que vous le mettez jour, vos tests continueront de s'excuter sans erreur. Mais vous avez obtenu une nouvelle fonctionnalit, vous pouvez excuter des tests avec TestNG. Et en plus, vous pouvez excuter des tests unitaires JUnit 4 annots. Tout cela sans avoir mettre jour votre installation de Maven ou installer quoi que ce soit. Et plus important encore, vous n'avez rien chang votre projet si ce n'est le numro de version d'un plugin dans un unique fichier de configuration de Maven, le Project Object Model (POM). C'est ce mme mcanisme que l'on retrouve dans tout Maven. Maven dispose de plugins pour tout faire, de la compilation du code Java la gnration de rapports et au dploiement sur un serveur d'applications. Maven a extrait les tches de la construction d'un projet dans des plugins qui sont centraliss pour leur maintenance et partags universellement. Si l'tat de l'art change pour une tape quelconque du build, si un nouveau framework de tests unitaires sort, si de nouveaux outils deviennent disponibles, vous n'avez plus ajouter une nouvelle verrue votre systme personnalis de build pour en profiter. Vous allez bnficier du fait que les plugins sont tlchargs depuis un dpt distant et maintenus centralement. C'est tout cela qu'implique la notion de rutilisation universelle par les plugins Maven.
Rutilisation universelle de la logique de build Les plugins contiennent toute la logique de traitement. Ils s'appuient sur les donnes et paramtres de configuration dfinit dans le Project Object Model (POM). Ils ne sont pas conus pour fonctionner avec des fichiers spcifiques des endroits connus. Portabilit / Intgration dans des outils Les outils tels qu'Eclipse, NetBeans, et IntelliJ ont maintenant un endroit unique pour aller rcuprer les informations sur un projet. Avant Maven, chaque EDI conservait sa manire ce qui tait, plus ou moins, son propre Project Object Model (POM). Maven a standardis cette description, et alors que chaque EDI continue maintenir ses propres fichiers dcrivant le projet, ils peuvent tre facilement gnrs partir du modle. Facilits pour la recherche et le filtrage des artefacts d'un projet Des outils tels que Nexus vous permettent d'indexer et de rechercher les contenus d'un dpt partir des informations contenues dans le POM.
[Link]
Les gros titres tels que "Qui sera le vainqueur ? Ant ou Maven ?" ne sont pas trs constructifs. Si vous exigez de nous une rponse, bien sr que nous dirons que Maven est une meilleure alternative que Ant comme technologie fondamentale pour un build ; en mme temps, les frontires de Maven changent tout le temps, et la communaut Maven cherche en permanence de nouvelles voies pour le rendre plus cumnique, plus interoprable, plus coopratif. Les principes au cur de Maven sont le build dclaratif, la gestion des dpendances, les dpts, la rutilisation universelle grce aux plugins, cependant la concrtisation de ces ides n'a que peu d'importance par rapport au fait que la communaut Open Source collabore pour amliorer l'efficacit des builds "l'chelle de l'entreprise".
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --> <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/> </target> <target name="clean" description="clean up" > <!-- Delete the ${build} and ${dist} directory trees --> <delete dir="${build}"/> <delete dir="${dist}"/> </target> </project>
Dans cet exemple, on peut voir qu'il faut dire Ant exactement ce quil doit faire. On a une cible compile qui inclut la tche javac pour compiler le code source du rpertoire src/main/java dans le rpertoire target/classes. Vous devez indiquer Ant exactement o se trouve votre code source, o le bytecode produit devra tre sauv, et comment packager tout cela dans un fichier JAR. Mme si des dveloppements rcents tendent rendre Ant moins procdural, pour un dveloppeur, Ant reste un langage de code procdural en XML. Comparons l'exemple Ant prcdent avec un exemple Maven. Avec Maven, pour crer un fichier JAR partir de code source Java, tout ce que vous avez faire est de crer un simple fichier [Link], mettre votre code source dans ${basedir}/src/main/java et excuter la commande mvn install depuis la ligne de commande. Le contenu du fichier [Link] Maven qui permet d'obtenir le mme rsultat que le simple fichier Ant dcrit dans l'Exemple 1.1, Simple fichier [Link] pour Ant est le suivant : Exemple 1.2. Simple fichier [Link] pour Maven
<project> <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>my-project</artifactId> <version>1.0</version> </project>
C'est tout ce dont vous avez besoin dans votre [Link]. Excuter mvn install depuis la ligne de commande va traiter les ressources, compiler le source, excuter les tests unitaires, crer un JAR, et installer ce JAR dans le dpt local pour qu'il soit rutilisable par d'autres projets. Toujours sans rien modifier, vous pouvez excuter la commande mvn site et vous trouverez un fichier [Link] dans target/site contenant des liens vers la JavaDoc et quelques rapports sur votre code source. Certes, c'est l'exemple de projet le plus simple possible. Il ne contient rien d'autre que du code source et produit un JAR. C'est un projet qui suit les conventions de Maven et qui ne demande aucune dpendance ou personnalisation. Si nous voulons personnaliser le comportement, notre fichier [Link] va grossir, et dans les plus gros projets, vous pouvez trouver une collection de POMs Maven trs complexes qui contiennent beaucoup de configuration de plugins et de dclarations de dpendances. Mais, mme lorsque les fichiers POM de votre projet grossissent, ils contiennent des informations d'une nature diffrente de celles du fichier de build Ant d'un projet de taille similaire. Les POMs Maven contiennent
des dclarations : "C'est un projet JAR" ou "Le code source se trouve dans src/main/java". Les scripts Ant contiennent des instructions explicites : "Ceci est le projet", "Le code source se trouve dans src/ main/java", "Excuter javac sur ce rpertoire, "Mettre les rsultats dans target/classes", "Crer un JAR partir de ....", etc. L o Ant se doit d'tre explicite avec le traitement, il y a quelque chose "d'inn" chez Maven qui sait o se trouve le code source et ce qu'il doit en faire. Les diffrences entre Ant et Maven dans cet exemple sont : Apache Ant Ant ne dispose d'aucune convention formelle ni comportement par dfaut. Il vous faut indiquer Ant exactement o trouver le source et o mettre les rsultats. Des conventions informelles ont merg au cours du temps, mais elles n'ont pas t intgres au produit. Ant est procdural. Il faut lui indiquer exactement ce qu'il doit faire et quand le faire. Il faut lui dire de compiler, puis de copier, puis de compresser. Ant n'a pas de cycle de vie. Vous devez dfinir des fonctions et les dpendances de ces fonctions. Vous devez ensuite rattacher une srie de tches chaque fonction manuellement. Apache Maven Maven possde ses conventions. Il sait o se trouve le code source car vous suivez une convention. Le plugin Maven Compiler place le bytecode dans target/classes et produit un fichier JAR dans le rpertoire target. Maven est dclaratif. Tout ce que vous avez faire est de crer un fichier [Link] et mettre votre code source dans le rpertoire par dfaut. Maven s'occupe du reste. Maven possde son propre cycle de vie que vous invoquez lorsque vous excutez la commande mvn install. Cette commande demande Maven d'excuter une srie d'tapes jusqu' la fin du cycle de vie. Une des consquences de ce parcours du cycle de vie, est que Maven excute un certain nombre de goals de plugins par dfaut qui vont raliser certaines tches comme de compiler et de crer un JAR. Maven intgre une certaine intelligence sur les tches communes sous la forme de plugins Maven. Si vous voulez crire et excuter des tests unitaires, tout ce que vous avez faire est d'crire ces tests et de les mettre dans ${basedir}/src/test/java, ajouter une dpendance de type test sur TestNG ou JUnit, et excuter la commande mvn test. Si vous voulez dployer une application web et non plus un JAR, tout ce que vous avez faire est de changer le type de votre projet en war et de positionner le rpertoire racine de l'application web sur ${basedir}/src/main/webapp. Bien sr, vous pourriez faire tout cela avec Ant mais vous devriez tout crire depuis le dbut. Dans Ant, vous devriez commencer par dfinir o devrait se trouver le fichier JAR de JUnit, ensuite vous devriez crer un classpath qui contienne ce fichier JAR de JUnit, puis vous devriez indiquer Ant o devrait se trouver le code source des tests, crire une fonction pour compiler le code source des tests en bytecode, et pour excuter ces tests unitaires avec JUnit.
Sans l'apport des technologies comme antlibs et Ivy (et mme avec ces technologies complmentaires), Ant laisse l'impression d'un build procdural personnalis. Un ensemble efficace de POMs Maven dans un projet qui respecte les conventions de Maven a peu de XML, aussi surprenant que cela puisse paratre, en comparaison de Ant. Un autre avantage de Maven est qu'il s'appuie sur des plugins Maven trs largement diffuss et partags. Tout le monde utilise le plugin Maven Surefire pour les tests unitaires, et si quelqu'un ajoute le support d'un nouveau framework de tests unitaires, vous obtenez cette nouvelle fonctionnalit dans votre build juste en incrmentant le numro de version de ce plugin particulier dans le POM de votre projet. La dcision d'utiliser Maven ou Ant n'est pas une dcision binaire, et Ant a toujours sa place pour les builds complexes. Si votre build contient un traitement trs spcifique, ou si vous avez crit des scripts Ant pour remplir une tche particulire de manire spcifique qui ne peut tre adapte aux standards Maven, vous pouvez toujours utiliser ces scripts dans Maven. Ant est disponible sous la forme d'un des principaux plugins de Maven. Des plugins personnaliss de Maven peuvent tre crits en utilisant Ant, et les projets Maven peuvent tre configurs pour excuter des scripts Ant durant le cycle de vie du projet Maven.
Maven fonctionne avec tous les kits de dveloppement Java TM certifis compatibles et galement avec certaines implmentations de Java non certifies. Les exemples fournis avec ce livre ont t crits et tests avec les versions officielles du Java Development Kit tlcharges depuis le site internet de Sun Microsystems. Si vous tes sous GNU/Linux, vous pouvez avoir besoin de tlcharger le JDK de Sun vous-mme et vrifier qu'il s'agit de la version que vous utilisez (en excutant la commande java version). Maintenant que Sun a mis Java en Open Source, cela devrait s'amliorer et nous devrions rapidement trouver la JRE et le JDK de Sun par dfaut mme dans les distributions puristes de GNU/ Linux. En attendant ce jour, vous pouvez avoir le tlcharger.
[Link]
les termes de cette licence avant de commencer utiliser le produit. Plus d'informtions sur l'Apache Software License se trouvent dans la Section 2.8, propos de l'Apache Software License .
Une fois Maven install, il vous reste quelques petites choses faire afin de pouvoir l'utiliser correctement. Vous devez ajouter le rpertoire bin de la distribution (dans notre exemple /usr/local/ maven/bin) au PATH de votre systme. Vous devez aussi positionner la variable d'environnement M2_HOME sur le rpertoire racine de votre installation (pour notre exemple, /usr/local/maven).
Note
Les instructions d'installation sont les mmes pour OSX Tiger et OSX Leopard. On nous a rapport que Maven 2.0.6 est livr avec la prversion de XCode. Si vous avez install XCode, excutez la commande mvn en ligne de commande pour vrifier sa disponibilit. XCode installe Maven dans le rpertoire /usr/share/maven. Il est recommand d'utiliser la dernire version de Maven 2.2.1, de nombreux bugs critiques ont t corrigs depuis la version 2.0.6 de Maven. Vous allez devoir ajouter les variables M2_HOME et PATH un script qui sera excut chaque fois que vous vous connecterez votre systme. Pour cela, ajouter les lignes suivantes au .bash_login.
export M2_HOME=/usr/local/maven export PATH=${M2_HOME}/bin:${PATH}
Maintenant que vous avez mis jour votre environnement avec ces quelques lignes, vous pouvez excuter Maven en ligne de commande.
12
Note
Pour ces instructions d'installation nous avons suppos que vous utilisiez le shell bash. [Link]. Installer Maven sur OSX avec MacPorts Si vous utilisez MacPorts, vous pouvez installer le port maven2 en excutant les instructions suivantes en ligne de commande.
$sudo port install maven2 Password: ****** ---> Fetching maven2 ---> Attempting to fetch [Link].bz2 from [Link] ---> Verifying checksum(s) for maven2 ---> Extracting maven2 ---> Configuring maven2 ---> Building maven2 with target all ---> Staging maven2 into destroot ---> Installing maven2 2.2.1_0 ---> Activating maven2 2.2.1_0 ---> Cleaning maven2
Pour plus d'informations sur le port maven2, allez voir maven2 Portfile 2. Pour plus d'informations sur le projet MacPorts et son installation, allez voir la page du projet MacPorts3.
Dfinir ces variables d'environnement en ligne de commande va vous permettre d'excuter Maven dans la mme console. Mais moins de les dfinir comme des variables du Systme avec le Panneau de Configuration, vous devrez excuter ces deux lignes chaque fois que vous vous connecterez votre systme. Vous devriez modifier ces deux variables avec le Panneau de Configuration de Microsoft Windows.
2 3
[Link] [Link]
13
Si vous obtenez cette sortie, vous savez que Maven est disponible et prt tre utilis. Si vous n'obtenez pas cette sortie et que votre systme d'exploitation ne peut pas trouver la commande mvn, vrifiez que vos variables d'environnement PATH et M2_HOME sont correctement dfinies.
Avez-vous dj achet un disque dur de 200 Go pour vous rendre compte qu'une fois install il faisait moins de 200 GiB ? Les ordinateurs fonctionnent en Gibibytes, mais les boutiques vendent des produits en Gigaoctets. MiB reprsente des Mebibyte soit 2 20 ou 1024 2. Ces mesures standardises sont valides et reconnues par l'IEEE, le CIPM, et l'IEC. Pour plus d'informations sur Kibibytes, Mebibytes, Gibibytes, et Tebibytes, lisez [Link] [[Link] Mebibyte],
14
conf/ lib/
Le fichier [Link] contient la licence logicielle pour Apache Maven. Cette licence sera dtaille dans la Section 2.8, propos de l'Apache Software License . Le fichier [Link] contient des remarques et les attributions exiges par les bibliothques dont dpend Maven. Le fichier [Link] contient lui les instructions d'installation. Le rpertoire bin/ contient le script mvn qui permet l'excution de Maven. Dans boot/ se trouve le fichier JAR ( [Link]) qui a pour fonction de crer le chargeur de classes (Classloader) dans lequel s'excute Maven. Le rpertoire conf/ contient un fichier [Link] global qui permet de personnaliser le comportement d'une installation de Maven. Si vous devez personnaliser Maven, il est d'usage de surcharger les paramtres dans le fichier [Link] qui se trouve dans ~/.m2. Le rpertoire lib/ contient un fichier JAR unique ([Link]) qui contient le cur de Maven.
Note
A moins que vous ne travailliez sur un systme Unix partag, vous ne devriez pas avoir modifier le fichier [Link] du rpertoire M2_HOME/conf. Modifier le fichier [Link] global dans l'installation de Maven est inutile dans la plupart des cas et risque de compliquer inutilement toute mise jour de Maven, puisque vous aurez vous souvenir de copier ce fichier [Link] modifi depuis votre ancienne installation de Maven dans la nouvelle. Si vous devez modifier le fichier [Link], vous devriez modifier le fichier [Link] qui vous est propre : ~/.m2/[Link].
Note
Sous Unix (et OSX), votre rpertoire utilisateur est symbolis par un tilde (i.e. ~/bin correspond au rpertoire /home/tobrien/bin). Sous Windows, nous utiliserons aussi ce caractre ~ pour symboliser votre rpertoire utilisateur. Ainsi, sous Windows XP votre rpertoire utilisateur est C:\Documents and Settings\tobrien et sous Windows
15
Vista, votre rpertoire utilisateur est C:\Users\tobrien. partir de maintenant, vous devrez traduire les chemins du type ~/m2 en fonction de votre systme d'exploitation.
Note
Si vous avez modifi le fichier global [Link] de M2_HOME/conf, vous devrez copier le [Link] dans le rpertoire conf de la nouvelle installation de Maven.
one: convert va lire le fichier [Link] et produire un [Link] compatible avec Maven 2. Si votre build Maven 1 a t personnalis avec un script Jelly dans le fichier [Link], il va vous falloir
tester d'autres options. Alors que Maven 1 prconisait l'utilisation de scripts Jelly pour personnaliser
5
[Link]
16
les builds, Maven 2, lui, prconise la personnalisation au travers de vos propres plugins, de plugins de script ou du plugin Maven Antrun. Ce qu'il faut retenir lorsque l'on migre de Maven 1 Maven 2, c'est que Maven 2 est un framework de build compltement diffrent. Maven 2 introduit le concept du Cycle de Vie Maven, et redfinit les relations entre plugins. Si vous migrez de Maven 1 Maven 2, vous devez passer du temps apprendre les diffrences qui existent entre ces deux versions. Bien qu'il puisse sembler plus important de commencer par apprendre la nouvelle structure du POM, vous devriez commencer par le cycle de vie. Une fois le cycle de vie de Maven compris, vous pourrez utiliser toute la puissance de Maven.
17
[Link] 6. Vous pouvez vous abonner cette liste de diffusion en suivant les instructions disponibles ici: [Link] 7. [Link] Sonatype maintient une version en ligne de ce livre ainsi que des formations autour d'Apache Maven.
18
Elle ne vous demande pas: d'inclure le code source du logiciel Apache lui-mme, ou toute modification que vous pourriez lui avoir apportes, dans vos distributions qui le contiennent; de donner l'Apache Software Foundation toute modification que vous auriez pu faire du logiciel (mme si de tels retours sont apprcis). Ceci clt le chapitre sur l'installation. La suite du livre contient des exemples d'utilisation de Maven.
19
Dcompressez cette archive dans le rpertoire de votre choix, puis allez dans le rpertoire ch-simple/. Vous y trouverez un rpertoire simple/ qui contient le code source de ce chapitre.
-Dversion=1.0-SNAPSHOT
[INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] Scanning for projects... Searching repository for plugin with prefix: 'archetype'. -----------------------------------------------------------------------Building Maven Default Project task-segment: [archetype:generate] (aggregator-style) -----------------------------------------------------------------------Preparing archetype:generate No goals needed for project - skipping Setting property: [Link] => 'false'. Setting property: [Link] => 'classpath'. Setting property: [Link] => 'false'. [archetype:generate {execution: default-cli}] Generating project in Interactive mode No archetype defined. Using maven-archetype-quickstart \ ([Link]:maven-archetype-quickstart:1.0) Choose archetype: ... 12: internal -> maven-archetype-mojo (A Maven Java plugin development project) 13: internal -> maven-archetype-portlet (A simple portlet application) 14: internal -> maven-archetype-profiles () 15: internal -> maven-archetype-quickstart () 16: internal -> maven-archetype-site-simple (A simple site generation project) 17: internal -> maven-archetype-site (A more complex site project) 18: internal -> maven-archetype-webapp (A simple Java web application) 19: internal -> jini-service-archetype (Archetype for Jini service project creation) Choose a number: (...) 15: : 15 Confirm properties configuration: groupId: [Link] artifactId: simple version: 1.0-SNAPSHOT package: [Link] Y: : Y ... [INFO] Parameter: groupId, Value: [Link] [INFO] Parameter: packageName, Value: [Link] [INFO] Parameter: package, Value: [Link] [INFO] Parameter: artifactId, Value: simple [INFO] Parameter: basedir, Value: /private/tmp [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] BUILD SUCCESSFUL
La
mvn correspond l'instruction d'excution de Maven 2. L'lment archetype:generate correspond un goal Maven. Si vous connaissez Apache Ant, un goal Maven
commande
est analogue une target Ant ; tous les deux dcrivent une unit de tche accomplir lors d'un build. La paire -Dname=value reprsente un argument pass au goal sous la forme de proprit -D, comme pour les proprits systme que vous pourriez passer la Machine Virtuelle Java via la ligne de commande. Le but du goal archetype:generate est de crer rapidement un projet partir d'un archtype. Dans ce contexte, un archtype se dfini comme "un modle original ou idal d'aprs lequel sont btis un ouvrage, une uvre ; un prototype1". Il existe un grand nombre d'archtypes disponibles
1
24
pour Maven, depuis une simple application Swing jusqu' une application web complexe. Le goal archetype:generate propose de choisir parmi environ 40 archtypes. Dans ce chapitre, nous allons utiliser l'archtype le plus basique pour crer un simple squelette de projet permettant de dmarrer. Le prfixe archetype correspond au plugin, et generate correspond au goal. Une fois ce projet gnr, allons regarder la structure de rpertoire Maven qui a t cre sous le rpertoire simple.
simple/ simple/[Link] /src/ /src/main/ /main/java /src/test/ /test/java
Ce rpertoire suit les recommandations de la disposition Maven standard des rpertoires. Nous dtaillerons cela plus tard dans ce chapitre, pour l'instant essayons de comprendre ces quelques rpertoires : Le plugin Maven Archetype cre un rpertoire simple/ dont le nom correspond l'artifactId. C'est ce qu'on appelle le rpertoire racine du projet. Chaque projet Maven possde ce qu'on appelle un Project Object Model (POM) dans un fichier [Link]. Ce fichier dcrit le projet, configure les plugins, et dclare les dpendances. Les sources et les ressources de notre projet se retrouvent sous le rpertoire src/main. Dans le cas de notre projet Java simple, cela consistera en quelques classes Java et fichiers de proprits. Pour un autre projet, on pourrait y trouver le rpertoire racine d'une application web ou les fichiers de configuration d'un serveur d'applications. Dans un projet Java, les classes Java sont dans src/ main/java et les ressources disponibles dans le classpath vont dans src/main/resources. Les tests de notre projet vont dans src/test. Dans ce rpertoire, les classes Java, comme par exemple les tests JUnit ou TestNG, sont dans src/test/java et les ressources du classpath pour les tests vont dans src/test/resources. Le plugin Maven Archetype a produit une classe unique [Link], qui contient 13 lignes de Java avec une fonction statique main qui affiche un message :
package [Link]; /** * Hello world! * */ public class App { public static void main( String[] args ) { [Link]( "Hello World!" );
25
} }
Le plus simple des archtypes Maven produit le programme le plus simple possible : un programme qui affiche "Hello World!" sur la sortie standard.
------------------------------------------------------T E S T S ------------------------------------------------------Running [Link] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.105 sec Results: Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [jar:jar] [INFO] Building jar: /simple/target/[Link] [INFO] [install:install] [INFO] Installing /simple/target/[Link] to \ ~/.m2/repository/com/sonatype/maven/simple/simple/1.0-SNAPSHOT/ \ [Link]
Vous venez juste de crer, compiler, tester, packager et installer le projet Maven le plus simple possible. Pour vous prouver que ce programme fonctionne, excutez-le depuis la ligne de commande.
$ java -cp target/[Link] [Link]
26
Hello World!
Ce fichier [Link] est le POM le plus basique que vous rencontrerez dans un projet Maven. La plupart du temps un fichier POM est considrablement plus complexe : il dfinit de nombreuses dpendances et personnalise le comportement des plugins. Les premiers lments groupId, artifactId, packaging, version sont ce que l'on appelle les coordonnes Maven qui identifient de manire unique un projet. Les balises name et url sont des lments descriptifs du POM donnant un nom comprhensible par un tre humain et associant le projet un site web. L'lment dependencies dfinit une dpendance unique, dans le scope test, sur un framework de test appel JUnit. Nous reverrons ces sujets par la suite dans la Section 3.5, Les concepts principaux . Tout ce que vous devez savoir, pour le moment, c'est que c'est le fichier [Link] qui permet Maven de s'excuter. Maven s'excute toujours selon un POM effectif, une combinaison de la configuration du fichier [Link] du projet, de l'ensemble des POMs parents, d'un super-POM dfini dans Maven, de la configuration de l'utilisateur et des profils actifs. Tous les projets tendent au final le super-POM, qui
27
dfinit une configuration par dfaut raisonnable et que nous dcrivons en dtails dans le Chapitre 9, Le Modle Objet de Projet. Mme si votre projet a un fichier [Link] minimal, le contenu du POM de celui-ci est interpol partir des contenus des POMs parents, de la configuration de l'utilisateur et de tout profil actif. Pour voir ce POM "effectif", excutez la commande suivante depuis le rpertoire racine de votre simple projet.
$mvn help:effective-pom
Lorsque vous excutez cette commande vous pouvez voir un POM nettement plus consistent qui montre la configuration par dfaut de Maven. Ce goal devient vite pratique lorsque vous essayez de dbogguer un build et que vous voulez voir comment les POMs des parents de ce projet contribuent au POM effectif. Pour plus d'informations sur le plugin Maven Help, lisez la Section 12.3, Usage du plugin Maven Help .
Un plugin Maven se compose d'un ou plusieurs goals. On peut prendre comme exemples de plugins Maven ceux qui constituent le cur de Maven comme le plugin Jar dont les goals permettent de crer des
28
fichiers JAR, le plugin Compiler avec ses goals pour compiler le code source et le code des tests unitaires, ou le plugin Surefire dont les goals permettent l'excution des tests unitaires et la production des rapports. On trouve aussi d'autres plugins, plus spcialiss, comme le plugin Hibernate3 pour l'intgration de la bibliothque trs connue de persistence Hibernate, le plugin JRuby qui permet l'excution de code Ruby durant un build Maven ou l'criture de plugins Maven en Ruby. Maven permet aussi de dfinir ses propres plugins. Vous pouvez crire votre propre plugin en Java ou dans de nombreux autres langages dont Ant, Groovy, Beanshell et, comme indiqu plus haut, Ruby.
goal
goal plugin
goal
Figure 3.1. Un plugin possde des Goals Un goal est une tche spcifique qui peut tre excute individuellement ou combine d'autres goals pour un build plus large. Un goal est une "tche unitaire" dans Maven. On peut prendre comme exemple le goal compile du plugin Compiler, qui, comme son nom l'indique, compile tout le code source du projet, ou le goal test du plugin Surefire, qui excute les tests unitaires. La configuration des goals s'effectue au travers de proprits qui sont utilises pour personnaliser le comportement. Par exemple, le goal compile du plugin Compiler dfinit un ensemble de paramtres de configuration qui vous permettent de prciser la version du JDK cible ou les options d'optimisation du compilateur. Dans l'exemple prcdent, nous avons pass les paramtres de configuration groupId et artifactId au goal generate du plugin Archetype via les paramtres de la ligne de commande -DgroupId=[Link] et -DartifactId=simple. Nous avons aussi pass le paramtre packageName au goal generate avec la valeur [Link]. Si nous n'avions pas prcis le paramtre packageName, le nom du package aurait t par dfaut [Link].
Note
Lorsque l'on fait rfrence au goal d'un plugin, il est courant d'utiliser le raccourci : pluginId:goalId. Par exemple, pour utiliser le goal generate du plugin Archetype, nous pouvons crire archetype:generate. Les goals ont des paramtres qui peuvent avoir des valeurs par dfaut raisonnables. Dans l'exemple de archetype:generate, nous n'avons pas prcis, via la ligne de commande, quel type d'archtype devait tre utilis pour crer le projet ; nous avons simplement indiqu un groupId et un artifactId. Comme nous n'avons pas fourni le type d'archtype crer, le goal generate nous a demand
29
d'intervenir, le goal generate s'est donc interrompu et nous a demand de choisir dans une liste. Par contre, si nous avions utilis le goal archetype:create, Maven aurait suppos que nous voulions crer un nouveau projet avec l'archtype maven-archetype-quickstart. C'est notre premier contact avec le concept de convention plutt que configuration. La convention, ou le comportement par dfaut, pour le goal create est de crer un projet basique partir de l'archtype Quickstart. Le goal create dfinit une proprit de configuration archetypeArtifactId dont la valeur par dfaut est mavenarchetype- quickstart. L'archtype Quickstart gnre le squelette d'un projet minimal qui contient un POM et une unique classe. Le plugin Archetype est bien plus puissant que cet exemple ne le laisse supposer, mais c'est une faon efficace de commencer rapidement de nouveaux projets. Plus tard dans ce livre, nous vous montrerons comment il est possible d'utiliser le plugin Archetype pour produire des projets plus complexes, comme des applications web, et comment utiliser le plugin Archetype pour dfinir vos propres structures de projets. Le cur de Maven n'intervient que trs peu dans les tches spcifiques qui composent le build de votre projet. Maven, tout seul, ignore comment compiler votre code ou produire un fichier JAR. Il dlgue tout cela des plugins Maven comme le plugin Compiler et le plugin Jar, qui sont tlchargs selon les besoins et mis jour rgulirement depuis le dpt central de Maven. Lorsque vous tlchargez Maven, vous n'obtenez que le cur de la plateforme qui ne sait que parser une ligne de commande, grer un classpath, parser un fichier POM et tlcharger des plugins Maven selon les besoins. Les utilisateurs ont facilement accs aux dernires options du compilateur grce Maven qui maintient le plugin Compiler en dehors de son cur et fournit un mcanisme de mise jour. Ainsi, les plugins Maven apportent une logique de build rutilisable universellement. Vous ne dfinissez pas la tche de compilation dans un fichier de build ; vous utilisez le plugin Compiler plugin qui est partag par tous les utilisateurs de Maven. Si le plugin Compiler est amlior, tout projet qui utilise Maven en bnficie immdiatement. (Et, si vous n'aimez pas le plugin Compiler, vous pouvez le remplacer par votre propre implmentation.)
30
atteint la phase package, il excute le goal jar du plugin Jar. Puisque notre projet Quickstart a (par dfaut) un packaging de type jar, le goal jar:jar est rattach la phase package.
Phases package
Goals jar:jar
Figure 3.2. Un goal est rattach une phase Nous savons que la phase package va crer un fichier JAR pour un projet ayant un packaging de type jar. Mais qu'en est-il des goals qui la prcdent, comme compiler:compile et surefire:test ? Ces goals s'excutent lors des phases qui prcdent la phase package selon le cycle de vie de Maven ; excuter une phase provoque l'excution de l'ensemble des phases qui la prcdent, le tout se terminant par la phase spcifie sur la ligne de commande. Chaque phase se compose de zro plusieurs goals, et puisque nous n'avons configur ou personnalis aucun plugin, cet exemple rattache un ensemble de goals standards au cycle de vie par dfaut. Les goals suivants ont t excuts dans l'ordre pendant que Maven parcourait le cycle de vie par dfaut jusqu' la phase package :
resources:resources Le goal resources du plugin Resources est rattach la phase process-resources. Ce goal copie toutes les ressources du rpertoire src/main/resources et des autres rpertoires
configurs comme contenant des ressources de test dans le rpertoire cible pour les tests.
compiler:testCompile Le goal testCompile du plugin Compiler est rattach la phase test-compile. Ce goal compile les tests unitaires du rpertoire src/test/java et des autres rpertoires configurs
comme contenant du code source de test dans le rpertoire cible pour les tests.
surefire:test Le goal test du plugin Surefire est rattach la phase test. Ce goal excute tous les tests et
produit des fichiers contenant leurs rsultats dtaills. Par dfaut, le goal arrtera le build en cas d'chec de l'un des tests.
31
jar:jar
Le goal jar du plugin Jar est li la phase package. Ce goal package le contenu du rpertoire cible en un fichier JAR.
Phases process-resources
Goals resources:resources
compile
compiler:compile
process-classes
process-test-resources resources:testResources
test-compile
compiler:testCompile
test
surere:test
prepare-package
package
jar:jar
Figure 3.3. Les goals sont lancs l'excution de la phase laquelle ils sont rattachs Pour rsumer, lorsque nous avons excut mvn install, Maven excute toutes les phases jusqu' la phase install, et pour cela il parcourt toutes les phases du cycle de vie, excutant tous les goals lis chacune de ces phases. Au lieu d'excuter une des phases du cycle de vie de Maven, vous pourriez obtenir le mme rsultat en spcifiant une liste de goals de plugin de la manire suivante :
mvn resources:resources \ compiler:compile \
32
Il est beaucoup plus simple d'excuter les phases du cycle de vie plutt que de lister explicitement les goals excuter en ligne de commande, de plus, ce cycle de vie commun permet chaque projet utilisant Maven d'adhrer un ensemble de standards bien dfinis. C'est ce cycle de vie qui permet un dveloppeur de passer d'un projet l'autre sans connatre tous les dtails du build de chacun d'entre eux. Si vous savez construire un projet Maven, vous savez tous les construire.
33
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>mavenbook</groupId> <artifactId>my-app</artifactId> coordinates <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>Maven Quick Start Archetype</name> <url>[Link] <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
Figure 3.4. Coordonnes d'un projet Maven Nous avons mis en vidence les coordonnes Maven de ce projet : groupId, artifactId, version et packaging. Ces identifiants combins forment ce qu'on appelle les coordonnes d'un projet2. Comme dans tout systme coordonnes, les coordonnes Maven permettent de dfinir un point spcifique dans "l'espace". Lorsqu'un projet est reli un autre en tant que dpendance, plugin ou comme projet parent, Maven l'identifie via ses coordonnes. Les coordonnes Maven sont souvent crites en utilisant les deux points comme sparateur selon le format suivant : groupId:artifactId:packaging:version. Dans le fichier [Link] ci-dessus, les coordonnes de notre projet sont les suivantes : mavenbook:myapp:jar:1.0-SNAPSHOT.
groupId
Le groupe, l'entreprise, l'quipe, l'organisation, le projet ou autre groupe. La convention pour les identifiants du groupe est qu'ils commencent par le nom de domaine invers de l'organisation qui cre le projet. Les projets de Sonatype devraient avoir un groupId qui commence par [Link], et les projets de l'Apache Software Foundation devraient avoir un groupId qui commence par [Link].
2
Il existe une cinquime coordonne, plus rarement utilise, appele classifier dont nous parlerons plus tard dans le livre. Vous pouvez l'oublier pour l'instant.
34
artifactId
Version spcifique d'un projet. Les projets qui ont t livrs ont un identifiant de version fixe qui fait rfrence une version bien spcifique du projet. Les projets en cours de dveloppement peuvent utiliser un identifiant de version qui indique que cette version n'est pas stable : SNAPSHOT. Le format de packaging est aussi un composant important des coordonnes Maven, mais il ne fait pas partie des identifiants uniques d'un projet. Le triplet groupId:artifactId:version d'un projet identifie de manire unique un projet ; vous ne pouvez pas avoir un projet avec le mme triplet groupId, artifactId, et version.
packaging
Le type du projet, jar par dfaut, dcrit le rsultat packag produit par le projet. Un projet avec un packaging jar produit une archive JAR ; un projet avec un packaging war produit, quant lui, une application web. Ces quatre lments sont la clef pour trouver et utiliser un projet particulier dans le vaste monde des projets "Maveniss". Les dpts Maven (publics, privs, et locaux) sont organiss autour de ces identifiants. Lorsque ce projet est install dans le dpt Maven local, il devient immdiatement disponible pour tout autre projet qui voudrait l'utiliser. Tout ce que vous avez faire est de l'ajouter comme dpendance un autre projet en utilisant les coordonnes Maven uniques propres l'artefact.
[Link] (groupId) (artifactId):(version):(packaging) derby:10.1:jar derby:10.2:jar derbytools:10.1:jar derbytools:10.2:jar Every "artifact" has a coordinate.
35
Maven tlcharge artefacts et plugins depuis un dpt distant et les enregistre dans le dpt Maven local de votre machine. Une fois que Maven a tlcharg un artefact depuis un dpt distant, il n'a plus besoin de le tlcharger nouveau. En effet, Maven cherchera toujours dans le dpt local avant d'aller chercher ailleurs. Sur Windows XP, votre dpt local se trouvera probablement dans C: \Documents and Settings\USERNAME\.m2\repository et sur Windows Vista, il se trouve dans C:\Users\USERNAME\.m2\repository. Sur les systmes Unix, votre dpt local Maven se trouve dans ~/.m2/repository. Quand vous construisez un projet comme celui de la section prcdente, la phase install excute un goal qui installe les artefacts de votre projet dans votre dpt Maven local. Dans votre dpt local, vous devriez voir l'artefact cr par notre projet simple. Si vous excutez la commande mvn install, Maven installera l'artefact de notre projet dans votre dpt local. Essayez-le.
$mvn install ... [INFO] [install:install] [INFO] Installing .../[Link] to \
36
~/.m2/repository/com/sonatype/maven/simple/1.0-SNAPSHOT/ \ [Link]
Comme le montrent les traces de cette commande, Maven a install le fichier JAR de notre projet dans notre dpt Maven local. Maven utilise le dpt local pour partager les dpendances entre projets locaux. Si vous dveloppez deux projets projet A et projet B o le projet B dpend de l'artefact produit par le projet A. Maven rcuprera l'artefact du projet A depuis votre dpt local quand il construira le projet B. Les dpts Maven sont la fois un cache local des artefacts tlchargs depuis un dpt distant et un mcanisme qui permet vos projets de dpendre les uns des autres.
37
Dans le monde de Maven, une dpendance n'est plus simplement un fichier JAR ; c'est un fichier POM qui son tour peut dclarer de nouvelles dpendances. Ce sont ces dpendances de dpendances que l'on appelle dpendances transitives et cela est rendu possible par le fait que les dpts Maven contiennent plus que du bytecode ; ils contiennent des mtadonnes sur les artefacts.
[Link] project-a 1.0-SNAPSHOT dependencies [Link] project-b 1.0-SNAPSHOT [Link] project-c 1.0-SNAPSHOT
Figure 3.6. Rsolution des dpendances transitives par Maven Dans le schma prcdent, le projet A dpend des projets B et C. Le Projet B dpend du projet D et le projet C dpend du projet E. L'ensemble des dpendances directes et transitives du projet A serait donc les projets B, C, D et E, mais tout ce que le projet A doit faire, c'est de dclarer ses dpendances aux projets B et C. Les dpendances transitives sont pratiques lorsque votre projet dpend d'autres projets qui ont leurs propres dpendances (comme Hibernate, Apache Struts, ou Spring Framework). Maven vous permet d'exclure certaines dpendances transitives du classpath du projet. Maven fournit enfin diffrentes portes pour les dpendances. Le fichier [Link] du projet simple contient une unique dpendance junit:junit:jar:3.8.1 ayant pour porte test indique dans la balise scope. Lorsqu'une dpendance Maven a une porte de type test, elle n'est pas disponible pour le goal compile du plugin Compiler. Cette dpendance sera ajoute au classpath des goals compiler:testCompile et surefire:test. Durant la cration du JAR d'un projet, les dpendances ne sont pas intgres l'artefact produit ; elles ne sont utilises que lors de la compilation. Par contre lorsque vous utilisez Maven pour produire un WAR ou un EAR, vous pouvez le configurer de manire packager les dpendances avec l'artefact produit et vous pouvez mme configurer Maven pour exclure certaines dpendances du fichier WAR par l'utilisation de la porte provided. La porte provided indique Maven que la dpendance est ncessaire la compilation, mais qu'elle ne doit pas tre intgre l'artefact produit par le build. Cette
38
porte est donc trs pratique lorsque vous dveloppez une application web. Vous aurez besoin du jar des spcifications Servlet pour compiler, mais vous ne voulez pas inclure le JAR de l'API Servlet dans le rpertoire WEB-INF/lib.
Cette commande excute la phase site du cycle de vie. Contrairement au cycle de vie du build, qui gre la gnration de code, la manipulation des ressources, la compilation, le packaging, etc., ce cycle de vie ne concerne que le traitement du contenu du site qui se trouve dans le rpertoire src/site et la production de rapports. Une fois la commande excute, vous devriez voir un site web du projet dans le rpertoire target/site. Ouvrez target/site/[Link] et vous devriez voir le squelette du site du projet Simple. Ce squelette contient certains rapports sous le menu de navigation "Project Reports" gauche, ainsi que des informations sur le projet, les dpendances et les dveloppeurs dans le menu "Project Information". Le site web du projet simple est quasiment vide puisque le POM contient trs peu d'informations, juste des coordonnes Maven, un nom, une URL et une unique dpendance de test. Sur ce site, vous noterez que des rapports par dfaut sont disponibles. Un rapport de test fournit les succs et les checs de l'ensemble des tests unitaires du projet. Un autre rapport produit la javadoc pour l'API du projet. Maven fournit un ensemble de rapports configurables, comme le rapport Clover qui examine la couverture des tests unitaires, le rapport JXR qui produit des listings de code source en HTML avec des rfrences croises, utile pour les revues de code, le rapport PMD qui analyse le code source la recherche de diffrentes erreurs de codage et le rapport JDepend qui analyse les dpendances entre packages dans un code source. Vous pouvez personnaliser les rapports du site en configurant quels sont ceux qui seront inclus dans le build via le fichier [Link].
3.6. En rsum
Dans ce chapitre, nous avons cr un projet simple que nous avons packag sous la forme d'un fichier JAR, puis nous avons install ce JAR dans le dpt local de Maven pour qu'il soit utilisable par d'autres projets, enfin nous avons produit un site web contenant de la documentation. Nous avons fait tout cela sans crire une seule ligne de code ni modifier un seul fichier de configuration. Nous nous sommes arrts en chemin pour dvelopper les dfinitions de certains concepts au cur de Maven. Dans le chapitre suivant, nous allons commencer personnaliser et modifier le fichier [Link] de notre projet pour lui ajouter des dpendances et configurer les tests unitaires.
39
Dcompressez cette archive dans le rpertoire de votre choix et allez dans le rpertoire custom/. Vous y trouverez un rpertoire nomm simple-weather/ qui contient le projet Maven qui sera dvelopp dans ce chapitre. Si vous souhaitez suivre avec le code d'exemple affich dans un navigateur web, allez [Link] et cliquez sur le rpertoire custom/.
l'ide d'introduire des outils utiles. Enfin, un unique chapitre suffit introduire, dvelopper, et dployer cet exemple.
42
Une fois que le plugin Maven Archetype a cr le projet, allez dans le rpertoire simple-weather et lisez le fichier [Link]. Vous devriez voir le document XML prsent dans Exemple 4.1, POM Initial pour le projet simple-weather . Exemple 4.1. POM Initial pour le projet simple-weather
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>simple-weather</artifactId> <packaging>jar</packaging> <version>1.0</version> <name>simple-weather2</name> <url>[Link] <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
Puis, nous allons configurer le plugin Maven Compiler pour compiler du code Java 5. Pour cela, ajoutez la balise build au POM initial comme montr dans l'Exemple 4.2, POM du projet simple-weather avec la configuration du compilateur . Exemple 4.2. POM du projet simple-weather avec la configuration du compilateur
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>simple-weather</artifactId> <packaging>jar</packaging> <version>1.0</version> <name>simple-weather2</name> <url>[Link] <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope>
43
</dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project>
Notez que nous avons pass le paramtre version au goal archetype:generate. Ce paramtre remplace la valeur par dfaut 1.0-SNAPSHOT. Dans ce projet, nous dveloppons la version 1.0 du projet simple-weather comme vous pouvez le voir dans la balise version du fichier [Link].
44
<url>[Link] </organization> <developers> <developer> <id>jason</id> <name>Jason Van Zyl</name> <email>jason@[Link]</email> <url>[Link] <organization>Sonatype</organization> <organizationUrl>[Link] <roles> <role>developer</role> </roles> <timezone>-6</timezone> </developer> </developers> ... </project>
Les ellipses dans l'Exemple 4.3, Ajout des Informations Organisationnelles, Lgales et la liste des dveloppeurs au fichier [Link] sont un moyen pour que le listing soit plus court et plus lisible. Lorsque vous rencontrez dans un [Link] des "..." juste aprs la balise ouvrante project et juste avant la balise fermante project, cela signifie que nous ne vous montrons pas le fichier [Link] dans son intgralit. Dans notre cas, les balises licenses, organization et developers ont t ajoutes avant la balise dependencies.
45
<artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>velocity</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> [...] </project>
Comme vous pouvez le voir nous avons ajout quatre balises de dpendance celle existante qui rfrenait la dpendance de scope test sur JUnit. Si vous ajoutez ces dpendances au fichier [Link] du projet et excutez la commande mvn install, vous verrez Maven tlcharger toutes ces dpendances et les dpendances transitives dans votre dpt local Maven. Comment avons-nous trouv ces dpendances ? "Savions" nous l'avance quelles seraient les bonnes valeurs pour le groupId et l'artifactId ? Certaines dpendances sont tellement utilises (comme Log4J) que vous vous souviendrez du groupId et de l'artifactId chaque fois que vous en aurez besoin. Velocity, Dom4J et Jaxen ont t localiss grce au site internet trs utile http:// [Link]. Il s'agit d'une version publique du Nexus de Sonatype. Elle fournit une interface permettant d'effectuer des recherches sur diffrents dpts Maven, vous pouvez l'utiliser pour trouver vos dpendances. Vous pouvez tester ceci par vous mme, ouvrez [Link] et cherchez des bibliothques trs utilises comme Hibernate ou le framework Spring. Quand vous recherchez un artefact sur ce site, il vous montrera un artifactId et toutes ses versions disponibles sur le dpt central de Maven. Si vous cliquez sur une version spcifique, vous obtiendrez une page qui contient les balises de dpendance que vous aurez copier/coller dans le [Link] de votre projet. Si vous avez besoin de trouver une dpendance, vous devrez consulter [Link].org1, car vous allez rapidement vous rendre compte que certaines bibliothques ont plus d'un groupId. Avec cet outil, vous pourrez utiliser le dpt Maven.
[Link]
46
[Link] La classe Main contient une mthode static main(). Il s'agit du point d'entre de votre systme. [Link] La classe Weather est un simple Java bean qui contient la position du rapport mto et quelques
Mme si nous ne dtaillerons pas le code ici, nous vous fournirons tout le code ncessaire pour vous permettre d'excuter cet exemple. Nous supposons que la plupart des lecteurs ont tlcharg les exemples qui accompagnent ce livre, mais nous prenons en compte ceux qui veulent suivre l'exemple de ce chapitre tape par tape. Les sections qui suivent listent les classes du projet simple-weather. Chacune de ces classes devrait tre mise dans le mme package : [Link]. Supprimons les classes App et AppTest gnres par archetype:generate et ajoutons notre nouveau package. Dans un projet Maven, tout le code source doit se trouver dans src/main/java. Depuis le rpertoire racine de ce nouveau projet, excutez les commandes suivantes :
$ $ $ $ $ $ $
Ainsi, nous avons cr un nouveau package appel [Link]. Maintenant, il nous faut mettre nos classes dans ce rpertoire. A l'aide de votre diteur de texte favori, crez un nouveau fichier appel [Link] avec le contenu de l'Exemple 4.5, Modle Objet de la classe Weather du projet Simple Weather . Exemple 4.5. Modle Objet de la classe Weather du projet Simple Weather
package [Link]; public class Weather {
47
public Weather() {} public String getCity() { return city; } public void setCity(String city) { [Link] = city; } public String getRegion() { return region; } public void setRegion(String region) { [Link] = region; } public String getCountry() { return country; } public void setCountry(String country) { [Link] = country; } public String getCondition() { return condition; } public void setCondition(String condition) { [Link] = condition; } public String getTemp() { return temp; } public void setTemp(String temp) { [Link] = temp; } public String getChill() { return chill; } public void setChill(String chill) { [Link] = chill; } public String getHumidity() { return humidity; } public void setHumidity(String humidity) { [Link] = humidity; } }
La classe Weather dfinit un simple bean utilis pour stocker les donnes mto extraites du flux RSS de Yahoo! Mto. Ce flux fournit un grand nombre d'informations, depuis les heures de lever et de coucher du soleil, la vitesse et la direction des vents. Pour garder cet exemple relativement simple, le modle objet de Weather ne garde que la temprature, le facteur vent, l'humidit et une description textuelle des conditions actuelles. Maintenant, dans le mme rpertoire, crez un fichier [Link]. Cette classe Main contiendra la mthode static main() point d'entre de cet exemple. Exemple 4.6. Classe Main du projet Simple Weather
package [Link]; import [Link]; import [Link]; public class Main { public static void main(String[] args) throws Exception {
48
// Configure Log4J [Link]([Link]() .getResource("[Link]")); // Read the Zip Code from the Command-line (if none supplied, use 60202) String zipcode = "60202"; try { zipcode = args[0]); } catch( Exception e ) {} // Start the program new Main(zipcode).start(); } private String zip; public Main(String zip) { [Link] = zip; } public void start() throws Exception { // Retrieve Data InputStream dataIn = new YahooRetriever().retrieve( zip ); // Parse Data Weather weather = new YahooParser().parse( dataIn ); // Format (Print) Data [Link]( new WeatherFormatter().format( weather ) ); } }
La mthode main() ci-dessus configure Log4J en rcuprant une ressource depuis le classpath, puis essaye de lire un code postal depuis la ligne de commande. Si une exception survient lors de la lecture du code postal, le programme utilisera par dfaut la valeur 60202 comme code postal. Une fois qu'il a un code postal, il instancie la classe Main et appelle la mthode start() de cette instance. La mthode start() appelle le YahooRetriever pour qu'il rcupre le XML reprsentant les prvisions mto. Le YahooRetriever renvoie un InputStream qui est ensuite pass en paramtre du YahooParser. Le YahooParser parse le XML de Yahoo! Mto et renvoie un objet de type Weather. Pour terminer, le WeatherFormatter prend en paramtre un objet de type Weather et retourne une String formate qui est affiche sur la sortie standard. Crez un fichier [Link] dans le mme rpertoire avec le contenu prsent dans l'Exemple 4.7, La classe YahooRetriever du projet Simple Weather . Exemple 4.7. La classe YahooRetriever du projet Simple Weather
package [Link]; import [Link]; import [Link]; import [Link]; import [Link];
49
public class YahooRetriever { private static Logger log = [Link]([Link]); public InputStream retrieve(int zipcode) throws Exception { [Link]( "Retrieving Weather Data" ); String url = "[Link] + zipcode; URLConnection conn = new URL(url).openConnection(); return [Link](); } }
Cette classe trs simple ouvre une URLConnection sur l'API de Yahoo! Mto et renvoie un InputStream. Pour crer quelque chose capable de parser ce flux, nous allons devoir crer le fichier [Link] dans le mme rpertoire. Exemple 4.8. Classe YahooParser du projet Simple Weather
package [Link]; import [Link]; import [Link]; import [Link]; import import import import [Link]; [Link]; [Link]; [Link];
public class YahooParser { private static Logger log = [Link]([Link]); public Weather parse(InputStream inputStream) throws Exception { Weather weather = new Weather(); [Link]( "Creating XML Reader" ); SAXReader xmlReader = createXmlReader(); Document doc = [Link]( inputStream ); [Link]( "Parsing XML Response" ); [Link]( [Link]("/rss/channel/y:location/@city") ); [Link]( [Link]("/rss/channel/y:location/@region") ); [Link]( [Link]("/rss/channel/y:location/@country") ); [Link]( [Link]("/rss/channel/item/y:condition/@text") ); [Link]( [Link]("/rss/channel/item/y:condition/@temp") ); [Link]( [Link]("/rss/channel/y:wind/@chill") ); [Link]( [Link]("/rss/channel/y:atmosphere/@humidity") ); return weather; }
50
private SAXReader createXmlReader() { Map<String,String> uris = new HashMap<String,String>(); [Link]( "y", "[Link] ); DocumentFactory factory = new DocumentFactory(); [Link]( uris ); SAXReader xmlReader = new SAXReader(); [Link]( factory ); return xmlReader; } }
La classe YahooParser est la classe la plus complexe de cet exemple. Nous n'allons pas dtailler l'utilisation de Dom4J ou de Jaxen ici, cependant cette classe mrite quelques explications. Dans la classe YahooParser, la mthode parse() prend un InputStream en paramtre et renvoie un objet de type Weather. Pour cela, elle doit parser un document XML avec Dom4J. Puisque nous nous intressons aux lments dans l'espace de nommage XML de Yahoo! Mto, nous avons besoin d'un SAXReader sensible aux espaces de nommage dans la mthode createXmlReader(). Une fois que nous avons cr ce parseur et que nous avons pars le document, nous obtenons en retour un objet de type [Link]. Au lieu de parcourir tous ses lments fils, nous rcuprons uniquement les informations qui nous intressent en les slectionnant avec des expressions XPath. Dom4J permet de parser le XML dans cet exemple et Jaxen apporte ses capacits XPath. Une fois que nous avons cr un objet de type Weather, nous avons besoin de formater ce rsultat pour qu'il soit lisible. Crez un fichier [Link] dans le mme rpertoire que les autres classes. Exemple 4.9. Classe WeatherFormatter du projet Simple Weather
package [Link]; import [Link]; import [Link]; import [Link]; import [Link]; import [Link]; import [Link]; public class WeatherFormatter { private static Logger log = [Link]([Link]); public String format( Weather weather ) throws Exception { [Link]( "Formatting Weather Data" ); Reader reader = new InputStreamReader( getClass().getClassLoader() .getResourceAsStream("[Link]")); VelocityContext context = new VelocityContext();
51
[Link]("weather", weather ); StringWriter writer = new StringWriter(); [Link](context, writer, "", reader); return [Link](); } }
La classe WeatherFormatter utilise Velocity pour appliquer un masque. La mthode format() prend un bean de type Weather en paramtre et renvoie une String formate. La premire chose que fait la mthode format() est de charger depuis le classpath un template Velocity appel [Link]. Puis nous crons un VelocityContext qui contient un unique objet de type Weather appel weather. Un objet de type StringWriter est cr pour contenir le rsultat de l'application du masque. Le masque est valu par un appel [Link]() et le rsultat est renvoy sous la forme d'une String. Avant de pouvoir excuter cet exemple, nous allons devoir ajouter des ressources notre classpath.
Une fois le rpertoire resources cr, nous pouvons y ajouter ces deux ressources. Tout d'abord, ajoutez le fichier [Link] dans le rpertoire resources, avec le contenu affich dans l'Exemple 4.10, Fichier de configuration Log4J du projet Simple Weather . Exemple 4.10. Fichier de configuration Log4J du projet Simple Weather
# Set root category priority to INFO and its only appender to CONSOLE. [Link]=INFO, CONSOLE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. [Link]=[Link] [Link]=INFO [Link]=[Link] [Link]=%-4r %-5p %c{1} %x - %m%n
52
Ce fichier [Link] configure Log4J pour qu'il affiche tous les messages de log sur la sortie standard en utilisant un PatternLayout. Enfin, nous avons besoin de crer [Link], le template Velocity utilis pour formater le rsultat de notre programme en ligne de commande. Crez le fichier [Link] dans le rpertoire resources/. Exemple 4.11. Template Velocity pour le projet Simple Weather
********************************* Current Weather Conditions for: ${[Link]}, ${[Link]}, ${[Link]} Temperature: ${[Link]} Condition: ${[Link]} Humidity: ${[Link]} Wind Chill: ${[Link]} *********************************
Ce template contient un certain nombre de rfrences une variable appele weather, il s'agit du bean Weather qui est pass la classe WeatherFormatter. La syntaxe ${[Link]} est un raccourci pour rcuprer et afficher la valeur de la proprit temp du bean. Maintenant que nous avons tout le code de projet au bon endroit, nous pouvons utiliser Maven pour excuter cet exemple.
[Link]
53
Nous n'avons pas pass de paramtre en ligne de commande la classe Main, aussi c'est le code postal par dfaut, 60202, qui a t utilis. Pour passer un code postal en paramtre, nous devrions utiliser l'argument -[Link] et lui passer un code postal :
$ mvn exec:java -[Link]=[Link] \
-[Link]="70112"
... [INFO] [exec:java] 0 INFO YahooRetriever - Retrieving Weather Data 134 INFO YahooParser - Creating XML Reader 333 INFO YahooParser - Parsing XML Response 420 INFO WeatherFormatter - Formatting Weather Data ********************************* Current Weather Conditions for: New Orleans, LA, US Temperature: 82 Condition: Fair Humidity: 71 Wind Chill: 82 ********************************* [INFO] Finished at: Sun Aug 31 09:33:34 CDT 2008 ...
Comme vous pouvez le voir, nous avons excut avec succs notre programme Simple Weather. Nous avons rcupr des donnes depuis Yahoo! Mto, donnes que nous avons parses et formates avec Velocity. Nous avons ralis tout cela sans faire grand chose d'autre que d'crire le code source du projet et un peu de configuration dans le [Link]. Remarquez l'absence du "processus de build". Nous n'avons pas eu dfinir comment le compilateur Java devait compiler notre code source en bytecode et nous n'avons pas eu besoin d'indiquer au systme de build o se trouvait le bytecode pour qu'il puisse excuter l'exemple. Tout ce que nous avons eu faire pour ajouter quelques dpendances a t de trouver leurs coordonnes Maven.
Vous listerez ainsi l'ensemble des goals disponibles pour le plugin Maven Exec. Le plugin Help vous fournira aussi les paramtres valides pour le plugin Exec. Si vous dsirez personnaliser le comportement du plugin Exec, vous devriez utiliser la documentation fournie par help:describe comme guide. Aussi utile que soit le plugin Exec, vous ne devriez pas l'utiliser pour excuter votre application
3 4
[Link] [Link]
54
autrement que pour la tester dans un environnement de dveloppement. Pour une solution plus robuste, utilisez le plugin Maven Assembly qui est prsent dans la Section 4.13, Construire une application package et excutable en ligne de commande , plus loin dans ce chapitre.
Comme vous pouvez vous en rendre compte, notre projet possde un grand nombre de dpendances. Alors que nous n'avons inclus que quatre bibliothques comme dpendances directes, nous avons en fait 15 dpendances. Dom4J dpend de Xerces et des XML Parser APIs, Jaxen dpend de la prsence de Xalan dans le classpath. Le plugin Dependency va afficher la combinaison finale des dpendances utilises pour compiler votre projet. Si vous voulez connatre l'arbre complet des dpendances de votre projet, vous pouvez excuter le goal dependency:tree.
55
$ mvn ... [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] ...
dependency:tree
[dependency:tree] [Link]:simple-weather:jar:1.0 +- log4j:log4j:jar:1.2.14:compile +- dom4j:dom4j:jar:1.6.1:compile | \- xml-apis:xml-apis:jar:1.0.b2:compile +- jaxen:jaxen:jar:1.1.1:compile | +- jdom:jdom:jar:1.0:compile | +- xerces:xercesImpl:jar:2.6.2:compile | \- xom:xom:jar:1.0:compile | +- xerces:xmlParserAPIs:jar:2.6.2:compile | +- xalan:xalan:jar:2.6.0:compile | \- [Link]:icu4j:jar:2.6.1:compile +- velocity:velocity:jar:1.5:compile | +- commons-collections:commons-collections:jar:3.1:compile | +- commons-lang:commons-lang:jar:2.1:compile | \- oro:oro:jar:2.0.8:compile +- [Link]:commons-io:jar:1.3.2:test \- junit:junit:jar:3.8.1:test
Si vous tes aventurier dans l'me ou si vous voulez voir le chemin complet des dpendances, avec les artefacts qui ont t rejets cause d'un conflit ou pour toute autre raison, excutez Maven avec le flag debug.
$ mvn install -X ... [DEBUG] [Link]:simple-weather:jar:1.0 (selected for null) [DEBUG] log4j:log4j:jar:1.2.14:compile (selected for compile) [DEBUG] dom4j:dom4j:jar:1.6.1:compile (selected for compile) [DEBUG] xml-apis:xml-apis:jar:1.0.b2:compile (selected for compile) [DEBUG] jaxen:jaxen:jar:1.1.1:compile (selected for compile) [DEBUG] jaxen:jaxen:jar:1.1-beta-6:compile (removed - ) [DEBUG] jaxen:jaxen:jar:1.0-FCS:compile (removed - ) [DEBUG] jdom:jdom:jar:1.0:compile (selected for compile) [DEBUG] xml-apis:xml-apis:jar:1.3.02:compile (removed - nearer: 1.0.b2) [DEBUG] xerces:xercesImpl:jar:2.6.2:compile (selected for compile) [DEBUG] xom:xom:jar:1.0:compile (selected for compile) [DEBUG] xerces:xmlParserAPIs:jar:2.6.2:compile (selected for compile) [DEBUG] xalan:xalan:jar:2.6.0:compile (selected for compile) [DEBUG] xml-apis:xml-apis:1.0.b2. [DEBUG] [Link]:icu4j:jar:2.6.1:compile (selected for compile) [DEBUG] velocity:velocity:jar:1.5:compile (selected for compile) [DEBUG] commons-collections:commons-collections:jar:3.1:compile (selected for compile) [DEBUG] commons-lang:commons-lang:jar:2.1:compile (selected for compile) [DEBUG] oro:oro:jar:2.0.8:compile (selected for compile) [DEBUG] junit:junit:jar:3.8.1:test (selected for test)
Dans la sortie de debug, vous voyez les rouages du mcanisme de gestion de dpendances. Ce que vous voyez ici c'est l'arbre des dpendances de ce projet. Maven affiche les coordonnes Maven compltes de toutes les dpendances de votre projet ainsi que les dpendances de vos dpendances (et les dpendances
56
des dpendances de vos dpendances). Vous pouvez voir que le projet simple-weather dpend de jaxen, qui dpend de xom, qui son tour dpend de icu4j. Vous pouvez voir aussi que Maven construit ce graphe de dpendances en supprimant les doublons et en rsolvant les conflits entre diffrentes versions. Si vous avez un problme avec certaines dpendances, il est souvent utile d'aller plus loin que la simple liste produite par dependency:resolve. Activer les traces en mode debug, vous permet de voir comment fonctionne le mcanisme de rsolution des dpendances de Maven.
Maintenant, nous allons crer deux tests unitaires. Le premier testera la classe YahooParser, et le second la classe WeatherFormatter. Dans le package weather, crez un fichier [Link] avec le contenu prsent dans l'exemple qui suit. Exemple 4.12. Test unitaire YahooParserTest du projet Simple Weather
package [Link]; import [Link]; import [Link]; import [Link]; import [Link]; public class YahooParserTest extends TestCase { public YahooParserTest(String name) { super(name); } public void testParser() throws Exception { InputStream nyData = getClass().getClassLoader().getResourceAsStream("[Link]"); Weather weather = new YahooParser().parse( nyData ); assertEquals( "New York", [Link]() ); assertEquals( "NY", [Link]() ); assertEquals( "US", [Link]() ); assertEquals( "39", [Link]() ); assertEquals( "Fair", [Link]() ); assertEquals( "39", [Link]() );
57
Cette classe YahooParserTest tend la classe TestCase de JUnit. Elle respecte le modle habituel d'un test JUnit : un constructeur qui prend un unique paramtre de type String et qui appelle le constructeur de la classe mre et un ensemble de mthodes publiques dont les noms commencent par test, et qui sont invoques en tant que tests unitaires. Nous avons une seule mthode de test, testParser, qui teste le YahooParser en parsant un document XML connu. Le document XML de test s'appelle [Link] et est charg depuis le classpath. Nous ajouterons les ressources pour les tests dans la Section 4.11, Ajouter des ressources pour les tests unitaires . Dans la structure de rpertoires Maven, le fichier [Link] se trouve dans le rpertoire qui contient les ressources de test ${basedir}/src/test/resources sous org/sonatype/mavenbook/ weather/yahoo/[Link]. Ce fichier est lu sous la forme d'un InputStream et pass la mthode parse() de YahooParser. La mthode parse() renvoie un objet de type Weather, qui est test par une srie d'appels la mthode assertEquals(), une mthode dfinie par TestCase. Dans le mme rpertoire, crez un fichier [Link]. Exemple 4.13. Test unitaire WeatherFormatterTest du projet Simple Weather
package [Link]; import [Link]; import [Link]; import [Link]; import [Link]; import [Link]; import [Link]; public class WeatherFormatterTest extends TestCase { public WeatherFormatterTest(String name) { super(name); } public void testFormat() throws Exception { InputStream nyData = getClass().getClassLoader().getResourceAsStream("[Link]"); Weather weather = new YahooParser().parse( nyData ); String formattedResult = new WeatherFormatter().format( weather ); InputStream expected = getClass().getClassLoader().getResourceAsStream("[Link]"); assertEquals( [Link]( expected ).trim(), [Link]() ); }
58
Ce second test unitaire du projet teste la classe WeatherFormatter. Comme pour le test YahooParserTest, la classe WeatherFormatterTest tend elle aussi la classe TestCase de JUnit. L'unique mthode de test lit la mme ressource depuis ${basedir}/src/test/resources dans le rpertoire org/sonatype/mavenbook/weather/yahoo via le classpath des tests unitaires. Nous ajouterons les ressources de test dans la Section 4.11, Ajouter des ressources pour les tests unitaires . WeatherFormatterTest passe ce fichier d'exemple au YahooParser qui renvoie un objet de type Weather. Celui-ci est ensuite format par WeatherFormatter. Etant donn que WeatherFormatter affiche une String, nous allons devoir la tester par rapport une valeur attendue. La valeur attendue a t mise dans un fichier texte [Link] qui se trouve dans le mme rpertoire que [Link]. Pour comparer le rsultat du test la valeur attendue, nous lisons cette valeur attendue dans un InputStream et nous utilisons la classe IOUtils de Commons IO pour convertir ce fichier en String. Cette String est ensuite compare au rsultat obtenu grce la mthode assertEquals().
59
</project>
Aprs avoir ajout cette dpendance au [Link], excutez mvn dependency:resolve et vous devriez voir que commons-io fait maintenant partie des dpendances avec le scope test. Nous devons encore faire une chose avant de pouvoir excuter les tests unitaires de ce projet. Nous devons crer dans le classpath les ressources dont ces tests unitaires ont besoin. Les diffrents scopes pour les dpendances sont expliqus en dtail dans la Section 9.4.1, Scope de dpendance .
Une fois que vous avez cr le rpertoire de ressources, crez un fichier [Link] dans le rpertoire resources. Exemple 4.15. Rsultat attendu du WeatherFormatterTest du projet Simple Weather
********************************* Current Weather Conditions for: New York, NY, US Temperature: 39 Condition: Fair Humidity: 67 Wind Chill: 39 *********************************
Ce fichier devrait vous rappeler quelque chose. C'est le mme rsultat que celui que nous avions obtenu lorsque nous avions excut le projet Simple Weather project avec le plugin Maven Exec. Le deuxime fichier que vous devrez ajouter au rpertoire de ressources est [Link]. Exemple 4.16. Donnes XML en entre de YahooParserTest du projet Simple Weather
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <rss version="2.0" xmlns:yweather="[Link]
60
xmlns:geo="[Link] <channel> <title>Yahoo! Weather - New York, NY</title> <link>[Link] <description>Yahoo! Weather for New York, NY</description> <language>en-us</language> <lastBuildDate>Sat, 10 Nov 2007 8:51 pm EDT</lastBuildDate> <ttl>60</ttl> <yweather:location city="New York" region="NY" country="US" /> <yweather:units temperature="F" distance="mi" pressure="in" speed="mph" /> <yweather:wind chill="39" direction="0" speed="0" /> <yweather:atmosphere humidity="67" visibility="1609" pressure="30.18" rising="1" /> <yweather:astronomy sunrise="6:36 am" sunset="4:43 pm" /> <image> <title>Yahoo! Weather</title> <width>142</width> <height>18</height> <link>[Link] <url>[Link] </image> <item> <title>Conditions for New York, NY at 8:51 pm EDT</title> <geo:lat>40.67</geo:lat> <geo:long>-73.94</geo:long> <link>[Link] <pubDate>Sat, 10 Nov 2007 8:51 pm EDT</pubDate> <yweather:condition text="Fair" code="33" temp="39" date="Sat, 10 Nov 2007 8:51 pm EDT" /> <description><![CDATA[ <img src="[Link] /><br /> <b>Current Conditions:</b><br /> Fair, 39 F<BR /><BR /> <b>Forecast:</b><BR /> Sat - Partly Cloudy. High: 45 Low: 32<br /> Sun - Sunny. High: 50 Low: 38<br /> <br /> ]]></description> <yweather:forecast day="Sat" date="10 Nov 2007" low="32" high="45" text="Partly Cloudy" code="29" /> <yweather:forecast day="Sun" date="11 Nov 2007" low="38" high="50" text="Sunny" code="32" /> <guid isPermaLink="false">10002_2007_11_10_20_51_EDT</guid> </item> </channel> </rss>
Ce fichier contient un document XML de test pour YahooParserTest. Nous utilisons ce fichier afin de tester le parseur YahooParser sans avoir rcuprer la rponse XML de Yahoo! Mto.
61
Excuter mvn test depuis la ligne de commande, a demand Maven d'excuter toutes les phases du cycle de vie jusqu la phase test. Le plugin Maven Surefire possde un goal test rattach la phase test. Ce goal test excute tous les tests unitaires du projet qu'il peut trouver dans src/test/java avec un nom de fichier de la forme **/Test*.java, **/*[Link] ou **/ *[Link]. Pour ce projet, vous pouvez vous rendre compte que le goal test du plugin Surefire a excut WeatherFormatterTest et YahooParserTest. Quand le plugin Maven Surefire lance les tests JUnit, il produit des rapports XML et texte dans le rpertoire ${basedir}/target/surefirereports. Si vos tests sont en chec, il vous faudra regarder dans ce rpertoire pour trouver les messages d'erreurs et les traces de vos tests unitaires.
62
plugin Surefire rencontre des tests en chec, vous allez devoir mettre la proprit de configuration de Surefire testFailureIgnore true. Exemple 4.17. Ignorer les tests unitaires en chec
<project> [...] <build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> </plugins> </build> [...] </project>
La documentation du plugin ([Link] indique que ce paramtre correspond une expression : Exemple 4.18. Expressions pour un paramtre de plugin
testFailureIgnore Set this to true to ignore a failure during \ testing. Its use is NOT RECOMMENDED, but quite \ convenient on occasion.
Cette expression peut tre configure depuis la ligne de commande en utilisant le paramtre -D :
$ mvn test -[Link]=true
63
$ mvn install -[Link]=true ... [INFO] [compiler:testCompile] [INFO] Not compiling test sources [INFO] [surefire:test] [INFO] Tests are skipped. ...
Quand le plugin Surefire atteint le goal test, il ne va pas lancer les tests unitaires si la proprit [Link] est true. Une autre faon de configurer Maven pour qu'il ne lance pas les tests unitaires est d'ajouter cette configuration au [Link] de votre projet. Pour cela, vous devez ajouter une balise plugin la configuration de votre build. Exemple 4.19. Court-circuiter les tests unitaires
<project> [...] <build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> </plugins> </build> [...] </project>
64
descripteur d'assemblage personnalis pour produire une archive plus complexe pour l'application Simple Weather. Dans ce chapitre, nous nous contenterons d'utiliser le format prdfini jar-withdependencies. Pour configurer le plugin Maven Assembly, nous devons ajouter le configuration de plugin suivante notre configuration de build existante dans le [Link]. Exemple 4.20. Configurer le descripteur Maven Assembly
<project> [...] <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build> [...] </project>
Une fois que vous avez ajout cette configuration, vous pouvez construire l'assemblage en excutant le goal assembly:assembly. Dans les traces affiches l'cran, le goal assembly:assembly est excut une fois que le build Maven atteint la phase install du cycle de vie :
$ mvn install assembly:assembly ... [INFO] [jar:jar] [INFO] Building jar: ~/examples/ch-custom/simple-weather/target/[Link] [INFO] [assembly:assembly] [INFO] Processing DependencySet (output=) [INFO] Expanding: \ .m2/repository/dom4j/dom4j/1.6.1/[Link] into \ /tmp/[Link] [INFO] Expanding: .m2/repository/commons-lang/commons-lang/2.1/\ [Link] into /tmp/[Link] ... (Maven Expands all dependencies into a temporary directory) ... [INFO] Building jar: \ ~/examples/ch-custom/simple-weather/target/\ [Link]
Une fois que notre application est assemble dans target/[Link], nous pouvons de nouveau lancer la classe Main depuis la ligne de commande. Pour lancer la classe Main de l'application Simple Weather, excutez les commandes suivantes depuis le rpertoire racine de votre projet.
65
[Link] 10002
0 INFO YahooRetriever - Retrieving Weather Data 221 INFO YahooParser - Creating XML Reader 399 INFO YahooParser - Parsing XML Response 474 INFO WeatherFormatter - Formatting Weather Data ********************************* Current Weather Conditions for: New York, NY, US Temperature: 44 Condition: Fair Humidity: 40 Wind Chill: 40 *********************************
Le format jar-with-dependencies cre un unique fichier JAR qui contient tout le bytecode du projet simple-weather ainsi que celui des dpendances dsassembles. Ce format assez original produit un fichier JAR de 9 MiB qui contient environ 5.290 classes, mais il facilite la distribution des applications dveloppes avec Maven. Plus tard dans ce livre, nous vous montrerons comment crer votre propre descripteur d'assemblage pour produire une distribution plus standard.
66
<configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>simple-command</id> <phase>package</phase> <goals> <goal>attached</goal> </goals> </execution> </executions> </plugin> </plugins> </build> [...] </project>
Une fois votre POM configur, tout ce qu'il vous reste faire pour produire l'assemblage est d'excuter la commande mvn package. La configuration de l'excution va s'assurer que le goal assembly:attached est excut quand Maven atteint la phase package durant son parcours du cycle de vie.
67
Dcompressez cette archive dans un rpertoire, puis ouvrez le rpertoire ch-simple-web/. Vous y trouverez un rpertoire nomm simple-webapp/ qui contient le projet Maven dvelopp dans ce chapitre.
Une fois que le plugin Maven Archetype a gnr le projet, ouvrez le rpertoire simple-web et regardez le fichier [Link]. Vous devriez voir le document XML prsent dans l'exemple suivant : Exemple 5.1. POM initial du projet simple-web
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>simple-webapp</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>simple-webapp Maven Webapp</name> <url>[Link] <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build>
70
Ensuite, vous allez devoir configurer le plugin Maven Compiler pour utiliser Java 5. Pour cela, ajoutez l'lment plugins au POM initial comme dcrit dans l'Exemple 5.2, POM du projet simple-web avec la configuration du compilateur . Exemple 5.2. POM du projet simple-web avec la configuration du compilateur
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>simple-webapp</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>simple-webapp Maven Webapp</name> <url>[Link] <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>simple-webapp</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project>
Notez que l'lment packaging contient la valeur war. Ce type de packaging permet de configurer Maven pour produire une archive WAR. Un projet avec le packaging war va produire un fichier WAR dans le rpertoire target/. Le nom par dfaut de ce fichier est ${artifactId}-${version}.war. Dans ce projet, le WAR par dfaut serait donc target/[Link]. Dans le projet simple-webapp, nous avons personnalis le nom du fichier WAR gnr en ajoutant l'lment finalName dans la configuration du build. En prcisant simple-webapp comme valeur de finalName, la phase package produit le fichier WAR target/[Link].
71
Une fois que vous avez configur le plugin Maven Jetty dans le [Link] de votre projet, vous pouvez invoquer son goal run pour dmarrer votre application web dans le conteneur de Servlet Jetty. Excutez la commande mvn jetty:run partir du rpertoire du projet simple-webapp/ de la manire suivante :
~/examples/ch-simple-web/simple-webapp $ mvn jetty:run ... [INFO] [jetty:run] [INFO] Configuring Jetty for project: simple-webapp Maven Webapp [INFO] Webapp source directory = \ ~/svnw/sonatype/examples/ch-simple-web/simple-webapp/src/main/webapp [INFO] [Link] file = \ ~/svnw/sonatype/examples/ch-simple-web/\ simple-webapp/src/main/webapp/WEB-INF/[Link] [INFO] Classes = ~/svnw/sonatype/examples/ch-simple-web/\ simple-webapp/target/classes 2007-11-17 22:11:50.532::INFO: Logging to STDERR via [Link] [INFO] Context path = /simple-webapp [INFO] Tmp directory = determined at runtime [INFO] Web defaults = org/mortbay/jetty/webapp/[Link] [INFO] Web overrides = none [INFO] Webapp directory = \ ~/svnw/sonatype/examples/ch-simple-web/simple-webapp/src/main/webapp
72
[INFO] Starting jetty 6.1.6rc1 ... 2007-11-17 22:11:50.673::INFO: jetty-6.1.6rc1 2007-11-17 22:11:50.846::INFO: No Transaction manager found 2007-11-17 22:11:51.057::INFO: Started SelectChannelConnector@[Link]:8080 [INFO] Started Jetty Server
Avertissement
Si vous utilisez le plugin Maven Jetty partir d'un environnement Windows, vous devrez probablement dplacer votre dpt local dans un rpertoire qui ne contient pas d'espaces. Des lecteurs nous ont remont des problmes lors du dmarrage de Jetty car leur dpt local tait stock dans le rpertoire "C:\Documents and Settings\<user>". La solution pour rgler ce problme est de dplacer votre dpt local Maven dans un rpertoire qui ne contient pas d'espaces et de redfinir son emplacement dans le fichier ~/.m2/ [Link] comme dcrit dans la Section A.2.1, Valeurs simples . Une fois que Maven a dmarr le conteneur de servlet Jetty, ouvrez l'URL [Link] dans un navigateur web. La page [Link] gnre par l'Archetype est triviale ; elle contient un titre de second niveau avec le texte "Hello World!". Maven s'attend ce que la racine du site web soit dans src/main/webapp. C'est dans ce rpertoire que vous trouverez le fichier [Link] utilis dans l'Exemple 5.4, Contenu de src/main/webapp/[Link] . Exemple 5.4. Contenu de src/main/webapp/[Link]
<html> <body> <h2>Hello World!</h2> </body> </html>
Dans src/main/webapp/WEB-INF, nous allons trouver le plus petit descripteur d'application [Link] imaginable, prsent dans l'exemple suivant : Exemple 5.5. Contenu de src/main/webapp/WEB-INF/[Link]
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "[Link] > <web-app> <display-name>Archetype Created Web Application</display-name> </web-app>
73
Pour commencer, nous allons devoir crer un nouveau package dans src/main/java nomm [Link] :
$ mkdir -p src/main/java/org/sonatype/mavenbook/web $ cd src/main/java/org/sonatype/mavenbook/web
Une fois que vous avez cr ce package, allez dans le rpertoire src/main/java/org/sonatype/ mavenbook/web et crez une classe SimpleServlet dans le fichier [Link], qui contient le code suivant : Exemple 5.6. Classe SimpleServlet
package [Link]; import [Link].*; import [Link].*; import [Link].*; public class SimpleServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = [Link](); [Link]( "SimpleServlet Executed" ); [Link](); [Link](); } }
Notre classe SimpleServlet est trs simple : une servlet qui crit un message simple sur le Writer de la rponse. Pour ajouter cette servlet votre application web et l'associer l'URL d'une requte, ajoutez les balises servlet et servlet-mapping de l'Exemple 5.7, Configurer la Servlet dans le fichier [Link] de votre projet. Le fichier [Link] se trouve dans src/main/webapp/WEB-INF. Exemple 5.7. Configurer la Servlet
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "[Link] > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>simple</servlet-name> <servlet-class>[Link]</servlet-class> </servlet> <servlet-mapping> <servlet-name>simple</servlet-name> <url-pattern>/simple</url-pattern>
74
</servlet-mapping> </web-app>
Tout est en place pour tester la servlet ; la classe est bien dans src/main/java et le fichier [Link] a t mis jour. Avant que vous ne lanciez le plugin Jetty, compilez votre projet en excutant mvn compile :
~/examples/ch-simple-web/simple-webapp $ mvn compile ... [INFO] [compiler:compile] [INFO] Compiling 1 source file to \ ~/examples/ch-simple-web/simple-webapp/target/classes [INFO] -----------------------------------------------------------------------[ERROR] BUILD FAILURE [INFO] -----------------------------------------------------------------------[INFO] Compilation failure /src/main/java/org/sonatype/mavenbook/web/[Link]:[4,0] \ package [Link] does not exist /src/main/java/org/sonatype/mavenbook/web/[Link]:[5,0] \ package [Link] does not exist /src/main/java/org/sonatype/mavenbook/web/[Link]:[7,35] \ cannot find symbol symbol: class HttpServlet public class SimpleServlet extends HttpServlet { /src/main/java/org/sonatype/mavenbook/web/[Link]:[8,22] \ cannot find symbol symbol : class HttpServletRequest location: class [Link] /src/main/java/org/sonatype/mavenbook/web/[Link]:[9,22] \ cannot find symbol symbol : class HttpServletResponse location: class [Link] /src/main/java/org/sonatype/mavenbook/web/[Link]:[10,15] \ cannot find symbol symbol : class ServletException location: class [Link]
La compilation choue car votre projet Maven n'a pas la dpendance vers l'API Servlet. Dans la section suivante, nous allons ajouter l'API Servlet au POM de notre projet.
75
Il est important de noter que nous utilisons le scope provided pour cette dpendance. Cela permet de prciser Maven que le jar est "provided" (fourni) par le conteneur et n'a ainsi pas besoin d'tre inclus dans le war. Si vous souhaitez crire votre propre tag JSP pour cette simple application web, vous devrez ajouter une dpendance sur la spcification JSP 2.0. Utilisez la configuration prsente dans l'exemple : Exemple 5.9. Ajouter la dpendance aux spcifications JSP 2.0
<project> [...] <dependencies> [...] <dependency> <groupId>[Link]</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies> [...] </project>
Une fois que vous avez ajout la dpendance sur l'API Servlet, excutez la commande mvn clean install suivie de la commande mvn jetty:run.
[tobrien@t1 simple-webapp]$ mvn ... [tobrien@t1 simple-webapp]$ mvn [INFO] [jetty:run] ... 2007-12-14 16:18:31.305::INFO: 2007-12-14 16:18:31.453::INFO: 2007-12-14 16:18:32.745::INFO: [INFO] Started Jetty Server
ce stade, vous devriez pouvoir rcuprer le rsultat de la SimpleServlet. Depuis la ligne de commande, vous pouvez utiliser curl pour afficher la rponse de cette servlet sur la sortie standard :
76
5.7. Conclusion
Aprs avoir lu ce chapitre, vous devriez tre en mesure de dmarrer rapidement une application web. Ce chapitre ne s'est pas tendu sur les millions de faons diffrentes de crer une application web complte, d'autres chapitres fourniront plus de dtails sur des projets qui mettent en uvre quelquesuns des frameworks web et autres technologies parmi les plus populaires.
77
Dcompressez cette archive dans n'importe quel rpertoire et ouvrez le rpertoire ch-multi/. Celuici inclut un rpertoire simple-parent/ qui contient le projet Maven multimodule dvelopp dans ce chapitre. Dans ce dernier, vous trouverez un fichier [Link] et deux sous-modules, simpleweather/ et simple-webapp/.
<version>1.0</version> <name>Multi Chapter Simple Parent Project</name> <modules> <module>simple-weather</module> <module>simple-webapp</module> </modules> <build> <pluginManagement> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </pluginManagement> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
Remarquez que le parent dfinit un ensemble de coordonnes Maven : le groupId avec pour valeur [Link], l'artifactId ayant pour valeur simple-parent et la version 1.0. Le projet parent ne cre pas de JAR ni de WAR comme c'tait le cas de nos projets prcdents. la place, il s'agit simplement d'un POM qui fait rfrence d'autres projets Maven. Le packaging appropri pour un projet du type simple-parent qui fournit un simple Modle Objet de Projet (Project Object Model) est pom. La section suivante du fichier [Link] liste les sous-modules du projet. Ces modules sont dclars via une balise XML modules et chacune des balises module qu'elle contient correspond un des sous-rpertoires du dossier simple-parent/. Maven sait qu'il faut chercher pour chacun de ces rpertoires un fichier [Link]. Ainsi, il ajoutera ces sous-modules la liste des projets Maven inclus dans le build. Enfin, nous dfinissons quelques prfrences qui seront hrites dans tous les sous-modules. La configuration du build du projet simple-parent dfinit la JVM Java 5 comme cible de compilation. Comme le plugin Maven Compiler est attach au cycle de vie par dfaut, il est possible d'utiliser la section pluginManagement du fichier [Link] pour effectuer cela. Nous discuterons de la balise pluginManagement plus en dtail dans les chapitres suivants, mais la configuration des plugins par
80
dfaut et l'ajout de nouveaux plugins sont ainsi beaucoup plus faciles voir lorsqu'ils sont dissocis de cette manire. La balise dependencies ajoute JUnit 3.8.1 comme une dpendance globale. La configuration du build comme les dpendances sont hrites dans tous les sous-modules. L'utilisation de l'hritage de POM vous permet d'ajouter des dpendances communes pour les dpendances universelles comme JUnit ou Log4J.
81
<version>1.6.1</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>velocity</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> <scope>test</scope> </dependency> </dependencies> </project>
Le fichier [Link] du module simple-weather fait rfrence un POM parent via un triplet de coordonnes Maven. Le POM parent du module simple-weather est identifi par son groupId avec pour valeur [Link], par l'artifactId simple-parent et par la version 1.0. Consultez l'Exemple 6.3, La classe WeatherService . Exemple 6.3. La classe WeatherService
package [Link]; import [Link]; public class WeatherService { public WeatherService() {} public String retrieveForecast( String zip ) throws Exception { // Retrieve Data InputStream dataIn = new YahooRetriever().retrieve( zip ); // Parse Data Weather weather = new YahooParser().parse( dataIn ); // Format (Print) Data return new WeatherFormatter().format( weather ); } }
Dans le dossier src/main/java/org/sonatype/mavenbook/weather se trouve la classe WeatherService. Celle-ci fait rfrence trois objets dfinis dans le Chapitre 4, Personnalisation d'un
82
projet Maven. Dans l'exemple de ce chapitre, nous crons un projet spar qui contient les services utiliss par le projet de l'application web. C'est un modle commun dans le dveloppement d'entreprise Java, une application complexe se compose souvent de plusieurs applications web. Vous pourriez donc avoir une application d'entreprise compose de plusieurs applications web et de plusieurs applications en ligne de commande. Souvent, vous voudrez extraire certains lments communs dans un service externalis pour pouvoir les rutiliser sur plusieurs projets. C'est donc dans cette optique que nous crons la classe WeatherService. Ainsi, nous verrons comment le projet simple-webapp fait rfrence un service dfini dans module spar : simple-weather. La mthode retrieveForecast() prend en paramtre une chane de caractres contenant un code postal. Celle-ci est pass la mthode retrieve() de la classe YahooRetriever qui retournera un flux XML provenant de Yahoo! Mto. Ce mme XML est ensuite pass la mthode parse() de la classe YahooParser qui analyse ce flux et le retourne sous la forme d'un objet Weather. Ce dernier est ensuite format par la classe WeatherFormatter en une chane de caractres prsentable.
83
</dependency> </dependencies> <build> <finalName>simple-webapp</finalName> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins> </build> </project>
Ce module simple-webapp contient une servlet trs simple qui se contente de rcuprer un code postal partir d'une requte HTTP, d'appeler la classe WeatherService que nous venons de voir prcdemment dans l'Exemple 6.3, La classe WeatherService et d'crire le rsultat dans le Writer de la rponse. Exemple 6.5. Servlet WeatherServlet du projet simple-webapp
package [Link]; import import import import [Link]; [Link].*; [Link].*; [Link].*;
public class WeatherServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String zip = [Link]("zip" ); WeatherService weatherService = new WeatherService(); PrintWriter out = [Link](); try { [Link]( [Link]( zip ) ); } catch( Exception e ) { [Link]( "Error Retrieving Forecast: " + [Link]() ); } [Link](); [Link](); } }
La WeatherServlet instancie la classe WeatherService dfinie dans le projet simple-weather. Le code postal fourni en paramtre de la requte est pass la mthode retrieveForecast() et le rsultat est crit dans le Writer de la rponse. Enfin, pour que tout cela fonctionne, il faut dclarer la servlet dans le fichier [Link] du module simple-webapp. Ce fichier se trouve dans le rpertoire src/main/webapp/WEB-INF. Les
84
balises servlet et servlet-mapping du fichier [Link] associent l'URI /weather la servlet WeatherServlet, comme le montre l'Exemple 6.6, Fichier [Link] du module simple-webapp . Exemple 6.6. Fichier [Link] du module simple-webapp
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "[Link] > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>simple</servlet-name> <servlet-class>[Link]</servlet-class> </servlet> <servlet> <servlet-name>weather</servlet-name> <servlet-class>[Link]</servlet-class> </servlet> <servlet-mapping> <servlet-name>simple</servlet-name> <url-pattern>/simple</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>weather</servlet-name> <url-pattern>/weather</url-pattern> </servlet-mapping> </web-app>
85
[INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [...] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO]
[install:install] Installing [Link] to [Link] ---------------------------------------------------------------------Building simple-webapp Maven Webapp task-segment: [clean, install] ---------------------------------------------------------------------[install:install] Installing [Link] to [Link] ---------------------------------------------------------------------Reactor Summary: ---------------------------------------------------------------------Simple Parent Project ............................... SUCCESS [3.041s] simple-weather ...................................... SUCCESS [4.802s] simple-webapp Maven Webapp .......................... SUCCESS [3.065s] ----------------------------------------------------------------------
Lorsque Maven est excut dans un projet avec des sous-modules, il commence par charger le POM parent et localiser tous les POMs des sous-modules. Maven regroupe alors tous ces POMs dans le plugin Maven Reactor. Il s'agit d'un plugin charg d'analyser les dpendances entre les modules. Le plugin Reactor s'occupe de l'ordonnancement des composants pour garantir que les modules interdpendants soient compils et installs dans le bon ordre.
Note
Le plugin Reactor prserve l'ordre des modules dfini dans le POM moins que des changements ne soient ncessaires. Une bonne technique pour comprendre ce mcanisme consiste imaginer que les modules avec les dpendances inter projets soient descendus dans une liste jusqu' ce que l'ordre des dpendances soit satisfaisant. Dans quelques rares occasions, il peut tre bon de rarranger manuellement l'ordre de vos modules par exemple si vous voulez qu'un module frquemment instable soit remont en dbut de build. Ds que le plugin Reactor a trouv l'ordre dans lequel les projets doivent tre construits, Maven excute les goals indiqus pour chaque module afin d'effectuer le build du projet multimodule. Dans cet exemple, vous pouvez effectivement remarquer que Maven commence par construire le module simple-weather avant l'application web simple-webapp en excutant la commande mvn clean install.
Note
Quand vous excutez Maven partir de la ligne de commande vous serez amens utiliser frquemment la phase clean avant l'excution d'autres phases du cycle de vie. Lorsque vous prcisez clean sur la ligne de commande, vous vous assurez que Maven enlve les fichiers gnrs lors des builds prcdents avant qu'il ne compile et package votre application. Excuter la commande clean n'est pas ncessaire, mais c'est une prcaution utile pour s'assurer que vous effectuez un "build propre".
86
Une fois que Jetty est dmarr, chargez la page [Link] zip=01201 dans votre navigateur pour consulter le service mto que nous venons de dvelopper.
87
Une fois tlcharge, dcompressez l'archive dans n'importe quel rpertoire et entrez dans le rpertoire ch-multi-spring/. Vous trouverez alors dans celui-ci un sous-rpertoire simple-parent/ qui contient le projet Maven multimodule que nous allons dvelopper dans ce chapitre. Dans le rpertoire de ce projet, vous trouverez un fichier [Link] et cinq sous-modules : simple-model/, simplepersist/, simple-command/, simple-weather/ et simple-webapp/.
apprhender la complexit d'une application d'entreprise. Enfin, en conclusion, au-del de ce qui est prsent dans ce chapitre, nous explorerons quelques pistes pour rendre vos applications modulaires. Dans ce chapitre, nous allons tudier un projet Maven multimodule qui produira deux applications : un outil en ligne de commande et une application web ; chacune de ces applications permettra d'interroger le flux Yahoo! Mto. Ces deux applications conserveront les rsultats des diffrentes requtes dans une base de donnes embarque et permettront de rcuprer l'historique des prvisions mtorologiques stockes dans celle-ci. Les deux applications rutiliseront le mme code mtier et partageront une bibliothque de persistance. L'exemple de ce chapitre est construit sur la base du code du parseur dvelopp dans le Chapitre 4, Personnalisation d'un projet Maven. Ce projet est divis en cinq sousmodules, dont voici la prsentation sur la Figure 7.1, Relations entre les modules de l'application d'entreprise .
Super POM
[Link] simple-webapp
[Link] simple-weather
Figure 7.1. Relations entre les modules de l'application d'entreprise Sur la Figure 7.1, Relations entre les modules de l'application d'entreprise , vous pouvez voir que projet simple-parent se compose de cinq sous-modules : simple-model Ce module dfinit un simple modle d'objets correspondant aux donnes retournes par le flux Yahoo! Mto. Ce modle contient les objets suivants : Weather, Condition, Atmosphere, Location, et Wind. Lorsque notre application parse le flux Yahoo! Mto, les parseurs dfinis
90
dans le module simple-weather transforment le XML en une liste d'objets Weather qui sera ensuite utilise dans les applications. Ce projet contient des objets du modle annots avec les annotations Hibernate3. Le module simple-persist utilise ces objets pour associer chacun d'entre eux une table de la base de donnes. simple-weather Ce module contient toute la logique ncessaire pour rcuprer des donnes du flux Yahoo! Mto et parser le XML obtenu. Ce XML est converti sous la forme d'objets du module simple-model. C'est pour cela que le module simple-weather doit dpendre du module simple-model. Enfin, simple-weather dfinit un service WeatherService qui est rfrenc par deux autres projets : simple-command et simple-webapp. simple-persist Ce module contient les DAOs (Data Access Objects) qui permettent d'enregistrer les objets Weather dans la base de donnes. Ces DAOs seront utiliss par les deux applications de ce projet multimodule. Ils permettront galement de faire le lien avec les objets du modle du module simple-model. Le module simple-persist a donc une dpendance directe au module simple-model et une dpendance vers le JAR contenant les Annotations Hibernate. simple-webapp L'application web contient deux contrleurs Spring MVC qui utilisent le service WeatherService dfini dans le module simple-weather et les DAOs provenant du module simple-persist. De plus, simple-webapp a une dpendance directe sur les modules simple-weather et simple-persist. Ce module dpend donc transitivement du module simple-model. simple-command Ce module contient une application en ligne de commande qui permet d'interroger le flux Yahoo! Mto. Ce projet contient une classe avec une mthode statique main() qui interagit avec le service WeatherService dfini dans le module simple-weather et les DAOs du projet simple-persist. Le module simple-command a une dpendance directe sur les modules simple-weather et simple-persist et une dpendance transitive au module simplemodel. Ce chapitre contient un exemple assez simple pour tre dcrit dans un livre et assez complexe pour justifier la cration de cinq sous-modules. Notre exemple est organis autour d'un modle contenant cinq classes, une bibliothque de persistance avec deux classes de service et une bibliothque d'analyse grammaticale du flux mto contenant cinq ou six classes. Dans un cas rel, un projet peut avoir un modle de plusieurs centaines de classes, plusieurs bibliothques de persistance et des bibliothques de services partages. Bien que nous ayons essay de garder un exemple suffisamment simple pour tre compris rapidement, nous vous proposons un projet bien plus complexe que le projet multimodule du chapitre prcdent. Vous pourriez tre tents de regarder rapidement les exemples dans ce chapitre et penser que Maven gnre trop de complexit compare la taille du modle d'objet. Bien que l'utilisation de Maven suggre un certain niveau de modularit, comprenez bien que nous avons volontairement
91
compliqu ici nos exemples dans le but de montrer les fonctionnalits Maven dans le cas de projets multimodule.
92
<version>1.0</version> <name>Multi-Spring Chapter Simple Parent Project</name> <modules> <module>simple-command</module> <module>simple-model</module> <module>simple-weather</module> <module>simple-persist</module> <module>simple-webapp</module> </modules> <build> <pluginManagement> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </pluginManagement> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
Note
Si les POMs Maven vous sont dj familiers, vous pouvez remarquer que ce POM de plus haut niveau ne dfinit pas de balise dependencyManagement. La balise dependencyManagement permet de dfinir la version des dpendances un endroit centralis dans un POM de haut-niveau. Ce mcanisme sera aborde dans le Chapitre 8, Optimiser et remanier les POMs. Notez les similarits de ce POM parent et celui de l'Exemple 6.1, POM du projet simple-parent . La seule relle diffrence entre ces deux POMs est la liste de leurs sous-modules. L o l'exemple prcdent comptait deux sous-modules, ce POM en dnombre cinq. Les sections suivantes explorent en dtail chacun de ces cinq sous-modules. Notre exemple utilisant des annotations, nous avons configur le compilateur pour cibler les JVM Java 5.
93
Figure 7.2. Modle objet pour les donnes mto Le fichier [Link] de ce modle objet contient une dpendance qui ncessite une explication. Notre modle objet est annot avec Hibernate Annotations. Celles-ci sont utilises pour associer ce modle aux tables de la base de donnes relationnelle. Cette dpendance est [Link]:hibernateannotations:[Link]. Regardons le [Link] affich dans l'Exemple 7.2, POM du module simple-model , ainsi que les quelques exemples d'utilisation de ces annotations. Exemple 7.2. POM du module simple-model
<project xmlns="[Link]
94
xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-model</artifactId> <packaging>jar</packaging> <name>Simple Object Model</name> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-annotations</artifactId> <version>[Link]</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>[Link]</version> </dependency> </dependencies> </project>
Dans le dossier src/main/java/org/sonatype/mavenbook/weather/model se trouve le fichier [Link]. Celui-ci contient l'objet Weather annot. Il s'agit d'un simple Java bean. Cela veut dire qu'il contient des variables d'instance prives comme id, location, condition, wind, atmosphere et date. Celles-ci sont exposes par l'intermdiaire d'accesseurs publiques en suivant ce pattern : une proprit nomme name disposera d'un getter public sans argument nomm getName(), et d'un setter prenant en paramtre un argument nomm setName(String name). Si nous montrons le getter et le setter de la proprit id, nous avons omis volontairement la plupart des getters et des setters des autres proprits afin de sauver quelques arbres. Consultez l'Exemple 7.3, Objet Weather annot . Exemple 7.3. Objet Weather annot
package [Link]; import [Link].*; import [Link]; @Entity @NamedQueries({ @NamedQuery(name="[Link]", query="from Weather w where [Link] = :location") }) public class Weather {
95
@Id @GeneratedValue(strategy=[Link]) private Integer id; @ManyToOne(cascade=[Link]) private Location location; @OneToOne(mappedBy="weather",cascade=[Link]) private Condition condition; @OneToOne(mappedBy="weather",cascade=[Link]) private Wind wind; @OneToOne(mappedBy="weather",cascade=[Link]) private Atmosphere atmosphere; private Date date; public Weather() {} public Integer getId() { return id; } public void setId(Integer id) { [Link] = id; } // Nous avons omis les autres getter et setter... }
La classe Weather utilise des annotations qui permettent de guider Hibernate pour associer cet objet une table de la base de donnes relationnelle. Bien qu'une explication dtaille des annotations Hibernate dpasse les limites de ce chapitre, en voici quelques grandes lignes. L'annotation @Entity marque la classe comme entit persistante. Nous avons omis l'annotation @Table sur cette classe, ainsi, Hibernate va utiliser le nom de la classe comme nom de table. L'annotation @NamedQueries dfinit une requte qui sera utilise par le WeatherDAO dans le module simple-persist. Le langage utilis dans la requte de l'annotation @NamedQuery est crit en HQL (Hibernate Query Language). Chaque champ de la classe est annot par des annotations dfinissant le type des diffrentes colonnes associer ainsi que les relations impliques sur celles-ci :
Id
La proprit id est annote avec @Id. Cette annotation marque ce champ comme proprit contenant la cl primaire de la table de base de donnes. L'annotation @GeneratedValue permet de contrler comment les nouvelles valeurs de la cl primaire sont gnres. Dans le cas de notre proprit id, nous utilisons la valeur IDENTITY de l'numration GenerationType qui permet d'utiliser la gnration d'identit fournie par la base de donnes sous-jacente.
Location
Chaque instance de la classe Weather contient un objet Location. Ce dernier reprsente un code postal. Son annotation @ManyToOne vous assure que tous les objets Weather qui possdent la mme Location pointent effectivement vers les mmes instances. L'attribut cascade de
96
l'annotation @ManyToOne permet d'assurer qu'un objet Location soit enregistr chaque sauvegarde d'un objet Weather.
Condition, Wind, Atmosphere
Chacun de ces objets est mapp avec une annotation @OneToOne dont la proprit cascade est [Link]. Cette proprit signifie qu' chaque sauvegarde d'un objet Weather une ligne sera cre dans chacune des tables suivantes : Condition, Wind et Atmosphere.
Date
Le champ Date n'est pas annot. Cela signifie qu'Hibernate va utiliser la configuration par dfaut pour son mapping. Le nom de la colonne sera date et possdera le type timestamp appropri pour un objet Date.
Note
Si vous dsirez omettre une proprit du mapping, vous pouvez annoter celle-ci avec @Transient. Ensuite, jetons un coup d'oeil un second objet du modle, Condition, affich dans l'Exemple 7.4, Classe Condition du module simple-model . Cette classe se trouve galement dans le dossier src/ main/java/org/sonatype/mavenbook/weather/model. Exemple 7.4. Classe Condition du module simple-model
package [Link]; import [Link].*; @Entity public class Condition { @Id @GeneratedValue(strategy=[Link]) private Integer id; private private private private String String String String text; code; temp; date;
@OneToOne(cascade=[Link]) @JoinColumn(name="weather_id", nullable=false) private Weather weather; public Condition() {} public Integer getId() { return id; } public void setId(Integer id) { [Link] = id; }
97
La classe Condition ressemble la classe Weather. Elle est annote avec @Entity et possde les mmes annotations sur la proprit id. Les champs text, code, temp et date ne possdent pas d'annotation et restent donc lis la base de donnes selon la configuration par dfaut. La proprit weather est annote avec @OneToOne et @JoinColumn qui permettent de rfrencer l'objet Weather associ via la cl trangre weather_id.
98
<version>1.0</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> <scope>test</scope> </dependency> </dependencies> </project>
Le POM du module simple-weather tend celui du simple-parent, configure le type de packaging jar et ajoute les dpendances suivantes :
[Link]:simple-model:1.0 Le module simple-weather parse et le transforme le flux RSS Yahoo! Mto en objet Weather. Il a donc une dpendance directe sur le module simple-model. log4j:log4j:1.2.14 Le module simple-weather utilise Log4J pour afficher ses messages de log. dom4j:dom4j:1.6.1 et jaxen:jaxen:1.1.1
Ces deux dpendances sont utilises pour parser le XML provenant de Yahoo! Mto.
[Link]:commons-io:1.3.2 (scope=test) Cette dpendance dont le scope est test est utilise par YahooParserTest.
Analysons maintenant le service WeatherService de l'Exemple 7.6, La classe WeatherService . Cette classe ressemble beaucoup au service WeatherService de l'Exemple 6.3, La classe WeatherService . Bien qu'ils aient le mme nom, le service de cet exemple comporte quelques lgres diffrences. Dans cette version, la mthode retrieveForecast() retourne un objet Weather et le formatage est dlgu l'application appelant le service WeatherService. L'autre modification
99
majeure concerne les classes YahooRetriever et YahooParser, qui sont maintenant des proprits du service WeatherService. Exemple 7.6. La classe WeatherService
package [Link]; import [Link]; import [Link]; public class WeatherService { private YahooRetriever yahooRetriever; private YahooParser yahooParser; public WeatherService() {} public Weather retrieveForecast(String zip) throws Exception { // Rcupration des donnes InputStream dataIn = [Link](zip); // Parsing des donnes Weather weather = [Link](zip, dataIn); return weather; } public YahooRetriever getYahooRetriever() { return yahooRetriever; } public void setYahooRetriever(YahooRetriever yahooRetriever) { [Link] = yahooRetriever; } public YahooParser getYahooParser() { return yahooParser; } public void setYahooParser(YahooParser yahooParser) { [Link] = yahooParser; } }
Pour finir, ce projet contient un fichier XML utilis par Spring pour crer ce qu'on appelle l' ApplicationContext dont voici le fonctionnement : nos applications web et en ligne de commande ont besoin d'interagir avec le service WeatherService, pour cela elles rcuprent une instance de cette classe par l'intermdiaire de l'ApplicationContext Spring en utilisant le nom de bean weatherService. Notre application web utilise un contrleur Spring MVC, celui-ci est associ une instance du service WeatherService. L'application en ligne de commande charge ce mme
100
service partir de la mthode statique main() grce l'ApplicationContext. Afin d'encourager la rutilisation du code, nous avons inclus le fichier [Link] dans le rpertoire src/main/resources, le rendant ainsi accessible dans le classpath. Les projets qui dpendent du module simple-weather peuvent donc charger ce fichier en utilisant la classe ClasspathXmlApplicationContext fournie par Spring et ainsi rcuprer une instance du service WeatherService par l'intermdiaire de son nom : weatherService. Exemple 7.7. ApplicationContext Spring du module simple-weather
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] default-lazy-init="true"> <bean id="weatherService" class="[Link]"> <property name="yahooRetriever" ref="yahooRetriever"/> <property name="yahooParser" ref="yahooParser"/> </bean> <bean id="yahooRetriever" class="[Link]"/> <bean id="yahooParser" class="[Link]"/> </beans>
Ce fichier dclare trois beans : yahooParser, yahooRetriever et weatherService. Le bean weatherService est une instance du service WeatherService. Le fichier XML configure galement les proprits de ce bean yahooParser et yahooRetriever qui rfrencent les noms des deux instances de classes en question. Vous pouvez comparer ce fichier [Link] la dfinition de l'architecture d'un sous-systme de ce projet multimodule. Certains projets comme simple-webapp et simple-command peuvent rfrencer ce contexte et rcuprer une instance du service WeatherService configure avec des instances des classes YahooRetriever et YahooParser en proprit.
101
objet Location partir d'un code postal. Commenons par regarder le POM du module simplepersist dans l'Exemple 7.8, POM du module simple-persist . Exemple 7.8. POM du module simple-persist
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-persist</artifactId> <packaging>jar</packaging> <name>Simple Persistence API</name> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>simple-model</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate</artifactId> <version>[Link]</version> <exclusions> <exclusion> <groupId>[Link]</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-annotations</artifactId> <version>[Link]</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>[Link]</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency>
102
Ce POM rfrence celui du module simple-parent en POM parent et dfinit quelques dpendances. Les dpendances listes dans le POM du module simple-persist sont :
[Link]:simple-model:1.0 Tout comme le module simple-weather, ce module de persistance rfrence les objets du modle dfinis dans le projet simple-model. [Link]:hibernate:[Link]
Nous dfinissions une dpendance sur la version [Link] d'Hibernate. Notez l'exclusion d'une dpendance transitive d'Hibernate, nous effectuons cela cause de la dpendance [Link]:jta qui n'est pas rcuprable partir du repository Maven public. Cette dpendance est l'une de ces dpendances Sun qui ne sont pas encore publies dans le dpt Maven libre 'central'. Afin d'viter le message nous demandant d'aller tlcharger cette dpendance, nous excluons simplement celle-ci d'Hibernate.
[Link]:servlet-api:2.4
Comme le projet contient une Servlet, nous devons inclure une version de Servlet API, ici la 2.4.
[Link]:spring:2.0.7
Note
C'est gnralement une bonne pratique de dpendre uniquement des composants Spring que vous utilisez. Spring dispose d'ailleurs d'artefacts spcifiques tels que spring-hibernate3. Pourquoi dpendre de Spring ? Lorsqu'il est utilis avec son intgration Hibernate, Spring permet l'utilisation des classes Helpers comme HibernateDaoSupport facilitant l'utilisation d'Hibernate. Pour savoir ce qu'il est possible de faire avec la classe HibernateDaoSupport, regardez le code de la classe WeatherDAO de l'Exemple 7.9, Classe WeatherDAO du module simple-persist . Exemple 7.9. Classe WeatherDAO du module simple-persist
package [Link]; import [Link]; import [Link]; import [Link]; import [Link];
103
import [Link]; import [Link]; import [Link]; import [Link]; public class WeatherDAO extends HibernateDaoSupport public WeatherDAO() {} public void save(Weather weather) { getHibernateTemplate().save( weather ); } public Weather load(Integer id) { return (Weather) getHibernateTemplate().load( [Link], id); } @SuppressWarnings("unchecked") public List<Weather> recentForLocation( final Location location ) { return (List<Weather>) getHibernateTemplate().execute( new HibernateCallback() { public Object doInHibernate(Session session) { Query query = getSession().getNamedQuery("[Link]"); [Link]("location", location); return new ArrayList<Weather>( [Link]() ); } }); } } {
C'est tout ? Pas vraiment, mais cela suffit pour obtenir une classe qui permet d'insrer de nouvelles lignes, en rcuprer par leur cl primaire et rcuprer toutes les lignes Weather qui rfrent un id de la table Location. Nous ne pouvons clairement pas arrter ce livre et insrer les cinq cents pages qu'il faudrait pour comprendre les subtilits d'Hibernate, contentons-nous de quelques rapides explications : Cette classe tend HibernateDaoSupport. Ce qui signifie que cette classe est associe une SessionFactory Hibernate qui permet la cration d'objets Session Hibernate. Avec Hibenate, chaque opration s'effectue par l'intermdiaire d'un objet Session, celle-ci s'occupe des accs la base de donnes et de la connexion via la DataSource JDBC. tendre HibernateDaoSupport vous permet galement d'accder au template HibernateTemplate en utilisant la mthode getHibernateTemplate(). La mthode save() prend une instance de la classe Weather et appelle la mthode save() de la classe HibernateTemplate. L'HibernateTemplate simplifie les appels aux oprations standards d'Hibernate et convertit les exceptions types des diffrentes bases de donnes en RuntimeException. Appelons la mthode save() qui insre une nouvelle ligne dans la table Weather. La mise jour d'une entit dj en base passe par la mthode update(). La mthode saveOrUpdate() cre une nouvelle ligne ou la modifie en fonction de la prsence d'une valeur non-nulle dans la proprit id de la classe.
104
De la mme manire, la mthode load() se contente d'appeler la mthode du mme nom de l'instance HibernateTemplate. Cette mthode prend un objet Class et un Serializable en paramtres. Dans notre exemple, l'objet Serializable correspond la valeur de id de l'objet Weather charger. Cette dernire mthode recentForLocation() appelle une NamedQuery dfinie dans l'objet modle Weather. Il s'agit de la requte nomme "[Link]" dont le code est "from Weather w where [Link] = :location". Nous chargeons cette NamedQuery en utilisant une rfrence de la Session Hibernate dans un HibernateCallback qui est lanc via un appel la mthode execute() de l'HibernateTemplate. Dans cette mthode, nous remplissons le paramtre location avec le paramtre pass dans la mthode recentForLocation(). C'est maintenant le bon moment de clarifier certains points. Les classes HibernateDaoSupport et HibernateTemplate proviennent du framework Spring. Elles ont t cres par Spring pour faciliter l'criture de DAO. Pour cela, nous avons besoin de modifier la configuration de l'ApplicationContext Spring du module simple-persist. Le fichier XML de l'Exemple 7.10, ApplicationContext Spring du module simple-persist se trouve dans le dossier src/main/ resources dans un fichier nomm [Link]. Exemple 7.10. ApplicationContext Spring du module simple-persist
<beans xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] default-lazy-init="true"> <bean id="sessionFactory" class="[Link]"> <property name="annotatedClasses"> <list> <value>[Link]</value> <value>[Link]</value> <value>[Link]</value> <value>[Link]</value> <value>[Link]</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.format_sql">true</prop> <prop key="[Link].factory_class"> [Link] </prop> <prop key="[Link]"> [Link] </prop> <prop key="[Link].pool_size">0</prop> <prop key="[Link].driver_class">
105
[Link] </prop> <prop key="[Link]"> jdbc:hsqldb:data/weather;shutdown=true </prop> <prop key="[Link]">sa</prop> <prop key="[Link]"></prop> <prop key="[Link]">true</prop> <prop key="[Link].batch_size">0</prop> </props> </property> </bean> <bean id="locationDAO" class="[Link]"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="weatherDAO" class="[Link]"> <property name="sessionFactory" ref="sessionFactory"/> </bean> </beans>
Cet ApplicationContext dfinit plusieurs choses. Le bean sessionFactory est le bean par lequel les DAOs pourront rcuprer les Session Hibernate. Ce bean est une instance de la classe AnnotationSessionFactoryBean et fournit une liste d'annotatedClasses. Notez que cette liste de classes annotes est la liste des classes dfinies dans le module simple-model. Ensuite, la sessionFactory est configure par l'intermdiaire d'une liste de proprits de configuration Hibernate (hibernateProperties). Dans cet exemple, nous utilisons les proprits Hibernate suivantes :
[Link]
Cette proprit permet de contrler le SQL qui sera gnr pour notre base de donnes. Comme nous utilisons HSQLDB, nous choisissons le dialecte [Link]. Hibernate possde nativement des dialectes pour la majorit des bases de donnes comme Oracle, MySQL, Postgres et SQL Server.
[Link].*
Dans cet exemple, nous configurons une connexion JDBC partir de la configuration Spring. Nos applications sont configures pour se lancer avec la base de donnes HSQLDB du rpertoire ./data/weather. Dans une vraie application d'entreprise, vous utiliseriez plutt quelque chose comme JNDI pour externaliser la configuration de la base de donnes de votre code applicatif. Dans la suite du fichier XML, sont dfinis les deux DAOs du module simple-persist. Chacun d'entre eux contient une rfrence vers la sessionFactory Hibernate que nous venons de dfinir. Comme l'ApplicationContext du module simple-weather, ce fichier [Link] dfinit l'architecture du sous-module. Si vous travailliez avec un plus grand nombre de classes persistantes, vous pourriez trouver utile de les externaliser dans un ApplicationContext spar.
106
Il reste encore une dernire pice du puzzle. Plus tard dans ce chapitre, nous verrons comment nous pouvons utiliser le plugin Maven Hibernate3 pour gnrer notre schma de base de donnes partir des objets annots du modle. Pour cela, le plugin Maven Hibernate3 a besoin de rcuprer les paramtres de connexion JDBC, la liste des classes annotes et un autre fichier de configuration nomm [Link] prsent dans le rpertoire src/main/resources. Le contenu de ce fichier (qui duplique une partie de la configuration du fichier [Link]) nous permet l'utilisation du plugin Maven Hibernate3 pour gnrer le DDL (Data Definition Language) du schma de la base de donnes. Consultez l'Exemple 7.11, Fichier [Link] du module simple-persist . Exemple 7.11. Fichier [Link] du module simple-persist
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "[Link] <hibernate-configuration> <session-factory> <!-- dialecte SQL --> <property name="dialect">[Link]</property> <!-- Configuration des connexions --> <property name="connection.driver_class">[Link]</property> <property name="[Link]">jdbc:hsqldb:data/weather</property> <property name="[Link]">sa</property> <property name="[Link]"></property> <property name="[Link]">true</property> <!-- Pool de connexion JDBC (utilisation du built-in) --> <property name="connection.pool_size">1</property> <!-- Dfinit le scope des context Hibernate --> <property name="current_session_context_class">thread</property> <!-- Dsactivation du cache de second niveau <property name="cache.provider_class"> [Link] </property> <!-- Affiche les requtes sur stdout --> <property name="show_sql">true</property> <!-- Dsactivation du batching, permet HSQLDB de propager ses erreurs correctement. --> <property name="jdbc.batch_size">0</property> <!-- Liste de toutes les classes annontes --> <mapping class="[Link]"/> <mapping class="[Link]"/> <mapping class="[Link]"/> <mapping class="[Link]"/> <mapping class="[Link]"/> -->
107
</session-factory> </hibernate-configuration>
Les contenus de l'Exemple 7.10, ApplicationContext Spring du module simple-persist et de l'Exemple 7.1, POM du projet simple-parent sont redondants. Le XML de l'ApplicationContext Spring sera utilis par l'application web et l'application en ligne de commande, le fichier [Link] n'est prsent que pour faire fonctionner le plugin Maven Hibernate3. Plus tard dans ce chapitre, nous verrons comment utiliser ce fichier [Link] et le plugin Maven Hibernate3 pour gnrer le schma de la base de donnes bas sur les objets annots du projet simple-model. Ce fichier [Link] configure les proprits des connexions JDBC et numre la liste des objets annots.
simple-weather
[Link]
weatherService
historyController
simple-persist
[Link]
= Dependency
weatherDAO locationDAO
Figure 7.3. Contrleurs Spring MVC rfrenant les modules simple-weather et simple-persist.
108
Le POM du module simple-webapp est affich dans l'Exemple 7.12, POM du module simplewebapp . Exemple 7.12. POM du module simple-webapp
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-webapp</artifactId> <packaging>war</packaging> <name>Simple Web Application</name> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>simple-weather</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>simple-persist</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> </dependencies> <build> <finalName>simple-webapp</finalName> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-jetty-plugin</artifactId> <dependencies>
109
<dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>[Link]</version> </dependency> </dependencies> </plugin> <plugin> <groupId>[Link]</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.0</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> </component> </components> </configuration> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>[Link]</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>
Au fur et mesure que nous avanons dans ce livre, les exemples deviennent de plus en plus substantiels. Vous avez d'ailleurs probablement not que le fichier [Link] commence devenir volumineux. Dans ce POM, nous configurons quatre dpendances et deux plugins. Regardons ce POM en dtail et tendons-nous sur certains des points de configuration importants : Ce projet simple-webapp dfinit quatre dpendances : les spcifications Servlet 2.4, la bibliothque de services simple-weather, la bibliothque de persistance simple-persist et l'intgralit du Spring Framework 2.0.7. Le plugin Maven Jetty est utilis de la manire la plus simple qui soit dans ce projet. Nous ajoutons simplement la balise plugin qui fait rfrence aux bons groupId et artifactId. Le fait que ce plugin soit facile configurer signifie que les dveloppeurs du plugin ont fait du bon travail en fournissant les valeurs par dfaut adquates pour la plupart des cas. Si vous avez besoin de surcharger cette configuration, vous pouvez le faire en ajoutant une balise configuration. Dans notre configuration de build, nous allons configurer le plugin Maven Hibernate3 pour qu'il utilise une instance de la base de donnes embarque HSQLDB. Pour que le plugin Maven Hibernate3 arrive se connecter la base, il doit rfrencer le driver JDBC d'HSQLDB dans son classpath. Pour rendre cette dpendance disponible au plugin, nous ajoutons sa dclaration directement dans la dclaration du plugin. Ici, nous rfrenons hsqldb:hsqldb:[Link]. Le plugin
110
Hibernate a galement besoin des drivers JDBC pour crer cette base de donnes, nous avons donc ajout cette dpendance dans sa configuration. C'est partir de l'utilisation du plugin Maven Hibernate3 que ce POM devient le plus intressant. Dans la section suivante, nous allons excuter le goal hbm2ddl pour gnrer une base de donnes HSQLDB. Nous avons inclus dans ce [Link] une rfrence vers la version 2.0 du hibernate3maven-plugin rcuprable partir du dpt Codehaus Mojo. Le plugin Maven Hibernate3 dispose de plusieurs moyens pour rcuprer le mapping Hibernate en fonction du cas d'utilisation. Si vous utilisez des fichiers XML pour le Mapping Hibernate (.[Link]), et que vous voulez gnrer les classes de votre modle par l'intermdiaire du goal hbm2java, vous devez indiquer votre implmentation la configuration. Si vous utilisez le plugin Hibernate3 en reverse engineering pour gnrer les fichiers .[Link] et les objets du modle partir d'une base de donnes existante, vous voudrez utiliser l'implmentation jdbcconfiguration. Dans notre exemple, nous utilisons simplement les objets annots du modle pour gnrer la base de donnes. En d'autres termes, nous avons notre mapping Hibernate, mais nous n'avons pas encore de base de donnes. Pour ce scnario, annotationconfiguration est l'implmentation la plus approprie. Le plugin Maven Hibernate3 sera plus largement dtaill dans la Section 7.7, Excution de l'application web .
Note
Une erreur classique consiste utiliser la balise extensions de la configuration pour ajouter des dpendances ncessaires un plugin. Il est fortement dcourag de procder de la sorte car les extensions peuvent polluer le classpath de votre projet, et provoquer des effets de bord dsagrables. De plus, le comportement des extensions a t modifi depuis la version 2.1 de Maven. Le seul usage correct de la balise extensions est l'ajout d'implmentations complmentaires. Regardons maintenant les deux contrleurs Spring MVC, chacun d'entre eux rfrence des beans dclars dans les simple-weather et simple-persist. Exemple 7.13. WeatherController du module simple-webapp
package [Link]; import import import import import import [Link]; [Link]; [Link]; [Link].*; [Link]; [Link];
public class WeatherController implements Controller { private WeatherService weatherService; private WeatherDAO weatherDAO; public ModelAndView handleRequest(HttpServletRequest request,
111
HttpServletResponse response) throws Exception { String zip = [Link]("zip"); Weather weather = [Link](zip); [Link](weather); return new ModelAndView("weather", "weather", weather); } public WeatherService getWeatherService() { return weatherService; } public void setWeatherService(WeatherService weatherService) { [Link] = weatherService; } public WeatherDAO getWeatherDAO() { return weatherDAO; } public void setWeatherDAO(WeatherDAO weatherDAO) { [Link] = weatherDAO; } }
WeatherController implmente l'interface Controller qui assure la prsence d'une mthode handleRequest() dont la signature est montre dans cet exemple. Si vous regardez le corps de cette mthode, vous constaterez que celle-ci invoque la mthode retrieveForecast() du service weatherService. Contrairement au chapitre prcdent, dans lequel une servlet instancie la classe WeatherService, le WeatherController est un bean contenant une proprit weatherService. Le conteneur Spring IoC a la responsabilit de charger le service weatherService dans le contrleur. Notez galement que nous n'utilisons pas le WeatherFormatter dans ce contrleur. Au lieu de cela, nous passons l'objet Weather retourn par la mthode retrieveForecast() au constructeur de la classe ModelAndView. Cette classe ModelAndView est utilise pour effectuer le rendu du template Velocity. Ce template disposera d'une rfrence sur la variable ${weather} contenant ce mme objet. Le template [Link] se trouve dans le rpertoire src/main/webapp/WEB-INF/vm, celui-ci est
affich dans l'Exemple 7.14, Modle [Link] interprt par le WeatherController . Dans ce WeatherController, avant d'effectuer le rendu des prvisions mto, nous passons l'objet Weather retourn par le service WeatherService la mthode save() de la classe WeatherDAO. Cet objet est sauvegard par Hibernate en base de donnes. Plus tard, dans le contrleur HistoryController, nous verrons comment rcuprer l'historique de ces prvisions mtorologiques. Exemple 7.14. Modle [Link] interprt par le WeatherController
<b>Current Weather Conditions for: ${[Link]}, ${[Link]}, ${[Link]}</b><br/>
112
<ul> <li>Temperature: ${[Link]}</li> <li>Condition: ${[Link]}</li> <li>Humidity: ${[Link]}</li> <li>Wind Chill: ${[Link]}</li> <li>Date: ${[Link]}</li> </ul>
La syntaxe de ce modle Velocity est rapide expliquer, les variables sont rfrences par l'intermdiaire de la notation ${}. L'expression entre les accolades fait rfrence une proprit, ou une proprit d'une proprit de la variable weather passe ce modle par le WeatherController. Le contrleur HistoryController est utilis pour rcuprer la liste des prvisions mtorologiques les plus rcentes parmi celles demandes par le WeatherController. Chaque fois que nous rcuprons une prvision dans le WeatherController, celui-ci enregistre l'objet Weather rcupr dans la base de donnes via le WeatherDAO. Ce DAO utilise ensuite Hibernate pour transformer l'objet Weather en une srie de lignes dans un ensemble de tables de la base de donnes. Le contrleur HistoryController est affich dans l'Exemple 7.15, HistoryController du module simple-web . Exemple 7.15. HistoryController du module simple-web
package [Link]; import import import import import import [Link].*; [Link].*; [Link]; [Link]; [Link].*; [Link].*;
public class HistoryController implements Controller { private LocationDAO locationDAO; private WeatherDAO weatherDAO; public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { String zip = [Link]("zip"); Location location = [Link](zip); List<Weather> weathers = [Link]( location ); Map<String,Object> model = new HashMap<String,Object>(); [Link]( "location", location ); [Link]( "weathers", weathers ); return new ModelAndView("history", model); } public WeatherDAO getWeatherDAO() { return weatherDAO;
113
} public void setWeatherDAO(WeatherDAO weatherDAO) { [Link] = weatherDAO; } public LocationDAO getLocationDAO() { return locationDAO; } public void setLocationDAO(LocationDAO locationDAO) { [Link] = locationDAO; } }
Le contrleur HistoryController est charg avec les deux DAOs du module simple-persist. Les instances de ces deux DAOs sont portes par les proprits WeatherDAO et LocationDAO. Le but de l'HistoryController est de rcuprer une List d'objets Weather en fonction du paramtre zip. Quand le WeatherDAO enregistre un objet Weather dans la base de donnes, il ne se contente pas de stocker le code postal, il enregistre un objet Location qui est li l'objet Weather du module simplemodel. Pour rcuprer la List des objets Weather, l'HistoryController commence par rcuprer l'objet Location qui correspond au paramtre zip reprsentant le code postal. Pour cela, on invoque la mthode findByZip() du DAO LocationDAO. Une fois cet objet Location rcupr, l'HistoryController essayera de rcuprer les objets Weather les plus rcents associs cette Location. Une fois la List<Weather> rcupre, une HashMap est cre contenant les deux variables du modle Velocity [Link] de l'Exemple 7.16, Modle [Link] utilis par l'HistoryController . Exemple 7.16. Modle [Link] utilis par l'HistoryController
<b> Weather History for: ${[Link]}, ${[Link]}, ${[Link]} </b> <br/> #foreach( $weather in $weathers ) <ul> <li>Temperature: $[Link]</li> <li>Condition: $[Link]</li> <li>Humidity: $[Link]</li> <li>Wind Chill: $[Link]</li> <li>Date: $[Link]</li> </ul> #end
Le modle [Link] du dossier src/main/webapp/WEB-INF/vm rfrence la variable location pour afficher les prvisions mto provenant du WeatherDAO. Ce template utilise une structure de
114
contrle Velocity, #foreach, pour itrer sur chaque lment de la variable weathers. Chaque lment de la liste weathers est assign une variable nomme weather. Le cur de la boucle, entre #foreach et #end, permet d'afficher les informations de chaque prvision. Nous venons de voir les implmentations de nos deux Controller. Nous venons galement de voir comment ils rfrencent les beans des modules simple-weather et simple-persist. Ces Controller rpondent aux requtes HTTP par l'intermdiaire de mystrieux systmes qui savent comment effectuer le rendu de templates Velocity. Toute la magie est configure dans l'ApplicationContext Spring du fichier src/main/webapp/WEB-INF/[Link]. Ce XML configure les contrleurs et rfrence d'autres beans manags par Spring. Il est charg par un ServletContextListener qui est configur pour charger galement les fichiers [Link] et [Link] partir du classpath. Regardons de plus prs le fichier [Link] de l'Exemple 7.17, Configuration des contrleurs Spring du fichier [Link] . Exemple 7.17. Configuration des contrleurs Spring du fichier [Link]
<beans> <bean id="weatherController" class="[Link]"> <property name="weatherService" ref="weatherService"/> <property name="weatherDAO" ref="weatherDAO"/> </bean> <bean id="historyController" class="[Link]"> <property name="weatherDAO" ref="weatherDAO"/> <property name="locationDAO" ref="locationDAO"/> </bean> <!-- you can have more than one handler defined --> <bean id="urlMapping" class="[Link]"> <property name="urlMap"> <map> <entry key="/weather.x"> <ref bean="weatherController" /> </entry> <entry key="/history.x"> <ref bean="historyController" /> </entry> </map> </property> </bean>
115
<bean id="viewResolver" class="[Link]"> <property name="cache" value="true"/> <property name="prefix" value=""/> <property name="suffix" value=".vm"/> <property name="exposeSpringMacroHelpers" value="true"/> </bean> </beans>
Le fichier [Link] dfinit deux contrleurs Spring. weatherController a deux proprits qui rfrencent weatherService et weatherDAO. historyController rfrence les beans weatherDAO et locationDAO. Quand l'ApplicationContext est cr, il est cr dans un environnement qui donne accs aux ApplicationContexts dfinit dans les fichiers simple-persist et simple-weather. Dans l'Exemple 7.18, [Link] du module simplewebapp vous pouvez voir comment Spring est configur pour fusionner plusieurs composants contenant des fichiers de configuration Spring diffrents. Le bean urlMapping dfinit les formats des URL pouvant invoquer les contrleurs WeatherController et HistoryController. Dans cet exemple, nous utilisons le SimpleUrlHandlerMapping et associons /weather.x au WeatherController et / history.x l'HistoryController. Comme nous utilisons le moteur de template Velocity, nous avons besoin de fournir quelques options de configuration spcifiques. Dans le bean velocityConfig, nous demandons Velocity de rechercher toutes les modles prsents dans le rpertoire /WEB-INF/vm. Enfin, le viewResolver est configur avec la classe VelocityViewResolver. Il existe un bon nombre d'implmentations du ViewResolver dans Spring, du standard ViewResolver pour afficher une JSP ou JSTL au ViewResolver capable d'effectuer le rendu de modles Freemarker. Dans cet exemple, nous configurons le moteur de template Velocity et modifions les prfixes et suffixes par dfaut pour modifier automatiquement les noms des modles passs aux objets ModelAndView. Pour finir, le projet simple-webapp possde un fichier [Link] qui fournit la configuration de base l'application web. Le fichier [Link] est affich dans l'Exemple 7.18, [Link] du module simplewebapp . Exemple 7.18. [Link] du module simple-webapp
<web-app id="simple-webapp" version="2.4" xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <display-name>Simple Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>
116
classpath:[Link] classpath:[Link] </param-value> </context-param> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/[Link]</param-value> </context-param> <listener> <listener-class> [Link].Log4jConfigListener </listener-class> </listener> <listener> <listener-class> [Link] </listener-class> </listener> <servlet> <servlet-name>weather</servlet-name> <servlet-class> [Link] </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>weather</servlet-name> <url-pattern>*.x</url-pattern> </servlet-mapping> </web-app>
Voici
un
peu
de
magie
qui
nous
permet
la
rutilisation
des
fichiers
[Link] et [Link] dans ce projet. Le contextConfigLocation est utilis par ContextLoaderListener pour crer un ApplicationContext. Quand la servlet weather est cre, le fichier [Link]
de l'Exemple 7.17, Configuration des contrleurs Spring du fichier [Link] value l'ApplicationContext cr partir du contextConfigLocation. Par ce moyen, vous pouvez dfinir un ensemble de beans dans un autre projet et les rfrencer par l'intermdiaire du classpath. Comme les JARs des modules simple-persist et simple-weather seront placs dans WEBINF/lib, tout ce que nous avons faire est d'utiliser le prfixe classpath: pour rfrencer ces fichiers. (Une autre option consisterait copier ces fichiers dans /WEB-INF et de les rfrencer avec quelque chose ressemblant /WEB-INF/[Link]). Le paramtre log4jConfigLocation est utilis par le Log4JConfigListener pour savoir o chercher le fichier de configuration de logging Log4J. Dans cet exemple, nous demandons Log4J de regarder dans le fichier /WEB-INF/[Link].
117
Cela assure que le systme Log4J est configur lors du dmarrage de l'application. Il est important de mettre ce Log4JConfigListener avant le ContextLoaderListener. Dans le cas contraire, vous pourriez manquer d'importants messages indiquant un ventuel problme survenu lors du dmarrage d'application. Si vous avez un ensemble particulirement grand de beans grs par Spring et que l'un d'entre eux n'arrive pas s'initialiser au dmarrage de l'application, votre application ne se lancera pas. Si vous avez initialis votre systme de log avant le dmarrage de Spring, vous aurez la chance de rcuprer une alerte ou un message d'erreur. Au contraire, si vous n'avez pas initialis le systme de log avant le dmarrage de Spring, prparez vous naviguer dans le noir pour comprendre pourquoi votre application refuse de dmarrer. Le ContextLoaderListener est essentiel pour le conteneur Spring. Quand l'application dmarre, ce listener construit un ApplicationContext grce au paramtre contextConfigLocation. Nous dfinissons un DispatcherServlet de Spring MVC nomm weather. Cela forcera Spring regarder dans le fichier /WEB-INF/[Link]. Vous pouvez avoir autant de DispatcherServlet que vous le dsirez, une DispatcherServlet peut contenir un ou plusieurs Controller Spring MVC. Toutes les requtes terminant par .x seront routes vers la servlet weather. Notez que l'extension .x n'a pas de signification particulire, c'est un choix arbitraire, il vous est possible de choisir n'importe quel format pour vos URLs.
L'excution de la commande mvn clean install dans le rpertoire de plus haut niveau de votre projet installera tous ces modules dans votre dpt local. Vous devez faire ceci avant de construire la base de donnes du projet simple-webapp. Pour construire la base de donnes partir du projet simplewebapp, excutez la commande suivante partir du rpertoire du projet simple-webapp :
$ mvn hibernate3:hbm2ddl [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'hibernate3'. [INFO] [Link]: checking for updates from central [INFO] -----------------------------------------------------------------------[INFO] Building Multi-Spring Chapter Simple Web Application [INFO] task-segment: [hibernate3:hbm2ddl] [INFO] -----------------------------------------------------------------------[INFO] Preparing hibernate3:hbm2ddl ... 10:24:56,151 INFO [Link] - export complete [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL
118
[INFO] ------------------------------------------------------------------------
Une fois cela fait, vous devriez avoir un rpertoire ${basedir}/data qui contient la base de donnes HSQLDB. Vous pouvez dmarrer l'application web avec la commande suivante :
$ mvn jetty:run [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'jetty'. [INFO] -----------------------------------------------------------------------[INFO] Building Multi-Spring Chapter Simple Web Application [INFO] task-segment: [jetty:run] [INFO] -----------------------------------------------------------------------[INFO] Preparing jetty:run ... [INFO] [jetty:run] [INFO] Configuring Jetty for project: Multi-Spring Chapter Simple Web Application ... [INFO] Context path = /simple-webapp [INFO] Tmp directory = determined at runtime [INFO] Web defaults = org/mortbay/jetty/webapp/[Link] [INFO] Web overrides = none [INFO] Starting jetty 6.1.7 ... 2008-03-25 10:28:03.639::INFO: jetty-6.1.7 ... 2147 INFO DispatcherServlet - FrameworkServlet 'weather': \ initialization completed in 1654 ms 2008-03-25 10:28:06.341::INFO: Started SelectChannelConnector@[Link]:8080 [INFO] Started Jetty Server
Une fois que Jetty est dmarr, vous pouvez lancer votre navigateur et ouvrir la page [Link] Vous devriez y voir les prvisions mtorologiques d'Evanston (Illinois). Modifiez le code postal pour obtenir votre propre rapport de prvisions.
Current Weather Conditions for: Evanston, IL, US * * * * * Temperature: 42 Condition: Partly Cloudy Humidity: 55 Wind Chill: 34 Date: Tue Mar 25 10:29:45 CDT 2008
119
simple-weather = Dependency
[Link]
weatherService simple-command
[Link]
simple-persist Main
[Link]
weatherDAO locationDAO
Figure 7.4. L'application en ligne de commande rfrence simple-weather et simple-persist Exemple 7.19. POM du module simple-command
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-command</artifactId> <packaging>jar</packaging> <name>Simple Command Line Tool</name> <build> <finalName>${[Link]}</finalName> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>[Link]</groupId>
120
<artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> <plugin> <groupId>[Link]</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.1</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> </component> </components> </configuration> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>[Link]</version> </dependency> </dependencies> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>simple-weather</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>simple-persist</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> <dependency>
121
Ce POM cre un fichier JAR qui contient la classe [Link] prsente dans l'Exemple 7.20, La classe Main du module simple-command . Dans ce POM nous configurons le plugin Maven Assembly pour utiliser le descripteur d'assemblage intgr appel jarwith-dependencies qui cr un JAR contenant tout le bytecode ncessaire au projet pour s'excuter : le bytecode du projet et celui de ses dpendances. Exemple 7.20. La classe Main du module simple-command
package [Link]; import [Link]; import [Link]; import [Link]; import [Link]; import import import import [Link]; [Link]; [Link]; [Link];
public class Main { private WeatherService weatherService; private WeatherDAO weatherDAO; private LocationDAO locationDAO; public static void main(String[] args) throws Exception { // Configuration de Log4J [Link]([Link]().getResource( "[Link]")); // Lecture du code postal partir de la ligne de commande String zipcode = "60202"; try { zipcode = args[0]; } catch (Exception e) { } // Lecture de l'opration partir de la ligne de commande String operation = "weather"; try { operation = args[1]; } catch (Exception e) { }
122
// Dmarrage du programme Main main = new Main(zipcode); ApplicationContext context = new ClassPathXmlApplicationContext( new String[] { "classpath:[Link]", "classpath:[Link]" }); [Link] = (WeatherService) [Link]("weatherService"); [Link] = (LocationDAO) [Link]("locationDAO"); [Link] = (WeatherDAO) [Link]("weatherDAO"); if( [Link]("weather")) { [Link](); } else { [Link](); } } private String zip; public Main(String zip) { [Link] = zip; } public void getWeather() throws Exception { Weather weather = [Link](zip); [Link]( weather ); [Link](new WeatherFormatter().formatWeather(weather)); } public void getHistory() throws Exception { Location location = [Link](zip); List<Weather> weathers = [Link](location); [Link](new WeatherFormatter().formatHistory(location, weathers)); } }
La classe Main possde des rfrences vers WeatherDAO, LocationDAO et WeatherService. La mthode statique main() de cette classe : Lit le code postal pass en premier argument de la ligne de commande Lit l'opration effectuer. Il s'agit du second argument passer la ligne de commande. Si l'opration est "weather", la dernire prvision sera rcupre partir du service web. Si l'opration est "history", le programme rcuprera l'historique des prvisions partir de la base de donnes. Charge l'ApplicationContext Spring en utilisant deux fichiers XML provenant des modules simple-persist et simple-weather Cre une instance de la classe Main Rcupre les proprits weatherService, weatherDAO, et locationDAO partir des beans Spring de l'ApplicationContext
123
Appelle la mthode approprie getWeather() ou getHistory() en fonction de l'opration demande. Dans l'application web, nous utilisions le VelocityViewResolver propos par Spring pour effectuer le rendu d'un template Velocity. Dans l'implmentation en ligne de commande, nous avons besoin d'crire manuellement une classe qui permet d'afficher les donnes mtorologiques partir d'un template Velocity. L'Exemple 7.21, WeatherFormatter affiche les prvisions mto en utilisant un template Velocity affiche la classe WeatherFormatter. Cette classe possde donc deux mthodes qui permettent d'afficher respectivement les prvisions mtorologiques et leur historique. Exemple 7.21. WeatherFormatter affiche les prvisions mto en utilisant un template Velocity
package [Link]; import import import import [Link]; [Link]; [Link]; [Link];
import [Link]; import [Link]; import [Link]; import [Link]; import [Link]; public class WeatherFormatter { private static Logger log = [Link]([Link]); public String formatWeather( Weather weather ) throws Exception { [Link]( "Formatting Weather Data" ); Reader reader = new InputStreamReader( getClass().getClassLoader(). getResourceAsStream("[Link]")); VelocityContext context = new VelocityContext(); [Link]("weather", weather ); StringWriter writer = new StringWriter(); [Link](context, writer, "", reader); return [Link](); } public String formatHistory( Location location, List<Weather> weathers ) throws Exception { [Link]( "Formatting History Data" ); Reader reader = new InputStreamReader( getClass().getClassLoader(). getResourceAsStream("[Link]")); VelocityContext context = new VelocityContext(); [Link]("location", location ); [Link]("weathers", weathers ); StringWriter writer = new StringWriter();
124
Le template [Link] affiche le code postal, la ville, le pays et les prvisions de temprature. Le template [Link] affiche le lieu et itre sur la liste des prvisions stockes dans la base de donnes. Ces deux templates se trouvent dans le dossier ${basedir}/src/main/resources. Exemple 7.22. Le template Velocity [Link]
**************************************** Current Weather Conditions for: ${[Link]}, ${[Link]}, ${[Link]} **************************************** * * * * * Temperature: ${[Link]} Condition: ${[Link]} Humidity: ${[Link]} Wind Chill: ${[Link]} Date: ${[Link]}
#foreach( $weather in $weathers ) **************************************** * Temperature: $[Link] * Condition: $[Link] * Humidity: $[Link] * Wind Chill: $[Link] * Date: $[Link] #end
assembly:assembly
-----------------------------------------------------------------------Building Multi-spring Chapter Simple Command Line Tool task-segment: [assembly:assembly] (aggregator-style) ------------------------------------------------------------------------
125
[INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] ... [INFO] [INFO] [INFO] [INFO] [INFO]
[resources:resources] Using default encoding to copy filtered [compiler:compile] Nothing to compile - all classes are up [resources:testResources] Using default encoding to copy filtered [compiler:testCompile] Nothing to compile - all classes are up [surefire:test]
[jar:jar] Building jar: .../simple-parent/simple-command/target/[Link] [assembly:assembly] Processing DependencySet (output=) Building jar: .../simple-parent/simple-command/target /[Link]
Le build suit le cycle de vie suivant : compilation, excution des tests unitaires et construction du JAR. Le goal assembly:assembly cre un JAR contenant les dpendances. Pour cela, toutes les dpendances sont dzippes dans un rpertoire temporaire, ensuite tout le bytecode est regroup dans un unique JAR cr dans le rpertoire target/ et nomm [Link]. Ce "super" JAR pse 15 MO. Avant d'excuter notre utilitaire partir de la ligne de commande, nous devons appeler le goal hbm2ddl du plugin Hibernate3 pour crer la base de donnes HSQLDB. Pour cela, excutez la commande suivante partir du rpertoire du projet simple-command :
$ mvn hibernate3:hbm2ddl [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'hibernate3'. [INFO] [Link]: checking for updates from central [INFO] -----------------------------------------------------------------------[INFO] Building Multi-spring Chapter Simple Command Line Tool [INFO] task-segment: [hibernate3:hbm2ddl] [INFO] -----------------------------------------------------------------------[INFO] Preparing hibernate3:hbm2ddl ... 10:24:56,151 INFO [Link] - export complete [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------
Une fois cette commande excute, vous devriez voir apparatre un rpertoire data/ dans le dossier simple-command. Ce rpertoire data/ contient la base de donnes HSQLDB. Pour excuter l'outil de prvisions en ligne de commande, lancez la commande suivante partir du rpertoire du projet simplecommand :
$ java -cp target/[Link] \
[Link] 60202
2321 INFO 2489 INFO YahooRetriever - Retrieving Weather Data YahooParser - Creating XML Reader
126
2581 INFO YahooParser - Parsing XML Response 2875 INFO WeatherFormatter - Formatting Weather Data **************************************** Current Weather Conditions for: Evanston, IL, US **************************************** * * * * * Temperature: 75 Condition: Partly Cloudy Humidity: 64 Wind Chill: 75 Date: Wed Aug 06 09:35:30 CDT 2008
**************************************** * Temperature: 39 * Condition: Heavy Rain * Humidity: 93 * Wind Chill: 36 * Date: 2007-12-02 13:45:27.187 **************************************** * Temperature: 75 * Condition: Partly Cloudy * Humidity: 64 * Wind Chill: 75 * Date: 2008-08-06 09:24:11.725 **************************************** * Temperature: 75 * Condition: Partly Cloudy * Humidity: 64 * Wind Chill: 75 * Date: 2008-08-06 09:27:28.475
7.10. Conclusion
Nous avons pass beaucoup de temps sur des sujets ne se rapportant pas directement Maven pour parcourir tout ce chemin. Nous l'avons fait pour prsenter un projet exemple aussi complet et significatif que possible pour que vous puissiez l'utiliser pour raliser de vritables systmes. Pour arriver ce rsultat, nous n'avons pas eu besoin de prendre de raccourcis, ni de vous merveiller avec des tours de magie la Ruby on Rails, ni de vous laisser croire qu'on peut crer une application Java d'entreprise en "10 minutes ! ". Trop de monde essayent de vous vendre le framework rvolutionnaire qui vous demanderait zro temps d'apprentissage. Ce que nous avons essay de faire dans ce chapitre est de
127
prsenter le tableau dans son intgralit, l'cosystme complet d'un build multimodule. Nous vous avons prsent Maven dans le contexte d'une application qui ressemble ce que vous pourriez voir dans la vraie vie, et non 10 minutes de vido roulant Apache Ant dans la boue et essayant de vous donner envie d'adopter Apache Maven. Si vous terminez ce chapitre en vous demandant en quoi il traite de Maven, notre mission est russie. Nous avons prsent un ensemble complexe de projets en utilisant des frameworks populaires que nous avons assembls par des build dclaratifs. Le fait que plus de 60% de ce chapitre ait t consacr au fonctionnement de Spring et Hibernate doit montrer que Maven, pour sa plus grosse partie, n'est pas l'tape la plus complique d'un projet. Il nous a permis de nous concentrer sur l'application elle-mme, et non sur le processus de build. Au lieu de passer du temps discuter du fonctionnement de Maven et le travail que vous devriez faire pour construire un projet qui intgre Spring et Hibernate, nous avons parl presque exclusivement des technologies utilises. Si vous commencez utiliser Maven et que vous prenez du temps pour l'apprendre, vous commencez vraiment profiter du fait que vous ne devez pas passer votre temps crire vos scripts de build. Vous ne devez pas perdre votre temps vous inquiter des aspects classiques de votre build. Vous pouvez utiliser le squelette du projet de ce chapitre comme fondation pour votre propre projet. Fondation laquelle vous ajouterez des modules au fur et mesure de vos besoins. Par exemple, le vritable projet dont ce chapitre est tir comporte deux projets modles, deux modules de persistance qui permettent de stocker des objets dans diffrents type de base de donnes, plusieurs applications web et une application Java mobile. Au total, le systme du monde rel duquel j'ai tir cet exemple contient au moins 15 modules interdpendants. Vous avez vu l'exemple de projet multimodule le plus complet que nous allons prsenter dans ce livre, notez cependant que cet exemple se contente d'aborder qu'une infime partie de ce qu'il est possible de faire avec Maven.
128
[Link] big-parent
[Link] weather-model
[Link] persist-xmldb
[Link] persist-jdbc
[Link] parse-noaa
[Link] parse-yahoo
Figure 7.5. Programmation avec des projets API Quand nous utilisons le terme projet API, nous faisons allusion un projet Maven qui contient uniquement des interfaces et des constantes. Sur la Figure 7.5, Programmation avec des projets API , deux des projets sont des projets API : persist-api et parse-api. Si les projets bigcommand et big-webapp utilisent les interfaces dfinies dans persist-api, il sera facile de changer d'implmentations et de framework de persistance. Ce diagramme en particulier montre deux implmentations du projet persist-api : une qui stocke ses donnes dans une base de donnes XML et l'autre qui stocke ses donnes dans une base de donnes relationnelle. Si vous dcidez de mettre en place certains des concepts de ce chapitre, vous pourriez rflchir comment passer un signal au programme pour permettre de changer d'ApplicationContext Spring et changer ainsi de base de donnes la vole. Comme pour la conception OO de l'application elle-mme, il est souvent prudent de sparer les interfaces d'une API de leurs implmentations en utilisant des projets Maven spars.
129
ce chapitre, nous prenons du recul pour tudier ce qu'il nous reste aprs l'exemple du Chapitre 7, Un projet multimodule d'entreprise.
132
exclusions vous rapproche du moment o un build chouera. Au fur et mesure que la complexit de vos projets Maven augmente, la liste de vos dpendances s'allonge et vous allez donc devoir stabiliser les dclarations de dpendance et de version dans des POMs parent. La duplication des versions des modules frres peut produire un problme assez redoutable qui ne rsulte pas directement de Maven, et dont on ne se souvient qu'aprs l'avoir rencontr plusieurs fois. Si vous utilisez le plugin Maven Release pour effectuer vos livraisons, toutes les versions de dpendance soeurs seront automatiquement mises jour pour vous, aussi ce n'est pas l que rside le problme. Si simple-web version 1.3-SNAPSHOT dpend de simple-persist version 1.3-SNAPSHOT, et si vous produisez la version 1.3 de ces deux projets, le plugin Maven Release est suffisamment intelligent pour changer les versions dans les POMs de votre projet multimodule automatiquement. Produire la livraison avec le plugin Release va automatiquement incrmenter les versions de votre build 1.4SNAPSHOT, et le plugin Release va commiter ces modifications sur le dpt de source. Livrer un norme projet multimodule ne pourrait tre plus facile, moins que... Les problmes arrivent lorsque les dveloppeurs fusionnent les modifications du POM et perturbent une livraison en cours. Un dveloppeur fusionne souvent des modifications et parfois il se trompe lors de la gestion du conflit sur la dpendance sur un module frre, revenant par inadvertance la version de la livraison prcdente. Comme les versions conscutives d'une dpendance sont souvent compatibles, cela n'apparat pas lorsque le dveloppeur lance le build, ni avec un systme d'intgration continue. Imaginez un build trs complexe o le tronc est rempli de composants la version 1.4-SNAPSHOT, et maintenant imaginez que le Dveloppeur A a mis jour le Composant A tout au fond de la hirarchie du projet pour qu'il dpende de la version 1.3-SNAPSHOT du Composant B. Mme si la plupart des dveloppeurs utilisent la version 1.4-SNAPSHOT, le build fonctionne correctement si les versions 1.3-SNAPSHOT et 1.4-SNAPSHOT du Composant B sont compatibles. Maven continuera construire le projet en utilisant la version 1.3-SNAPSHOT du Composant B depuis le dpt local des dveloppeurs. Tout semble bien se passer le projet est construit, l'intgration continue est au vert, etc. Quelqu'un peut alors rencontrer un bug trange en rapport avec le Composant B, mais il va se dire que c'est la faute "pas de chance" et va poursuivre son dveloppement. Pendant ce temps, dans la salle des machines la pression monte, jusqu' ce qu'une des pices explose ... Quelqu'un, appelons le Mr. Distrait, a rencontr un conflit lors de la fusion du Composant A, et a malencontreusement indiqu que le Composant A dpend de la version 1.3-SNAPSHOT du Composant B alors que le projet continuait sa marche en avant. Une quipe de dveloppeurs essaye de corriger un bug dans le Composant B depuis tout ce temps et ils ne comprennent pas pourquoi ils n'arrivent pas le corriger en production. Finalement, quelqu'un regarde le Composant A et s'aperoit de cette dpendance sur une mauvaise version. Heureusement, ce bug n'tait pas suffisamment important pour coter de l'argent ou des vies, mais Monsieur Distrait se sent un peu bte et les autres ont perdu un peu de leur confiance en lui pour ce problme de dpendances entre composants. (Heureusement, Monsieur Distrait se rend compte que ce problme est une erreur d'utilisateur et ne vient pas de Maven, mais il est plus que probable qu'il commence un vilain blog dans lequel il se plaint de Maven sans arrt pour se sentir mieux.)
133
Heureusement, la duplication de dpendance et les erreurs de dpendance entre projets frres peuvent tre facilement vites avec quelques modifications. La premire chose faire est de trouver toutes les dpendances utilises sur plus d'un projet et de les dplacer dans la section dependencyManagement du POM parent. Nous allons laisser de ct les dpendances entre modules frres pour l'instant. Le pom simple-parent contient maintenant :
<project> ... <dependencyManagement> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-annotations</artifactId> <version>[Link]</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>[Link]</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate</artifactId> <version>[Link]</version> <exclusions> <exclusion> <groupId>[Link]</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </dependencyManagement> ... </project>
Une fois ces dpendances remontes, nous allons devoir supprimer les versions de ces dpendances de tous les POMs ; sinon, elles vont surcharger ce qui est dfini dans la balise dependencyManagement du projet parent. Regardons juste le simple-model pour plus de clart :
<project> ...
134
<dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-annotations</artifactId> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate</artifactId> </dependency> </dependencies> ... </project>
La seconde chose faire est de corriger la duplication des versions de hibernate-annotations et hibernate-commons-annotations puisqu'elles devraient rester identiques. Nous allons faire cela en crant une proprit appele [Link]. La section simple-parent rsultante ressemble ceci :
<project> ... <properties> <[Link]>[Link]</[Link]> </properties> <dependencyManagement> ... <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-annotations</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>${[Link]}</version> </dependency> ... </dependencyManagement> ... </project
Notre dernier problme corriger est celui des dpendances entre modules frres. Une technique que nous pourrions utiliser est de les dplacer dans la section dependencyManagement, comme toutes les autres, et de dfinir les versions des projets frres dans le projet parent qui les contient. Cette approche est certainement valide, mais nous pouvons aussi rsoudre ce problme de version en utilisant deux proprits prdfinies ${[Link]} et ${[Link]}. Puisqu'il s'agit de dpendances entre frres, il n'y a pas grand-chose gagner les lister dans le parent, aussi nous allons faire confiance la proprit prdfinie ${[Link]}. Comme ces projets font tous partie du mme groupe, nous pouvons scuriser d'avantage ces dclarations en faisant rfrence au groupe du
135
POM courant via la proprit prdfinie ${[Link]}. La section dependency de simplecommand ressemble maintenant cela :
<project> ... <dependencies> ... <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-weather</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-persist</artifactId> <version>${[Link]}</version> </dependency> ... </dependencies> ... </project>
Voici un rsum des deux optimisations que nous avons ralises pour rduire ce problme de duplication des dpendances : Remonter les dpendances communes dans dependencyManagement Si plus d'un projet dpend d'une dpendance particulire, vous pouvez ajouter celle-ci dependencyManagement. Le POM parent peut contenir une version et un ensemble d'exclusions ; tout ce que les POMs fils ont besoin de faire pour rfrencer cette dpendance est d'utiliser le groupId et l'artifactId. Les projets fils peuvent ne pas dclarer la version et les exclusions si la dpendance fait partie des dpendances de la balise dependencyManagement. Utiliser la version et le groupId pr-dfinis pour les projets frres Utiliser ${[Link]} et ${[Link]} pour faire rfrence un projet frre. Les projets frres ont la plupart du temps le mme groupId, et presque toujours la mme version. Utiliser ${[Link]} vous aidera viter les incohrences de versions entre projets frres comme nous l'avons vu plus tt.
136
Remonter la version de HSQLDB dans une proprit du POM de plus haut niveau se fait au travers de la balise XML properties :
<project> ... <properties> <[Link]>[Link]</[Link]> <[Link]>[Link]</[Link]> </properties> ... </project>
Nous pouvons noter que la configuration de hibernate3-maven-plugin est duplique dans les modules simple-webapp et simple-command. Il est possible de grer la configuration des plugins dans le POM de plus haut niveau de la mme manire que pour la gestion des dpendances avec la section dependencyManagement de ce POM. Pour ce faire, nous allons utiliser la balise XML pluginManagement sous la balise XML build du POM de plus haut niveau :
<project> ... <build> <pluginManagement> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>[Link]</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.1</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> </component> </components> </configuration> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>${[Link]}</version> </dependency> </dependencies> </plugin> </plugins> </pluginManagement>
137
dependency:analyze
Scanning for projects... Reactor build order: Chapter 8 Simple Parent Project Chapter 8 Simple Object Model Chapter 8 Simple Weather API Chapter 8 Simple Persistence API Chapter 8 Simple Command Line Tool Chapter 8 Simple Web Application Chapter 8 Parent Project Searching repository for plugin with prefix: 'dependency'.
138
[INFO] Nothing to compile - all classes are up to date [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:testCompile] [INFO] Nothing to compile - all classes are up to date [INFO] [dependency:analyze] [WARNING] Used undeclared dependencies found: [WARNING] [Link]:persistence-api:jar:1.0:compile [WARNING] Unused declared dependencies found: [WARNING] [Link]:hibernate-annotations:jar:[Link]:compile [WARNING] [Link]:hibernate:jar:[Link]:compile [WARNING] junit:junit:jar:3.8.1:test ... [INFO] -----------------------------------------------------------------------[INFO] Building Chapter 8 Simple Web Application [INFO] task-segment: [dependency:analyze] [INFO] -----------------------------------------------------------------------[INFO] Preparing dependency:analyze [INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:compile] [INFO] Nothing to compile - all classes are up to date [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:testCompile] [INFO] No sources to compile [INFO] [dependency:analyze] [WARNING] Used undeclared dependencies found: [WARNING] [Link]:simple-model:jar:1.0:compile [WARNING] Unused declared dependencies found: [WARNING] [Link]:velocity:jar:1.5:compile [WARNING] [Link]:jstl:jar:1.1.2:compile [WARNING] taglibs:standard:jar:1.1.2:compile [WARNING] junit:junit:jar:3.8.1:test
Dans ces traces tronques vous pouvez voir le rsultat du goal dependency:analyze. Ce goal analyse le projet pour voir s'il existe des dpendances indirectes, ou si on fait rfrence des dpendances qui ne sont pas dclares directement. Dans le projet simple-model, le plugin Dependency indique une dpendance utilise mais pas dclare sur [Link]:persistence-api. Pour obtenir plus d'informations, allez dans le rpertoire simple-model et excutez le goal dependency:tree qui va lister toutes les dpendances du projet, directes et transitives.
$ mvn [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO]
dependency:tree
Scanning for projects... Searching repository for plugin with prefix: 'dependency'. -----------------------------------------------------------------------Building Chapter 8 Simple Object Model task-segment: [dependency:tree] -----------------------------------------------------------------------[dependency:tree] [Link]:simple-model:jar:1.0
139
[INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO]
+- [Link]:hibernate-annotations:jar:[Link]:compile | \- [Link]:persistence-api:jar:1.0:compile +- [Link]:hibernate:jar:[Link]:compile | +- [Link]:ehcache:jar:1.2.3:compile | +- commons-logging:commons-logging:jar:1.0.4:compile | +- asm:asm-attrs:jar:1.5.3:compile | +- dom4j:dom4j:jar:1.6.1:compile | +- antlr:antlr:jar:2.7.6:compile | +- cglib:cglib:jar:2.1_3:compile | +- asm:asm:jar:1.5.3:compile | \- commons-collections:commons-collections:jar:2.1.1:compile \- junit:junit:jar:3.8.1:test -----------------------------------------------------------------------BUILD SUCCESSFUL ------------------------------------------------------------------------
Dans cette trace, nous pouvons voir que la dpendance persistence-api est apporte par hibernate. Une analyse rapide du code source de ce module va trouver de nombreux imports de [Link] ce qui confirme que nous faisons directement rfrence cette dpendance. La correction la plus simple est d'ajouter une rfrence directe cette dpendance. Dans cet exemple, nous indiquons la version de la dpendance dans la section dependencyManagement de simple-parent car cette dpendance est lie Hibernate et c'est l qu'on dclare la version d'Hibernate. Un jour va arriver o vous allez vouloir changer la version d'Hibernate pour votre projet. Mettre la version de persistence-api ct de la version d'Hibernate permettra d'viter d'oublier de la mettre jour lorsque vous diterez le POM parent pour modifier la version d'Hibernate. Si vous regardez le rsultat du dependency:analyze pour le module simple-web, vous verrez qu'il faut aussi ajouter une rfrence directe simple-model. Le code de simple-webapp fait directement rfrence aux objets mtier de simple-model, et simple-model est visible dans simple-webapp en tant que dpendance transitive via simple-persist. Puisqu'il s'agit d'une dpendance vers un module frre qui partage la mme version et le mme groupId, la dpendance peut tre dclare dans le [Link] de simple-webapp avec ${[Link]} et ${[Link]}. Comment fait le plugin Maven Dependency pour trouver ces problmes ? Comment dependency:analyze sait-il quelles classes et quelles dpendances le bytecode de votre projet fait rfrence ? Le plugin Dependency utilise l'outil ASM d'ObjectWeb ([Link] pour analyser le bytecode brut. Le plugin Dependency utilise ASM pour parcourir toutes les classes du projet, et lister toutes les classes rfrences qui n'en font pas partie. Ensuite, il parcourt toutes les dpendances directes et transitives, et marque les classes trouves dans les dpendances directes. Toute classe qui n'a pas t trouve dans les dpendances directes, est recherche dans les dpendances transitives et ainsi il gnre la liste des dpendances utilises, mais non dclares. Par contre, la liste des dpendances dclares mais non utilises est un peu plus dlicate valider et bien moins utile que les dpendances utilises mais non dclares. Premirement, car certaines dpendances ne sont utilises qu' l'excution ou que pour les tests, et donc ne seront pas rfrences dans le bytecode. Celles-ci sont assez faciles voir dans les traces ; par exemple, JUnit apparat dans cette liste comme on pouvait s'y attendre car elle n'est utilise que pour les tests unitaires. Vous remarquerez
140
aussi les dpendances vers Velocity et l'API Servlet pour le module simple-web. L encore, on pouvait s'y attendre, car le projet n'a aucune rfrence directe aux classes de ces artefacts, mme s'ils restent essentiels durant l'excution. Soyez prudents lorsque vous supprimez une dpendance dclare mais inutilise, moins que vous n'ayez une trs bonne couverture de tests, vous risquez d'avoir des surprises pendant l'excution. Un problme beaucoup plus dangereux peut apparatre avec l'optimisation du bytecode. Par exemple, le compilateur a le droit de substituer la valeur d'une constante et d'optimiser en supprimant la rfrence. Supprimer cette dpendance va empcher la compilation, alors que l'outil indique qu'elle n'est pas utilise. Les versions futures du plugin Maven Dependency fourniront de meilleures techniques pour dtecter ou ignorer ces problmes. Vous devriez utiliser dependency:analyze rgulirement pour dtecter ces erreurs classiques dans vos projets. On peut configurer le build pour qu'il choue si ce plugin rencontre certaines conditions, et il peut aussi produire un rapport.
141
<artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>[Link]</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.1</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> </component> </components> </configuration> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>${[Link]}</version> </dependency> </dependencies> </plugin> </plugins> </pluginManagement> </build> <properties> <[Link]>[Link]</[Link]> <[Link]>[Link]</[Link]> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>[Link]</groupId>
142
<artifactId>hibernate-annotations</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate</artifactId> <version>[Link]</version> <exclusions> <exclusion> <groupId>[Link]</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
Le POM prsent dans l'Exemple 8.2, POM final de simple-command correspond au POM pour simple-command, la version utilisable en ligne de commande de l'outil. Exemple 8.2. POM final de simple-command
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-command</artifactId> <packaging>jar</packaging> <name>Chapter 8 Simple Command Line Tool</name> <build>
143
<pluginManagement> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>[Link]</mainClass> <addClasspath>true</addClasspath> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>[Link]</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </pluginManagement> </build> <dependencies> <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-weather</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-persist</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>spring</artifactId> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>velocity</artifactId> </dependency> </dependencies>
144
</project>
Le POM prsent dans l'Exemple 8.3, POM final de simple-model correspond au POM du projet simple-model. Le projet simple-model contient les objets mtiers utiliss tout au long de l'application. Exemple 8.3. POM final de simple-model
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-model</artifactId> <packaging>jar</packaging> <name>Chapter 8 Simple Object Model</name> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-annotations</artifactId> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate</artifactId> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>persistence-api</artifactId> </dependency> </dependencies> </project>
Le POM prsent dans l'Exemple 8.4, POM final de simple-persist correspond au POM du projet simple-persist. Le projet simple-persist contient toute la logique de persistance qui est mise en uvre avec Hibernate. Exemple 8.4. POM final de simple-persist
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId>
145
<version>1.0</version> </parent> <artifactId>simple-persist</artifactId> <packaging>jar</packaging> <name>Chapter 8 Simple Persistence API</name> <dependencies> <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-model</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate</artifactId> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-annotations</artifactId> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate-commons-annotations</artifactId> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>spring</artifactId> </dependency> </dependencies> </project>
Le POM prsent dans l'Exemple 8.5, POM final de simple-weather correspond au POM du projet simple-weather. Le projet simple-weather est le projet qui contient toute la logique pour parser le flux RSS de Yahoo! Mto. Ce projet dpend du projet simple-model. Exemple 8.5. POM final de simple-weather
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version>
146
</parent> <artifactId>simple-weather</artifactId> <packaging>jar</packaging> <name>Chapter 8 Simple Weather API</name> <dependencies> <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-model</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> <scope>test</scope> </dependency> </dependencies> </project>
Enfin, le POM prsent dans l'Exemple 8.6, POM final de simple-webapp correspond au POM du projet simple-webapp. Le projet simple-webapp contient une application web qui enregistre les prvisions mto obtenues dans une base de donnes HSQLDB et interagit avec les bibliothques produites par le projet simple-weather. Exemple 8.6. POM final de simple-webapp
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <parent> <groupId>[Link]</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent>
147
<artifactId>simple-webapp</artifactId> <packaging>war</packaging> <name>Chapter 8 Simple Web Application</name> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-model</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-weather</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>${[Link]}</groupId> <artifactId>simple-persist</artifactId> <version>${[Link]}</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>spring</artifactId> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>jstl</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>velocity</artifactId> </dependency> </dependencies> <build> <finalName>simple-webapp</finalName> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.9</version> <dependencies>
148
<dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>${[Link]}</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>
8.7. Conclusion
Ce chapitre vous a prsent plusieurs techniques pour amliorer votre matrise de vos dpendances et de vos plugins afin de faciliter la maintenance de vos builds. Nous vous recommandons de revoir priodiquement vos builds afin de vrifier que les duplications et donc les risques potentiels soient minimiss. Au cours de la vie d'un projet, il est invitable que de nouvelles dpendances soient ajoutes. Vous pouvez vous retrouver dans une situation o une dpendance qui autrefois n'tait utilise qu' un seul endroit l'est maintenant en plus de 10, celle-ci devant donc tre remonte. Les listes des dpendances utilises ou inutilises changent dans le temps et elles peuvent tre nettoyes facilement avec le plugin Maven Dependency.
149
9.2. Le POM
Les projets Maven, les dpendances, les builds, les artefacts : tous sont des objets qu'il va falloir modliser et dcrire. Ces objets sont dcrits dans un fichier XML appel Modle Objet de Projet. Le POM indique Maven quel type de projet il va devoir traiter et comment il va devoir s'adapter pour transformer les sources et produire le rsultat attendu. Ainsi, comme le fichier [Link] dcrit, configure et personnalise une application web Java, c'est la prsence d'un fichier [Link] qui dfinit un projet Maven. Il s'agit d'une dclaration dcrivant un projet Maven; c'est le plan abstrait que Maven doit comprendre et suivre pour construire votre projet. Vous pouvez aussi voir dans ce fichier [Link] un quivalent un fichier Makefile ou un fichier [Link] pour Ant. Quand vous utilisez GNU make pour construire une application comme par exemple MySQL, vous aurez le plus souvent un fichier Makefile contenant toutes les instructions explicites pour produire un binaire partir des sources. Quand vous utilisez Apache Ant, vous avez trs probablement un fichier [Link] qui contient les instructions explicites pour nettoyer, compiler, packager et dployer une application. make, Ant, et Maven ont en commun le fait qu'il leur faut un fichier avec un nom pr-dtermin, qu'il s'agisse de Makefile, [Link], ou [Link], mais c'est l que les similarits s'arrtent. Si vous regardez un [Link] Maven, la plus grande partie du POM se compose de descriptions. O se trouve le code source ? O sont les ressources ? Quel est le packaging ? Si vous regardez un fichier [Link] pour Ant, vous verrez quelque chose d'entirement diffrent. Vous verrez des instructions explicites pour des tches comme la compilation de classes Java. Le POM Maven est dclaratif, et mme si vous pouvez y inclure des personnalisations procdurales via le plugin Maven Ant, en gnral vous n'aurez pas besoin de vous plonger dans les dlicats dtails procduraux de la construction de votre projet. Le POM n'est pas spcifique la construction de projets Java. Mme si la plupart des exemples de ce livre sont des applications Java, il n'y a rien de spcifique Java dans la dfinition d'un Modle Objet de Projet Maven. Si effectivement les plugins par dfaut de Maven permettent de construire des artefacts sous forme de JAR partir d'un ensemble de sources, de tests et de ressources, rien ne vous empche de dfinir un POM pour un projet qui contient des sources C# et produit un binaire Microsoft propritaire avec des outils Microsoft. De mme, rien ne vous empche d'utiliser un POM pour un livre technique. En effet, le source de ce livre et ses exemples sont rpartis dans un projet Maven multimodule qui utilise l'un des nombreux plugins Maven pour Docbook afin d'appliquer une feuille XSL Docbook standard
un ensemble de chapitres prsents sous la forme de fichiers XML. Certains ont cr des plugins Maven pour transformer du code Adobe Flex en SWCs et SWFs ; d'autres utilisent Maven pour construire des projets crits en C. Nous avons donc tabli que le POM dcrit et dclare, et qu'il se diffrencie de Ant ou de Make en ne fournissant pas d'instructions explicites. Nous avons vu que les concepts du POM ne sont pas propres Java. Regardons tout cela plus en dtail au travers de la Figure 9.1, Le Modle Objet de Projet pour une analyse du contenu d'un POM.
POM POM Relationships Coordinate groupId artifactId version Multi-Module Inheritance Dependencies General Project Information General Contributors Licenses Proles directories extensions resources plugins reporting Build Environment Environment Information Maven Environment Build Settings build
Figure 9.1. Le Modle Objet de Projet Le POM se compose de quatre catgories de description et de configuration : Informations gnrales sur le projet Cette catgorie regroupe le nom l'URL et la licence du projet, l'organisation qui produit ce projet, et une liste de dveloppeurs et de contributeurs. Configuration du build Dans cette section, nous configurons le build Maven en personnalisant le comportement par dfaut. Nous pouvons changer l'endroit o se trouvent les sources et les tests, ajouter de nouveaux plugins, lier des goals de plugins au cycle de vie et personnaliser les paramtres de gnration du site web.
154
Environnement du build L'environnement du build consiste en un ensemble de profils qui peuvent tre activs pour tre utiliss dans diffrents environnements. Par exemple, au cours du dveloppement vous pouvez vouloir dployer sur un serveur qui sera diffrent de celui sur lequel vous dploierez en production. L'environnement de build adapte la configuration du build pour un environnement spcifique et il s'accompagne souvent d'un fichier [Link] personnalis dans le rpertoire ~/.m2. Ce fichier [Link] est dtaill dans le Chapitre 11, Profils de Build et dans la Section A.2, Dtails des settings . Relations entre POM Un projet est rarement isol. Il dpend souvent d'autres projets, hrite d'une configuration de POM de projets parent, dfinit ses propres coordonnes, et peut comporter des sous-modules.
155
<updatePolicy>never</updatePolicy> </releases> </pluginRepository> </pluginRepositories> <build> <directory>target</directory> <outputDirectory>target/classes</outputDirectory> <finalName>${[Link]}-${[Link]}</finalName> <testOutputDirectory>target/test-classes</testOutputDirectory> <sourceDirectory>src/main/java</sourceDirectory> <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory> <testSourceDirectory>src/test/java</testSourceDirectory> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> <testResources> <testResource> <directory>src/test/resources</directory> </testResource> </testResources> </build> <pluginManagement> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.1</version> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-1</version> </plugin> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>2.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> </plugin> <plugin> <artifactId>maven-dependency-plugin</artifactId> <version>2.0</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.3</version> </plugin> <plugin> <artifactId>maven-ear-plugin</artifactId> <version>2.3.1</version> </plugin>
156
<plugin> <artifactId>maven-ejb-plugin</artifactId> <version>2.1</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.2</version> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <version>2.2</version> </plugin> <plugin> <artifactId>maven-javadoc-plugin</artifactId> <version>2.4</version> </plugin> <plugin> <artifactId>maven-plugin-plugin</artifactId> <version>2.3</version> </plugin> <plugin> <artifactId>maven-rar-plugin</artifactId> <version>2.2</version> </plugin> <plugin> <artifactId>maven-release-plugin</artifactId> <version>2.0-beta-7</version> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>2.2</version> </plugin> <plugin> <artifactId>maven-site-plugin</artifactId> <version>2.0-beta-6</version> </plugin> <plugin> <artifactId>maven-source-plugin</artifactId> <version>2.0.4</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.4.2</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1-alpha-1</version> </plugin> </plugins> </pluginManagement> <reporting> <outputDirectory>target/site</outputDirectory> </reporting>
157
</project>
Le Super POM dfinit des variables de configuration standards qui seront hrites par tous les projets. Les valeurs de ces variables sont dfinies dans les sections numrotes : Le Super POM par dfaut dclare un unique dpt Maven distant ayant pour ID central. C'est ce dpt central de Maven qui est configur par dfaut dans toutes les installations de Maven pour tre interrog. Cette configuration peut tre surcharge par un fichier [Link] personnalis. Attention, le Super POM par dfaut a dsactiv la rcupration des artefacts snapshots depuis le dpt central de Maven. Si vous avez besoin d'un dpt snapshot, vous devrez configurer vos dpts dans votre fichier [Link] ou votre fichier [Link]. Le fichier [Link] et les profils sont traits dans le Chapitre 11, Profils de Build ainsi que dans Section A.2, Dtails des settings . Le dpt central de Maven contient aussi des plugins Maven. Le dpt de plugins est par dfaut le dpt central de Maven. La rcupration des snapshots est dsactive par dfaut et la rgle de gestion des mises jour indique "never", ce qui signifie que Maven ne met jamais automatiquement jour un plugin si une nouvelle version est publie. L'lment build dfinit les positions par dfaut des rpertoires selon la disposition Maven standard des rpertoires. Depuis la version 2.0.9 de Maven les versions par dfaut des plugins du cur sont dfinies dans le Super POM. Cela a t mis en place pour apporter une certaine stabilit aux utilisateurs qui ne prcisent pas de version dans leurs POMs.
Super POM
= Inherits from
Figure 9.2. Le Super POM est toujours le parent de plus haut niveau
158
fichiers source se trouvant dans src/main/java dont les tests JUnit excuter sont dans src/test/ java et que vous voulez produire le site web de ce projet avec la commande mvn site, vous n'avez rien configurer. Vous n'avez besoin, dans ce cas, que du POM le plus simple possible, tel celui prsent dans l'Exemple 9.2, Le POM le plus simple possible . Ce POM dfinit un groupId, un artifactId et une version : les trois coordonnes exiges pour tout projet. Exemple 9.2. Le POM le plus simple possible
<project> <modelVersion>4.0.0</modelVersion> <groupId>[Link].ch08</groupId> <artifactId>simplest-project</artifactId> <version>1</version> </project>
Un POM aussi simple serait plus qu'adquat pour un projet trs simple par exemple, une bibliothque Java qui produirait un fichier JAR. Ce POM ne fait aucune rfrence un autre projet, ne dpend de rien et il lui manque des informations basiques comme son nom et une URL. Si vous criez un tel fichier et un sous-rpertoire src/main/java contenant du code source, l'excution de la commande mvn package produirait le JAR target/[Link].
L'excution du goal effective-pom devrait afficher un document XML rsultant de la fusion du Super POM et du POM de l'Exemple 9.2, Le POM le plus simple possible .
159
l'importance la possibilit de lister les dveloppeurs et les contributeurs, de pouvoir produire une documentation claire pour un projet et de pouvoir grer automatiquement les livraisons grce au plugin Maven Release. Par contre, pour quelqu'un qui travaille dans le contexte d'une petite quipe au sein d'une entreprise, les capacits de Maven pour grer les distributions ou lister les dveloppeurs peuvent avoir un moindre intrt. La suite de ce chapitre va traiter les caractristiques du POM en lui-mme. Au lieu de vous bombarder avec un listing de 10 pages contenant tout un ensemble de POMs , nous allons nous concentrer sur la cration d'une bonne rfrence pour chacune des sections spcifiques du POM. Dans ce chapitre, nous allons parler des relations entre les POMs mais sans ajouter un nouvel exemple pour l'illustrer. Si vous voulez un tel exemple, vous le trouverez dans le Chapitre 7, Un projet multimodule d'entreprise.
Par exemple, la version "1.3.5" correspond la version majeure 1, mineure 3 et incrmentale 5. La version "5" correspond la version majeure 5 sans version mineure ou incrmentale. Le qualifieur est utilis pour les builds des tapes intermdiaires : distributions alpha ou beta, et il est spar des autres lments de version par un tiret. Par exemple, la version "1.3-beta-01" a une version majeure 1, mineure 3 et un qualifieur "beta-01". Suivre ces prconisations pour les numros de version prend tout son sens lorsque vous commencez utiliser des intervalles pour vos versions dans les POMs. Les intervalles de versions seront abords dans la Section 9.4.3, Intervalle de versions pour une dpendance . Ils permettent de spcifier une dpendance dont la version est comprise dans cet intervalle. Cela n'est possible que parce que Maven est capable de trier les versions en se basant sur le format de numro de version dont nous venons de parler. Si votre numro de version respecte le format <majeure>.<mineure>.<incrmentale><qualifieur> alors vos versions seront correctement ordonnes, "1.2.3" sera donc bien considre comme plus rcente que "1.0.2". La comparaison se fera en utilisant les valeurs numriques des versions majeure, mineure et incrmentale. Si votre numro de version ne respecte pas ce standard, alors vos versions seront compares comme des chanes de caractres ; la chane "1.0.1b" sera compare la chane "1.2.0b".
160
[Link]. Numro de version de build Un des problmes avec les numros de version est l'ordonnancement des qualifieurs. Prenez par exemple, les numros de version 1.2.3-alpha-2 et 1.2.3-alpha-10 o alpha-2 correspond au second build alpha et alpha-10 au dixime build alpha. Alors que le build alpha-10 devrait tre considr comme plus rcent que le build alpha-2, Maven va mettre alpha-10 avant alpha-2. Ceci est d un problme connu dans la faon dont Maven traite les numros de version. Maven doit, en thorie, considrer le nombre aprs le qualifieur comme le numro du build. En d'autres termes, le qualifieur devrait tre "alpha", et le numro du build 2. Mme si Maven a t conu pour sparer le numro du build du qualifieur, cette fonctionnalit ne fonctionne pas actuellement. En consquence, "alpha-2" et "alpha-10" sont compars comme des chanes de caractres, ce qui positionne "alpha-10" avant "alpha-2" alphabtiquement. Pour contourner cette limitation, vous devez complter gauche vos numros de version de build qualifis. Si vous utilisez "alpha-02" et "alpha-10" vous n'aurez plus ce problme, et tout continuera bien fonctionner le jour o Maven traitera correctement les numros de version de build. [Link]. Les versions SNAPSHOT Les numros de versions dans Maven peuvent contenir une chane de caractres pour indiquer que le projet est en cours de dveloppement. Si une version contient la chane SNAPSHOT, alors Maven va prendre en compte cette clef et la convertir en une valeur de type date et heure au format UTC (Coordinated Universal Time) quand vous installerez ou publierez ce composant. Par exemple, si votre projet est en version 1.0-SNAPSHOT et que vous dployez ses artefacts sur un dpt Maven, Maven va alors convertir cette version en 1.0-20080207-230803-1 si vous ralisez votre dploiement le 7 Fvrier 2008 23:08 UTC. En d'autres termes, quand vous dployez un snapshot, vous ne livrez pas un composant logiciel ; vous livrez un instantan d'un composant. Pourquoi utiliser cette fonctionnalit ? Les versions SNAPSHOT sont utilises pour les projets en cours de dveloppement. Si votre projet dpend d'un composant logiciel en cours de dveloppement, vous pouvez dpendre d'une version SNAPSHOT, Maven essayera alors de tlcharger priodiquement la dernire version snapshot du dpt lorsque vous lancerez votre build. De mme, si la prochaine livraison de votre systme est la version "1.4", tant que votre projet n'est pas livr dfinitivement, il devrait tre en version "1.4-SNAPSHOT". Par dfaut, Maven ne va pas vrifier la prsence de versions SNAPSHOT sur les dpts distants. Pour pouvoir dpendre de versions SNAPSHOT les utilisateurs doivent donc activer explicitement le tlchargement des snapshots au travers des balises XML repository ou pluginRepository dans le POM. Lorsque vous livrez un projet vous devriez remplacer toutes vos dpendances sur des versions SNAPSHOT par des dpendances vers des versions stables. Si un projet dpend d'un SNAPSHOT, il n'est pas stable car ses dpendances peuvent voluer dans le temps. Les artefacts publis sur les dpts Maven stables comme [Link] ne peuvent pas dpendre de versions
161
SNAPSHOT. Le Super POM de Maven dsactive la publication de snapshots sur le dpt Central. Les versions SNAPSHOT sont utilises uniquement pour le dveloppement.
Si vous crivez ce XML dans un fichier [Link] et que vous excutez la commande mvn help:effective-pom, vous verrez le message suivant s'afficher sur la sortie standard :
... <finalName>[Link]-project-a</finalName> ...
Quand Maven lit un POM, il remplace les rfrences vers des proprits lorsqu'il charge le XML du POM. On rencontre frquemment des proprits dans un usage avanc de Maven. Ces proprits sont similaires celles que l'on trouve dans d'autres systmes comme Ant ou Velocity. Il s'agit tout simplement de variables dlimites par ${...}. Maven fournit trois variables implicites qui peuvent tre utilises pour accder aux variables d'environnement, aux informations du POM et votre configuration de Maven : env La variable env permet d'accder aux variables d'environnement de votre systme d'exploitation ou de votre shell. Par exemple, une rfrence ${[Link]} dans un POM Maven serait remplace par le contenu de la variable d'environnement ${PATH} (ou %PATH% sous Windows). project La variable project permet d'accder au POM. Vous pouvez utiliser un chemin pav de points ('.') pour rfrencer la valeur d'un lment du POM. Par exemple, dans cette section nous avons utilis le groupId et l'artifactId pour dfinir la valeur de l'lment finalName dans la configuration du build. La syntaxe pour cette rfrence tait : ${[Link]}${[Link]}. settings La variable settings permet d'accder aux informations de votre configuration de Maven. L encore, vous pouvez utiliser un chemin pav de points (.) pour rfrencer la valeur d'un lment
162
du fichier [Link]. Par exemple, ${[Link]} ferait rfrence la valeur de l'lment offline du fichier ~/.m2/[Link].
Note
Vous pouvez rencontrer d'anciens builds qui utilisent ${[Link]} ou simplement ${xxx} pour rfrencer des proprits du POM. Ces mthodes ont t marques comme abandonnes, et vous ne devriez utiliser que ${[Link]}. En plus de ces trois variables implicites, vous pouvez rfrencer les proprits systme et toute proprit configure dans un POM Maven ou dans un profil de build : Proprits systme en Java Toutes les proprits accessibles via la mthode getProperties() de la classe [Link] sont visibles comme proprits du POM. Voici quelques exemples de proprits systme : ${[Link]}, ${[Link]}, ${[Link]}, et ${[Link]}. Une liste complte des proprits systme se trouve dans la Javadoc de la classe [Link]. x Il est possible de dfinir des proprits supplmentaires grce la balise properties, soit dans un fichier [Link], dans le fichier [Link], ou enfin en les chargeant depuis des fichiers externes. Si vous dfinissez une proprit fooBar dans votre fichier [Link], cette proprit est rfrence par ${fooBar}. Ces proprits de configuration sont trs pratiques lorsque pour construire votre systme, vous devez filtrer des ressources que vous dployez sur diffrentes plateformes. Voici la syntaxe pour dclarer ${foo}=bar dans un POM:
<properties> <foo>bar</foo> </properties>
Pour une liste plus dtaille des proprits disponibles, lisez le Chapitre 15, Proprits et filtrage des ressources.
163
<groupId>[Link]</groupId> <artifactId>xfire-java5</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> </dependencies> ... </project>
La premire dpendance est une dpendance de compilation vers la bibliothque XFire SOAP de chez Codehaus. Vous pouvez utiliser une dpendance de ce type dans votre projet lorsque celui-ci dpend d'une bibliothque pour compiler, excuter les tests et s'excuter. La deuxime dpendance est une dpendance sur JUnit avec la porte (scope) test. Vous pouvez utiliser une dpendance dans le scope test lorsque vous n'avez besoin de cette bibliothque que pour compiler et excuter les tests. La dernire dpendance de l'Exemple 9.3, Dpendances d'un projet est une dpendance sur l'API Servlet 2.4. Cette dernire dpendance se trouve dans le scope provided. Vous pouvez utiliser le scope provided quand votre application a besoin d'une bibliothque la compilation ainsi que pour les tests et que cette bibliothque est fournie par un conteneur l'excution.
et sont packages avec l'application. provided Les dpendances du scope provided sont utilises lorsqu'elles doivent tre fournies par le JDK ou un conteneur. Par exemple, si vous dveloppez une application web, vous aurez besoin de l'API Servlet dans votre classpath pour pouvoir compiler une servlet, mais vous ne voudrez pas inclure l'API Servlet dans votre fichier WAR ; le JAR de l'API Servlet est fourni par votre serveur d'applications ou par votre conteneur de servlet. Les dpendances du scope provided font partie
164
du classpath de compilation (mais pas de celui d'excution). Elles ne sont pas transitives et ne seront pas packages avec l'application. runtime Les dpendances du scope runtime sont des dpendances ncessaires l'excution de l'application et des tests, mais qui sont inutiles la compilation. Par exemple, vous pouvez avoir besoin d'un JAR pour l'API JDBC la compilation et uniquement de l'implmentation du driver JDBC l'excution. test Les dpendances du scope test sont des dpendances qui ne sont pas ncessaires l'application durant son fonctionnement normal, elles ne servent que durant les phases de compilation et d'excution des tests. Nous avons dj parl du scope test dans la Section 4.10, Ajouter des dpendances dans le scope test . system Le scope system est assez proche du scope provided sauf que vous devez fournir un chemin explicite vers le JAR sur le systme de fichiers local. Il permet la compilation utilisant des objets natifs faisant partie des bibliothques systme. On suppose que cet artefact est toujours prsent et donc il ne sera pas cherch dans un dpt. Si vous utilisez le scope system, vous devez automatiquement lui adjoindre une balise systemPath. Il est important de noter que l'utilisation de ce scope n'est pas recommande (vous devriez toujours essayer de rfrencer des dpendances qui se trouvent dans un dpt Maven public ou priv).
165
<groupId>[Link]</groupId> <artifactId>my-project</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>ehcache</artifactId> <version>1.4.1</version> <optional>true</optional> </dependency> <dependency> <groupId>swarmcache</groupId> <artifactId>swarmcache</artifactId> <version>1.0RC2</version> <optional>true</optional> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.13</version> </dependency> </dependencies> </project>
Une fois que vous avez dclar ces dpendances comme optionnelles, vous devrez les ajouter de manire explicite dans les projets qui dpendront de my-project. Par exemple, si vous crivez une application qui dpend de my-project et que vous voulez utiliser l'implmentation EHCache, vous devrez ajouter la balise dependency suivante votre projet.
<project> <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>my-application</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>my-project</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>swarmcache</artifactId> <version>1.4.1</version> </dependency> </dependencies> </project>
Dans un monde idal, vous ne devriez pas avoir besoin de dpendances optionnelles. Au lieu d'avoir un gros projet avec un ensemble de dpendances optionnelles, vous devriez isoler le code spcifique EHCache dans un sous-module my-project-ehcache et le code spcifique SwarmCache dans un autre sous-module my-project-swarmcache. Ainsi, les projets qui rfrencent my-project
166
et qui doivent ajouter une dpendance spcifique, pourraient rfrencer une dpendance vers une implmentation spcifique et bnficieraient ainsi des dpendances transitives.
Si vous voulez dpendre de JUnit pour toutes les versions infrieures 3.8.1, vous ne devez spcifier que la borne suprieure comme dans l'Exemple 9.6, Dfinition d'un intervalle de versions : JUnit <= 3.8.1 . Exemple 9.6. Dfinition d'un intervalle de versions : JUnit <= 3.8.1
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>[,3.8.1]</version>ex-de <scope>test</scope> </dependency>
Une version avant ou aprs la virgule n'est pas obligatoire et signifie +/- l'infini. Par exemple, "[4.0,)" signifie toute version suprieure ou gale 4.0. "(,2.0)" signifie toute version strictement infrieure 2.0. "[1.2]" signifie uniquement la version 1.2, et rien d'autre.
Note
Quand vous dclarez une version "normale" telle que la version 3.8.2 de JUnit, Maven voit cette dclaration comme "accepter toute version, mais en prfrant la version 3.8.2". Ce
167
qui signifie que lorsqu'un conflit est dtect, Maven s'autorise l'utilisation des algorithmes de rsolution de conflit pour choisir la meilleure version. Si vous spcifiez [3.8.2], cela indique que seule la version 3.8.2 sera utilise et aucune autre. Si ailleurs il se trouve une dpendance qui spcifie [3.8.1], le build va chouer en vous indiquant le conflit en question. Nous vous prcisons tout cela pour que vous soyez au courant de cette option, mais n'utilisez l que lorsque c'est vritablement ncessaire. Pour rsoudre ces conflits de version, il est prfrable de passer par la balise dependencyManagement.
168
Pour illustrer la relation entre le scope d'une dpendance transitive et le scope d'une dpendance directe, voici quelques exemples. Si le projet-a possde une dpendance dans le scope test vers le projet-b qui a une dpendance dans le scope compile vers le projet-c. Le projet-c sera donc une dpendance transitive du projet-a dans le scope test. Vous pouvez voir cela comme une ligne de transitivit qui agit comme un filtre sur le scope de dpendance. Les dpendances transitives qui sont dans les scopes test et provided n'ont en gnral pas d'effet sur un projet. L'exception cette rgle concerne les dpendances transitives provided de dpendances elles-aussi provided qui seront donc des dpendances dans le scope provided du projet. Les dpendances transitives qui sont dans les scopes compile et runtime affectent le projet quelque soit le scope de la dpendance directe. Les dpendances transitives qui sont dans le scope compile resteront dans ce scope quelque soit le scope de la dpendance directe. Les dpendances transitives qui sont dans le scope runtime seront en gnral dans le mme scope que la dpendance directe sauf lorsque cette dernire est dans le scope compile. Quand une dpendance transitive est dans le scope runtime et que la dpendance directe est dans le scope compile alors la dpendance transitive sera dans le scope effectif runtime.
Souvent, vous voudrez remplacer une dpendance transitive par une autre implmentation de la fonctionnalit. Par exemple, si vous dpendez d'une bibliothque qui elle-mme dpend de l'API JTA de Sun, vous pouvez vouloir remplacer cette dpendance transitive. Hibernate en est un bon exemple. Hibernate dpend du JAR de l'API JTA de Sun qui n'est pas disponible sur le dpt central de Maven car il n'est pas librement distribuable. Heureusement, le projet Apache Geronimo a cr une implmentation indpendante de cette bibliothque qui est librement redistribuable. Pour remplacer une dpendance transitive par une autre, vous devrez exclure la dpendance transitive et ajouter l'autre dpendance votre
169
projet. L'Exemple 9.8, Exclusion et remplacement d'une dpendance transitive donne un exemple d'un tel remplacement. Exemple 9.8. Exclusion et remplacement d'une dpendance transitive
<dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate</artifactId> <version>[Link]</version> <exclusions> <exclusion> <groupId>[Link]</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>geronimo-jta_1.1_spec</artifactId> <version>1.1</version> </dependency> </dependencies>
Dans l'Exemple 9.8, Exclusion et remplacement d'une dpendance transitive , rien n'indique que la dpendance geronimo-jta_1.1_spec en remplace une autre, il se trouve juste qu'il s'agit d'une bibliothque qui prsente la mme API que la dpendance JTA originale. Voici d'autres raisons pour lesquelles vous voudriez exclure ou remplacer des dpendances transitives : 1. Le groupId ou l'artifactId de l'artefact a chang alors que le projet ncessite une version avec l'autre nom de cet artefact, ce qui fait que vous vous retrouvez avec deux copies du mme projet dans votre classpath. Normalement, Maven dtecte ce genre de conflit et utilise une unique version du projet, mais quand les groupId et artifactId sont diffrents, Maven les considre comme deux bibliothques distinctes. 2. Un artefact n'est pas utilis dans votre projet et la dpendance transitive n'a pas t rendue optionnelle. Dans ce cas, vous voulez exclure cette dpendance non requise pour votre projet car vous essayez de rduire le nombre de bibliothques que vous redistribuez avec votre application. 3. Un artefact est fourni par votre conteneur l'excution et donc il ne doit pas tre inclus par votre build. Par exemple, si une dpendance dpend de l'API Servlet et que vous voulez tre sr que cette dpendance transitive ne se retrouve pas dans le rpertoire WEB-INF/lib de l'application web. 4. Pour exclure une dpendance qui peut tre une API avec plusieurs implmentations. C'est le cas prsent dans l'Exemple 9.8, Exclusion et remplacement d'une dpendance transitive ; o une API de Sun qui demande une acceptation d'une licence et une installation manuelle dans un dpt personnel (le JAR JTA de Sun) peut tre remplace par une version librement redistribuable de la mme API disponible sur le dpt central de Maven (l'implmentation JTA de Geronimo).
170
Vous pourrez alors, dans un projet fils, ajouter une dpendance au connecteur Java MySQL avec le XML suivant :
<project> <modelVersion>4.0.0</modelVersion>
171
<parent> <groupId>[Link]</groupId> <artifactId>a-parent</artifactId> <version>1.0.0</version> </parent> <artifactId>project-a</artifactId> ... <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> </project>
Faites attention au fait que le projet fils n'a pas dclar explicitement la version de la dpendance mysql-connector-java. Comme cette dpendance a t dclare dans la balise dependencyManagement du POM de plus haut niveau, le numro de version va se propager jusqu' la dpendance mysql-connector-java du projet fils. Attention, si le projet fils avait dfini une version, celle-ci aurait remplac la version dfinie dans la section dependencyManagement du POM de plus haut niveau. Tout cela signifie que la version dclare dans dependencyManagement n'est utilise que lorsque le projet fils ne dclare pas de version. La gestion des dpendances avec un POM de haut niveau est diffrente de la dclaration d'une dpendance partage au travers d'un POM parent. Pour commencer, toutes les dpendances sont hrites. Si mysql-connector-java tait dclare comme une dpendance du projet de plus haut niveau, chaque projet fils ferait rfrence cette dpendance. Au lieu d'ajouter des dpendances inutiles, l'utilisation de la balise dependencyManagement vous permet de consolider et de centraliser la gestion des versions des dpendances sans ajouter de dpendances hrites par tous les projets fils. En d'autres termes, la balise dependencyManagement est quivalente une variable d'environnement qui vous permet de dclarer une dpendance dans un sous-projet sans avoir prciser de numro de version.
172
Note
Si l'utilisation des '.' est trs courante pour les groupIds, vous devriez viter d'en utiliser pour les artifactIds. En effet, cela peut provoquer des problmes lors de l'interprtation d'un nom complet jusqu'aux sous-composants. version Quand un artefact est dlivr, on lui affecte un numro de version. Ce numro de version peut tre un identifiant numrique tel que "1.0", "1.1.1" ou "1.1.2-alpha-01". Vous pouvez aussi utiliser ce que l'on appelle une version snapshot. Une version snapshot est une version d'un composant en cours de dveloppement. Les numros de version snapshot se terminent toujours par SNAPSHOT ; par exemple "1.0-SNAPSHOT", "1.1.1-SNAPSHOT" ou "1-SNAPSHOT". La Section [Link], Numro de version de build dcrit les numros de versions et les intervalles de versions. Il existe un quatrime identifiant moins utilis : classifier On utilise un classifier lorsqu'on livre le mme code, mais sous la forme de plusieurs artefacts distincts pour des raisons techniques. Par exemple, si vous voulez construire deux arterfacts d'un JAR, un compil avec le compilateur Java 1.4 et un autre avec le compilateur Java 6,
1
[Link]
173
vous utiliserez le classifier pour produire deux JARs diffrents avec la mme combinaison groupId:artifactId:version. Si votre projet utilise des extensions en code natif, vous utiliserez le classifier pour distinguer les artefacts selon chaque plate-forme cible. Les classifiers sont couramment utiliss lors du packaging du code source, de la JavaDoc d'un artefact ou d'assemblage de binaires. Dans ce livre, lorsque nous voquons des dpendances, nous utilisons souvent le format simplifi suivant pour dcrire une dpendance : groupId:artifactId:version. Pour rfrencer la version 2.5 de Spring, nous utiliserions [Link]:spring:2.5. Quand vous demandez Maven d'afficher une liste des dpendances grce au plugin Maven Dependency, vous verrez que Maven a tendance produire des traces en utilisant cette criture simplifie.
Figure 9.3. Relations dans un projet multimodule La structure des rpertoires sur le systme de fichiers suit les relations entre les modules. L'ensemble des projets illustr par la Figure 9.3, Relations dans un projet multimodule aurait la structure de rpertoires suivante :
top-parent-project/[Link] top-parent-project/subparent-parent-project/[Link]
174
Les projets sont lis entre eux par les projets top-parent-project et subparent-parent-project comme sous-modules dans un POM. Par exemple, le projet [Link]:topparent-project est un projet multimodule avec un packaging de type pom. Le fichier [Link] du projet top-parent-project doit possder la balise modules suivante : Exemple 9.10. Balise modules du projet top-parent-project
<project> <groupId>[Link]</groupId> <artifactId>top-parent-project</artifactId> ... <modules> <module>subparent-parent-project</module> <module>project-c</module> </modules> ... </project>
Quand Maven parse le POM du projet top-parent-project, il analyse la balise modules pour s'apercevoir que le projet top-parent-project rfrence les projets subparent-parent-project et project-c. Maven va alors traiter les fichiers [Link] dans chacun de ces sous-rpertoires. Maven rpte cette opration pour chacun des sous-modules : il lira le fichier subparent-parent-project/ [Link] pour s'apercevoir que le projet subparent-parent-project fait rfrence deux projets dans la balise modules suivante : Exemple 9.11. Balise modules du projet subparent-parent-project
<project> ... <modules> <module>project-a</module> <module>project-b</module> </modules> ... </project>
Attention au fait que nous appelons "modules" les projets qui composent un projet multimodule et non projets "enfants" ou "fils". Nous agissons ainsi dlibrment pour ne pas confondre les projets qui sont lis dans un projet multimodule de ceux qui hritent d'un mme POM.
175
parent. Quand un projet spcifie un parent, il hrite de l'ensemble des informations du POM du projet
parent. Il peut redfinir les valeurs du POM parent et en ajouter. Tous les POMs de Maven hritent d'un POM parent. Si un POM ne spcifie pas de parent direct au travers de la balise parent, ce POM hritera des valeurs dfinies dans le Super POM. L'Exemple 9.12, Hritage entre projets prsente la balise parent du project-a qui hrite du POM du projet aparent. Exemple 9.12. Hritage entre projets
<project> <parent> <groupId>[Link]</groupId> <artifactId>a-parent</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>project-a</artifactId> ... </project>
L'excution de la commande mvn help:effective-pom dans le project-a va afficher un POM qui est le rsultat de la fusion du Super POM avec le POM du projet a-parent et celui du project-a. Les hritages implicites et explicites du project-a sont prsents dans Figure 9.4, Hritage pour les projets a-parent et project-a .
Super POM (implicit) a-parent inherits from the Super POM [Link] a-parent (explicit) project-a inherits from a-parent [Link] project-a
Figure 9.4. Hritage pour les projets a-parent et project-a Quand un projet spcifie un projet parent, Maven utilise le POM de ce parent comme point de dpart avant de traiter le POM du projet courant. Il hrite de tout, jusqu'au groupId et au numro de version. Vous pouvez remarquer que le project-a ne spcifie aucun des deux, le groupId et la version sont tous les deux hrits du projet a-parent. Lorsqu'une balise parent est prsente, tout ce qu'un POM a
176
besoin de dfinir est l'artifactId. Cela n'est pas obligatoire, le project-a peut avoir un groupId et une version diffrents de ceux du parent, mais s'ils ne sont pas dfinis alors Maven utilisera ceux du POM parent. Si vous commencez utiliser Maven pour grer et construire de gros projets multimodules, vous aurez souvent crer des projets qui auront un mme groupId et une mme version. Quand vous hritez d'un POM, vous avez le choix entre utiliser les valeurs hrites de ce POM ou les surcharger slectivement. Ce qui suit est une liste d'lments qu'un POM Maven hrite de son POM parent : les identifiants (il faut au moins surcharger le groupId ou l'artifactId). les dpendances les dveloppeurs et les contributeurs les listes de plugins les listes de rapports les excutions de plugin (les excutions qui ont le mme id sont fusionnes) les configuration de plugin Quand Maven hrite de dpendances, il va ajouter les dpendances dfinies dans les projets fils celles des projets parents. C'est ainsi que vous pouvez spcifier des dpendances utilises tout au long de projets qui hritent d'un mme POM parent. Par exemple, si votre projet fait usage de Log4J pour ses traces, vous pouvez ajouter cette dpendance dans votre POM de plus haut niveau. Tous les projets qui hriteront de ce POM auront automatiquement Log4J comme dpendance. De mme, si vous voulez vous assurer que tous vos projets utilisent la mme version d'un plugin Maven, vous pouvez dfinir la version de ce plugin Maven dans la section pluginManagement d'un POM parent de haut niveau. Maven assume que le POM parent est disponible dans le dpt local ou dans le rpertoire parent (../ [Link]) du projet courant. Si aucune de ces options n'est valide, ce comportement par dfaut peut tre redfini par la balise relativePath. Par exemple, certaines organisations prfrent une structure plat des projets o le fichier [Link] du projet parent ne se trouve pas dans le rpertoire parent d'un projet fils. Il peut se trouver dans un rpertoire au mme niveau que celui du projet. Si votre projet fils se trouve dans le rpertoire ./projet-a et que le projet parent se trouve dans ./a-parent, vous prciserez dans le POM le chemin relatif du projet parent-a ainsi :
<project> <parent> <groupId>[Link]</groupId> <artifactId>a-parent</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../a-parent/[Link]</relativePath> </parent> <artifactId>projet-a</artifactId> </project>
177
178
Si vous crez ce projet dans un rpertoire persistence-deps, tout ce que vous avez faire ensuite est d'crire ce fichier [Link] et d'excuter la commande mvn install. Comme c'est un projet dont le packaging est de type pom, ce POM s'installe dans votre dpt local. Vous pouvez maintenant ajouter ce projet comme dpendance de votre projet et toutes ses dpendances seront automatiquement ajoutes votre projet. Quand vous ajoutez une dpendance vers ce projet persistence-deps, n'oubliez pas de spcifier qu'il s'agit d'une dpendance dont le packaging est de type pom. Exemple 9.14. Dclaration d'une dpendance vers un POM
<project> <description>Ce projet ncessite JDBC</description> ... <dependencies> ... <dependency> <groupId>[Link]</groupId> <artifactId>persistence-deps</artifactId> <version>1.0</version> <type>pom</type> </dependency> </dependencies> </project>
Si plus tard vous dcidez de changer de pilote JDBC (en utilisant par exemple JTDS), vous n'avez qu' remplacer les dpendances dans le projet persistence-deps pour utiliser [Link]:jtds au lieu de mysql:mysql-java-connector puis mettre jour le numro de version. Tous les projets qui dpendent de persistence-deps utiliseront JTDS s'ils dcident d'utiliser la nouvelle version. La consolidation des dpendances est une bonne pratique qui permet de rduire la taille des fichiers [Link] qui ont un grand nombre de dpendances. Si vous devez partager un grand nombre de dpendances entre plusieurs projets, vous pouvez aussi tablir des relations parent-enfant entre ceux-ci et extraire toutes les dpendances communes dans le projet parent. La limite de cette approche parent-enfant est qu'un projet peut n'avoir qu'un seul parent. Parfois, il est donc plus simple de regrouper ces dpendances et de rfrencer une dpendance de type pom. Ainsi, votre projet peut rfrencer autant de POM de dpendance selon ses besoins.
Note
Maven utilise le niveau d'une dpendance dans l'arbre lorsqu'il rsout un conflit, ne retenant que la dpendance la plus proche. Cette technique de regroupement de
179
dpendances les fait descendre d'un niveau dans l'arbre. Ne l'oubliez pas lorsque vous devez choisir entre regrouper des dpendances dans un fichier [Link] ou utiliser la balise dependencyManagement dans un POM parent.
Super POM Submodule Relationship Parent/Child Relationship [Link] sonatype [Link] book-examples [Link] maven-book [Link] book-chapters
Figure 9.5. Hritage dans le projet multimodule maven-book Quand nous construisons ce livre sur Maven que vous tes en train de lire, nous excutons la commande mvn package dans un projet multimodule qui s'appelle maven-book. Ce projet multimodule se
180
compose de deux sous-modules : book-examples et book-chapters. Aucun de ces projets ne partage le mme parent, ils ne sont lis que par le fait qu'ils sont tous les deux des modules du projet mavenbook. Le projet book-examples construit les archives ZIP et TGZ que vous avez tlcharges pour obtenir les exemples de ce livre. Quand nous excutons le build du projet book-examples depuis le rpertoire book-examples/ avec la commande mvn package, il ne sait pas qu'il n'est qu'une partie du projet maven-book. Le projet book-examples ne s'intresse pas au projet maven-book, tout ce qu'il sait est que son parent est le POM sonatype de plus haut-niveau et qu'il construit une archive d'exemples. Dans ce cas, le projet maven-book existe uniquement comme facilitateur en regroupant des modules. Chacun de ces trois projets : maven-book, book-examples et book-chapters ont le mme parent "d'entreprise" sonatype. C'est une pratique courante dans les organisations qui ont adopt Maven. Au lieu d'avoir chaque projet qui tende le Super POM par dfaut, certaines organisations dfinissent un POM d'entreprise de haut niveau qui sert de parent par dfaut quand un projet n'a aucune raison d'en dpendre d'un autre. Dans ce livre, par exemple, il n'y a aucune raison pour que les projets bookexamples et book-chapters partagent le mme POM parent. Il s'agit de projets compltement diffrents avec leurs propres dpendances et configurations. Ils utilisent des plugins trs diffrents pour construire ce que vous tres en train de lire. Le POM sonatype permet une organisation de personnaliser le comportement par dfaut de Maven et de fournir des informations propres l'organisation pour le dploiement et les profils. [Link]. Projet multimodule d'entreprise Regardons un exemple qui fournit une image plus prcise de ce que pourrait tre un vritable projet o l'hritage et les relations multimodules existent cte cte. La Figure 9.6, Hritage dans un projet multimodule d'entreprise montre un ensemble de projets qui ressemblent ceux que l'on pourrait rencontrer dans une vritable application d'entreprise. Il y a un POM de haut niveau pour l'entreprise avec un artifactId ayant pour valeur sonatype. Il y a ensuite un projet multimodule big-system qui rfrence les sous-modules server-side et client-side.
181
Super POM
Submodule Relationship Parent/Child Relationship [Link] client-web 1.0-SNAPSHOT [Link] admin-web 1.0-SNAPSHOT
[Link] server-lib 1.0-SNAPSHOT [Link] swing-app 1.0-SNAPSHOT [Link] trading-client 1.0-SNAPSHOT [Link] streaming-client 1.0-SNAPSHOT
Figure 9.6. Hritage dans un projet multimodule d'entreprise De quoi s'agit-il ? Essayons de donner un sens toutes ces flches. Tout d'abord, regardons bigsystem. Le projet big-system pourrait tre le projet dans lequel vous excuteriez la commande mvn package pour construire et tester le systme dans son entier. Le projet big-system rfrence les sousmodules client-side et server-side. Chacun de ces projets regroupe le code qui s'excute ct serveur et ct client. Concentrons-nous sur le projet server-side. Sous ce projet server-side se trouve un projet appel server-lib et un projet multimodule web-apps. Sous web-apps nous retrouvons deux applications web Java : client-web et admin-web. Commenons par les relations parent/enfant de client-web et admin-web avec web-apps. Puisque ces deux applications web utilisent le mme framework (Wicket par exemple), ces deux projets partagent un mme ensemble de dpendances. Les dpendances vers l'API Servlet, l'API JSP et Wicket seraient toutes regroupes dans le projet web-apps. Ces deux projets client-web et admin-web doivent aussi dpendre de server-lib. Cette dpendance sera dfinie comme une dpendance de web-apps
182
vers server-lib. Puisque client-web et admin-web partagent tous les deux cette configuration en hritant de web-apps, ces deux projets auront des POMs succincts contenant tout au plus les identifiants, le parent et le nom de l'artefact final. Maintenant, concentrons-nous sur la relation parent/enfant de web-apps et server-lib vers serverside. Dans ce cas-ci, supposons qu'il existe deux groupes de dveloppeurs spars, l'un qui travaille sur le code ct serveur et l'autre sur le code ct client. La liste des dveloppeurs serait configure dans le POM du projet server-side et hrite par ses projets fils : web-apps, server-lib, client-web et admin-web. Nous pourrions aussi imaginer que le projet server-side soit configur diffremment pour prendre en compte les spcificits du dveloppement ct serveur. Le projet server-side pourrait utiliser un profil qui n'aurait de sens que pour tous les projets server-side. Ce profil pourrait contenir les informations de connexion la base de donnes, ou le POM de ce projet server-side pourrait configurer une version spcifique du plugin Maven Jetty qui serait rcupre par tous les projets qui hriteraient du POM server-side. Dans cet exemple, la principale raison d'utiliser les relations parent/enfant est cet ensemble de dpendances partages et la configuration commune un groupe de projets qui sont lis logiquement. Tous les projets sous big-system sont lis les uns aux autres en tant que sous-modules, cependant tous les sous-modules ne sont pas obligs de dclarer comme parent le projet qui les a dclars comme sous-module. Tout est sous-module pour des raisons de simplification, pour construire le systme dans son ensemble allez dans le rpertoire du projet big-system et excutez la commande mvn package. Si vous regardez attentivement la figure vous noterez qu'il n'existe pas de relation parent/enfant entre les projets server-side et big-system. Pourquoi donc ? L'hritage de POM est trs puissant, mais il ne doit pas tre utilis tort et travers. Quand le partage de dpendances et de configuration a du sens, il faut utiliser la relation parent/enfant. Mais elle n'a pas de sens lorsque les deux projets sont trs diffrents. Ce qui est le cas, par exemple, des projets server-side et client-side. Il est tout fait possible de concevoir un systme o client-side et server-side hritent du POM commun de big-system. Cependant chaque apparition d'une divergence significative entre ces deux projets il va falloir trouver des manires subtiles pour factoriser la configuration commune dans big-system sans perturber tous les projets fils. Mme si client-side et server-side partagent la mme dpendance Log4J, ils peuvent avoir des configurations de plugins trs diffrentes. Il existe un certain point, dont la position dpend de votre style et de votre exprience, au-del duquel vous estimerez que la duplication de configuration est acceptable pour garder des projets comme client-side et server-side indpendants . Concevoir un systme qui se compose de dizaines de projets sur plus de cinq niveaux d'hritage de POM n'est pas la meilleure ide qu'on puisse avoir. Dans une telle configuration, vous n'avez pas dupliqu votre dpendance Log4J, mais vous devrez naviguer entre les cinq niveaux de POM pour comprendre comment Maven calcule votre POM effectif. Toute cette complexit pour viter d'avoir dupliquer cinq fois les quelques lignes d'une dpendance. Avec Maven, il y a toujours "une manire Maven de faire", mais il en existe bien d'autres. Au final, tout est question de prfrences et de style. Dans la plupart des cas vous n'aurez pas de soucis si vos sousmodules dclarent le mme projet comme parent, mais il se peut que votre utilisation de Maven volue dans temps.
183
Par exemple, supposez que vous vouliez excuter un goal antrun:run pour afficher une notification lors du pre-clean, ou archiver le rpertoire de build du projet avant qu'il ne soit supprim. Excuter directement le goal clean:clean ne lancera pas le cycle de vie, vos tches annexes ne seront donc pas excutes. Par contre, si vous utilisez la phase clean, vous utiliserez le cycle de vie du mme nom (clean) et traverserez de ce fait les trois phases du cycle de vie de jusqu' la phase clean. L'Exemple 10.1, Excuter un goal lors du pre-clean montre une configuration de build qui permet de rattacher le goal antrun:run la phase pre-clean pour afficher une alerte avant la suppression de l'artefact en cours de nettoyage. Dans cet exemple, le goal antrun:run est utilis pour excuter des commandes Ant qui permettent de tester l'existence d'un artefact de projet. Ainsi, si l'artefact du projet est trouv et est donc sur le point d'tre effac, une alerte s'affichera l'cran. Exemple 10.1. Excuter un goal lors du pre-clean
<project> ... <build> <plugins>... <plugin> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <id>file-exists</id> <phase>pre-clean</phase> <goals> <goal>run</goal> </goals> <configuration> <tasks> <!-- adds the ant-contrib tasks (if/then/else used below) --> <taskdef resource="net/sf/antcontrib/[Link]" /> <available file="${[Link]}/${[Link]}.${[Link]}" property="[Link]" value="true" /> <if> <not> <isset property="[Link]" /> </not> <then> <echo>No ${[Link]}.${[Link]} to delete</echo> </then> <else> <echo>Deleting ${[Link]}.${[Link]}</echo> </else> </if> </tasks> </configuration> </execution> </executions>
186
<dependencies> <dependency> <groupId>ant-contrib</groupId> <artifactId>ant-contrib</artifactId> <version>1.0b2</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>
Excuter la commande mvn clean avec une telle configuration sur un projet produira un rsultat ressemblant celui-ci :
[INFO] Scanning for projects... [INFO] ---------------------------------------------------------------------[INFO] Building Your Project [INFO] task-segment: [clean] [INFO] ---------------------------------------------------------------------[INFO] [antrun:run {execution: file-exists}] [INFO] Executing tasks [echo] Deleting [Link] [INFO] Executed tasks [INFO] [clean:clean] [INFO] Deleting directory ~/corp/your-project/target [INFO] Deleting directory ~/corp/your-project/target/classes [INFO] Deleting directory ~/corp/your-project/target/test-classes [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] -----------------------------------------------------------------------[INFO] Total time: 1 second [INFO] Finished at: Wed Nov 08 11:46:26 CST 2006 [INFO] Final Memory: 2M/5M [INFO] ------------------------------------------------------------------------
En plus de configurer Maven pour excuter un goal lors de la phase pre-clean, vous pouvez personnaliser le plugin Clean pour effacer des dossiers en plus du rpertoire contenant le build. Vous pouvez configurer le plugin pour supprimer une liste de fichier en lui spcifiant un fileSet. L'exemple ci-dessous configure le plugin Clean pour supprimer tous les fichiers du rpertoire target-other/ en utilisant des wildcards standard Ant : * et **. Exemple 10.2. Personaliser le comportement du plugin Clean
<project> <modelVersion>4.0.0</modelVersion> ... <build> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <configuration>
187
<filesets> <fileset> <directory>target-other</directory> <includes> <include>*.class</include> </includes> </fileset> </filesets> </configuration> </plugin> </plugins> </build> </project>
compile process-classes
188
Description Copie et traite les ressources de test dans le rpertoire destination des tests Compile le code source des tests dans le rpertoire destination des tests Excute les tests en utilisant le framework de test appropri. Le code de ces tests ne doit pas tre ncessaire au packaging ni au dploiement. Effectue les oprations ncessaires pour la prparation du package avant que celui-ci ne soit rellement cr. Il en rsulte souvent une version dzippe et prte t package du futur package (Maven 2.1+) Package le code compil dans un format distribuable tel que JAR, WAR ou EAR Effectue les actions ncessaires avant de lancer les tests d'intgration, comme configurer un environnement par exemple. Traite et dploie si ncessaire le package dans l'environnement o les tests pourront tre excuts Effectue les actions ncessaires la fin de l'excution des tests d'intgration, comme nettoyer l'environnement par exemple Lance des points de contrle pour vrifier que le package est valide et qu'il passe les critres qualit Installe le package dans le dpt local, celuici pourra ainsi tre utilis comme dpendance par d'autres projets locaux Copie le package final sur le dpt distant. Permet de partager le package avec d'autres utilisateurs et projets (souvent pertinent pour une vraie livraison)
prepare-package
package pre-integration-test
integration-test
post-integration-test
verify
install
deploy
189
Pour plus d'informations propos de la gnration de site Maven, consultez le Chapitre 16, Gnration du Site.
[Link]
190
10.2.1. JAR
JAR est le type de packaging par dfaut, c'est galement le plus commun et le plus souvent rencontr. Les goals par dfaut rattachs au cycle de vie pour un projet possdant ce type de packaging sont montrs dans le Tableau 10.2, Goals par dfaut pour le packaging de type JAR . Tableau 10.2. Goals par dfaut pour le packaging de type JAR Phase du cycle de vie process-resources compile process-test-resources test-compile test package install deploy Goal resources:resources compiler:compile resources:testResources compiler:testCompile surefire:test jar:jar install:install deploy:deploy
10.2.2. POM
POM est le plus simple des types de packaging. L'artefact gnr est le pom lui-mme plutt qu'un fichier JAR, SAR ou EAR. Il ne possde pas de code tester ni mme compiler, et n'a pas de ressources traiter. Les goals par dfaut d'un projet du type POM sont affichs dans le Tableau 10.3, Goals par dfaut d'un projet du type POM . Tableau 10.3. Goals par dfaut d'un projet du type POM Phase du cycle de vie package install deploy Goal site:attach-descriptor install:install deploy:deploy
191
Tableau 10.4. Goals par dfaut d'un projet du type Plugin Phase du cycle de vie generate-resources process-resources compile process-test-resources test-compile test package install deploy Goal plugin:descriptor resources:resources compiler:compile resources:testResources compiler:testCompile surefire:test jar:jar, plugin:addPluginArtifactMetadata install:install, plugin:updateRegistry deploy:deploy
10.2.4. EJB
Les EJBs (Enterprise Java Beans) proposent un mcanisme standard d'accs aux donnes. Ils proposent une approche oriente modle (model-driven development) pour le dveloppement d'applications Java d'entreprise. Maven fournit un support pour les EJB 2 et 3. Les paramtres par dfaut du plugin recherchent la prsence des fichiers de configuration EJB 2.1, vous devez configurer le plugin EJB pour packager spcifiquement un EJB3. Les goals par dfaut pour des projets du type EJB sont prsents dans le Tableau 10.5, Goals par dfaut d'un projet du type EJB . Tableau 10.5. Goals par dfaut d'un projet du type EJB Phase du cycle de vie process-resources compile process-test-resources test-compile test package install deploy Goal resources:resources compiler:compile resources:testResources compiler:testCompile surefire:test ejb:ejb install:install deploy:deploy
10.2.5. WAR
Le packaging de type WAR ressemble galement aux types JAR et EJB, l'exception prs du goal war:war de la phase package. Notez que le plugin war:war ncessite la prsence d'un fichier de configuration [Link] dans le rpertoire src/main/webapp/WEB-INF. Les goals par dfaut d'un projet de type WAR sont prsents dans le Tableau 10.6, Goals par dfaut d'un projet de type WAR .
192
Tableau 10.6. Goals par dfaut d'un projet de type WAR Phase du cycle de vie process-resources compile process-test-resources test-compile test package install deploy Goal resources:resources compiler:compile resources:testResources compiler:testCompile surefire:test war:war install:install deploy:deploy
10.2.6. EAR
Les EARs sont probablement les artefacts les plus simples d'une application Java EE. Ils sont constitus d'un descripteur de dploiement nomm [Link], de ressources et de modules. Le plugin EAR possde un goal nomm generate-application-xml. Celui-ci gnre le fichier [Link] partir de la configuration dfinie dans le POM du projet EAR. Les goals par dfaut d'un projet de type EAR sont prsents dans le Tableau 10.7, Goals par dfaut d'un projet de type EAR . Tableau 10.7. Goals par dfaut d'un projet de type EAR Phase du cycle de vie generate-resources process-resources package install deploy Goal ear:generate-application-xml resources:resources ear:ear install:install deploy:deploy
193
central. Voici l'exemple d'un projet qui rfrence le plugin Israfil Flex et qui utilise un type de packaging personnalis SWF comme rsultat de la construction du code source Adobe Flex. Exemple 10.3. Type de packaging personnalis pour Adobe Flex (SWF)
<project> ... <packaging>swf</packaging> ... <build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-flex2-plugin</artifactId> <version>1.4-SNAPSHOT</version> <extensions>true</extensions> <configuration> <debug>true</debug> <flexHome>${[Link]}</flexHome> <useNetwork>true</useNetwork> <main>org/sonatype/mavenbook/[Link]</main> </configuration> </plugin> </plugins> </build> ... </project>
Dans la Section 17.6, Plugins et le cycle de vie Maven , nous vous montrons comment crer votre propre type de packaging avec un cycle de vie personnalis. Cet exemple devrait vous donner une ide de ce que vous avez faire pour rfrencer un nouveau type de packaging. Tout ce dont vous avez besoin est de rfrencer le plugin qui fournit votre nouveau type de packaging. Le plugin Israfil Flex est un plugin Maven non officiel hberg sur Google Code, pour plus d'informations sur son fonctionnement et son utilisation, rendez-vous l'adresse [Link] Ce plugin fournit le cycle de vie suivant pour les projets de type SWF : Tableau 10.8. Cycle de vie par dfaut d'un projet de type SWF Phase du cycle de vie compile install deploy Goal flex2:compile-swc install deploy
194
phase package du cycle de vie WAR appelle war:war alors que cette mme phase appelle jar:jar pour le cycle de vie JAR. La plupart des cycles de vie que vous rencontrerez partageront certains goals pour grer les ressources, excuter les tests et compiler votre code. Dans cette section, nous explorerons quelques-uns des goals utiliss sur plusieurs cycles de vie.
Ce fichier XML utilise la mme syntaxe pour grer ses proprits que celle que du POM. La premire variable rfrence est la variable project, celle-ci est une variable implicite qui est galement disponible dans le POM. La variable project propose un moyen d'accder certaines informations du POM. Les trois variables suivantes sont [Link], [Link] et [Link]. Ces variables sont dfinies dans un fichier de properties src/main/filters/[Link].
195
Pour configurer le filtrage des ressources avec le fichier [Link], nous avons besoin de prciser deux choses dans le POM du projet : une liste de fichiers de proprits dans la balise filters de la configuration du build et un boolen qui permet Maven de savoir si un rpertoire doit tre filtr. Le comportement par dfaut de Maven est de ne pas effectuer de filtre mais de juste copier les ressources dans le rpertoire destination : vous devez donc configurer explicitement le filtrage des ressources. Ce comportement par dfaut permet d'viter les mauvaises surprises comme, par exemple, filtrer sans que vous le dsiriez des fichiers contenant des lments ${...}. Exemple 10.6. Filtrage des ressources (remplacer les proprits)
<build> <filters> <filter>src/main/filters/[Link]</filter> </filters> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build>
Comme pour tous les rpertoires dans Maven, celui contenant les ressources du projet ne se trouve pas forcment dans src/main/resources. Il ne s'agit que de la valeur par dfaut dfinie dans le Super POM. Notez galement que vous n'avez pas besoin de centraliser toutes vos ressources dans un unique rpertoire. Vous pouvez les sparer dans plusieurs sous-rpertoires dans src/main. Imaginez que votre projet contienne des centaines de fichiers XML et des centaines d'images. Au lieu de centraliser toutes vos ressources dans le rpertoire src/main/resources, il voudrez probablement crer deux rpertoires src/main/xml et src/main/images. Pour ajouter des rpertoires la liste des rpertoires contenant les ressources, ajoutez la balise resource suivante dans la configuration de votre build. Exemple 10.7. Ajouter des rpertoire ressources complmentaires
<build> ... <resources> <resource> <directory>src/main/resources</directory> </resource> <resource> <directory>src/main/xml</directory> </resource> <resource>
196
Lorsque vous construisez un projet qui produit une application en ligne de commande ou console, vous voudrez souvent crire des scripts shell et les rfrencer dans le JAR produit par un build. Quand vous utilisez le plugin Assembly pour distribuer votre application via un ZIP ou un TAR, vous pouvez placer tous vos scripts dans un rpertoire du type src/main/command. Dans la configuration des ressources du POM suivant, vous verrez comment nous pouvons utiliser le filtrage des ressources et avec une rfrence vers une variable pour modifier le nom du JAR. Pour plus d'informations sur le plugin Maven Assembly, consultez le Chapitre 14, Maven Assemblies. Exemple 10.8. Fitrage de resources Scripts
<build> <groupId>[Link]</groupId> <artifactId>simple-cmd</artifactId> <version>2.3.1</version> ... <resources> <resource> <filtering>true</filtering> <directory>${basedir}/src/main/command</directory> <includes> <include>[Link]</include> <include>[Link]</include> </includes> <targetPath>${basedir}</targetPath> </resource> <resource> <directory>${basedir}/src/main/resources</directory> </resource> </resources> ... </build>
Si vous excutez la commande mvn process-resources dans ce projet, vous vous retrouverez avec deux fichiers dans ${basedir} : [Link] et [Link]. Nous avons inclus ces deux fichiers dans la balise resource, configur le filtrage, et affect le targetPath la valeur ${basedir}. Dans une seconde balise resource, nous avons configur le chemin par dfaut des ressources pour qu'elles soient copies sans filtrage dans le rpertoire de destination. L'Exemple 10.8, Fitrage de resources Scripts montre comment dclarer deux rpertoires ressources et les configurer diffremment. Le projet de l'Exemple 10.8, Fitrage de resources Scripts doit disposer un fichier [Link] dans le dossier src/main/command qui contient le code suivant :
@echo off java -jar ${[Link]}.jar %*
197
Aprs avoir excut la commande mvn process-resources, un fichier nomm [Link] devrait apparatre dans ${basedir}, en voici son contenu :
@echo off java -jar [Link] %*
La possibilit de personnaliser le filtrage pour un sous-ensemble spcifique de ressources est l'une des raisons de sparer vos ressources par type sur un projet. Plus un projet est complexe, plus il sera avantageux de sparer les ressources dans diffrents rpertoires. L'alternative au fait de conserver diffrentes sortes de ressources ncessitant diffrentes configurations de filtre dans des rpertoires diffrents est d'utiliser un ensemble complexe de pattern 'include' et 'exclude' pour diffrencier les types de configuration. Cette seconde solution est beaucoup plus complexe maintenir et mettre en place.
10.3.2. Compilation
La plupart des cycles de vie rattachent le goal compile du plugin Compiler la phase compile. Cette phase appelle compile:compile qui est configur pour compiler tout le code source et copier le bytecode dans le rpertoire destination du build. Si vous n'avez pas personnalis les valeurs dfinies dans le Super POM, compile:compile compilera toutes les sources du rpertoire src/main/java dans target/classes. Le plugin Compiler appelle javac et utilise les paramtrages par dfaut : 1.3 pour le code source, et 1.1 pour le bytecode produit. Autrement dit, le plugin Compiler prsume que le code source de votre projet est conforme Java 1.3 et qu'il doit tourner sur une JVM Java 1.1. Si vous voulez modifier ce paramtrage, vous devez fournir la configuration suivante du plugin Compiler dans le POM de votre projet. Exemple 10.9. Modifier les versions du code source et du bytecode pour le plugin Compiler
<project> ... <build> ... <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> ... </build> ... </project>
Notez que nous avons configur le plugin Compiler, pas le goal compile:compile. Si nous voulions configurer le source et le bytecode gnr juste pour le goal compile:compile, nous aurions plac la balise configuration sous la balise execution du goal compile:compile. Nous avons effectu
198
cette configuration au niveau du plugin, car compile:compile n'est pas le seul goal intress par cette configuration. Le plugin Compiler est rutilis pour la compilation des tests via le goal compile:testCompile, cette configuration nous permet donc de faire d'une pierre deux coups. Si vous voulez personnaliser l'emplacement du code source, vous pouvez modifier la configuration du build. Si vous dsirez placer le code source de votre projet dans le rpertoire src/java au lieu du rpertoire src/main/java, et si vous voulez que votre projet soit gnr dans classes au lieu target/classes, vous pouvez toujours modifier la configuration par dfaut du sourceDirectory dfinie dans le Super POM. Exemple 10.10. Modifier le rpertoire du code source par dfaut
<build> ... <sourceDirectory>src/java</sourceDirectory> <outputDirectory>classes</outputDirectory> ... </build>
Avertissement
Alors qu'il pourrait vous sembler ncessaire de configurer Maven pour qu'il utilise votre propre structure de rpertoires, nous n'essayerons jamais assez de vous disuader de modifier la configuration Maven par dfaut. Nous n'essayons pas ici de vous laver le cerveau pour vous forcer utiliser la structure Maven, mais il reste beaucoup simple de suivre quelques conventions pour que tout le monde puisse comprendre rapidement votre projet.
199
testSourceDirectory et testOutputDirectory. Si vous voulez stocker le code source de vos tests dans src-test/ au lieu du rpertoire src/test/java et que vous voulez enregistrer le bytecode dans le rpertoire classes-test/ au lieu target/test-classes, utilisez la configuration suivante.
10.3.5. Tester
La plupart des cycles de vie rattachent le goal test du plugin Surefire leur phase test. Le plugin Surefire est un plugin Maven permettant d'excuter des tests unitaires. Le comportement par dfaut du plugin Surefire est de rechercher toutes les class se terminant par '*Test' dans le rpertoire source des tests, puis de les excuter comme des tests JUnit2. Le plugin Surefire peut galement tre configur pour excuter des tests unitaires TestNG3. Aprs avoir excut la commande mvn test, vous aurez probablement not que le plugin Surefire a produit des rapports d'excution dans le rpertoire target/surefire-reports. Ce rpertoire de rapports contient deux fichiers pour chaque test excut par le plugin : un fichier XML qui contient les informations d'excution du test, un fichier texte qui contient la sortie des tests unitaires. Si un problme est survenu durant la phase de test et qu'un test unitaire a chou, vous pouvez utiliser la sortie standard de Maven et ce rpertoire pour trouver la cause du problme. Ce rpertoire surefire-reports/ est galement utilis durant la gnration du site pour crer un rsum 'facile lire' du rsultat des tests unitaires. Si vous travaillez sur un projet qui contient des tests unitaires qui chouent, mmais que vous voulez tout de mme gnrer votre artefact, vous devez configurer le plugin Surefire pour qu'il poursuive le build mme en cas d'chec. Le comportement par dfaut est d'arrter le build lorsqu'un test unitaire choue. Pour modifier ce comportement, vous devez affecter la proprit testFailureIgnore du plugin Surefire 'true'. Exemple 10.12. Configurez le plugin Surefire pour ignorer les tests en chec
<build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore>
2 3
[Link] [Link]
200
Si vous souhaitez ne pas excuter l'ensemble des tests, vous pouvez excuter la commande suivante :
$ mvn install -[Link]=true
La variable [Link] agit sur les plugins Compiler et Surefire. En prcisant cette variable, vous demandez Maven d'ignorer les tests.
10.3.7. Dploiement
Le goal deploy du plugin Deploy est souvent rattach la phase deploy du cycle de vie. Cette phase est utilise pour dployer un artefact sur un dpt Maven distant. Cela est souvent utilis pour mettre jour un dpt distant quand vous effectuez une release. La procdure de dploiement peut aller d'une simple copie de fichier d'un rpertoire dans un autre, un ensemble complexe de transferts SCP de fichiers en utilisant une cl publique. Les prfrences de dploiement ncessitent souvent des accs un dpt distant, et donc, elles sont souvent stockes hors du fichier [Link]. Ces prfrences se retrouvent donc souvent dans un fichier propre chaque utilisateur : ~/.m2/[Link]. Tout ce que vous avez besoin de savoir pour le moment est que le goal deploy:deploy est rattach la phase deploy et qu'il permet le transfert d'un artefact sur un dpt de publication et la mise jour des informations d'un dpt qui peuvent tre affectes par un tel dploiement.
201
Quand un dveloppeur rcupre le code source d'un projet non-portable, il n'est pas en mesure de construire le projet sans remanier une grosse partie du script de build. [Link]. Portabilit sur l'environnement Un build est qualifi de portable d'un environnement l'autre s'il possde un mcanisme pour personnaliser son comportement et sa configuration en fonction de l'environnement. Par exemple, un projet qui contient une rfrence une base de donnes de test dans un environnement de test et une base de donnes de production dans un environnement de production, est portable sur ces deux environnements. Il est probable que ce build ait diffrentes proprits pour chaque environnement. Quand vous changez pour un environnement qui n'est pas dfini et qui ne possde pas de profil associ, le projet ne fonctionnera pas. Donc un projet n'est portable que sur des environnements bien dfinis. Quand un nouveau dveloppeur rcupre le code source d'un projet dpendant de l'environnement, il devra excuter le build dans cet environnement ou crer l'environnement adquat pour russir construire le projet. [Link]. Portabilit interne une organisation Le point clef de cet environnement est que seuls quelques-uns ont accs des ressources internes l'organisation, comme le gestionnaire de configuration ou le dpt interne Maven. Un projet dans une grande entreprise peut dpendre de la prsence d'une base de donnes accessible uniquement pour les dveloppeurs internes. Un projet Open Source peut exiger un certain niveau de droits pour pouvoir publier le site web et les artefacts produits sur un dpt public. Si vous essayez de construire un projet interne hors du rseau interne de l'entreprise (par exemple de l'autre ct du firewall), le build va chouer. Il se peut que cela vienne de plugins propres l'entreprise qui ne sont pas disponibles ou de dpendances du projet inaccessibles car vous n'avez pas les droits ncessaires pour accder au dpt distant d'entreprise. Un tel projet n'est portable que sur les environnements au sein d'une organisation. [Link]. Vritable Portabilit (Universelle) Tout le monde peut tlcharger le code source d'un projet vritablement portable, le compiler et l'installer sans avoir configurer le build pour son environnement spcifique. C'est le plus haut niveau de portabilit ; aucun travail supplmentaire n'est ncessaire pour construire ce projet. Ce niveau de portabilit est important surtout pour les projets libres qui dpendent de la facilit avec laquelle les contributeurs potentiels vont pouvoir construire le projet partir du code source tlcharg. N'importe quel dveloppeur peut tlcharger le code source d'un projet vritablement portable.
204
est trs difficile d'introduire de nouvelles dpendances ou des changements sans se coordonner avec la personne qui gre ce build non-portable. Ces builds non-portables ont tendances se dvelopper dans des environnements trs politiques o une personne ou un groupe veut contrler quand et comment un projet est construit et dploy. "Comment construit-on le systme ? Oh, nous devons appeler Jack et lui demander de nous le construire, personne d'autre ne peut dployer en production". C'est une situation prilleuse qui est beaucoup plus frquente qu'on ne le pense. Si vous travaillez dans cette organisation, Maven et les profils Maven sont votre porte de sortie. l'autre bout du spectre de la portabilit se trouvent les builds trs portables. Ces builds sont des builds trs difficiles raliser. Ils restreignent vos dpendances aux projets et aux outils qui sont librement distribuables et facilement accessibles. De nombreux packages commerciaux doivent tre exclus des builds les plus portables car ils ne peuvent tre tlchargs sans que vous n'ayez accepter une licence spcifique. Cette large portabilit va galement restreindre les dpendances aux logiciels qui sont distribus sous la forme d'artefacts Maven. Par exemple, si vous dpendez des pilotes JDBC d'Oracle, vos utilisateurs devront les tlcharger et les installer manuellement ; ce n'est pas trs portable car vous devrez fournir les instructions ncessaires pour configurer l'environnement afin que les personnes intresses puissent construire votre application. D'un autre ct, vous pourriez utiliser un pilote JDBC disponible sur le dpt public de Maven comme MySQL ou HSQLDB. Comme nous l'avons vu prcdemment, les projets libres ont intrt avoir des builds le plus portable possible. Les builds trs portables rduisent le cot de contribution d'un projet. Dans un projet libre (comme Maven), on trouve deux groupes d'utilisateurs trs distincts : les dveloppeurs et les utilisateurs finaux. Quand un utilisateur final utilise Maven et qu'il dcide de contribuer en proposant un patch Maven, d'utilisateur du produit final d'un build, il doit devenir capable de construire ce produit par luimme. Il doit donc tout d'abord se transformer en dveloppeur, mais il risque de perdre de sa motivation contribuer au projet s'il dpese trop d'negie apprendre le construire. Avec un projet trs portable, un utilisateur n'a pas connatre les arcanes du build d'un projet pour se transformer en dveloppeur, il peut tlcharger le code source, le modifier, construire son artefact et proposer sa contribution sans avoir demander de l'aide pour configurer son environnement. Plus le cot d'entre pour contribuer un projet libre est bas et plus le nombre de contributions augmente, surtout ces petites contributions qui font la diffrence pour la russite d'un projet. Une des consquences de l'adoption de Maven par un grand nombre de projets Open Source est que contribuer ces projets est devenu beaucoup plus facile.
205
xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>simple</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>simple</name> <url>[Link] <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <profiles> <profile> <id>production</id> <build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <debug>false</debug> <optimize>true</optimize> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>
Dans cet exemple, nous avons ajout un profil nomm production pour surcharger la configuration par dfaut du plugin Maven Compiler. Examinons la syntaxe de ce profil en dtail. L'lment profiles est dans le [Link], il contient un ou plusieurs lments profile. Puisque les profils crasent les paramtres par dfaut du [Link], l'lment profiles est habituellement positionn en fin de [Link]. Chaque profil doit avoir un lment id. Cette balise id contient le nom qui est utilis pour invoquer ce profil en ligne de commande. Un profil est invoqu en passant l'argument -P<profile_id> la ligne de commande Maven. Un lment profile peut contenir de nombreux lments prsents dans l'lment project d'un POM. Dans cet exemple, nous surchargeons le comportement du plugin Compiler et nous devons craser la configuration du plugin qui se trouve normalement dans l'lment build/plugins.
206
Nous surchargeons la configuration du plugin Maven Compiler. Nous nous assurons que le bytecode produit par le profil de production ne contient pas les informations de dbogage et qu'il a t optimis par le compilateur. Pour excuter la commande mvn install avec le profil de production, vous devez passer l'argument -Pproduction en ligne de commande. Pour vrifier que le profil de production surcharge la configuration par dfaut du plugin Compiler, excutez Maven avec les options de debug (-X) actives :
~/examples/profile $ mvn clean install -Pproduction -X ... (omitting debugging output) ... [DEBUG] Configuring mojo '[Link]:maven-compiler-plugin:2.0.2:testCompile' [DEBUG] (f) basedir = ~\examples\profile [DEBUG] (f) buildDirectory = ~\examples\profile\target ... [DEBUG] (f) compilerId = javac [DEBUG] (f) debug = false [DEBUG] (f) failOnError = true [DEBUG] (f) fork = false [DEBUG] (f) optimize = true [DEBUG] (f) outputDirectory = \ ~\svnw\sonatype\examples\profile\target\test-classes [DEBUG] (f) outputFileName = simple-1.0-SNAPSHOT [DEBUG] (f) showDeprecation = false [DEBUG] (f) showWarnings = false [DEBUG] (f) staleMillis = 0 [DEBUG] (f) verbose = false [DEBUG] -- end configuration -... (omitting debugging output) ...
Cet extrait de la sortie en mode debug de Maven nous montre la configuration du plugin Compiler avec le profil de production. Comme nous pouvons le voir, la variable debug est false et la variable optimize est true.
207
<build> <defaultGoal>...</defaultGoal> <finalName>...</finalName> <resources>...</resources> <testResources>...</testResources> <plugins>...</plugins> </build> <reporting>...</reporting> <modules>...</modules> <dependencies>...</dependencies> <dependencyManagement>...</dependencyManagement> <distributionManagement>...</distributionManagement> <repositories>...</repositories> <pluginRepositories>...</pluginRepositories> <properties>...</properties> </profile> </profiles> </project>
Un profil peut donc redfinir tous ces lments. Il peut redfinir le nom de l'artefact final, les dpendances et le build d'un projet en surchargeant la configuration des plugins. Un profil peut aussi redfinir les paramtres de distribution. Par exemple, si pour une tape de validation vous devez publier vos artefacts sur un serveur de pr-production, vous allez crer un profil de validation qui va surcharger la balise distributionManagement.
[Link]
208
exclure le projet simple-script du build. Si vous n'excluez pas le projet simple-script de votre build en Java 5, celui-ci va chouer car Java 5 ne fournit pas la classe ScriptEngine. tudions plus en dtail le fichier [Link] du projet de bibliothque : Exemple 11.3. Inclusion dynamique de sous-modules par activation de profil
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>simple</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>simple</name> <url>[Link] <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <profiles> <profile> <id>jdk16</id> <activation> <jdk>1.6</jdk> </activation> <modules> <module>simple-script</module> </modules> </profile> </profiles> </project>
Si vous excutez la commande mvn install en Java 6, vous vous apercevrez que Maven descend dans le sous-rpertoire simple-script pour y construire le projet simple-script. Si vous excutez la mme commande mvn install en Java 5, le build n'essayera pas de construire le sous-module simple-script. Analysons cette configuration d'activation en dtail : La balise activation indique les conditions d'activation du profil. Dans cet exemple, nous avons indiqu que ce profil sera activ pour les versions de Java partir de Java "1.6". Ce qui inclut donc "1.6.0_03", "1.6.0_02" ou tout autre version commenant par "1.6". Les conditions d'activation ne sont pas limites la version de Java, pour une liste complte des paramtres d'activation rendezvous la section Configuration de l'activation. Nous ajoutons le module simple-script dans ce profil. L'ajout de ce module fait que Maven va aller regarder dans le sous-rpertoire simple-script/ la recherche d'un fichier [Link].
209
L'exemple prcdent dfinit un ensemble trs prcis de paramtres d'activation. Regardons chacun d'entre eux plus en dtail : La balise activeByDefault contrle si ce profil est actif par dfaut. Ce profil n'est actif que pour les versions du JDK commenant par "1.5". Ce qui inclut "1.5.0_01" et "1.5.1".
210
Ce profil cible aussi une version trs spcifique de Windows XP, la version 5.1.2600 sur une plateforme 32-bit. Si votre projet utilise le plugin natif pour compiler du code en C, vous risquez de vous retrouver crire plusieurs projets suivant les plateformes. La balise property indique Maven qu'il doit activer ce profil si la proprit mavenVersion a pour valeur 2.0.5. La proprit mavenVersion est une proprit implicite qui est disponible pour tous les builds Maven. La balise file nous permet d'activer un profil sur la prsence (ou l'absence) d'un fichier. Le profil dev sera activ si un fichier [Link] existe la racine du projet. Le profil dev ne sera activ que s'il n'existe pas de fichier [Link] la racine du projet.
Attention au point d'exclamation qui prfixe le nom de la proprit. Le point d'exclamation est souvent appel le caractre "bang" ce qui signifie "non". Ce profil est activ quand aucune proprit ${[Link]} n'est dfinie.
211
l'ensemble des profils actifs et o ils sont dfinis. Voici les instructions pour excuter le goal activeprofiles :
$ mvn help:active-profiles Active Profiles for Project 'My Project': The following profiles are active: - my-settings-profile (source: [Link]) - my-external-profile (source: [Link]) - my-internal-profile (source: [Link])
212
Lorsque vous excutez Maven sur votre poste avec cette configuration, ce profil sera activ et la proprit [Link] aura pour valeur dev. Vous pouvez utiliser cette proprit pour activer les profils dfinis dans le fichier [Link] d'un projet comme nous allons le voir. Regardons donc, comment le fichier [Link] dfinirait un profil qui serait activ par le fait que la proprit [Link] ait pour valeur dev. Exemple 11.7. Profil d'un projet activ quand [Link] vaut 'dev'
<project> ... <profiles> <profile> <id>development</id> <activation> <property> <name>[Link]</name> <value>dev</value> </property> </activation> <properties> <[Link]>[Link]</[Link]> <[Link]> jdbc:mysql://localhost:3306/app_dev </[Link]> <[Link]>development_user</[Link]> <[Link]>development_password</[Link]> </properties> </profile> <profile> <id>production</id> <activation> <property> <name>[Link]</name> <value>prod</value> </property> </activation> <properties> <[Link]>[Link]</[Link]> <[Link]>jdbc:mysql://master01:3306,slave01:3306/app_prod</[Link]> <[Link]>prod_user</[Link]> </properties> </profile> </profiles> </project>
213
Ce projet dfinit de nouvelles proprits comme [Link] et [Link] qui pourraient tre utilises pour configurer un plugin Maven ailleurs dans le fichier [Link]. Il existe de nombreux plugins qui peuvent manipuler une base de donnes, excuter du SQL, ou comme le plugin Maven Hibernate3, peuvent gnrer un ensemble d'objets annots utiliss par les frameworks de persistance. Certains de ces plugins peuvent tre configurs dans un fichier [Link] grce ces proprits. Ces proprits peuvent aussi tre utilises pour filtrer des ressources. Dans cet exemple, comme nous avons dfini un profil dans le fichier ~/.m2/[Link] qui spcifie la valeur dev pour [Link], le profil de dveloppement sera toujours actif chaque excution de Maven sur cette machine. Par contre, si nous voulions modifier ce comportement par dfaut, nous pourrions prciser la valeur de cette proprit en ligne de commande. Si nous avons besoin d'activer le profil de production, nous pourrions excuter Maven avec la commande :
~/examples/profiles $ mvn install -[Link]=prod
Spcifier une proprit en ligne de commande surchargera la valeur par dfaut dfinie dans le fichier ~/.m2/[Link]. Nous aurions pu aussi dfinir un profil avec un id "dev" et l'invoquer directement avec l'argument -P en ligne de commande, mais l'utilisation de cette proprit [Link] nous permet d'crire de nouveaux fichiers [Link] en respectant ce standard. Tous vos projets pourraient possder un profil qui serait activ par la mme proprit [Link] dfinie dans les fichiers ~/.m2/[Link] de chaque dveloppeur. Ainsi, les dveloppeurs peuvent partager une configuration commune pour le dveloppement sans avoir la dfinir dans des fichiers [Link] non-portables.
214
Cet utilisateur a dfini un profil par dfaut qui donne [Link] la valeur prod et qui spcifie le mot de passe de production. Quand le build du projet est excut, le profil de production est activ par la proprit [Link] et la proprit [Link] est remplie. Ainsi, vous pouvez mettre toute la configuration spcifique la production dans le fichier [Link] du projet et retirer seulement le mot de passe ncessaire pour accder la base de donnes de production.
Note
Ces informations prives sont en gnral contraires la portabilit, mais ce que nous venons de faire a du sens. Vous ne voudriez pas partager vos secrets avec n'importe qui.
215
<classifier>win</classifier> </configuration> </plugin> </plugins> </build> </profile> <profile> <id>linux</id> <activation> <os> <family>unix</family> </os> </activation> <build> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> <classifier>linux</classifier> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>
Si le systme d'exploitation fait partie de la famille Windows, ce fichier [Link] qualifie l'artefact Jar avec "-win". Si le systme d'exploitation est un membre de la famille Unix, l'artefact est qualifi avec "-linux". Ce fichier [Link] permet donc d'ajouter des classificateurs aux artefacts, mais il est plus verbeux que ncessaire, car il recopie la configuration du plugin Maven Jar dans les deux profils. Cet exemple pourrrait tre rcrit en utilisant des variables pour rduire la redondance : Exemple 11.10. Qualification des artefacts avec des profils activs selon la plateforme d'excution et en utilisant des variables
<project> ... <build> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> <classifier>${envClassifier}</classifier> </configuration> </plugin> </plugins> </build> ... <profiles> <profile>
216
<id>windows</id> <activation> <os> <family>windows</family> </os> </activation> <properties> <envClassifier>win</envClassifier> </properties> </profile> <profile> <id>linux</id> <activation> <os> <family>unix</family> </os> </activation> <properties> <envClassifier>linux</envClassifier> </properties> </profile> </profiles> </project>
Dans ce fichier [Link], chaque profil n'a pas besoin d'inclure une balise build pour configurer le plugin Jar. Au lieu de cela, le profil est activ par la famille laquelle appartient le systme d'exploitation, et valorise la proprit envClassifier soit win soit linux. Cette proprit envClassifier est rfrence dans la balise build du fichier [Link] pour ajouter un classificateur l'artefact JAR produit par le projet. Ainsi l'artefact JAR produit s'appellera ${finalName}${envClassifier}.jar et sera utilis comme dpendance grce la syntaxe suivante : Exemple 11.11. Dpendance vers un artefact qualifi
<dependency> <groupId>[Link]</groupId> <artifactId>my-project</artifactId> <version>1.0</version> <classifier>linux</classifier> </dependency>
11.6. En rsum
Lorsqu'ils sont utiliss judicieusement, les profils facilitent grandement la configuration du build pour diffrentes plateformes. Si quelque part dans votre build vous avez besoin de dfinir un chemin spcifique une plateforme pour un serveur d'applications, vous pouvez mettre ces lments de configuration dans un profil qui sera activ selon la nature de votre systme d'exploitation. Si vous avez un projet qui doit produire diffrents artefacts pour diffrents environnements, vous pouvez personnaliser le comportement du build selon les diffrents environnements et plateformes par des
217
profils spcifiques ceux-ci. L'utilisation de profils permet de rendre les builds portables, il n'est plus ncessaire de rcrire votre logique de construction pour l'adapter un nouvel environnement. Surchargez la configuration qui doit tre modifie et partagez celle qui peut l'tre.
218
Les proprits dfinies sur la ligne de commande sont disponibles dans le POM Maven ou pour un plugin Maven. Pour plus d'informations sur le rfrencement des proprits Maven, lisez le Chapitre 15, Proprits et filtrage des ressources. Les proprits peuvent aussi tre utilises pour activer des profils de build. Pour plus d'informations sur les profils de build Maven, lisez le Chapitre 11, Profils de Build.
-amd,--also-make-dependents
-B,--batch-mode -C,--strict-checksums -c,--lax-checksums -cpu,--check-plugin-updates -D,--define <arg> -e,--errors -emp,--encrypt-master-password <arg> -ep,--encrypt-password <arg> -f,--file -fae,--fail-at-end
-npu,--no-plugin-updates -o,--offline -P,--activate-profiles <arg> -pl,--projects <arg> -q,--quiet -r,--reactor -rf,--resume-from <arg> -s,--settings <arg> -U,--update-snapshots
If project list is specified, also build projects that depend on projects on the list Run in non-interactive (batch) mode Fail the build if checksums don't match Warn if checksums don't match Force upToDate check for any relevant registered plugins Define a system property Produce execution error messages Encrypt master security password Encrypt server password Force the use of an alternate POM file. Only fail the build afterwards; allow all non-impacted builds to continue Stop at first failure in reactorized builds NEVER fail the build, regardless of project result Alternate path for the global settings file Display help information Do not recurse into sub-projects Don't use ~/.m2/[Link] for plugin versions Suppress upToDate check for any relevant registered plugins Work offline Comma-delimited list of profiles to activate Build specified reactor projects instead of all projects Quiet output - only show errors Dynamically build reactor from subdirectories Resume reactor from specified project Alternate path for the user settings file Forces a check for updated releases and snapshots on remote repositories Synonym for cpu Display version information WITHOUT stopping build Display version information Produce execution debug output
220
Si vous voulez de l'aide sur les goals et les paramtres disponibles pour un plugin Maven spcifique, allez la Section 12.3, Usage du plugin Maven Help .
221
222
223
-U, --update-snapshots Force la recherche de mises jour de versions stables et snapshots sur les dpts distants Si pour vous la scurit est importante, utilisez l'option -C l'excution de Maven. Les dpts Maven possdent un checksum MD5 et SHA1 pour chaque artefact stock. Maven est configur pour avertir l'utilisateur final lorsque le checksum ne correspond pas l'artefact tlcharg. L'utilisation de l'option -C fera chouer le build si Maven rencontre un artefact avec un mauvais checksum. L'option -U est trs utile lorsque vous voulez vous assurer que Maven vrifie qu'il utilise bien les dernires versions stables et SNAPSHOT des dpendances.
224
Avec cette option Maven excutera un goal ou une tape du cycle de vie du projet dans le rpertoire courant. Maven n'essayera pas de construire tous les projets d'un build multimodule quand vous utilisez l'option -N.
Ainsi, simple-model ne sera pas reconstruit et le build reprendra l o nous l'avions laiss dans simple-weather. Si simple-weather est construit avec succs, Maven poursuivra et construira les autres projets.
225
Seuls ces deux projets seront construits, ce qui nous vitera d'avoir excuter Maven sparment dans chaque rpertoire.
Lorsque nous utilisons --also-make, Maven va examiner la liste de projets (ici, uniquement simplecommand) et va descendre dans l'arbre des dpendances la recherche des projets qu'il va devoir construire. Dans ce cas, il va automatiquement construire simple-model, simple-weather et simple-persist mais sans construire simple-webapp.
12.2.4. Modifier simple-weather et vrifier que nous n'avons rien cass grce --also-make-dependents
Supposons que nous ayons modifi simple-weather. Nous voulons nous assurer que nous n'avons cass aucun des projets qui en dpendent. (Dans ce cas-ci, nous voulons nous assurer que nous n'avons pas cass simple-command et simple-webapp, mais dans un Reactor plus complexe cela ne serait pas si vident.) Nous voulons aussi viter d'avoir reconstruire et tester les projets dont nous savons qu'ils n'ont pas chang. Dans ce cas-ci, nous voulons viter de construire simple-persist. Nous pouvons utiliser --also-make-dependents ainsi :
$ mvn --projects simple-weather --also-make-dependents install
Quand nous utilisons --also-make-dependents, Maven va examiner tous les projets de notre reactor pour trouver ceux qui dpendent de simple-weather et va automatiquement construire ceux-ci et aucun autre. Dans notre cas, il va automatiquement construire simple-weather puis simple-command et simple-webapp.
226
Note
Pour une vision plus conceptuelle du POM et des plugins, lisez le Chapitre 3, Mon premier projet avec Maven. Le plugin Maven Help a quatre goals. Les trois premiers goals active-profiles, effectivepom et effective-settings dcrivent un projet particulier et doivent tre excuts depuis le rpertoire racine d'un projet. Le dernier goal describe est un peu plus complexe, il affiche des informations sur un plugin ou le goal d'un plugin. Voici des informations gnrales sur ces quatre goals : help:active-profiles Liste les profils (du projet, de l'utilisateur, globaux) qui sont actifs pour le build courant. help:effective-pom Affiche le POM effectif pour le build en cours, en prenant en compte les profils activs. help:effective-settings Affiche la configuration calcule des settings pour le projet, en prenant en compte la configuration de l'utilisateur et les modifications apportes par les profils actifs. help:describe Dcrit les attributs d'un plugin. Il n'est pas ncessaire de l'excuter dans le rpertoire d'un projet. Vous devez fournir au moins le groupId et le artifactId du plugin dont vous voulez la description.
227
... Group Id: [Link] Artifact Id: maven-help-plugin Version: 2.0.1 Goal Prefix: help Description: The Maven Help plugin provides goals aimed at helping to make sense out of the build environment. It includes the ability to view the effective POM and settings files, after inheritance and active profiles have been applied, as well as a describe a particular plugin goal to give usage information. ...
L'excution du goal describe en passant le paramtre plugin a affich les coordonnes Maven du plugin, le prfixe du goal et une description succincte du plugin. Mme si ces informations sont utiles, la plupart du temps on voudra en savoir un peu plus. Pour afficher la liste des goals avec leurs paramtres grce au plugin Help, il faut excuter le goal help:describe avec le paramtre full comme cidessous :
$ mvn help:describe -Dplugin=help -Dfull ... Group Id: [Link] Artifact Id: maven-help-plugin Version: 2.0.1 Goal Prefix: help Description: The Maven Help plugin provides goals aimed at helping to make sense out of the build environment. It includes the ability to view the effective POM and settings files, after inheritance and active profiles have been applied, as well as a describe a particular plugin goal to give usage information. Mojos: =============================================== Goal: 'active-profiles' =============================================== Description: Lists the profiles which are currently active for this build. Implementation: [Link] Language: java Parameters: ----------------------------------------------[0] Name: output Type: [Link] Required: false Directly editable: true Description:
228
This is an optional parameter for a file destination for the output of this mojo...the listing of active profiles per project. ----------------------------------------------[1] Name: projects Type: [Link] Required: true Directly editable: false Description: This is the list of projects currently slated to be built by Maven. ----------------------------------------------This mojo doesn't have any component requirements. =============================================== ... removed the other goals ...
Cette option est fort utile pour dcouvrir un plugin, tous ses goals et leurs paramtres. Mais parfois on veut encore plus d'informations. Pour obtenir les informations sur un unique goal, renseignez le paramtre mojo en plus du paramtre plugin. La commande suivante liste l'ensemble des informations sur le goal compile du plugin Compiler.
$ mvn help:describe -Dplugin=compiler -Dmojo=compile -Dfull
229
Pour plus d'informations sur les paramtres de configuration disponibles, utilisez cette mme commande en y ajoutant l'argument -Ddetail :
$ mvn help:describe -Dcmd=compiler:compile -Ddetail [INFO] [help:describe {execution: default-cli}] [INFO] 'compiler:compile' is a plugin goal (aka mojo). Mojo: 'compiler:compile' compiler:compile Description: Compiles application sources Deprecated. No reason given Implementation: [Link] Language: java Bound to phase: compile Available parameters: compilerArgument Sets the unformatted argument string to be passed to the compiler if fork is set to true. This is because the list of valid arguments passed to a Java compiler
varies based on the compiler version. Deprecated. No reason given compilerArguments Sets the arguments to be passed to the compiler (prepending a dash) if fork is set to true. This is because the list of valid arguments passed to a Java compiler varies based on the compiler version. Deprecated. No reason given compilerId (Default: javac) The compiler id of the compiler to use. See this guide for more information. Deprecated. No reason given compilerVersion Version of the compiler to use, ex. '1.3', '1.5', if fork is set to true. Deprecated. No reason given debug (Default: true) Set to true to include debugging information in the compiled class files. Deprecated. No reason given encoding The -encoding argument for the Java compiler. Deprecated. No reason given excludes A list of exclusion filters for the compiler. Deprecated. No reason given executable Sets the executable of the compiler to use when fork is true. Deprecated. No reason given failOnError (Default: true) Indicates whether the build will continue even if there are compilation errors; defaults to true. Deprecated. No reason given fork (Default: false) Allows running the compiler in a separate process. If 'false' it uses the built in compiler, while if 'true' it will use an executable. Deprecated. No reason given includes A list of inclusion filters for the compiler. Deprecated. No reason given maxmem Sets the maximum size, in megabytes, of the memory allocation pool, ex. '128', '128m' if fork is set to true. Deprecated. No reason given
232
meminitial Initial size, in megabytes, of the memory allocation pool, ex. '64', '64m' if fork is set to true. Deprecated. No reason given optimize (Default: false) Set to true to optimize the compiled code using the compiler's optimization methods. Deprecated. No reason given outputFileName Sets the name of the output file when compiling a set of sources to a single file. Deprecated. No reason given showDeprecation (Default: false) Sets whether to show source locations where deprecated APIs are used. Deprecated. No reason given showWarnings (Default: false) Set to true to show compilation warnings. Deprecated. No reason given source The -source argument for the Java compiler. Deprecated. No reason given staleMillis (Default: 0) Sets the granularity in milliseconds of the last modification date for testing whether a source needs recompilation. Deprecated. No reason given target The -target argument for the Java compiler. Deprecated. No reason given verbose (Default: false) Set to true to show messages about what the compiler is doing. Deprecated. No reason given
Si vous dsirez rcuprer la liste des goals d'un plugin, vous pouvez excuter le goal help:describe et lui passer un paramtre. Ce paramtre accepte soit un prfixe de plugin soit un groupId et un artifactId comme le montrent les exemples suivants :
$ mvn help:describe -Dplugin=compiler [INFO] [help:describe {execution: default-cli}] [INFO] [Link]:maven-compiler-plugin:2.0.2 Name: Maven Compiler Plugin Description: Maven Plugins Group Id: [Link] Artifact Id: maven-compiler-plugin Version: 2.0.2 Goal Prefix: compiler
233
This plugin has 2 goals: compiler:compile Description: Compiles application sources Deprecated. No reason given compiler:testCompile Description: Compiles application test sources Deprecated. No reason given
Vous pouvez utiliser le groupId et l'artifactId du plugin pour obtenir la mme liste de goals.
$ mvn help:describe -Dplugin=[Link]:maven-compiler-plugin
En passant l'argument -Ddetail au goal help:describe, vous demandez Maven d'afficher tous les goals d'un plugin avec tous leurs paramtres.
234
235
</plugin>
13.1.5. Configuration des paramtres par dfaut pour une excution en ligne de commande
Depuis Maven 2.2.0, vous pouvez fournir des paramtres de configuration pour les goals qui sont excuts partir de la ligne de commande. Pour cela, utilisez un id spcial pour l'excution, defaultcli. L'Exemple 13.4, Configuration d'un plugin pour une excution en ligne de commande montre comment rattacher un goal la phase package du cycle de vie qui produit le binaire. Cet exemple configure galement l'excution default-cli du plugin Assembly pour qu'il utilise le descripteur jar-with-dependencies. Le descripteur [Link] sera utilis durant le cycle de vie, et jar-withdependencies sera utilis lors de l'excution de la commande mvn assembly:assembly partir de la console. Exemple 13.4. Configuration d'un plugin pour une excution en ligne de commande
<plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <appendAssemblyId>false</appendAssemblyId> </configuration> <executions> <execution> <id>assemble-binary</id> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <descriptors> <descriptor>src/main/assembly/[Link]</descriptor> </descriptors> </configuration> </execution> <execution> <id>default-cli</id> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin>
13.1.6. Configuration des paramtres pour les goals rattachs au cycle de vie par dfaut
Depuis Maven 2.2.0, si vous dsirez personnaliser le comportement d'un goal qui est dj rattach au cycle de vie par dfaut, vous pouvez utiliser un id spcial pour l'excution, "default-<goal>". Ainsi,
236
vous pouvez par exemple personnaliser le comportement du goal jar du plugin Jar qui est rattach la phase package du cycle de vie par dfaut. Vous pouvez personnaliser les paramtres de configuration d'une excution comme le prsente l'Exemple 13.5, Configuration d'un paramtre pour l'excution d'un goal par dfaut . Exemple 13.5. Configuration d'un paramtre pour l'excution d'un goal par dfaut
<plugin> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <id>default-jar</id> <configuration> <excludes> <exclude>**/somepackage/*</exclude> </excludes> </configuration> </execution> <execution> <id>special-jar</id> <phase>package</phase> <goals> <goal>jar</goal> </goals> <configuration> <includes> <include>**/sompackage/*</include> </includes> <classifier>somepackage</classifier> </configuration> </execution> </executions> </plugin>
Dans cet exemple, le goal par dfaut jar est configur pour exclure le contenu d'un certain package. Un autre goal, jar, est rattach la phase package pour crer un fichier JAR qui contient seulement le contenu d'un package spcifique. Configurer les paramtres des goals par dfaut peut aussi tre intressant si vous avez besoin de configurer deux goals avec des valeurs de configuration diffrentes pour certains paramtres. L'Exemple 13.6, Configurer deux paramtres d'un goal d'un plugin montre comment configurer le goal resources:resources pour qu'il ne tienne pas compte des rpertoires vides tout en configurant le goal resources:testResources pour qu'il les prenne en compte. Exemple 13.6. Configurer deux paramtres d'un goal d'un plugin
<plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>default-resources</id>
237
<configuration> <includeEmptyDirs>false</includeEmptyDirs> </configuration> </execution> <execution> <id>default-testResources</id> <configuration> <includeEmptyDirs>true</includeEmptyDirs> </configuration> </execution> </executions> </plugin>
238
[Link]
qu'on ne les utilise pas de la mme manire. Le goal assembly:assembly est conu pour tre invoqu directement depuis la ligne de commande et il ne doit jamais tre li une phase du cycle de vie. Au contraire, le mojo single est lui conu pour faire partie de votre build de tous les jours et doit tre rattach une phase du cycle de vie du build de votre projet. La raison de cette diffrence est que le goal assembly:assembly est ce que Maven appelle un mojo agrgateur ; c'est dire un mojo qui a t conu pour tre excut au plus une fois dans un build, quelque soit le nombre de projets qui sont construits. Il tire sa configuration du projet racine - habituellement le POM de plus haut niveau ou la ligne de commande. Quand il est rattach un cycle de vie, un mojo agrgateur peut provoquer de dsagrables effets secondaires. Il peut forcer l'excution de la phase package du cycle de vie en avance de phase, ce qui fait que le build excute cette phase package deux fois. Comme le goal assembly:assembly est un mojo agrgateur, cela peut poser des problmes avec les builds Maven multimodules et il doit donc tre appel seul en ligne de commande. Ne rattachez jamais l'excution de assembly:assembly une phase du cycle de vie. assembly:assembly tait le goal originel du plugin Assembly et il n'a jamais t conu pour faire partie du processus de build standard d'un projet. Quand il est devenu vident que les archives produites par assembly taient une exigence lgitime des projets, le mojo single a t dvelopp. Ce mojo suppose qu'il a t rattach la bonne partie du processus de build et que, donc, il aura accs aux fichiers et artefacts du projet dont il a besoin pour s'excuter au sein d'un grand projet Maven multimodule. Dans un environnement multimodule, il s'excutera autant de fois qu'il est li aux POMs des diffrents modules. Contrairement assembly:assembly, single ne forcera jamais l'excution d'une tape du cycle de vie en avance de phase. Le plugin Assembly propose plusieurs autres goals en plus de ces deux l. Cependant, le dtail de ces autres mojos dpasse le cadre de ce chapitre, car ils servent pour des cas d'utilisation obsoltes ou exotiques : on a trs rarement besoin d'eux. Autant que possible, pour produire vos packages utilisez assembly:assembly depuis la ligne de commande et single pour rattacher cette opration aux phases du cycle de vie.
Le descripteur bin est utilis pour packager les fichiers LICENSE, README et NOTICE du projet avec son artefact principal, pour peu que ce dernier soit un jar. Vous pouvez voir cela comme la plus petite distribution binaire pour un projet autosuffisant.
240
jar-with-dependencies Le descripteur jar-with-dependencies construit une archive JAR avec le contenu du jar
du projet principal et les contenus des dpendances d'excution de ce projet. Associ avec la bonne dfinition de la Main-Class dans le fichier Manifest (dont on parle dans Configuration du Plugin ci-dessous), ce descripteur permet de produire un jar excutable autosuffisant votre projet, mme si ce dernier possde des dpendances.
project
Le descripteur project construit une archive partir de la structure de rpertoire du projet telle qu'elle existe sur votre systme de fichier, et probablement dans votre outil de gestion de configuration. Bien sr, le rpertoire target n'est pas pris en compte ainsi que les fichiers de mtadonnes comme les rpertoires CVS et .svn que nous avons l'habitude de voir. En bref, le but de ce descripteur est de crer une archive du projet qui, une fois dcompresse, permet de construire le projet avec Maven.
src
Le descripteur src produit une archive du code source de votre projet avec les fichiers [Link], ainsi que les ventuels fichiers LICENSE, README et NOTICE qui se trouvent dans le rpertoire racine du projet. Ce descripteur produit une archive qui peut tre construite par Maven dans la plupart des cas. Cependant, il suppose que tout le code source et les ressources soient dans le rpertoire standard src et donc, qu'il peut oublier les fichiers et les rpertoires non-standards mme s'ils sont critiques pour le build.
241
Imaginez que vous voulez produire un JAR excutable partir de votre projet. Si votre projet est autosuffisant et sans dpendance, vous pouvez obtenir ce rsultat partir de votre artefact avec un peu de configuration du plugin JAR. Cependant, la plupart des projets ont des dpendances et celles-ci doivent tre incorpores pour obtenir un JAR excutable. Dans ce cas, vous voulez vous assurer qu' chaque fois que vous installez ou dployez l'artefact JAR de votre projet, le JAR excutable le soit aussi. Supposons que la classe principale de votre projet est [Link], la configuration de POM suivante permet de crer un JAR excutable : Exemple 14.1. Descripteur assembly pour un JAR excutable
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>executable-jar</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>Assemblies Executable Jar Example</name> <url>[Link] <dependencies> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-2</version> <executions> <execution> <id>create-executable-jar</id> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <descriptorRefs> <descriptorRef> jar-with-dependencies </descriptorRef>
242
</descriptorRefs> <archive> <manifest> <mainClass>[Link]</mainClass> </manifest> </archive> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Il y a deux points auxquels il faut prter attention dans la configuration ci-dessus. Premirement, nous utilisons l'lment descriptorRefs dans configuration plutt que le paramtre descriptorId que nous avions utilis prcdemment. Cela nous permet de construire diffrents packages durant la mme excution du plugin Assembly tout en supportant notre cas d'utilisation avec trs peu de configuration supplmentaire. Deuximement, la balise archive sous configuration spcifie l'attribut MainClass du fichier manifest dans le JAR produit. Cette section est gnralement disponible dans les plugins qui crent des fichiers JAR comme le plugin JAR utilis pour le packaging par dfaut des projets. Maintenant, vous pouvez produire un JAR excutable simplement en excutant la commande mvn package. Aprs, nous listerons le contenu du rpertoire target pour vrifier que le JAR excutable a bien t gnr. Enfin, pour prouver qu'il s'agit bien d'un JAR excutable, nous essayerons de l'excuter :
$ mvn package ... (output omitted) ... [INFO] [jar:jar] [INFO] Building jar: ~/mvn-examples-1.0/assemblies/executable-jar/target/\ [Link] [INFO] [assembly:single {execution: create-executable-jar}] [INFO] Processing DependencySet (output=) [INFO] Building jar: ~/mvn-examples-1.0/assemblies/executable-jar/target/\ [Link] ... (output omitted) ... $ ls -1 target ... (output omitted) ... [Link] [Link] ... (output omitted) ... $ java -jar \
target/[Link]
Hello, World!
Des traces prsentes ci-dessus vous pouvez voir que maintenant le build normal du projet produit un nouvel artefact en plus du principal fichier JAR. Ce nouvel artefact a le classifieur jar-withdependencies. Enfin, nous avons vrifi que ce nouveau JAR est rellement excutable et que son excution produit le rsultat attendu : l'affichage de Hello, World!.
243
244
balise pluginManagement qui est dcrite dans l'Exemple 14.2, Configuration de l'assembly du projet dans le POM de plus haut niveau . Exemple 14.2. Configuration de l'assembly du projet dans le POM de plus haut niveau
<project> ... <build> <pluginManagement> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-2</version> <executions> <execution> <id>create-project-bundle</id> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <descriptorRefs> <descriptorRef>project</descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin> </plugins> </pluginManagement> </build> ... </project>
Le POM de chaque projet rfrence le plugin dont la configuration est dcrite dans l'Exemple 14.2, Configuration de l'assembly du projet dans le POM de plus haut niveau par une dclaration minimale dans son build comme le montre l' Exemple 14.3, Activation de la configuration du plugin Assembly dans les projets fils . Exemple 14.3. Activation de la configuration du plugin Assembly dans les projets fils
<build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> </plugin> </plugins> </build>
Pour produire l'ensemble des assemblies du projet, excutez la commande mvn install depuis le rpertoire racine. Vous devriez voir Maven installer les artefacts avec des classifieurs dans votre dpt.
245
$ mvn install ... Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\ second-project/target/[Link] to ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\ [Link] ... Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\ second-project/target/[Link].bz2 to ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\ [Link].bz2 ... Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\ second-project/target/[Link] to ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\\ [Link] ...
Lorsque vous excutez install, Maven va copier l'artefact principal de chaque projet ainsi que chaque assembly dans votre dpt Maven local. Tous ces artefacts sont maintenant disponibles comme dpendance pour d'autres projets localement. Si votre but final est de crer un paquet qui inclut les assemblies de diffrents projets vous pouvez crer un autre projet qui rfrence comme dpendances les assemblies de ces projets. Ce projet chapeau prend la responsabilit de construire l'assembly englobant tous les autres. Le POM de ce projet assembly chapeau ressemblerait au document XML dcrit dans l'Exemple 14.4, POM du projet assembly chapeau . Exemple 14.4. POM du projet assembly chapeau
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>project-bundle</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <name>Assemblies-as-Dependencies Example Project Bundle</name> <url>[Link] <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>first-project</artifactId> <version>1.0-SNAPSHOT</version> <classifier>project</classifier> <type>zip</type> </dependency> <dependency> <groupId>[Link]</groupId> <artifactId>second-project</artifactId> <version>1.0-SNAPSHOT</version> <classifier>project</classifier>
246
<type>zip</type> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-2</version> <executions> <execution> <id>bundle-project-sources</id> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <descriptorRefs> <descriptorRef> jar-with-dependencies </descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Le POM de ce projet assembly chapeau fait rfrence aux assemblies des projets first-project et second-project. Au lieu de rfrencer l'artefact principal de chaque projet, le POM de ce projet assembly spcifie un classifieur project et un type zip. Cela indique Maven qu'il va devoir rsoudre une archive de type ZIP qui a t cre par l'assembly project. Remarquez que le projet assembly produit lui-mme un assembly jar-with-dependencies. L'assembly produit par jarwith-dependencies n'est pas une archive particulirement lgante puisqu'il construit un fichier JAR contenant toutes les dpendances dcompresses. jar-with-dependencies demande Maven de rcuprer toutes les dpendances, de les dcompresser et ensuite de crer une archive unique en y incluant le rsultat du projet courant. Dans ce projet, cela produit un unique fichier JAR qui agrge les contenus des assemblies de first-project et de second-project. Cet exemple illustre comment les capacits de base du plugin Maven Assembly peuvent tre combines sans ncessiter un descripteur d'assembly. Il cre une unique archive qui contient les rpertoires de plusieurs projets les uns ct des autres. Cette fois, le jar-with-dependencies est juste un format de stockage et nous n'avons pas besoin de spcifier l'attribut de manifest Main-Class. Pour construire ce paquet, nous excutons le projet project-bundle comme d'habitude :
$ mvn package ... [INFO] [assembly:single {execution: bundle-project-sources}] [INFO] Processing DependencySet (output=)
247
Pour vrifier que l'assembly project-bundle contient bien les lments dcompresss et combins des assemblies dpendances, excutez la commande jar tf :
$ jar tf \
target/[Link]
... first-project-1.0-SNAPSHOT/[Link] first-project-1.0-SNAPSHOT/src/main/java/org/sonatype/mavenbook/[Link] first-project-1.0-SNAPSHOT/src/test/java/org/sonatype/mavenbook/[Link] ... second-project-1.0-SNAPSHOT/[Link] second-project-1.0-SNAPSHOT/src/main/java/org/sonatype/mavenbook/[Link] second-project-1.0-SNAPSHOT/src/test/java/org/sonatype/mavenbook/[Link]
Maintenant que vous avez lu cette section, son titre devrait avoir un peu plus de sens. Vous avez combin les assemblies de deux projects dans un assembly grce un projet assembly dpendant de chacun de ces assemblies.
248
l'archive finale. C'est dans cette section que vous configurez si les dpendances doivent tre dcompresses, ajoutes directement au rpertoire lib/ ou renommes. Cette section vous permet aussi de contrler quelles dpendances doivent tre ajoutes l'assembly et avec quelles permissions. Informations concernant les dpts Parfois il est utile d'isoler l'ensemble des artefacts ncessaires la construction d'un projet, qu'il s'agisse d'artefacts de dpendance, des POMs des artefacts de dpendance ou mme d'un POM anctre du projet (le POM parent, son parent, etc.). Cette section vous permet d'inclure une ou plusieurs structures de rpertoires de dpt d'artefact dans votre assembly avec diffrentes options de configuration. Le plugin Assembly n'est pas capable d'inclure les artefacts de plugin dans ces dpts pour l'instant. Informations concernant les modules Cette section du descripteur d'assembly vous permet de profiter des relations parent-enfant lors de la construction de votre archive personnalise pour inclure des fichiers de code source, des artefacts et des dpendances des sous-modules de votre projet. C'est la section la plus complexe du descripteur d'assembly car elle vous permet de travailler avec des modules et des sous-modules de deux faons : comme un ensemble de balises fileSets (via la section sources) ou comme un ensemble de dependencySets (via la section binaries).
249
archiveurs vont se bloquer s'il y a aucun fichier incorporer mais sans une balise format et une balise id il n'y a aucune archive raliser. La balise id est utilise la fois pour le nom et le classifieur dans le dpt Maven de l'artefact de l'archive produite. Le format dtermine quel composant archiveur sera utilis pour produire l'archive assembly finale. Tous les descripteurs d'assembly doivent contenir une balise id et au moins une balise format : Exemple 14.5. Balises obligatoires d'un descripteur d'assembly
<assembly> <id>bundle</id> <formats> <format>zip</format> </formats> ... </assembly>
L'id de l'assembly est une chane de caractres sans espace. La pratique standard est d'utiliser des tirets entre les mots de l'id de l'assembly. Si vous produisez un assembly qui construit une structure unique d'un package intressant, vous lui donnerez une id comme unique-package-interessant. Il est possible de dclarer plusieurs formats diffrents dans un mme descripteur d'assembly, ce qui vous permet de crer les archives de distribution habituelles .zip, .[Link] et .tar.bz2 facilement. Si vous ne trouvez pas le format d'archive qu'il vous faut, vous pouvez crer un format personnel. Les formats personnels sont dcrits dans la Section 14.5.8, componentDescriptors et containerDescriptorHandlers . Le plugin Assembly supporte nativement plusieurs formats d'archive, ce qui inclut : jar zip tar bzip2 gzip [Link] tar.bz2 rar war ear
250
sar dir L'id et le format sont indispensables car ils vont faire partie des coordonnes de l'archive assemble. L'exemple de Exemple 14.5, Balises obligatoires d'un descripteur d'assembly va crer un artefact d'assembly de type zip avec comme classifieur bundle.
Supposons que vous construisiez le projet my-app dans sa version 1.0, la configuration de l'Exemple 14.6, Ajout d'un fichier JAR dans un assembly avec la balise files , permet d'inclure le JAR de votre projet dans le rpertoire lib/ de l'assembly, en supprimant le numro de version pour
251
obtenir au final un fichier renomm en [Link]. Ensuite, il faut rendre ce JAR lisible par tout le monde et ditable son propritaire (c'est ce que que reprsente le mode 0644 pour les fichiers avec le format sur quatre chiffres des permissions Unix). Pour plus d'informations sur le format de la valeur de la balise fileMode, consultez l'explication de Wikipdia sur le systme octal de reprsentation des droits2. Vous pouvez construire un assembly trs complexe avec ces balises file, si vous connaissez la liste exhaustive des fichiers inclure. Mme si vous ne connaissez pas cette liste au lancement du build, vous pouvez trs facilement utiliser un plugin Maven personnalis pour produire ce descripteur d'assembly avec des rfrences comme celui ci-dessus. Si la section files vous permet un contrle trs fin des permissions, de la position et du nom de chaque fichier dans l'archive assembly, crire une balise file pour chaque fichier est une tche pnible. La plupart du temps vous allez travailler sur des groupes de fichiers et de dpendances grce la balise fileSets. Les quatre sections suivantes sont conues pour vous permettre de slectionner des listes de fichiers correspondant des critres particuliers.
Cet ensemble de fichiers se compose de tout le contenu du rpertoire src/main/java de notre projet. Il profite des valeurs par dfaut des nombreux paramtres de cette section, aussi regardons les brivement. Tout d'abord, vous avez remarqu que nous n'avons pas indiqu o nous souhaitons mettre les fichiers inclure dans l'assembly. Par dfaut, le rpertoire de destination (que l'on peut prciser au moyen de la balise outputDirectory) est le mme que le rpertoire source (dans notre cas, src/main/java). De plus, nous n'avons pas spcifi de format respecter pour l'inclusion ou l'exclusion de fichiers. Dans ce cas, le comportement par dfaut est de slectionner tous les fichiers qui se trouvent dans le rpertoire source avec quelques exceptions importantes. Les exceptions cette rgle sont surtout les fichiers et les rpertoires de mtadonnes des outils de gestion de configuration. Ces exceptions par dfaut sont utilises lorsque la balise useDefaultExcludes est true, ce qui est le cas par dfaut. Lorsque l'option useDefaultExcludes est active, les rpertoires tels que .svn/ et CVS/ sont exclus d'office
2
[Link]
252
de la liste des fichiers inclure dans l'archive assembly. La Section 14.5.3, Patterns d'exclusion par dfaut pour la balise fileSets prsente une liste dtaille des formats d'exclusion par dfaut. Si vous voulez contrler plus finement cet ensemble de fichiers, vous pouvez le spcifier explicitement. L' Exemple 14.7, Inclusion de fichiers avec la balise fileSet montre une balise fileSet qui spcifie toutes les valeurs par dfaut. Exemple 14.7. Inclusion de fichiers avec la balise fileSet
<assembly> ... <fileSets> <fileSet> <directory>src/main/java</directory> <outputDirectory>src/main/java</outputDirectory> <includes> <include>**</include> </includes> <useDefaultExcludes>true</useDefaultExcludes> <fileMode>0644</fileMode> <directoryMode>0755</directoryMode> </fileSet> </fileSets> ... </assembly>
Les sections includes se composent d'une liste de balises include qui contiennent des patterns de chemin et de nom de fichier. Ces formats peuvent avoir un ou plusieurs jokers comme ** qui correspond un ou plusieurs rpertoires, * qui correspond une partie d'un nom de fichier ou ? qui remplace un caractre quelconque dans un nom de fichier. L'Exemple 14.7, Inclusion de fichiers avec la balise fileSet utilise une balise fileMode pour spcifier que les fichiers de ce groupe devront tre lisibles par tous mais ditables uniquement par le propritaire. Comme la balise fileSet peut inclure des rpertoires, il existe aussi une balise directoryMode pour spcifier le mode du rpertoire. Elle fonctionne comme fileMode. Comme il faut avoir les droits d'excution sur un rpertoire pour pouvoir en lister le contenu, il faut s'assurer que les rpertoires sont bien excutables en plus d'tre lisibles. Comme pour les fichiers, seul le propritaire peut modifier les rpertoires et leurs contenus dans cet exemple. La balise fileSet possde des options supplmentaires. Premirement, elle peut contenir une balise excludes de la mme forme que la balise includes. Les patterns d'exclusion vous permettent d'exclure des fichiers spcifiques d'un fileSet s'ils correspondent au pattern spcifi. Les patterns d'inclusion prennent le pas sur ceux d'exclusion. Vous pouvez aussi mettre true l'lment filtering si vous voulez remplacer les expressions dans les fichiers ainsi slectionns par les valeurs des proprits. Les expressions sont dlimites soit par ${ et } (expression standard Maven, par exemple ${[Link]}) ou par @ suivi de @ (expression standard Ant, par exemple @[Link]@). Vous pouvez choisir la fin de ligne dans vos fichiers grce la balise lineEnding. Les valeurs autorises pour la balise lineEnding sont :
253
keep Conserve la fin de ligne des fichiers originaux. (C'est la valeur par dfaut). unix Fin de ligne de type Unix lf Juste le caractre Nouvelle Ligne dos Fin de ligne de type MS-DOS crlf Caractre Retour la Ligne suivi du caractre Nouvelle Ligne Enfin, si vous voulez vous assurer que tous les lments de slection de fichiers sont utiliss, vous pouvez mettre la balise useStrictFiltering true (la valeur par dfaut est false). Cela peut-tre trs utile si des patterns inutiliss indiquent des fichiers manquants dans un rpertoire intermdiaire. Lorsque la balise useStrictFiltering est true, le plugin Assembly chouera si un pattern d'inclusion n'est pas satisfait. En d'autres termes, si vous avez un pattern d'inclusion qui inclut un fichier d'un build et que ce fichier est absent alors, lorsque la balise useStrictFiltering est true le build Maven chouera lorsqu'il ne trouvera pas ce fichier.
[Link] [Link]
254
"**/CVS/**", "**/.cvsignore", // SCCS "**/SCCS", "**/SCCS/**", // Visual SourceSafe "**/[Link]", // Subversion "**/.svn", "**/.svn/**", // Arch "**/.arch-ids", "**/.arch-ids/**", //Bazaar "**/.bzr", "**/.bzr/**", //SurroundSCM "**/.MySCMServerInfo", // Mac "**/.DS_Store" };
Ce tableau de patterns par dfaut exclut les fichiers temporaire d' diteurs tels que GNU Emacs5, les fichiers temporaires les plus classiques sous Mac et les fichiers des outils de gestion de configuration (mme si Visual SourceSafe est plus une maldiction qu'un outil de gestion de configuration). Si vous avez besoin de redfinir ces patterns d'exclusion par dfaut, mettez useDefaultExcludes false et dfinissez votre propre liste de patterns d'exclusion dans votre descripteur d'assembly.
[Link]
255
La balise dependencySet ci-dessus va rechercher toutes les dpendances d'excution de votre projet (le scope runtime scope inclut le contenu du scope compile implicitement), et va ensuite les ajouter au rpertoire racine de l'archive assembly. Elle va aussi copier l'artefact principal de votre projet, s'il existe, dans ce rpertoire racine.
Note
Une minute ? Je pensais que la balise dependencySet grait l'inclusion des dpendances de mon projet, pas son archive principale ? Cet effet secondaire non-intuitif tait un bug trs utilis de la version 2.1 du plugin Assembly, et, comme Maven accorde une trs grande importance la compatibilit ascendante, ce comportement non-intuitif et incorrect a d tre prserv pour la version 2.2. Vous pouvez interdire ce comportement en mettant false la balise useProjectArtifact. Mme si l'ensemble des dpendances par dfaut peut tre trs utile sans configuration supplmentaire, cette section du descripteur d'assembly supporte de nombreuses options de configuration pour vous permettre d'adapter son comportement vos besoins spcifiques. Par exemple, la premire chose que vous pourriez vouloir faire par rapport cette liste de dpendances est d'exclure l'artefact du projet en mettant useProjectArtifact false (sa valeur par dfaut est true pour des raisons historiques). Cela vous permettra de grer le rsultat du build de votre projet indpendamment des fichiers des dpendances. De mme, vous pouvez choisir de dcompresser les dpendances en mettant la balise unpack true (elle est false par dfaut). Lorsque l'option unpack est active, le plugin Assembly va dcompresser les contenus des dpendances dans le rpertoire racine de l'archive. partir maintenant, vous pouvez faire plusieurs choses avec cet ensemble de dpendances. Les sections qui vont suivre prsentent comment dfinir l'endroit o seront enregistres ces dpendances et comment inclure et exclure des dpendances selon leur scope. Enfin, nous nous tendrons sur cette fonctionnalit de dcompression des dpendances en explorant certaines de ses options avances. [Link]. Configurer l'emplacement des dpendances C'est la combinaison de deux options de configuration qui dtermine o va se retrouver un fichier de dpendance dans l'archive assembly : outputDirectory et outputFileNameMapping. Vous pouvez configurer l'emplacement des dpendances dans votre assembly selon les proprits des artefacts des dpendances. Disons que vous voulez mettre toutes vos dpendances dans des rpertoires qui correspondent au groupId de l'artefact. Dans ce cas, vous pouvez utiliser la balise outputDirectory sous dependencySet et lui donner pour valeur :
<assembly>
256
Cela aura pour effet de mettre chaque dpendance dans un rpertoire dont le nom correspond au groupId de son artefact. Si vous voulez aller plus loin dans la personnalisation et que vous souhaitez retirer le numro de version du nom de fichier des dpendances. Il suffit de configurer le renommage des dpendances grce la balise outputFileNameMapping comme suit :
<assembly> ... <dependencySets> <dependencySet> <outputDirectory>${[Link]}</outputDirectory> <outputFileNameMapping> ${[Link]}.${[Link]} </outputFileNameMapping> </dependencySet> </dependencySets> ... </assembly>
Dans l'exemple prcdent, une dpendance sur commons:commons-codec version 1.3, se retrouverait dans le fichier commons/[Link]. [Link]. Interpolation de proprits pour l'emplacement des dpendances Comme nous l'avons dj mentionn dans la Section 14.4.1, Rfrence de proprit dans un descripteur d'assembly , aucun de ces lments n'est interpol avec le reste du descripteur d'assembly. En effet, leurs valeurs brutes doivent tre traites par des interprteurs d'expression d'artefact spcifiques. Les expressions utilisables pour ces deux lments sont lgrement diffrentes. Les expressions ${project.*}, ${pom.*} et ${*} qui sont disponibles dans le POM et dans le reste du descripteur le sont aussi dans ces deux cas. Pour la balise outputFileNameMapping le traitement suivant est appliqu pour rsoudre les expressions : 1. Si l'expression correspond au pattern ${artifact.*} : a. Recherche dans l'instance Artifact de la dpendance (rsolution des attributs : groupId, artifactId, version, baseVersion, scope, classifier et file.*) b. Recherche dans l'instance ArtifactHandler de la dpendance (rsolution de : expression)
257
c. Recherche dans l'instance du projet associ l'artefact de la dpendance (rsolution : principalement les proprits du POM) 2. Si l'expression correspond au pattern ${pom.*} ou ${project.*}: a. Recherche dans l'instance du projet (MavenProject) du build en cours. 3. Si l'expression correspond au pattern ${dashClassifier?} et que l'instance Artifact de la dpendance a un classifier, rsoud jusqu'au classifieur prcd d'un tiret (-classifier). Sinon rsoud comme tant une chane vide. 4. Essaye de rsoudre l'expression avec l'instance du projet du build en cours. 5. Essaye de rsoudre l'expression avec les proprits du POM du build en cours. 6. Essaye de rsoudre l'expression avec les proprits systme disponibles. 7. Essaye de rsoudre l'expression avec les variables d'environnement du systme d'exploitation. La valeur de la balise outputDirectory est interpole de manire assez semblable, la diffrence prs qu'il n'y a pas d'information du type ${artifact.*} disponible. Seules les instances ${project.*} des artefacts permettent de rsoudre les expressions. Donc les expressions associes ces patterns ne sont pas disponibles (il s'agit des lments 1a, 1b, et 3 de la liste ci-dessus). Comment sait-on quand utiliser outputDirectory et outputFileNameMapping ? Quand les dpendances sont dcompresses, seul l'outputDirectory est utilis pour calculer l'emplacement final. Quand les dpendances sont gres comme un tout (c'est dire non dcompresses), les deux lments outputDirectory et outputFileNameMapping peuvent tre utiliss ensemble. Quand ils le sont, le rsultat est quivalent :
<archive-root-dir>/<outputDirectory>/<outputFileNameMapping>
Quand l'outputDirectory est absent, il n'est pas utilis. Quand c'est l'outputFileNameMapping qui est absent, on prend sa valeur par dfaut qui est : ${[Link]}${[Link]}${dashClassifier?}.${[Link]}
[Link]. Inclusion et exclusion de dpendance par scope Dans la Section 9.4, Dpendances d'un projet , nous avons not que toutes les dpendances d'un projet ont un scope. Le scope dtermine le moment o une dpendance sera utilise au cours du processus de build. Par exemple, les dpendances dans le scope test ne font pas partie du classpath au moment de la compilation du code source du projet ; par contre, elles font partie du classpath de compilation des tests unitaires. C'est fait ainsi car le code source de votre projet ne devrait pas contenir du code spcifique pour les tests. En effet, tester n'est pas une des fonctions de votre projet (c'est une fonction du processus de build du projet). De mme, les dpendances dans le scope provided doivent tre prsentes dans l'environnement o sera dploy le projet. Cependant, si un projet dpend d'une dpendance provided
258
particulire, il est possible qu'il ait besoin de celle-ci pour compiler. C'est pour cette raison que les dpendances du scope provided sont prsentes dans le classpath de compilation mais qu'elles ne sont pas empaquetes avec l'artefact ou un assembly du projet. Dans cette mme Section 9.4, Dpendances d'un projet , nous avions vu que les scopes de dpendances en induisent d'autres. Par exemple, le scope de dpendance runtime inclut les dpendances du scope compile, car toutes les dpendances utilises au moment de la compilation (sauf celles du scope provided) seront ncessaires pour l'excution du code. Les manires dont un scope d'une dpendance directe affecte le scope des dpendances transitives sont trs complexes. Dans un descripteur d'assembly Maven, nous pouvons utiliser les scopes pour filtrer des ensembles de dpendances et leur appliquer des traitements diffrents . Par exemple, si nous projetons de packager une application web avec Jetty6 et crer ainsi une application autonome, nous allons devoir inclure toutes les dpendances du scope provided dans les rpertoires du Jetty que nous intgrons. Cela nous assurera que ces dpendances provided sont effectivement prsentes dans l'environnement d'excution. Les dpendances d'excution qui ne font pas partie du scope provided continuent aller dans le rpertoire WEB-INF/lib, donc ces deux ensembles de dpendances doivent tre traits distinctement. Ces blocs de dpendances ressemblent au document XML qui suit. Exemple 14.9. Dfinition de blocs de dpendances par l'utilisation des scopes
<assembly> ... <dependencySets> <dependencySet> <scope>provided</scope> <outputDirectory>lib/${[Link]}</outputDirectory> </dependencySet> <dependencySet> <scope>runtime</scope> <outputDirectory> webapps/${webContextName}/WEB-INF/lib </outputDirectory> </dependencySet> </dependencySets> ... </assembly>
Les dpendances du scope provided sont ajoutes au rpertoire lib/ situ la racine de l'assembly. Ce rpertoire va contenir l'ensemble des bibliothques qui seront incluses dans le classpath global d'excution de Jetty. Nous utilisons un sous-rpertoire dont le nom est l'artifactId du projet pour retrouver plus facilement d'o vient une bibliothque particulire. Les dpendances d'excution sont incluses dans le rpertoire WEB-INF/lib de l'application web, qui se trouve dans le sousrpertoire standard de Jetty : webapps/, et dont le nom est donn par la configuration de la proprit webContextName du POM. Ce que nous venons de faire dans cet exemple est de sparer les
6
[Link]
259
dpendances spcifiques l'application de celles qui sont prsentes dans le classpath global d'un conteneur de servlets. Cependant, sparer en ne tenant compte que du scope peut s'avrer insuffisant, notamment dans le cas d'applications web. Il est tout fait concevable qu'une ou plusieurs des dpendances pour l'excution soient un assemblage de ressources standardises et non-compiles qui seront utilises par l'application web. Par exemple, nous pourrions avoir un ensemble d'applications qui rutiliseraient le mme ensemble de fichiers de Javascript, CSS, SWF et d'images. Pour faciliter la standardisation de ces ressources, une bonne pratique consiste les mettre dans une archive et de les dployer sur un dpt Maven. partir de ce moment l, elles peuvent tre rfrences comme une dpendance Maven standard ventuellement comme une dpendance de type zip - normalement dans le scope runtime. Souvenezvous qu'il s'agit de ressources et non d'une dpendance du code de l'application vers un binaire ; et donc il ne faut pas les inclure dans le rpertoire WEB-INF/lib. Ces archives de ressources doivent tre spares des dpendances binaires d'excution et dcompresses la racine de l'application web. Pour pouvoir effectuer ce type de sparation, nous allons utiliser les patterns d'inclusion et d'exclusion qui se basent sur les coordonnes d'une dpendance. En d'autres termes, nous allons supposer que vous avez trois ou quatre applications web qui rutilisent les mmes ressources et que vous voulez crer un assembly qui met les dpendances du scope provided dans le rpertoire lib/, les dpendances du scope runtime dans webapps/<contextName>/WEBINF/lib et enfin dcompresse une dpendance particulire du scope runtime la racine de votre application web. Nous pouvons raliser tout a car le plugin Assembly permet de dfinir plusieurs patterns d'inclusion et d'exclusion pour un mme lment dependencySet. Dans la prochaine section, nous allons essayer de dvelopper cette ide. [Link]. Configuration fine : inclusion et exclusion de dpendances Une dpendance de ressources peut tre une simple liste de ressources (CSS, Javascript, images ...) dans un projet dont un assembly cre une archive de type ZIP. En fonction des particularits de votre application web, vous voudrez distinguer les dpendances de ressources des dpendances de binaires grce leur type. La plupart des applications web vont dpendre d'autres dpendances de type jar. Du coup, il est possible de dire avec certitude que toutes les dpendances de type zip sont des dpendances de ressources. Or, nous pourrions avoir une situation o les ressources sont conserves sous un format jar mais que nous pouvons distinguer les ressources par un classifieur resources. Dans tous les cas, nous pouvons spcifier un pattern d'inclusion pour cibler ces dpendances de ressources et appliquer une logique diffrente que celle utilise pour les binaires. Nous pouvons effectue cette distinction par l'intermdiaire de balises includes et excludes dans le dependencySet. Les balises includes et excludes sont des listes. Elles acceptent des sous-lments du type include et exclude. Chaque balise include et exclude contient une valeur sous forme de chane de caractre et pouvent contenir des caractres jokers. Les dpendances peuvent respecter ces patterns de plusieurs faons. Gnralement, trois formats de pattern sont supports :
groupId:artifactId - sans la version
260
groupId:artifactId:type[:classifier] - id de conflit
Ce pattern vous permet de fournir un ensemble plus large de coordonnes pour crer des patterns include/exclude plus spcifiques.
groupId:artifactId:type[:classifier]:version - identit complte de l'artefact
Si vous avez rcuprer un artefact bien spcifique, vous pouvez renseigner l'intgralit des coordonnes. Tous ces formats de patterns supportent l'utilisation du joker *, il permet de remplacer n'importe quelle sous-section de l'identit et peut tre employ dans plusieurs sous-sections (bloc entre ':'). En outre, notez que la section classifieur du pattern ci-dessus est facultative, les dpendances qui n'ont pas de classifieur ne prennent pas en compte la section 'classificateur' de ce pattern. Dans l'exemple donn ci-dessus, la distinction essentielle est le type zip de l'artefact et il faut noter qu'aucune des dpendances n'a de classifieur, le pattern suivant serait respect par toutes les ressources de type :
*:zip
Le pattern ci-dessus utilise la seconde identit de la dpendance : l'id de conflit. Maintenant que nous avons un pattern qui distingue les dpendances de ressources des dpendances de binaires, nous pouvons modifier notre liste de dpendances pour grer ces archives diffremment : Exemple 14.10. Utilisation des l'inclusion et d'exclusion de dpendances dans le dependencySets
<assembly> ... <dependencySets> <dependencySet> <scope>provided</scope> <outputDirectory>lib/${[Link]}</outputDirectory> </dependencySet> <dependencySet> <scope>runtime</scope> <outputDirectory> webapps/${webContextName}/WEB-INF/lib </outputDirectory> <excludes> <exclude>*:zip</exclude> </excludes> </dependencySet> <dependencySet> <scope>runtime</scope> <outputDirectory> webapps/${webContextName}/resources </outputDirectory> <includes> <include>*:zip</include> </includes> <unpack>true</unpack>
261
Dans l'Exemple 14.10, Utilisation des l'inclusion et d'exclusion de dpendances dans le dependencySets , la liste de dpendances du scope runtime de notre dernier exemple a t mise jour pour exclure les dpendances de type ressource. Seules les dpendances binaires (c'est dire celles qui ne sont pas de type zip) sont ajoutes dans le rpertoire WEB-INF/lib de l'application. Les dpendances de ressources sont regroupes dans un seul ensemble de dpendances. Cet ensemble est configur pour copier ses dpendances dans le rpertoire ressource de l'application. La balise includes du dernier dependencySet annule les exclusions du dependencySet prcdent. Ainsi, les dpendances ressources sont incluses en utilisant un seul pattern d'identit : *:zip. La dernire balise dependencySet fait rfrence des ressources partages, elle est configure pour dcompresser cellesci la racine de l'application web. L'Exemple 14.10, Utilisation des l'inclusion et d'exclusion de dpendances dans le dependencySets prsume que le projet contenant les ressources partages dispose d'un type diffrent des autres dpendances. Que se passerait-il si celles-ci avaient le mme type que celui des autres dpendances ? Comment diffrencieriez-vous cette dpendance ? Dans ce cas, si une dpendance de ressources partages a t package comme un JAR avec le classificateur de type resources, vous pouvez changer le pattern d'identit pour qu'il filtre cette dpendance :
*:jar:resources
Au lieu d'accepter les artefacts de type zip sans classifieur, nous retenons ici les artefacts de type jar avec un classifieur resources. Comme pour la section fileSets, dependencySets supporte l'utilisation du flag useStrictFiltering. Lorsque celui-ci est activ, n'importe quel pattern qui n'accepte aucune dpendance fera chouer l'assembly, et donc par consquent, le build. Cela est trs pratique comme soupape de scurit, pour vous assurer que les dpendances de votre projet et votre descripteur d'assembly sont bien synchroniss. Par dfaut, ce flag est dsactiv pour des raisons de rtrocompatibilit. [Link]. Dpendances transitives, pices jointes et artefacts de projet La section dependencySet vous propose deux autres mcanismes pour vous aider dans le choix de vos artefacts : la slection de dpendances transitives et la possibilit de travailler avec des artefacts du projet. Ces deux fonctionnalits proviennent de la ncessit de supporter des configurations existantes qui utilisent une dfinition un peu plus librale du mot "dpendance". Comme premier exemple, examinons l'artefact principal du projet. Dans la majorit des cas, il ne doit pas tre considr comme une dpendance. Pourtant, les plus anciennes versions du plugin Assembly l'utilisaient dans le calcul des dpendances. Pour fournir une rtrocompatibilit avec cette "fonctionnalit", la version 2.2 du plugin Assembly dispose d'un flag mettre dans le dependencySet, celui-ci est appel
262
useProjectArtifact. La valeur par dfaut de ce flag est true. Par dfaut, un ensemble de
dpendances prendra en compte l'artefact du projet dans la slection de ses dpendances. Si vous prfrez grer l'artefact du projet sparment, affectez ce flag false.
Astuce
Les auteurs de ce livre vous recommandent de toujours laisser le flag useProjectArtifact false. Comme extension naturelle l'inclusion d'un artefact projet, les artefacts rattachs un projet peuvent galement tre grs par un dependencySet en utilisant le flag useProjectAttachments (celuici est dsactiv par dfaut). Activer ce flag permet aux patterns qui prcisent des classifieurs et des types d'artefacts de prendre en compte les artefacts rattachs. Ils partagent la mme identit groupId/ artifactId/version, mais diffrents type et classifier. Cette fonctionnalit peut s'avrer utile pour inclure les JARs de Javadoc ou de source dans un assembly. En plus de traiter avec des artefacts du projet, il est galement possible de prendre en compte les dpendances transitives pour calculer un ensemble de dpendances grce deux paramtres. Le premier, appel useTransitiveDependencies (et activ par dfaut), permet d'activer l'inclusion des dpendances transitives lors de la slection par pattern. Comme exemple pour savoir comment il peut tre utilis, considrez ce qui arrive lorsque votre POM a une dpendance sur un autre assembly. Cet assembly aura (probablement) un classifieur qui permet de le distinguer de l'artefact principal du projet, ce qui en fait une pice jointe. Cependant, une particularit du processus de rsolution des dpendances Maven est que les informations des dpendances transitives pour l'artefact principal sont toujours utilises pour rsoudre l'artefact de l'assembly. Si l'assembly package les dpendances en lui, dans ce cas, utiliser la rsolution des dpendances transitives dupliquerait ces dpendances. Pour viter cela, nous pouvons simplement utiliser le flag useTransitiveDependencies en le positionnant false. L'autre flag permettant de rsoudre les dpendances est plus subtil. Il est appel
useTransitiveFiltering et sa valeur par dfaut est false. Pour comprendre ce que fait ce flag,
nous devons d'abord comprendre quelles informations sont disponibles pour un artefact donn lors du processus de rsolution des dpendances. Quand un artefact est une dpendance d'un autre (c'est dire avec au moins un niveau intermdiaire entre lui et votre POM), il possde ce que Maven appelle un "chemin de dpendances". Il s'agit d'une liste de chanes de caractres qui correspondent l'identit complte de chaque artefact (groupId:artifactId:type:[classifier:]version) de dpendances entre cet artefact et votre POM. Si vous vous rappelez des trois types d'identits des artefacts disponibles pour crire un pattern, vous remarquerez que les entres dans ce chemin de dpendances - l'identit complte de l'artefact - correspondent au troisime type. Lorsque le flag useTransitiveFiltering est positionn true, toutes les entres du chemin de dpendances d'un artefact peuvent agir sur l'inclusion ou l'exclusion de cet artefact. Si vous envisagez l'utisation de ce filtrage transitif, prennez garde ! Un artefact peut tre inclus partir de nombreux emplacement dans un graphe de dpendance, mais dans Maven 2.0.9, seul le premier chemin
263
de dpendances est utilis pour ce type de slection. Cela peut conduire des problmes difficiles rsoudre dans la collecte des dpendances de votre projet.
Avertissement
La plupart des assemblies ne ncessitent pas ce niveau de contrle sur les listes de dpendances. Rflchissez attentivement pour savoir si vous en avez vraiment besoin. Astuce : ce n'est probablement pas le cas. [Link]. Options avances de dpaquetage Comme nous l'avons vu prcdemment, certaines dpendances de projet ont besoin d'tre dcompresses durant la cration d'un assembly. Dans les exemples ci-dessus, la dcision de savoir s'il fallait dcompresser ou pas tait simple. Elle ne tient pas compte de ce qui doit tre dpaquet, ou plus important, de ce qui ne doit pas l'tre. Pour obtenir plus de contrle sur le processus de dpaquetage, vous pouvez configurer la balise unpackOptions dans votre dependencySet. Ainsi, vous avez la possibilit de choisir quels fichiers vous voulez inclure dans votre assembly, et quels fichiers doivent tre filtrs pour rsoudre des expressions partir des informations du POM. En fait, les options disponibles pour dpaqueter vos ensembles de dpendances sont similaires celles disponibles pour l'inclusion ou l'exclusion de fichier. Pour continuer notre exemple d'application web, supposons que certaines dpendances de ressources aient t zippes avec un fichier qui dcrit les dtails de leur licence de distribution. Dans le cas de notre application web, ces licences se prsenteront sous la forme d'un fichier NOTICES inclu dans notre paquetage. Pour exclure ce fichier, ajoutons-le simplement aux options de dpaquetage dans la balise dependencySet qui gre les artefacts de ressources : Exemple 14.11. Exclusion de fichiers dans le dpaquetage d'une dpendance
<asembly> ... <dependencySets> <dependencySet> <scope>runtime</scope> <outputDirectory> webapps/${webContextName}/resources </outputDirectory> <includes> <include>*:zip</include> </includes> <unpack>true</unpack> <unpackOptions> <excludes> <exclude>**/LICENSE*</exclude> </excludes> </unpackOptions> </dependencySet> </dependencySets> ...
264
</assembly>
Notez que la balise exclude que nous utilisons ressemble beaucoup celle de la dclaration du fileSet. Ici, nous excluons les fichiers qui commencent par le mot LICENSE des rpertoires de nos artefacts de ressources. Vous pouvez considrer la section des options de dpaquetage comme une seconde balise fileSet applique chaque dpendance faisant partie de cet ensemble. En d'autres mots, il s'agit d'un fileSet utilis pour le dpaquetage des dpendances. Tout comme nous avons spcifi un modle d'exclusion pour les dossiers dans les dpendances de ressources afin de bloquer certains fichiers, vous pouvez galement choisir un ensemble restreint de fichiers inclure en utilisant la section includes. La mme configuration que celle dfinissant inclusions et exclusions dans les fileSets peut-tre utilise dans le cas de balises unpackOptions. En plus de mcanisme d'inclusion et d'exclusion, les options de dpaquetage sur une liste de dpendances peuvent galement utiliser un flag filtering, dont la valeur par dfaut est false. Encore une fois, cela ressemble beaucoup au mcanisme propos par les ensembles de fichiers discut ci-dessus. Les expressions peuvent utiliser, soit la syntaxe Maven : ${property}, soit la syntaxe Ant : @property@. Le filtrage des ressources est particulirement intressant pour les ensembles de dpendances. Elle permet de crer des modles de ressources normaliss et versionns qui peuvent tre personnaliss chaque intgration un assembly. Une fois que vous matrisez cette fonctionnalit de filtrage, que vous avez dpaquet les dpendances de ressources partages, vous serez en mesure de commencer liminer et centraliser certaines ressources partages. [Link]. Rsum des ensembles de dpendances Au final, il est important de mentionner que les ensembles de dpendances supportent les mmes options de configuration fileMode et directoryMode que les ensembles de fichiers. Cependant, vous devrez vous rappeler que l'option directoryMode ne sera utilise que si les dpendances sont dpaquetes.
265
plugin et bien d'autres informations sont hrites du projet parent par l'enfant, il semble naturel que la tche de transformation de ces modules en un fichier unique et distribuable doive incomber au projet de plus haut niveau dans la hirarchie. C'est l qu'intervient la balise moduleSet. Les ensembles de modules permettent l'inclusion de ressources appartenant chacun des modules du projet dans l'assembly final. Tout comme vous pouvez choisir un groupe de fichiers inclure dans un assembly en utilisant les balises fileSet et dependencySet, vous pouvez inclure un ensemble de fichiers et de ressources en utilisant la balise moduleSet pour se rfrer aux modules d'un build multimodule. Cela est rendu possible grce aux deux types d'inclusion spcifiques aux modules : l'un bas sur les fichiers, l'autre sur les artefacts. Avant d'entrer dans les particularits ces deux types d'inclusion de modules ressources dans un assembly, regardons un peu de comment slectionner les modules traiter. [Link]. Slection des modules Maintenant, vous devriez commencer matriser les patterns includes/excludes. Ils sont galement utiliss dans les descripteurs d'assembly pour slectionner les fichiers et les dpendances. Dans un descripteur d'assembly, lorsque vous faites rfrence des modules, vous pouvez galement utiliser ces patterns includes/excludes pour dfinir les rgles qui s'appliquent sur diffrents ensembles de modules. La particularit des patterns includes et excludes d'un moduleSet est qu'ils ne permettent pas d'utiliser de jokers. (Du moins dans Maven 2.2-beta-2, cette fonctionnalit n'ayant pas t trs demande, elle n'a donc pas t implmente.) la place de cela, chaque balise include et exclude correspond simplement au groupId et l'artifactId du module, spars par un caractre ':' ainsi :
groupId:artifactId
En plus des balises includes et excludes, le moduleSet propose d'autres outils de slection : le flag includeSubModules (dont la valeur par dfaut est true). La relation parent-enfant d'une structure multimodule n'est pas limite deux niveaux d'un projet. En fait, vous pouvez inclure un module, peu importe son niveau de profondeur dans votre build. Chaque projet qui est un module d'un module du projet courant est considr comme un sous-module. Dans certains cas, vous souhaitez construire chaque module sparment (y compris les sous-modules). Pour cela, affectez simplement la valeur du flag useSubModules true. Lorsque vous essayez d'inclure des fichiers de la structure de rpertoires de chaque module, vous souhaitez dclarer cette structure de rpertoires une seule fois. Si votre structure de rpertoires du projet correspond aux dclarations des relations parent-enfant dfinies dans les POMs, alors les patterns de fichiers comme **/src/main/java peuvent s'appliquer non seulement aux rpertoires directs de ce module, mais galement pour les rpertoires de ses propres modules. Dans ce cas, il n'est pas ncessaire de traiter les sous-modules directement (ils seront traits comme des sous-rpertoires des modules de votre projet), et donc il faut affecter la valeur du flag useSubModules false. Une fois que nous avons dtermin comment la slection module doit s'excuter sur l'ensemble des modules, nous sommes prts choisir ce qu'ils doivent contenir. Comme mentionn ci-dessus, il est possible d'inclure des fichiers ou des artefacts provenant du module du projet.
266
[Link]. Balise sources Supposez que vous dsirez inclure le code sources de tous les modules dans votre assembly, mais que vous voulez exclure un module en particulier. Peut-tre avez-vous un projet appel secret-sauce qui contient du code secret et sensible que vous ne voulez pas distribuer dans votre projet. Le moyen le plus simple d'effectuer cela est d'utiliser la balise moduleSet qui inclus chaque rpertoire d'un projet dans ${[Link]} et qui exclu le module secret-sauce de l'assembly. Exemple 14.12. Inclusion et exclusion de modules dans un moduleSet
<assembly> ... <moduleSets> <moduleSet> <includeSubModules>false</includeSubModules> <excludes> <exclude> [Link]:secret-sauce </exclude> </excludes> <sources> <outputDirectoryMapping> ${[Link]} </outputDirectoryMapping> <excludeSubModuleDirectories> false </excludeSubModuleDirectories> <fileSets> <fileSet> <directory>/</directory> <excludes> <exclude>**/target</exclude> </excludes> </fileSet> </fileSets> </sources> </moduleSet> </moduleSets> ... </assembly>
Dans l'Exemple 14.12, Inclusion et exclusion de modules dans un moduleSet , puisque nous devons grer les sources de chaque module, il est plus simple de traiter seulement les modules directs du projet en cours, en manipulant les sous-modules avec le joker sur le chemin/fichier. Renseignez l'lment includeSubModules false. Ainsi, nous n'avons donc pas nous soucier de l'apparition de sousmodules dans le rpertoire racine de l'archive assebly. La balise exclude s'occupera d'exclure votre module secret secret-sauce. Normalement, les sources d'un module sont incluses dans l'assembly dans un sous-rpertoire qui porte le nom de l'artifactId du module. Toutefois, comme Maven permet d'avoir des
267
modules dans des rpertoires dont le nom ne correspond pas leur artifactId, il est souvent prfrable d'utiliser une expression ${[Link]} pour prserver le nom du rpertoire du module courant. (${[Link]} revient au mme que d'appeler la mthode [Link]().getName()). Il est important de se rappeler que les modules ne sont pas ncessairement des sous-rpertoires du projet qui les dclare. Si votre projet possde une structure un peu particulire, vous pouvez avoir besoin de recourir la dclaration de balises moduleSet spciales qui sauront comprendre et tenir compte des particularits de votre projet.
Avertissement
Pour essayer de minimiser les particularits votre projet, comme Maven est flexible, si vous vous surprenez crire trop de configuration, c'est qu'il y a probablement un moyen plus facile d'y arriver. Continuons parcourir l'Exemple 14.12, Inclusion et exclusion de modules dans un moduleSet . Comme nous ne traitons pas les sous-modules de manire explicite, nous devons faire en sorte que les rpertoires des sous-modules ne soient pas exclus des rpertoires sources que nous avons pour chaque module direct. Affecter le flag excludeSubModuleDirectories false permet d'appliquer les mmes patterns de fichiers sur les structures de rpertoires du module en cours de traitement et sur ses sous-modules. Enfin, dans l'Exemple 14.12, Inclusion et exclusion de modules dans un moduleSet , le rsultat produit par chacun des modules ne nous intresse pas. Nous avons donc exclu le rpertoire target/ de tous les modules. Il est intressant de mentionner que la balise sources peut inclure des lments de type fileSet directement ou dans ses sous-balises imbriques. Ces balises de configuration sont utilises pour fournir une rtrocompatibilit avec les anciennes versions du plugin Assembly (versions 2.1 et prcdentes) qui ne prenaient pas en charge plusieurs ensembles de fichiers pour un mme module sans crer de modulesSet spars. Elles sont dprcies, vous ne devez pas les utiliser. [Link]. Interpolation de l'outputDirectoryMapping dans les moduleSets Dans la Section [Link], Configurer l'emplacement des dpendances , nous avons utilis la balise outputDirectoryMapping pour changer le nom du rpertoire sous lequel est inclue chaque source des modules. Les expressions contenues dans cette balise sont rsolues exactement de la mme manire que celles de la balise outputFileNameMapping, qui utilisait des sets de dpendances (rfrez-vous l'explication de cet algorithme dans la section Section 14.5.4, Section dependencySets ). Dans l'Exemple 14.12, Inclusion et exclusion de modules dans un moduleSet , vous avons utilis l'expression ${[Link]}. Vous avez peut-tre remarqu que le dbut de cette expression, module, n'est pas list dans l'algorithme de rsolution des expressions de la section Section 14.5.4, Section dependencySets . Cet objet la base de cette expression est spcifique la configuration des moduleSets. Il fonctionne de la mme manire que les rfrences ${artifact.*} disponibles pour la balise outputFileNameMapping, la diffrence qu'il s'applique aux instances MavenProject, Artifact et ArtifactHandler du module au lieu de celles d'un artefact de dpendance.
268
[Link]. Balise binaries Tout comme la balise sources se charge de l'inclusion des sources d'un module, la balise binaries se charge d'inclure le rsultat du build d'un module, ou ses artefacts. Bien que cette section fonctionne essentiellement comme une faon de spcifier un dependencySets appliquer chaque module de la srie, quelques fonctionnalits propres aux artefacts des modules mritent d'tre explores : attachmentClassifier et includeDependencies. En plus de cela, la balise binaries contient des options de configuration similaires la balise dependencySet, en rapport avec la manipulation de l'artefact du module lui-mme. Il s'agit des balises : unpack, outputFileNameMapping, outputDirectory, directoryMode et fileMode. Enfin, ces balises binaries d'un module peuvent contenir une balise dependencySets pour spcifier comment les dpendances de chaque module doivent tre incluses dans l'assembly. D'abord, jetons un coup d'oeil la faon dont ces options peuvent tre utilises pour grer les artefacts propres au module. Supposons que nous voulons inclure les jars de Javadoc de nos modules dans notre assembly. Dans ce cas, nous ne nous soucions pas de l'inclusion des dpendances, nous voulons simplement ajouter le jar de la Javadoc. Toutefois, comme ce jar un peu particulier est toujours prsent en tant que pice jointe de l'artefact principal, nous devons spcifier le classifieur utiliser pour le rcuprer. Pour simplifier, nous ne couvrirons pas dpaquetage des jars de Javadoc des modules, puisque la configuration est exactement la mme que celle utilise pour les dpendances que nous avons dj traite dans ce chapitre. Le moduleSet devrait ressembler l'Exemple 14.13, Inclure la Javadoc des modules dans un assembly . Exemple 14.13. Inclure la Javadoc des modules dans un assembly
<assembly> ... <moduleSets> <moduleSet> <binaries> <attachmentClassifier>javadoc</attachmentClassifier> <includeDependencies>false</includeDependencies> <outputDirectory>apidoc-jars</outputDirectory> </binaries> </moduleSet> </moduleSets> ... </assembly>
Dans l'Exemple 14.13, Inclure la Javadoc des modules dans un assembly , vous ne spcifiez pas directement de valeur au flag includeSubModules flag, celui-ci est activ par dfaut. Cependant, nous tenons absolument traiter tous les modules - mme les sous-modules - en utilisant ce moduleSet : nous n'utilisons aucune sorte de pattern de fichier qui pourrait correspondre des structures de sousrpertoire l'intrieur du module. Pour chaque module, la balise attachmentClassifier rcupre l'artefact qui lui est attach avec le classifieur Javadoc. La balise includeDependencies signale au plugin Assembly que les dpendances des modules ne nous intressent pas, nous rcuprons juste les
269
pices jointes. Enfin, la balise outputDirectory demande au plugin Assembly de mettre tous les jars de Javadoc dans un rpertoire nomm apidoc-jars/ en dehors du rpertoire de l'assembly. Nous ne faisons rien de trs compliqu dans cet exemple. Cependant, il est important de noter que les mmes changements pour la rsolution des expressions, dont nous avons parl propos de la balise outputDirectoryMapping de la section sources, s'appliquent galement ici. Tout ce qui est accessible par ${artifact.*} dans la configuration de la balise outputFileNameMapping du dependencySet est galement disponible dans ${module.*}. La mme chose s'applique pour toute balise outputFileNameMapping lorsqu'elle est utilise directement dans une balise binaries. Enfin, examinons un exemple dans lequel nous voulons simplement traiter l'artefact du module et ses dpendances dans le scope runtime. Dans ce cas, nous voulons mettre les artefacts de chaque module une structure de rpertoires spare, en fonction de l'artifactId et de la version des modules. Cette configuration du moduleSet reste simple et ressemble au code de l'Exemple 14.14, Inclusion des artefacts d'un module et de ses dpendances dans un assembly : Exemple 14.14. Inclusion des artefacts d'un module et de ses dpendances dans un assembly
<assembly> ... <moduleSets> <moduleSet> <binaries> <outputDirectory> ${[Link]}-${[Link]} </outputDirectory> <dependencySets> <dependencySet/> </dependencySets> </binaries> </moduleSet> </moduleSets> ... </assembly>
Dans l'Exemple 14.14, Inclusion des artefacts d'un module et de ses dpendances dans un assembly , nous utilisons la balise dependencySet en la laissant vide. Comme vous devez inclure toutes les dpendances, par dfaut, vous n'avez pas besoin d'effectuer de configuration. Lorsque la balise outputDirectory est spcifie dans la balise binaires, toutes les dpendances vont tre incluses dans le mme rpertoire, aux cts de l'artefact du module. Ainsi, nous n'avons pas besoin le configurer tout cela dans le dependencySet. La plupart du temps, les binaires d'un module restent assez simples. Dans les deux parties - la partie principale, charge de la manipulation de l'artefact du module lui-mme, et la partie charge des ensembles de dpendances, et qui traite les dpendances du module - les options de configuration restent trs similaires celles des ensembles de dpendances. Bien entendu, la balise binaires fournit
270
galement des options pour contrler quelles dpendances sont incluses et quel artefact principal de projet vous souhaitez utiliser. Comme pour la balise source, la balise binaries dispose d'options de configuration qui sont fournies uniquement pour des causes de rtrocompatibilit. Celles-ci devraient tre dprcies, comment l'utilisation des sous-sections includes et excludes. [Link]. moduleSets, POMs parents et balise binaries Enfin, clturons cette discussion avec un avertissement. En ce qui concerne les relations parentsmodule, il existe des interactions subtiles entre le fonctionnement interne de Maven et l'excution d'un moduleSet dans une balise binaires. Lorsqu'un POM dclare un parent, ce parent doit tre rsolu d'une faon ou d'une autre avant que le POM en question puisse tre construit. Si un parent est dans un dpt Maven, pas de problme. Cependant, vous vous exposez de gros problmes si le parent dispose d'un POM de plus haut niveau dans le mme build, en particulier si le POM parent utilise les binaires de ces modules. Maven 2.0.9 trie les projets d'un build multimodule en fonction de leurs dpendances, de manire construire les dpendances d'un projet avant celui-ci. Le problme est que l'lment parent est considr comme une dpendance, ce qui signifie que le build du projet parent doit tre effectu avant que le projet enfant soit construit. Si une partie du build de ce parent inclut la cration d'un assembly qui utilise les binaires des modules, ces binaires ne seront pas encore crs et ne pourront donc pas tre inclus. Cela provoquera ainsi l'chec de la construction de l'assembly. Il s'agit d'une question complexe et subtile. Elle limite srieusement l'utilit de la section binaires de la partie module du descripteur d'assembly. En fait, ce sujet, un bug a t cr sur le gestionnaire d'anomalie du plugin Assembly : [Link] Il faut esprer que les futures versions de Maven vont trouver un moyen de rparer cette fonctionnalit, puisque l'obligation de construire le parent en premier n'est pas forcment ncessaire.
271
La seconde fonctionnalit est appele groupVersionAlignments. Ici encore, cette balise reprsente une liste de configurations individuelles groupVersionAlignment, dont le but est de normaliser tous les artefacts inclus pour un groupId particulier de manire n'utiliser qu'une seule version. Chaque entre se compose de deux lments obligatoires : un id et une version, ainsi qu'une section optionnelle appele excludes qui fournit une liste d'artifactId qui doivent tre exclus de ce ralignement. Malheureusement, ce remaniement ne semble pas modifier les POMs impliqus dans le dpt, ni ceux lis des artefacts raligns, ni ceux qui dpendent des artefacts raligns. De ce fait, il est difficile d'imaginer un rel cas d'utilisation pour ce genre de ralignement. En gnral, le plus simple est d'utiliser les mmes principes que ceux des dependencySets de votre descripteur d'assembly. Mme si la balise repositories supporte d'autres options, elles sont principalement fournies pour des raisons de rtrocompatibilit, et seront probablement dprcies dans les prochaines releases.
272
Assembly pour assurer la rtrocompatibilit. Vos besoins peuvent voluer, si vous dsirer inclure un site provenant de plusieurs modules, privilgiez l'utilisation des fileSet ou des moduleSet plutt que d'activer le flag includeSiteDirectory.
273
Inclus dans votre projet, ce descripteur serait un bon moyen de packager le contenu afin qu'il puisse tre dcompress directement dans une application web existante pour fusionner avec celle-ci (pour ajouter une fonctionnalit, par exemple). Toutefois, si votre quipe construit plusieurs de ces projets "webfragment", vous aurez probablement envie de rutiliser ce descripteur plutt que de le dupliquer. Pour dployer ce descripteur dans son propre artefact, nous allons le mettre dans le rpertoire src/main/ resources/assemblies d'un projet qui lui sera ddi. La structure de projet de cet artefact assembly-descriptor devrait ressembler cela :
|-- [Link] `-- src `-- main `-- resources `-- assemblies `-- [Link]
274
Notez le chemin vers le fichier descripteur web-fragment. Par dfaut, Maven inclus les fichiers du rpertoire src/main/resources dans le JAR final. Ainsi, notre descripteur d'assembly sera inclu sans aucune autre configuration de notre part. Notez galement le prfixe de chemin assemblies/, le plugin Assembly s'attend ce prfixe de chemin pour tous les descripteurs fournis dans le classpath des plugins. Il est important de mettre notre descripteur l'emplacement relatif appropri. Ainsi, il sera rcupr par le plugin Assembly lors de son excution. Souvenez-vous, ce projet est maintenant en dehors de votre projet web-fragment. Le descripteur d'assembly possde son propre artefact avec sa propre version et, peut-tre, son propre cycle de release. Une fois que vous avez install ce nouveau projet via Maven, vous pourrez le rfrencer dans vos projets web-fragment. Pour plus de clart, le processus devrait ressembler ceci :
$ mvn install (...) [INFO] [install:install] [INFO] Installing (...)/web-fragment-descriptor/target/\ [Link] to /Users/~/.m2/repository/org/sonatype/mavenbook/assemblies/\ web-fragment-descriptor/1.0-SNAPSHOT/\ [Link] [INFO] --------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] --------------------------------------------------------------[INFO] Total time: 5 seconds (...)
Comme notre projet web-fragment-descriptor ne contient pas de code source, le JAR rsultant ne contiendra rien d'autre que notre descripteur d'assembly web-fragment. Maintenant, utilisons ce nouvel artefact :
<project> (...) <artifactId>my-web-fragment</artifactId> (...) <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-2</version> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>web-fragment-descriptor</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <executions> <execution> <id>assemble</id> <phase>package</phase> <goals>
275
<goal>single</goal> </goals> <configuration> <descriptorRefs> <descriptorRef>web-fragment</descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin> (...) </plugins> </build> (...) </project>
Deux choses sont particulires sur cette configuration du plugin Assembly : Nous devons inclure la dclaration de la dpendance vers notre web-fragment-descriptor au niveau de la dclaration des plugins afin d'avoir accs au descripteur d'Assembly par l'intermdiaire du classpath du plugin. Comme nous utilisons des rfrences du classpath plutt qu'un fichier local, nous devons utiliser la balise descriptorRefs la place de la balise descriptor. Notez galement, que mme si le descripteur d'assembly se trouve en fait dans assemblies/[Link] dans le classpath du plugin, nous pouvons le rfrencer sans utiliser le prfixe assemblies/. Ceci est rendu possible car le plugin Assembly suppose que les descripteurs d'assembly se trouvent effectivement cet emplacement. Maintenant, vous tes libre de rutiliser la configuration du POM ci-dessus dans autant de projets que vous voulez, avec l'assurance que la totalit des fragments web de l'assembly soient pris en compte. Si vous avez besoin de faire des ajustements sur le format de votre assembly - peut-tre pour d'inclure d'autres ressources, ou pour affiner les dpendances ou le fileSet - vous pouvez tout simplement incrmenter la version du projet de votre descripteur d'assembly, et le dployer nouveau. Les POMs rfrenant l'artefact assembly-descriptor peuvent ainsi adopter cette nouvelle version du descripteur s'ils le souhaitent. Un dernier point concernant la rutilisation de l'assembly-descriptor : vous souhaiterez peuttre partager la configuration du plugin. Pour cela, ajoutez la configuration ci-dessus la section pluginManagement de votre POM parent, puis rfrencez la configuration de votre plugin dans votre POM comme ceci :
(...) <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> </plugin> (...)
276
Si vous avez ajout le reste de la configuration du plugin - comme dcrit dans l'exemple prcdent - dans la section pluginManagement du POM parent de votre projet, tous les projets qui en hritent profiteront du format d'assemblage avanc dans leurs propres builds en ajoutant ces quelques lignes.
277
<moduleSet> <includes> <include>*-addons</include> </includes> <binaries> <outputDirectory>/WEB-INF/lib</outputDirectory> <includeDependencies>true</includeDependencies> <dependencySets> <dependencySet/> </dependencySets> </binaries> </moduleSet> </moduleSets> </assembly>
Pour un projet parent donn - appel app-parent - contenant trois modules : app-core, app-web et app-addons, notez ce qu'il se passe lorsque nous essayons d'excuter ce build multimodule :
$ mvn package [INFO] Reactor build order: [INFO] app-parent <----- PARENT BUILDS FIRST [INFO] app-core [INFO] app-web [INFO] app-addons [INFO] --------------------------------------------------------------[INFO] Building app-parent [INFO] task-segment: [package] [INFO] --------------------------------------------------------------[INFO] [site:attach-descriptor] [INFO] [assembly:single {execution: distro}] [INFO] Reading assembly descriptor: src/main/assembly/[Link] [INFO] --------------------------------------------------------------[ERROR] BUILD ERROR [INFO] --------------------------------------------------------------[INFO] Failed to create assembly: Artifact: [Link]:app-web:jar:1.0-SNAPSHOT (included by module) does not have an artifact with a file. Please ensure the package phase is run before the assembly is generated. ...
Le projet parent - app-parent - est le premier tre construit. C'est parce que chacun des autres projets dsigne ce POM comme son parent, forant ainsi l'ordre de construction. Le module app-web, qui est le premier module dsign dans le descripteur d'assembly, n'a pas encore t construit. Par consquent, il ne dispose d'aucun des artefacts qui lui sont associs, et donc la construction de l'assembly est impossible. Une solution de contournement consiste supprimer la balise executions de la dclaration du plugin Assembly. Celle-ci lie le plugin la phase package du cycle de vie dans le fichier POM parent. Une fois cette suppression effectue, excutez ces deux tches Maven : la premire, package, permet de construire le projet multimodule ; et la seconde, assembly:assembly, pour invoquer directement le plugin assembly qui va utiliser les artefacts construits lors de l'excution prcdente pour construire le paquet de distribution. Pour effectuer cela, utilisez la ligne de commande suivante :
278
Cependant, cette approche prsente plusieurs inconvnients. Premirement, elle rend le processus d'assemblage plus complexe en lui rajoutant une tche manuelle qui peut accrotre les risques d'erreur. En outre, cela pourrait signifier que les artefacts joints - qui sont associs en mmoire lors de l'excution de la construction du projet - ne seront pas accessibles au second passage sans recourir des rfrences au systme de fichiers. Au lieu d'utiliser la balise moduleSet pour lister les artefacts du projet multimodule, il est souvent prfrable d'utiliser une approche moins technique : l'aide d'un module ddi la distribution et aux dpendances inter-projet. Avec cette approche, vous crez un nouveau module dans votre build dont le seul but est d'effectuer l'assemblage. Le POM de ce module contient des rfrences aux dpendances des autres modules, et il configure le plugin Assembly pour qu'il soit rattach la phase package de son cycle de vie. Le descripteur d'assembly lui-mme utilise une section dependencySets la place d'un moduleSets pour lister les artefacts et dterminer o les inclure dans l'archive rsultante. Cette approche vite les inconvnients lis la relation parent-enfant mentionns plus haut, et offre l'avantage d'utiliser une section de configuration plus simple dans le descripteur d'assembly. Pour cela, nous pouvons crer une nouvelle structure de projet qui ressemble fortement celle utilise par l'approche module-set prsente prcdemment. Avec l'ajout de ce nouveau projet de distribution, vous devriez avoir cinq POMs au total : app-parent, app-core, app-web, app-addons et appdistribution. Le nouveau POM app-distribution devrait ressembler cela :
<project> <parent> <artifactId>app-parent</artifactId> <groupId>[Link]</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>app-distribution</artifactId> <name>app-distribution</name> <dependencies> <dependency> <artifactId>app-web</artifactId> <groupId>[Link]</groupId> <version>1.0-SNAPSHOT</version> <type>war</type> </dependency> <dependency> <artifactId>app-addons</artifactId> <groupId>[Link]</groupId> <version>1.0-SNAPSHOT</version> </dependency> <!-- Not necessary since it's brought in via app-web. <dependency> [2] <artifactId>app-core</artifactId> <groupId>[Link]</groupId>
279
Notez que nous devons inclure les dpendances vers les autres modules dans la structure du projet puisque nous n'avons pas de section modules dans ce POM. Notez aussi que nous n'utilisons pas de dpendance explicite vers app-core. Puisqu'il s'agit galement d'une dpendance du projet app-web, nous n'avons pas besoin de la traiter (ou, d'viter de la traiter) deux reprises. Ensuite, lorsque nous dplaons le descripteur d'assembly [Link] dans le projet appdistribution, nous devons galement modifier la configuration de la section dependencySets :
<assembly> ... <dependencySets> <dependencySet> <includes> <include>*-web</include> </includes> <useTransitiveDependencies>false</useTransitiveDependencies> <outputDirectory>/</outputDirectory> <unpack>true</unpack> </dependencySet> <dependencySet> <excludes> <exclude>*-web</exclude> </excludes> <useProjectArtifact>false</useProjectArtifact> <outputDirectory>/WEB-INF/lib</outputDirectory> </dependencySet> </dependencySets> ... </assembly>
Cette fois, si nous lanons la construction partir du rpertoire de plus haut niveau du projet, nous obtiendrons de meilleurs rsultats :
$ mvn (...) [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO]
package
--------------------------------------------------------------Reactor Summary: --------------------------------------------------------------module-set-distro-parent ...............SUCCESS [3.070s] app-core .............................. SUCCESS [2.970s] app-web ............................... SUCCESS [1.424s] app-addons ............................ SUCCESS [0.543s] app-distribution ...................... SUCCESS [2.603s] ----------------------------------------------------------------------------------------------------------------------------BUILD SUCCESSFUL
280
--------------------------------------------------------------Total time: 10 seconds Finished at: Thu May 01 18:00:09 EDT 2008 Final Memory: 16M/29M ---------------------------------------------------------------
Comme vous pouvez le voir, l'approche par dependency-set est beaucoup plus stable et - aussi longtemps que la logique interne de tri de Maven ne sera pas aussi perfcetionne que celle du plugin Assembly offre moins de possibilits de se tromper lors de l'excution d'un build.
14.7. En rsum
Comme nous l'avons vu dans ce chapitre, le plugin Maven Assembly permet de la cration de formats d'archives personnalises. Bien que dans le dtail ces archives peuvent tre complexes, ce n'est pas ncessairement toujours le cas - comme nous l'avons vu avec les descripteurs d'assembly prdfinis. Mme si votre but est d'inclure les dpendances et certains fichiers de votre projet dans une structure de rpertoires unique et archive, l'criture d'un descripteur d'assembly ne doit pas tre trop complexe. Les assemblies sont utiles pour un large ventail de cas d'utilisation. Ils sont le plus couramment utilises pour distribuer des applications. Mme s'il existe de nombreuses manires diffrentes d'utiliser le plugin Assembly, les deux faons les plus conseilles pour vous viter des problmes est d'utiliser des descripteurs d'assembly standardiss et d'viter l'utilisation des moduleSets lors de la cration des archives de distribution.
281
Des proprits implicites sont directement disponibles partir de n'importe quel projet Maven, en voici la liste :
project.*
POM (Project Object Model) Maven. Vous pouvez utiliser le prfixe project.* pour rfrencer des valeurs du POM.
settings.*
Configuration Maven. Vous pouvez utilisez le prfixe settings.* pour rfrencer des valeurs du fichier ~/.m2/[Link].
env.*
Les variables d'environement, comme PATH et M2_HOME, peuvent tre rfrences en utilisant le prfixe env.*. Proprits Systme Les proprits pouvant tre rcupres par la mthode [Link]() peuvent tre utilises directement comme proprit Maven. En plus de ces proprits implicites, l'utilisateur peut dfinir ses propres proprits partir du POM, du fichier de paramtrage ~/.m2/[Link] ou dans un profil Maven. Les paragraphes suivants fournissent ainsi le dtail des diffrentes proprits disponibles dans un projet Maven.
La majorit des projets multimodule partagent les mmes groupId et version. Lorsque vous dclarez une interdpendance entre deux modules possdant les mmes groupId et version, c'est souvent une bonne ide que d'utiliser des proprits pour rfrencer ces valeurs :
<dependencies> <dependency> <groupId>${[Link]}</groupId> <artifactId>sibling-project</artifactId> <version>${[Link]}</version> </dependency> </dependencies>
[Link] L'artefactId d'un projet est souvent utilis pour le nom de l'archive rsultant du projet. Par
exemple, dans un projet avec un packaging du type WAR, vous voudrez peut-tre produire un fichier WAR sans que sa version apparaisse dans son nom. Pour cela, utilisez la proprit [Link] dans votre POM comme ceci :
<build>
284
<finalName>${[Link]}</finalName> </build>
[Link] et [Link]
Les nom et description du projet sont souvent utiliss dans la documentation. Au lieu d'avoir maintenir ce contenu plusieurs endroits, vous pouvez utiliser ces proprits.
[Link].*
Vous ne devez jamais utiliser la valeur en dur target/classes pour rfrencer le rpertoire destination de Maven. Une bonne pratique consiste utiliser des proprits pour rfrencer ce genre de rpertoire. [Link] [Link] [Link] [Link] [Link] [Link] Les proprits sourceDirectory, scriptSourceDirectory et testSourceDirectory fournissent un accs aux rpertoires source du projet. Les proprits outputDirectory et testOutputDirectory fournissent un accs aux rpertoires utiliss par Maven pour produire le bytecode et le rsultat de son build. La proprit directory dsigne le rpertoire qui contient tous ces rpertoires destination. Autres types de proprit Des centaines de proprits sont utilisables partir POM. La prsentation complte de la structure du POM est disponible l'adresse [Link] Pour consulter la liste complte des proprits disponibles dans le Model Maven, tournez-vous vers la Javadoc du projet maven-model cette adresse [Link] apidocs/[Link]. Une fois la Javadoc charge, ouvrez la classe Model. partir de la Javadoc de cette classe, vous devriez pouvoir naviguer sur les diffrentes proprits du POM que vous pouvez utiliser. Par exemple, si vous dsirez rfrencer le rpertoire destination du build, vous pouvez donc utiliser cette Javadoc pour trouver quelle proprit rfrencer : [Link]().getOutputDirectory(). Cette mthode est accessible sous la forme d'une proprit par l'intermdiaire de la notation suivante : ${[Link]}. Pour plus d'informations propos du module Maven Model, le module qui dfinit la structure du POM, consultez la page du projet Maven Model l'adresse [Link]
285
Contient la valeur courante du PATH dans l'environnement dans lequel Maven est lanc. Ce PATH contient la liste des rpertoires utiliss pour rechercher les scripts et excutables.
[Link]
(Sur les systmes *nix ) cette variable dfinie le rpertoire home de l'utilisateur. Nous vous conseillons cependant d'utiliser la proprit ${[Link]} qui donne le mme rsultat.
env.JAVA_HOME
Cette proprit contient le chemin vers le rpertoire d'installation Java. Elle peut pointer soit vers un JDK (Java Development Kit), soit vers une JRE (Java Runtime Environment). Nous vous conseillons galement d'utiliser la proprit ${[Link]} qui donne, l encore, le mme rsultat.
env.M2_HOME
Contient le chemin vers le rpertoire d'installation de Maven. Si vous avez le choix, privilgez l'utilisation des proprits systme Java. Prfrez donc l'utilisation de la proprit ${[Link]} celle de ${[Link]}. Cela vous permet d'augmenter la portabilit de votre build en le faisant adhrer davantage au paradigme WORA (Write-One-Run-Anywhere) mis en avant par Java.
286
Description Version de la JRE Fabriquant de la JRE URL du fabriquant de la JRE Rpertoire d'installation de Java Version des spcifications de la JVM Frabiquant des spcifications de la JVM Nom des spcifications de la JVM Version de l'implmentation de la JVM Fabiquant de l'implmentation de la JVM Nom de l'implmentation de la JVM Version des spcifications de la JRE Frabriquant des spcifications de la JRE Nom des spcifications de la JRE Version du format des classes Classpath Java Rpertoires des extensions Nom du systme d'exploitation Architecture du systme d'exploitation Version du systme d'exploitation Caractre de spatation des fichiers et rpertoires ("/" sous UNIX, "\" sous Windows) Caractre de sparation des chemins (":" sous UNIX, ";" sous Windows) Sparateur de lignes ("\n" sous UNIX et Windows) Nom de l'utilisateur Rpertoire personnel de l'utilisateur Rpertoire de travail de l'utilisateur
[Link]
[Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link] [Link]
[Link]
[Link]
287
peuvent tre dfinies dans un POM ou dans un profil. Les proprits dfinies de la sorte peuvent tre rfrences de la mme manire que toute autre proprit disponible dans Maven. Les proprits dfinies par l'utilisateur peuvent tre utilises directement dans un POM ou dans le filtrage des ressources par l'intermdiaire du plugin Maven Resource. Voici un exemple de dfinition d'une proprit dans un POM Maven. Exemple 15.1. Dfinition d'une proprit dans un POM
<project> ... <properties> <[Link].a>This is some text</[Link].a> <[Link]>[Link]</[Link]> </properties> ... <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>hibernate</artifactId> <version>${[Link]}</version> </dependency> </dependencies> ... </project>
L'exemple prcdent dfinit deux proprits : [Link].a et [Link]. La proprit [Link] est utilise dans la dclaration d'une dpendance. L'utilisation du caractre '.' en sparateur dans les noms de proprit est pratique courante dans les POMs et profils. Cette notation n'offre rien de spcial, la cl [Link] est simplement utilise pour rfrencer la valeur "[Link]". L'exemple ci-dessous montre comment dfinir une proprit partir d'un profil dans un POM Maven. Exemple 15.2. Proprit utilisateur dfinie dans un profil d'un POM
<project> ... <profiles> <profile> <id>some-profile</id> <properties> <[Link]>This is some text</[Link]> </properties> </profile> </profiles> ... </project>
L'exemple prcdent prsente comment dfinir une proprit utilisateur dans un profil. Pour plus d'information propos des proprits utilisateurs et des profils, consultez le Chapitre 11, Profils de Build.
288
[Link]
289
Votre programme utilisera ce fichier lors de son excution. Avant cela, votre build remplacera les rfrences des diffrentes proprits ([Link], [Link], ...) par les valeurs dfinies dans votre fichier [Link]. Le filtrage des ressources est dsactiv par dfaut pour vous viter de mauvaises surprises. Aussi, pour activer cette fonctionnalit, vous devez modifier le contenu de la balise resources dans votre POM. Dans l'Exemple 15.4, Dfinition de variables et activation du filtrage des ressources , le POM dfinit les variables utilises dans l'Exemple 15.3, Rfrencer des proprits Maven partir d'une ressource et active le filtrage des ressources pour tout le rpertoire src/main/ resources. Exemple 15.4. Dfinition de variables et activation du filtrage des ressources
<project> ... <properties> <[Link]> [Link]</[Link]> <[Link]>jdbc:mysql://localhost:3306/development_db</[Link]> <[Link]>dev_user</[Link]> <[Link]>s3cr3tw0rd</[Link]> </properties> ... <build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build> ... <profiles> <profile> <id>production</id> <properties> <[Link]>[Link]</[Link]> <[Link]>jdbc:oracle:thin:@proddb01:1521:PROD</[Link]> <[Link]>prod_user</[Link]> <[Link]>s00p3rs3cr3t</[Link]> </properties> </profile> </profiles> </project>
Les quatre variables sont dfinies dans la balise properties et le filtrage des ressources est activ pour les ressources du rpertoire src/main/resources. Pour activer la fonctionnalit de filtrage, vous devez affecter la valeur true la balise filtering pour chaque rpertoire que vous dsirez filtrer. La construction d'un projet contenant les ressources de l'Exemple 15.3, Rfrencer des proprits Maven partir d'une ressource et le POM de l'Exemple 15.4, Dfinition de variables et activation du filtrage des ressources va crer dans le rpertoire target/classes le fichier suivant, vous remarquerez d'ailleurs que toutes les proprits ont bien t remplaces :
290
$ mvn install ... $ cat target/classes/[Link] ... <bean id="dataSource" destroy-method="close" class="[Link]"> <property name="driverClassName" value="[Link]"/> <property name="url" value="jdbc:mysql://localhost:3306/development_db"/> <property name="username" value="dev_user"/> <property name="password" value="s3cr3tw0rd"/> </bean> ...
Le POM de l'Exemple 15.4, Dfinition de variables et activation du filtrage des ressources dfinit galement le profil production. Celui-ci surcharge les proprits par dfaut avec des valeurs appropries l'environnement de production. Dans ce POM, la configuration par dfaut des connexions la base de donnes cible une base de donnes MySQL locale installe sur la machine du dveloppeur. Lorsque ce projet est construit avec le profil 'production' activ, Maven mettra jour cette configuration pour se connecter une base de donnes Oracle en utilisant un autre driver, une autre URL, et un autre couple utilisateur / mot de passe. Si vous construisez un projet avec la ressource de l'Exemple 15.3, Rfrencer des proprits Maven partir d'une ressource , le POM de l'Exemple 15.4, Dfinition de variables et activation du filtrage des ressources et le profil 'production' activ lorsque vous listerez le contenu du rpertoire target/classes vous constaterez qu'il contient un fichier correctement filtr avec les valeurs de production :
$ mvn -Pproduction install ... $ cat target/classes/[Link] ... <bean id="dataSource" destroy-method="close" class="[Link]"> <property name="driverClassName" value="[Link]"/> <property name="url" value="jdbc:oracle:thin:@proddb01:1521:PROD"/> <property name="username" value="prod_user"/> <property name="password" value="s00p3rs3cr3t"/> </bean> ...
291
Cette commande cre un projet Maven minimaliste qui contient une classe Java dans le rpertoire src/ main/java et un simple POM. Ensuite, vous pouvez construire le site en excutant la commande mvn site. Pour construire le site et afficher le rsultat dans un navigateur web, vous pouvez utiliser la commande mvn site:run. Celle-ci construira le site et dmarrera une instance de Jetty.
$ cd sample-project $ mvn site:run [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'site'. [INFO] -----------------------------------------------------------------------[INFO] Building sample-project [INFO] task-segment: [site:run] (aggregator-style) [INFO] -----------------------------------------------------------------------[INFO] Setting property: [Link] => '[Link]'. [INFO] Setting property: [Link] => 'false'. [INFO] Setting property: [Link] => 'classpath'. [INFO] Setting property: [Link] => 'false'. [INFO] [site:run] 2008-04-26 11:52:26.981::INFO: Logging to STDERR via [Link] [INFO] Starting Jetty on [Link] 2008-04-26 11:52:26.046::INFO: jetty-6.1.5 2008-04-26 11:52:26.156::INFO: NO JSP Support for /, did not find [Link] 2008-04-26 11:52:26.244::INFO: Started SelectChannelConnector@[Link]:8080
Une fois Jetty dmarr sur le port 8080, le site du projet est disponible l'adresse [Link] partir de votre navigateur web. Vous devriez y dcouvrir un rsultat similaire la Figure 16.1, Site gnr par Maven .
Figure 16.1. Site gnr par Maven Si vous cliquez sur ce site web, vous constaterez qu'il n'est pas trs pratique comme vritable site de projet. Il ne contient aucne information (et n'est pas trs joli). Tant que le projet sample-project n'est
294
pas configur pour afficher la liste des dveloppeurs, le gestionnaire d'anomalies ou le code source, toutes les pages du projet ne contiendront aucune information intressante. Mme la page d'index du site est vide de contenu, elle affiche un message indiquant qu'aucune description n'a t associe ce projet. Pour personnaliser ce site, vous devez commencer par ajouter du contenu votre projet et dans votre POM. Si vous dcidez d'utiliser le plugin Maven Site pour construire le site de votre projet, vous voudrez donc le personnaliser. Vous voudrez renseigner les champs du POM qui permettent de lister les personnes participant au projet. Vous voudrez personnaliser galement le menu gauche du site et les liens affichs en haut de la page. Pour personnaliser le contenu de ce site, dont le menu de navigation, vous devez diter le descripteur de site.
Ce descripteur rfrence une image, [Link]. Celle-ci doit tre place dans le rpertoire ${basedir}/src/site/resources/images. En plus des changements du descripteur de site, vous voudrez crer une page [Link] placer dans le rpertoire ${basedir}/src/site/apt. ditez ce fichier pour lui donner le contenu suivant. Ce fichier sera transform en [Link] et servira de page d'accueil votre site.
Welcome to the Sample Project, we hope you enjoy your time on this project site. We've tried to assemble some great user documentation and developer information, and we're really excited that you've taken the time to visit this site. What is Sample Project
295
Well, it's easy enough to explain. This sample project is a sample of a project with a Maven-generated site from Maven: The Definitive Guide. A dedicated team of volunteers help maintain this sample site, and so on and so forth.
Pour visualiser votre site, excutez les commandes mvn clean site et mvn site:run :
$ mvn clean site $ mvn site:run
Une fois cela fait, ouvez un navigateur et rendez-vous l'adresse [Link] La page affiche devrait ressembler la caputure d'cran de la Figure 16.2, Site web personnalis du projet .
296
Les deux balises bannerLeft et bannerRight sont configures avec : un nom (name), un empalcement d'image (src) et un lien (href). Dans le descripteur de site ci-dessus, le plugin Maven Site utilisera les images [Link] et [Link] pour le coins en haut gauche et en haut droite du site. Maven recherchera ces images dans le rpertoire ${basedir}/src/site/ resources/images.
Les balises item peuvent galement tre imbriques. En imbriquant vos items, vous crez un sous-menu dans le menu navigation sous la forme d'un arbre extensible ou rtractable. L'exemple suivant ajoute un lien "Developer Resources" qui pointe vers la page /developer/[Link]. Quand un utilisateur regardera cette page, les menus au dessus de l'lemnt slectionn seront dvelopps. Exemple 16.4. Ajout d'un lien au menu du site
<project name="Sample Project"> ... <body> ...
297
<menu name="Sample Project"> ... <item name="Developer Resources" href="/developer/[Link]" collapse="true"> <item name="System Architecture" href="/developer/[Link]"/> <item name="Embedder's Guide" href="/developer/[Link]"/> </item> </menu> ... </body> </project>
Lorsque l'attribut collapse d'un item a pour valeur true, Maven pliera celui-ci jusqu' ce qu'un utilisateur consulte cette page particulire. Dans l'exemple prcdent, lorsque l'utilisateur ne regarde pas la page "Developer Resources", Maven n'affiche pas les liens "System Architecture" et "Embedder's Guide". la place, il affichera une flche pointant sur le lien "Developer Resources". Quand l'utilisateur regardera cette page, ces liens s'afficheront avec une flche pointe vers le bas.
298
| +| | | | | | | +| | +-
Notez que la documentation pour les dveloppeurs se trouve dans le fichier src/site/apt/ developer/[Link]. Celui-ci se trouve dans un sous-rpertoire d'apt, il en sera de mme pour sa page HTML correspondante. Quand le plugin Site effectue le rendu du rpertoire src/site/ apt, il gnre les fichiers HTML dans des rpertoires relatifs la racine du site. Si un fichier se trouve dans le rpertoire apt, son fichier gnr se trouvera la racine du site web. Si un fichier se trouve dans le rpertoire apt/developer, son fichier gnr se trouvera dans le rpertoire developer/ du site web.
299
Introduction to Sample Project --Brian Fox --26-Mar-2008 --Welcome to Sample Project This is a sample project, welcome! We're excited that you've decided to read the index page of this Sample Project. We hope you enjoy the simple sample project we've assembled for you. Here are some useful links to get you started: * {{{[Link]}News}} * {{{[Link]}Features}} * {{{[Link]}FAQ}} []
Si le document APT de l'Exemple 16.5, Document APT est plac dans src/site/apt/[Link], le plugin Maven Site en analysera le contenu APT avec Doxia et produira un fichier [Link] contenant le XHTML gnr.
300
<answer> <p> If you want to add code to this project, just start putting Java source in src/main/java. If you want to put some source code in this FAQ, use the source element: </p> <source> for( int i = 0; i < 1234; i++ ) { // do something brilliant } </source> </answer> </faq> </part> </faqs>
L'url contenue dans une balise incluse de la section distributionManagement est prfixe par un indicateur dav. Celui-ci indique au plugin Maven Site qu'il va lui falloir dployer le site vers une URL avec le protocole WebDAV. Une fois la configuration effectue dans le POM de votre projet sampleproject, vous pouvez lancer le dploiement via la commande suivante :
$ mvn clean site-deploy
Si vous disposez d'un serveur configur pour comprendre le protocole WebDAV, Maven dploiera le site de votre projet sur ce serveur distant. Si vous dployez ce site sur un serveur accessible au public, vous devrez probablement ajouter de la configuration d'authentification pour l'accs scuris. Si votre serveur serveur vous demande un identifiant et un mot de passe (ou tout autre moyen d'authentification), vous pouvez configurer ces valeurs dans votre fichier ~/.m2/[Link].
301
La section authentification peut contenir diffrents types d'lments. Par exemple, si vous utilisez un dploiement par SCP, vous voudrez peut-tre utiliser une authentification par cl publique. Pour cela, utilisez les balises spcifiques publicKey et passphrase plutt que password. Il se peut que vous deviez configurer l'lment username selon la configuration de votre serveur.
Les prfrences ci-dessus rendent les rpertoires lisibles et modifiables par leur propirtairer et les membres de son groupe. Les utilisateurs anonymes, quant eux, pourront uniquement lire et lister le
302
contenu du rpertoire. De la mme manire, le propritaire et les membres de son groupe disposeront d'un accs en lecture et criture sur n'importe quel fichier, alors que les utilisateurs anonymes disposeront d'un accs en lecture seule.
Aprs une nouvelle gnration de votre site, le titre de votre menu sera ainsi tram par un fond gris et spar du reste du menu par un peu plus d'espace. En utilisant ce fichier, n'importe quel lment de la structure d'un site Maven peut tre dcor par l'intermdiaire de styles personnaliss. Lorsque vous modifiez le fichier [Link] d'un projet Maven, les modifications impactent uniquement son site. Si vous dsirez effectuer des modifications qui s'appliquent sur plusieurs projets, vous pouvez crer uns skin personnalise.
Astuce
Il n'existe pas de bonne documentation sur la structure du modle par dfaut d'un site Maven. Si vous essayez de personnaliser le style de votre projet Maven, le mieux est
303
d'utiliser une extension Firefox comme Firebug pour vous aider naviguer dans le DOM de vos pages web.
Si vous replacez la dfinition de la macro par celle prsente ci-dessous, vous injecterez du javascript dans chaque lment du menu pour fermer et ouvrir l'arbre sans avoir recharger entirement la page :
#macro ( menuItem $item $listCount ) #set ( $collapse = "none" ) #set ( $currentItemHref = $[Link]( $[Link], $relativePath ) ) #set ( $currentItemHref = $[Link]( "\\", "/" ) ) #if ( $item && $[Link] && $[Link]() > 0 ) #if ( $[Link] == false ) #set ( $collapse = "collapsed" )
1
[Link] doxia/siterenderer/resources/[Link]?revision=595592
304
#else ## By default collapsed #set ( $collapse = "collapsed" ) #end #set ( $display = false ) #displayTree( $display $item ) #if ( $alignedFileName == $currentItemHref || $display ) #set ( $collapse = "expanded" ) #end #end <li class="$collapse"> #if ( $[Link] ) #if ( ! ( $[Link]().startsWith("http") || $[Link]().startsWith("https") ) ) #set ( $src = $[Link]( $[Link], $relativePath ) ) #set ( $src = $[Link]( "\\", "/" ) ) <img src="$src"/> #else <img src="$[Link]" align="absbottom" style="border-width: 0"/> #end #end #if ( $alignedFileName == $currentItemHref ) <strong>$[Link]</strong> #else #if ( $item && $[Link] && $[Link]() > 0 ) <a onclick="expand('list$listCount')" style="cursor:pointer">$[Link]</a> #else <a href="$currentItemHref">$[Link]</a> #end #end #if ( $item && $[Link] && $[Link]() > 0 ) #if ( $collapse == "expanded" ) <ul id="list$listCount" style="display:block"> #else <ul id="list$listCount" style="display:none"> #end #foreach( $subitem in $[Link] ) #set ( $listCounter = $listCounter + 1 ) #menuItem( $subitem $listCounter ) #end </ul> #end </li> #end
Cette modification rajoute un nouveau paramtre la macro menuItem. Pour que cette modification fonctionne, vous devez donc mettre jour toutes les rfrences cette macro; dans le cas contraire, le XHTML rsultant sera incorrect ou incomplet. Pour effectuer ces mises jour, apportez la mme modification la macro mainMenu. Trouvez cette macro en recherchant un bloc semblable celui-l :
#macro ( mainMenu $menus )
305
... #end
Cette nouvelle macro mainMenu est entirement compatible avec la version prcdente, elle fournit un support javascript aux lments racines du menu. Un clic sur un de ces lments racines permet aux utilisateurs d'afficher l'arbre complet dans devoir attendre le chargement de la page. La mise jour de la macro menuItem rajoute un appel une fonction javascript expand(). Cette fonction doit donc tre ajoute au template XHTML principal, par exemple en bas du modle. Recherchez la section avec un contenu ressemblant ceci :
<head> ... <meta http-equiv="Content-Type" content="text/html; charset=${outputEncoding}" /> ... </head>
306
} } </script> #if ( $[Link] ) #foreach( $item in $[Link]() ) #if ( $[Link] == "script" ) $[Link]() #else $[Link]() #end #end #end </head>
Aprs avoir modifi le modle du site, vous devez mettre jour le POM de votre projet pour qu'il utilise votre nouveau modle. Pour personnaliser le modle du site, vous devez utiliser la balise templateDirectory dans les proprits de configuration du plugin Maven Site. Exemple 16.10. Personnaliser le modle de page dans le POM du projet
<project> ... <build> <plugins> <plugin> <artifactId>maven-site-plugin</artifactId> <configuration> <templateDirectory>src/site</templateDirectory> <template>[Link]</template> </configuration> </plugin> </plugins> </build> ... </project>
Vous devriez pouvoir maintenant regnrer le site de votre projet. En effectuant cela, vous pourrez remarquer que les ressources et CSS du site Maven manquent. Lorsqu'un projet Maven personnalise le template du site, le plugin Maven Site s'attend que le projet fournisse toutes les images et CSS. Pour obtenir les ressources initiales pour le site de votre projet, le plus simple reste de les copier partir du dpot Subversion du projet de modle par dfaut de Doxia. Cela peut se faire en excutant les commandes suivantes :
$ svn co \
[Link] trunk/doxia-site-renderer
$ rm \
doxia-site-renderer/src/main/resources/org/apache/maven/\ doxia/siterenderer/resources/css/[Link]
307
$ cp -rf \
Rcuprez le projet doxia-site-renderer et copiez toutes ses ressources dans le rpertoire src/ site/resources de votre projet. Lorsque vous regnrez un site, vous pouvez remarquer galement que certains lments du menu ne possdent pas de style CSS. Cela est d une mauvaise intgration entre la CSS du site et votre modle personnalis. Pour corriger cela, modifiez votre fichier [Link] pour changer la couleur de vos liens dans le menu en ajoutant les lignes suivantes :
[Link], [Link], a:link { color:#36a; }
Aprs avoir regnr le site, la couleur du lien du menu devrait tre rpare. Si vous appliquez le nouveau modle au projet sample-project de ce chapitre, vous noterez que le menu s'affiche maintenant sous la forme d'un arbre. Un clic sur "Developer Resources" ne vous emmne plus sur la page du mme nom ; la place, son sous-menu est affich. Du coup, suite la modification de l'lment "Developer Resources" en un sous-menu dynamique, vous ne pouvez plus accder la page developer/[Link]. Le plus simple reste donc d'ajouter au sous-menu un lment "Overview" qui pointe sur cette mme page : Exemple 16.11. Ajouter un lment du menu dans le descripteur de site
<project name="Hello World"> ... <menu name="Main Menu"> ... <item name="Developer Resources" collapse="true"> <item name="Overview" href="/developer/[Link]"/> <item name="System Architecture" href="/developer/[Link]"/> <item name="Embedder's Guide" href="/developer/[Link]"/> </item> </menu> ... </project>
308
Plus rapide que de dfinir votre propre skin, vous pouvez galement utiliser l'une des skins alternatives fournies par Maven. Chaque skin propose son propre layout pour la navigation, le contenu, les logos et les templates : Maven Classic Skin - [Link]:maven-classic-skin:1.0 Maven Default Skin - [Link]:maven-default-skin:1.0 Maven Stylus Skin - [Link]:maven-stylus-skin:1.0.1 Pour obtenir la liste complte des skins disponibles, rendez-vous l'adresse suivante : http:// [Link]/maven2/org/apache/maven/skins/. La cration d'une skin consiste simplement construire un projet Maven qui contienne votre personnalisation de la feuille de style [Link]. Ainsi, elle peut tre identifie par le triplet groupId, artifactId et version. Elle peut galement contenir des ressources (comme des images) et remplacer le modle du site par dfaut (modle dcrit en utilisant la syntaxe Velocity). Cela permet de gnrer des structures de page XHTML compltement diffrentes de celle propose par dfaut. Dans la plupart des cas, la personnalisation de la CSS peut s'avrer suffisante. Pour illustrer cela, crons une skin pour le projet sample-project. La premire tape consiste en la personnalisation de la feuille de style [Link]. Avant de commencer crire cette CSS, nous devons crer un projet Maven spar. Celui-ci sera rfrenc par le descripteur de site du projet sample-project. Utilisons donc le plugin Maven Achetype pour crer un projet vide. Pour cela, excuter la commande suivante partir du rpertoire parent du projet sample-project :
$ mvn archetype:create -DartifactId=sample-site-skin
-DgroupId=[Link]
Cette commande cre un projet (et un rpertoire) appel sample-site-skin. Rendez vous dans celuici et supprimez tout le code source et les tests qui y ont t gnrs. Crez-y ensuite un rpertoire pour y mettre les ressources (de la skin) :
$ cd sample-site-skin $ rm -rf src/main/java src/test $ mkdir src/main/resources
309
Comme pour la personnalisation du modle, commencer en personnalisant la CSS existante est une bonne ide. Copiez donc cette CSS de la skin par dfaut dans le fichier [Link] de votre projet. Pour rcuprer une copie de ce fichier, enregistrez le contenu du fichier maven-theme.css2 dans le rpertoire src/main/resources/css/ de votre projet skin. Une fois ce fichier rcupr, personnalisez-le en utilisant la CSS de votre ancien fichier [Link]. Remplacez le bloc #navcolumn h5 par le code ci-dessous :
#navcolumn h5 { font-size: smaller; border: 1px solid #aaaaaa; background-color: #bbb; margin-top: 7px; margin-bottom: 2px; padding-top: 2px; padding-left: 2px; color: #000; }
Ceci fait, construisez l'artefact de votre projet sample-site-skin et installez le JAR produit dans votre dpt local. Pour cela, excutez la commande suivante :
$ mvn clean install
Revenez ensuite dans le rpertoire du projet sample-project. Si vous avez dj personnalis le fichier [Link] en dbut de ce chapitre, renommez-le en [Link] pour qu'il ne soit pas utilis par le plugin Maven Site :
$ mv src/site/resources/css/[Link] src/site/resources/css/[Link]
Pour utiliser votre skin sample-site-skin dans le site du projet sample-project, ajoutez la rfrence cet artefact (sample-site-skin) dans le descripteur de site de votre projet (sampleproject). Pour rfrencer une skin dans votre site, utilisez la balise du mme nom : Exemple 16.12. Configurer une skin personnalise dans le descripteur de site
<project name="Sample Project"> ... <skin> <groupId>[Link]</groupId> <artifactId>sample-site-skin</artifactId> </skin> ... </project>
Vous pouvez considrer la skin de votre site comme une dpendance. Les skins ont un groupId et un artifactId comme n'importe quel artefact. Utiliser une skin pour votre site vous permet de consolider
2
[Link]
310
les personnalisations d'un projet pour rutiliser les CSS et modles aussi facilement que pour n'importe quel autre artefact.
311
Ce morceau de code XML permet d'afficher la version (dans le cas du projet sample-project, on affichera "Version: 1.0-SNAPSHOT") dans le coin en haut gauche de votre site, juste ct de la dernire date de publication. Il est possible d'afficher la version de votre projet aux positions suivantes :
312
left Dans la barre en haut gauche, juste en dessous du logo right Dans la barre en haut droite, juste en dessous du logo navigation-top En haut du menu navigation-bottom En bas du menu none Masque compltement la version
Par dfaut, la date de publication sera affiche selon le format MM/dd/yyyy. Il est possible de modifier celui-ci en utilisant la notation standard prsente dans la Javadoc de la classe
313
[Link] (pour plus d'informations, consultez la Javadoc de la classe SimpleDateFormat3) Par exemple, pour modifier le format de la date pour qu'il utilise le masque yyyyMM-dd, utilisez la balise publishDate suivante.
[Link]
314
<name>id</name> <version>1.0.0</version> <required>true</required> <type>String</type> </field> ... </fields> </class> </classes> </model> </pre></div>
Avertissement
Les macros Doxia NE DOIVENT PAS tre indentes dans les documents APT. Si vous le faites, le parseur APT ignorera ces macros compltement. Pour plus d'information sur l'utilisation de la macro snipet, rfrez-vous au guide de cette macro sur le Site Maven l'adresse suivante [Link]
315
brancher les milliers de cbles coaxiaux et de prises stro aux milliers d'entres numriques et analogiques. loignez-vous de votre Home cinma et allumez la tl, vous venez de raliser de l'injection de dpendances, et vous tiez vous-mme un conteneur d'inversion de contrle. Quel est le rapport avec tout a ? Transposons cette analogie en Java. Votre Playstation 3 comme votre Java Bean fournissent tous les deux une interface. La Playstation 3 deux entres : l'alimentation et la prise rseau, et une sortie vers la TV. Votre Java Bean possde trois proprits : power, network et tvOutput. Quand vous ouvrez la bote de votre Playstation 3, le manuel ne vous dcrit pas en dtail comment la connecter tous les types de tlviseurs. De mme, votre bean Java fournit une liste de proprits sans pour autant vous donner une recette explicite pour crer et grer un systme complet de composants. Dans un conteneur d'IoC tel que Plexus, il vous incombe de dclarer les relations dans un ensemble de composants qui fournit une interface d'entre et de sortie. Vous n'instanciez pas d'objets, Plexus s'en charge. Le code de votre application n'est pas responsable de la gestion des tats des composants, c'est le rle de Plexus. Lorsque vous dmarrez Maven, Plexus est dmarr pour grer un systme d'lments connexes, comme votre systme stro. Quels sont les avantages apports par l'utilisation d'un conteneur IoC ? Quel est l'avantage d'acheter des composants stro distincts ? Si l'un des composants se casse, vous pouvez le remplacer sans avoir dpenser les 15 000 ncessaires pour remplacer l'ensemble de votre systme. Si votre tlviseur vous lche, vous pouvez le remplacer sans que cela n'affecte le lecteur CD. Et le plus important pour vous, les composants de votre chane hi-fi cotent moins chers et sont plus fiables car les fabricants peuvent se contenter de construire des composants en s'appuyant un ensemble d'entres et de sorties connues. Les conteneurs d'inversion de contrle et d'injection de dpendances encouragent donc la catgorisation et l'mergence de standards. L'industrie du logiciel aime s'imaginer comme source de toutes les nouvelles ides, mais l'injection de dpendances et l'inversion de contrle ne sont rellement que de nouveaux mots pour dfinir des concepts bien connus : la standardisation et l'interchangabilit des apppareils. Si vous voulez en savoir plus sur l'IoC et l'injection de dpendances, vous pouvez vous renseigner sur la Ford T, le Cotton Gin ou l'mergence d'un standard pour le chemin de fer au 19me sicle.
318
Dans un conteneur Java IoC, il existe plusieurs moyens d'injecter des dpendances dans un objet : injection par constructeur, accesseur ou proprit. Bien que Plexus soit capable d'utiliser ces trois techniques d'injection de dpendances, Maven en utilise seulement deux : l'injection par proprit et par accesseur. Injection par constructeur L'injection par constructeur permet de fournir des objets ncessaires lors de la cration de l'objet. Par exemple, si vous avec un objet du type Person qui possde un constructeur Person(String name, Job job), vous pouvez lui passer ainsi deux valeurs, donc deux dpendances. Injection par accesseur Ce type d'injection utilise les accesseurs des proprits des Java Beans pour remplir ses dpendances. Par exemple, si vous avec un objet du type Person qui possde deux proprits name et job, un conteneur IoC utilisant l'injection par accesseur crera une instance de la classe Person en utilisant le constructeur par dfaut et appellera ensuite les mthodes setName() et setJob(). Injection par proprit Les deux types d'injection prcdents se basent sur l'appel de mthodes et constructeurs publics. En utilisant l'injection par proprit, un conteneur IoC peut remplir les dpendances d'un composant en utilisant directement ses proprits. Par exemple, si vous avec un objet du type Person qui contient deux proprits name et job, votre conteneur IoC utilisera ces champs directement pour remplir les dpendances (i.e. [Link] = "Thomas"; [Link] = job;)
[Link]
319
Note
Si Maven est bas sur Plexus, cela ne veut pas dire que la communaut Maven est "antiSpring" (nous avons d'ailleurs consacr un chapitre complet Spring dans cet ouvrage). La question "Pourquoi vous n'avez pas utilis Spring ?" revient assez souvent pour que nous effectuons cet apart. Nous le savons, Spring est la star, et c'est mrit. Cependant, nous avons une tche dans notre liste qui consiste introduire (et documenter) Plexus auprs des dveloppeurs : dans l'industrie logicielle c'est toujours bien d'avoir le choix.
Note
Mojo ? Qu'est-ce qu'un Mojo ? Le mot mojo dfinit dans le dictionnaire par plusieurs dfinitions comme un "charme magique ou un sort", une "amulette, souvent dans un petit sac de flanelle contenant un ou plusieurs objets magiques" et du "magntisme personnel, charme". Maven utilise le terme Mojo comme jeu de mots autour du terme Pojo (Plainold Java Object), un Pojo Maven est donc appel Mojo. Un Mojo est bien plus qu'un goal Maven, c'est un composant gr par Plexus qui peut inclure des rfrences d'autres composants Plexus.
"mojo." The American Heritage Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004. [Link] 02 Mar. 2008. [Link]
320
L'Exemple 17.1, Plugin Descriptor montre le descripteur du plugin Maven Zip. Comme son nom l'indique, ce plugin permet de construire des archives Zips partir des rsultats du build. Normalement, vous ne devriez jamais avoir crire votre propre plugin pour construire des archives avec Maven. Utilisez simplement le plugin Maven Assembly, il est capable de produire des archives dans de multiples formats. Regardez le descripteur de site suivant, cela vous donnera une ide de ce genre de fichier. Exemple 17.1. Plugin Descriptor
<plugin> <description></description> <groupId>[Link]</groupId> <artifactId>maven-zip-plugin</artifactId> <version>1-SNAPSHOT</version> <goalPrefix>zip</goalPrefix> <isolatedRealm>false</isolatedRealm> <inheritedByDefault>true</inheritedByDefault> <mojos> <mojo> <goal>zip</goal> <description>Zips up the output directory.</description> <requiresDirectInvocation>false</requiresDirectInvocation> <requiresProject>true</requiresProject> <requiresReports>false</requiresReports> <aggregator>false</aggregator> <requiresOnline>false</requiresOnline> <inheritedByDefault>true</inheritedByDefault> <phase>package</phase> <implementation>[Link]</implementation> <language>java</language> <instantiationStrategy>per-lookup</instantiationStrategy> <executionStrategy>once-per-session</executionStrategy> <parameters> <parameter> <name>baseDirectory</name> <type>[Link]</type> <required>false</required> <editable>true</editable> <description>Base directory of the project.</description> </parameter> <parameter> <name>buildDirectory</name> <type>[Link]</type> <required>false</required> <editable>true</editable> <description>Directory containing the build files.</description> </parameter> </parameters> <configuration> <buildDirectory implementation="[Link]"> ${[Link]}</buildDirectory> <baseDirectory implementation="[Link]"> ${basedir}</baseDirectory>
321
</configuration> <requirements> <requirement> <role>[Link]</role> <role-hint>zip</role-hint> <field-name>zipArchiver</field-name> </requirement> </requirements> </mojo> </mojos> <dependencies> <groupId>[Link]</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependencies> </plugin>
Un descripteur de site se compose de trois parties : la configuration haut-niveau qui contient les lments du type groupId et artifactId, la dclaration des mojos et la dclaration des dpendances. Regardons chacune de ces sections dans le dtail.
[Link]
322
communaut Codehaus4 pour crer une hirarchie de ClassLoader qui est modlise par un objet ClassRealm. N'hsitez pas ignorer cette proprit et laisser sa valeur false. inheritedByDefault Si cette proprit est true, il vous est possible de configurer vos mojos dans un projet enfant en reprenant la configuration dfinie dans son projet parent. Si vous configurez un mojo pour tre excut durant une phase spcifique dans un projet parent et que cette proprit est true, l'excution de celui-ci aura lieu dans le projet fils. l'inverse, si cette proprit est false, l'excution ne tiendra pas compte du projet fils.
[Link]
323
celui-ci pour crer un plugin qui agrge un rapport sur tous les projets d'un build. Un goal qui possde ce flag aggregator positionn true doit tre lanc uniquement partir d'un projet haut-niveau d'un build Maven. La valeur par dfaut de cette proprit est false. Elle est marque comme deprecated pour les prochaines releases. requiresOnline Spcifie si un goal donn peut s'excuter en mode hors connexion (option -o de la ligne de commande). Si un goal ncessite l'utilisation de ressources rseau et que ce flag est activ, Maven affichera une erreur si le goal est excut en mode hors connexion. La valeur par dfaut de cette proprit est false. inheritedByDefault Si cette proprit est positionne true, un mojo configur dans un projet parent reprendra cette configuration pour le projet enfant. Si vous configurez un mojo pour s'excuter dans une phase spcifique d'un projet parent et que ce flag est activ, cette excution sera hrite pour le projet enfant. Cette proprit est positionne par dfaut false. phase Si vous ne rattachez pas ce goal une phase spcifique, cet lment dfinit la phase par dfaut du mojo. Si vous ne prcisez pas cet lment, Maven demandera l'utilisateur de spcifier explicitement la phase dans le POM. implementation Il s'agit de la classe du Mojo instancier par Maven. Cette proprit est une proprit de composant Plexus (dfinie dans le ComponentDescriptor de Plexus). language Java est le langage par dfaut d'un Mojo Maven. Cette proprit contrle le ComponentFactory utilis par Plexus pour crer et instancier le Mojo. Ce chapitre se concentre sur l'criture de plugin Java, cependant notez qu'il est possible d'utiliser d'autres langages : Groovy, Beanshell, Ruby... Dans le cas o vous utiliseriez un de ces langages alternatifs, vous auriez configurer cet lment. instantiationStrategy Cette proprit est une proprit de configuration de composants Plexus, elle permet de contrler la stratgie utilise par Plexus pour grer ses instances de composants. Dans Maven, tous les mojos sont configurs avec une instantiationStrategy ayant pour valeur per-lookup. Une nouvelle instance du composant (mojo) est cre chaque fois qu'on demande Plexus de nous le fournir. executionStrategy Il s'agit du choix de la stratgie utilise par Maven pour excuter un Mojo. Les diffrentes valeurs utilisables dans cet lment sont once-per-session et always. Note : cette proprit est dornavant deprecated et n'est plus utilise par Maven, elle sera supprime dans les prochaines releases.
324
parameters Cette balise dcrit chacun des paramtres du Mojo. Quel est son nom ? Quel est son type ? Estil obligatoire ? Chaque paramtre possde les lments suivants : name Il s'agit du nom du paramtre (exemple baseDirectory) type Il s'agit du type Java du paramtre (exemple [Link]) required Indique si le paramtre est obligatoire. Affect true, le paramtre doit obligatoirement tre pass au goal excut avec une valeur non nulle. editable Si un paramtre n'est pas ditable (si cette proprit est positionne false), alors la valeur de ce paramtre ne pourra pas tre modifie dans un POM. Par exemple, si le descripteur de plugin dfinit la valeur de la proprit buildDirectory ${basedir}, aucun POM ne pourra pas surcharger cette valeur. description Courte description utilise lors de la gnration de la documentation du plugin (utilise par le plugin Help) configuration Cet lment fournit les valeurs par dfaut de tous les paramtres du Mojo utilisant la notation pour les expressions Maven. Cet exemple fournit la valeur par dfaut des paramtres Mojo baseDir et buildDirectory. Dans cet lment, l'implmentation spcifie le type ([Link]), la valeur du paramtre peut contenir soit une valeur par dfaut en dur soit une rfrence une proprit Maven. requirements C'est ici que le descripteur de plugin devient intressant. Un Mojo est un composant gr par Plexus. Grce cela, il est possible de rfrencer n'importe quel autre composant gr par Plexus. Cette proprit permet de dfinir des dpendances vers d'autres composants Plexus. Mme s'il est intressant de savoir comment lire un descripteur de plugin, vous ne devriez pratiquement jamais avoir en crire un. Les descripteurs de plugin sont gnrs automatiquement partir d'annotations prsentes dans le code source du Mojo.
325
Le plugin Archetype va crer ainsi le rpertoire nomm my-first-plugin qui contiendra le POM suivant. Exemple 17.2. Le POM d'un projet de plugin
<?xml version="1.0" encoding="UTF-8"?><project> <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>first-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <packaging>maven-plugin</packaging> <name>first-maven-plugin Maven Mojo</name> <url>[Link] <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>maven-plugin-api</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
L'lment le plus important d'un POM de projet de plugin est la balise packaging, celle-ci doit contenir la valeur maven-plugin. Ce type de packaging personnalise le cycle de vie Maven pour
326
inclure les goals ncessaires la cration du descripteur de plugin. Le cycle de vie Plugin a t prsent dans le Section 10.2.3, Plugin Maven , il ressemble fortement au cycle de vie Jar ces trois exceptions prs : le goal plugin:descriptor est rattach la phase generateresources, le goal plugin:addPluginArtifactMetadata est rattach la phase package, et le goal plugin:updateRegistry est rattach la phase install. L'autre partie importante d'un POM de projet de plugin est la dpendance sur Maven Plugin API. Ici, le projet dpend de la version 2.0 de maven-plugin-api et ainsi que de JUnit pour les tests unitaires.
L'excution du goal a t-elle russi ? Ou, au contraire, une erreur est-elle survenue durant l'excution du goal ? Lorsque Maven charge et excute un Mojo, il appelle la mthode setLog() et passe ainsi au plugin ainsi un journal pour y crire ses traces.
protected Log getLog()
Comme nous venons de voir, Maven appelle la mthode setLog() avant d'excuter votre Mojo, celui-ci peut donc rcuprer le journal inject par l'intermdiaire de la mthode getLog(). Au lieu d'afficher l'avancement sur la sortie standard ou dans la console, il est prfrable d'utiliser les mthodes de l'objet Log.
void execute() throws [Link]
Cette mthode est appele par Maven au moment de lancer l'excution du goal. L'interface Mojo est responsable de deux choses : excuter un goal et en tracer les rsultats. Lorsque vous crivez un plugin, vous pouvez faire hriter vos Mojos de la classe AbstractMojo. AbstractMojo implmente les mthodes setLog() et getLog(). Il vous reste donc implmenter la mthode execute() qui est dclare comme abstraite dans cette classe mre. L'Exemple 17.3, Un simple EchoMojo prsente une implmentation simple d'un Mojo qui se contente d'afficher un message dans la console. Exemple 17.3. Un simple EchoMojo
package [Link]; import [Link]; import [Link]; import [Link];
327
/** * Echos an object string to the output screen. * @goal echo * @requiresProject false */ public class EchoMojo extends AbstractMojo { /** * Any Object to print out. * @parameter expression="${[Link]}" default-value="Hello World..." */ private Object message; public void execute() throws MojoExecutionException, MojoFailureException { getLog().info( [Link]() ); } }
Si vous crez ce Mojo dans le rpertoire ${basedir} sous src/main/java l'emplacement org/sonatype/mavenbook/mojo/[Link] dans le projet cr prcdemment et que vous excutez la commande mvn install, vous devriez tre capable d'appeler votre directement goal partir de la ligne de commande :
$ mvn [Link]:first-maven-plugin:1.0-SNAPSHOT:echo
Cette (longue) ligne de commande est un simple appel mvn suivi d'un argument : groupId:artifactId:version:goal. Lorsque vous excutez cette ligne de commande, vous devriez voir apparatre le message "Hello Maven World..." dans votre console. Pour personnaliser ce message, vous pouvez passer le paramtre suivant cette mme ligne de commande :
$ mvn [Link]:first-maven-plugin:1.0-SNAPSHOT:echo \
Cette ligne de commande excute le goal EchoMojo et affiche le message "The Eagle has Landed".
Vous pouvez utiliser le prfixe jar. Ainsi, la ligne de commande devient beaucoup plus digeste : mvn jar:jar. Comment Maven sait-il transformer jar:jar en [Link]:mavenjar:2.3 ? Maven regarde dans un fichier du dpt Maven pour obtenir la liste des plugins pour un groupId spcifique. Par dfaut, Maven est configur pour rechercher les plugins dans deux groupes :
328
[Link] et [Link]. Lorsque vous spcifiez un nouveau prfixe comme mvn hibernate3:hbm2ddl, Maven scanne les mtadonnes du dpt Maven la recherche du plugin appropri. Maven commence par parcourir les groupes [Link] la recherche du prfixe hibernate3. S'il n'y trouve pas de prfixe hibernate3, il continuera en parcourant les mtadonnes du groupe [Link].
Lorsque Maven parcourt les mtadonnes d'un groupId, il rcupre deuis le dpt Maven le fichier XML qui contient les mtadonnes des artefacts de ce groupe. Ce fichier XML est spcifique chaque dpt. Si vous n'avez pas configur de dpt, Maven se contentera de chercher dans les mtadonnes du groupe [Link] dans votre dpt Maven local (~/.m2/repository) dans le fichier org/apache/maven/plugins/[Link]. L'Exemple 17.4, Mtadonnes Maven du groupe Maven Plugin prsente une partie du fichier XML [Link] du groupe [Link]. Exemple 17.4. Mtadonnes Maven du groupe Maven Plugin
<?xml version="1.0" encoding="UTF-8"?> <metadata> <plugins> <plugin> <name>Maven Clean Plugin</name> <prefix>clean</prefix> <artifactId>maven-clean-plugin</artifactId> </plugin> <plugin> <name>Maven Compiler Plugin</name> <prefix>compiler</prefix> <artifactId>maven-compiler-plugin</artifactId> </plugin> <plugin> <name>Maven Surefire Plugin</name> <prefix>surefire</prefix> <artifactId>maven-surefire-plugin</artifactId> </plugin> ... </plugins> </metadata>
Comme vous pouvez le voir dans l'Exemple 17.4, Mtadonnes Maven du groupe Maven Plugin , c'est ce fichier [Link] qui rend possible l'excution de la commande mvn surefire:test. Maven parcourt [Link] et [Link] : les plugins du groupe [Link] sont considrs comme des plugins du cur Maven, alors que les plugins du groupe [Link] sont considrs comme des plugins moins importants. Le projet Apache Maven gre le groupe [Link], et c'est une communaut open source indpendante qui a la charge du projet Codehaus Mojo. Si vous dsirez publier vos plugins avec votre groupId, et que Maven parcourt automatiquement le prfixe de plugin de votre nouveau groupId, vous pouvez personnaliser les groupes traits par Maven dans vos fichiers Maven de configuration personnelle.
329
Pour excuter votre goal echo first-maven-plugin en utilisant la commande first:echo, ajoutez le groupId [Link] dans votre fichier ~/.m2/[Link] comme le montre l'Exemple 17.5, Personnaliser les groupes de plugins dans les Settings Maven . Ainsi, un nouveau groupe sera ajout en dbut de liste des groupes analyss par Maven. Exemple 17.5. Personnaliser les groupes de plugins dans les Settings Maven
<settings> ... <pluginGroups> <pluginGroup>[Link]</pluginGroup> </pluginGroups> </settings>
Ceci fait, vous pouvez maintenant excuter votre goal par l'intermdiaire de la commande mvn first:echo partir de n'importe quel rpertoire. Vous constaterez que Maven saura interprter correctement votre prfixe. Cela fonctionne car le projet respecte certaines conventions de nommage. Si votre projet plugin a un artifactId qui respecte le format maven-first-plugin ou firstmaven-plugin, Maven affectera automatiquement le prfixe first votre plugin. En d'autres termes, lorsque le plugin Maven Plugin a gnr le descripteur de votre plugin et que vous n'avez pas spficifi de goalPrefix dans votre projet, le goal plugin:descriptor rcuprera le prfixe de votre plugin partir de son artifactId lorsqu'il suit l'un des formats suivants : ${prefix}-maven-plugin, OU maven-${prefix}-plugin Si vous dsirez dfinir explicitement un prfixe de plugin, you avez besoin de configurer le plugin Maven Plugin. Le plugin Maven Plugin est responsable de la construction du descripteur de plugin et doit galement effectuer certaines tches durant les phases de packaging et de chargement. Le plugin Maven Plugin est configurable comme n'importe quel autre plugin via la balise build. Pour configurer le prfixe de votre plugin, ajoutez le code XML dans la balise build du projet first-maven-plugin. Exemple 17.6. Configuration d'un prfixe de plugin
<?xml version="1.0" encoding="UTF-8"?><project> <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>first-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <packaging>maven-plugin</packaging> <name>first-maven-plugin Maven Mojo</name> <url>[Link] <build> <plugins> <plugin> <artifactId>maven-plugin-plugin</artifactId> <version>2.3</version> <configuration> <goalPrefix>blah</goalPrefix>
330
</configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>maven-plugin-api</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
L'Exemple 17.6, Configuration d'un prfixe de plugin configure le prfixe du plugin pour qu'il prenne la valeur blah. Si vous avez ajout le groupe [Link] la liste des groupes pluginGroups de votre fichier ~/.m2/[Link], vous devriez pouvoir excuter EchoMojo en lanant la commande suivante mvn echo:blah.
trace, elle propose donc un mcanisme similaire l'API fournie par Log4J5. Ces diffrents niveaux sont utilisables par l'intermdiaire de plus mthodes ddies : debug, info, error et warn. Afin de sauver les arbres, nous ne listerons ici que les mthodes du niveau degug.
void debug( CharSequence message )
Affiche un message en utilisant le niveau debug et ajoute une trace de l'tat de la pile partir d'une Throwable Exception ou Error)
void debug( Throwable t )
Affiche la trace de l'tat de la pile de laThrowable (Exception ou Error) Chacun de ces quatre niveaux expose ces trois mthodes. Ces quatre niveaux rpondent quatre buts diffrents. Le niveau debug est ddi aux personnes qui dsirent une vue trs dtaille de ce qui se
5
[Link]
331
passe lors de l'excution d'un Mojo. Vous ne devez donc jamais prsumer que vos utilisateurs utilisent ce niveau. Pour cela, il est prfrable d'utiliser le niveau info qui est destin afficher des messages d'informations gnraux lors d'une utilisation normale du mojo. Par exemple, si vous construisez un plugin qui compile du code, utilisez ce niveau info pour afficher la sortie du compilateur l'cran. Le niveau de logging warn est utilis pour afficher des vnements et messages d'erreurs que votre Mojo pourrait rencontrer. Par exemple, si vous essayez d'excuter un plugin qui compile du code source Ruby mais que ce code n'est pas disponible, affichez un warning. Contrairement aux erreurs (qui disposent d'un niveau ddi : error), les warnings ne sont pas destins afficher des erreurs bloquantes. Vous utiliseriez plutt le niveau error lorsque votre Mojo qui doit compiler du code, ne trouve pas de compilateur. Dans ce cas, vous voudrez probablement afficher un message d'erreur et lever une exception. Vous pouvez considrer que vos utilisateurs verront les messages en info et tous les messages d'erreurs.
332
ne devrait s'excuter qu' partir du projet de plus haut-niveau d'un build Maven. Sa valeur par dfaut est false. @requiresOnline (true|false) Spcifie si un goal donn peut s'excuter en mode hors connexion. Si un goal ncessite l'utilisation de ressources rseau et que ce flag est activ, Maven affichera une erreur si le goal est excut en mode hors connexion. La valeur par dfaut pour cette proprit est false. @requiresDirectInvocation Si vous affectez cette proprit true, le goal pourra seulement s'excuter via un appel direct en ligne de commande par un utilisateur. Si quelqu'un essaye de rattacher ce goal une phase du cycle de vie dans un POM, Maven affichera un message d'erreur. La valeur par dfaut pour est proprit est false. @phase <phaseName> Cette annotation spcifie la phase par dfaut d'un goal. Si vous n'avez pas spcifi de phase pour excuter ce goal, Maven rattachera celui-ci la phase dfinie par cette annotation. @execute [goal=goalName|phase=phaseName [lifecycle=lifecycleId]] Cette annotation peut tre utilise de diffrentes manires. Si une phase est fournie, Maven excutera un cycle de vie parallle en fin d'une phase spcifique. Le rsultat de cette excution parallle est rendu disponible dans la proprit Maven ${executedProperty}. La seconde manire d'utiliser cette annotation est de spcifier explicitement un goal en utilisant la notation prefix:goal. Lorsque vous spcifiez un goal, Maven excute celui-ci dans un environnement parallle, qui n'affecte pas le build Maven courant. La troisime manire d'utiliser cette annotation est de spcifier une phase dans un cycle de vie alternatif en utilisant un identifiant de cycle de vie.
@execute phase="package" lifecycle="zip" @execute phase="compile" @execute goal="zip:zip"
Si vous regardez le code source du EchoMojo, vous noterez que Maven n'utilise pas des annotations standards au format Java 5. la place, il utilise les Commons Attributes6. Commons Attributes fournissait un moyen d'utiliser des annotations avant qu'elles ne fassent partie intgrante des spcifications Java. Pourquoi ne pas utiliser les annotations Java 5 ? Maven ne les utilise pas car il a t conu pour des JVMs pr-Java 5. Comme Maven dsire rester compatible avec les versions antrieures de Java, il ne peut pas utiliser les fonctionnalits disponibles dans Java 5.
[Link]
333
qu'importante, ces exception ont un impact sur ce qui arrive lorsqu'une excution "choue". Une MojoExecutionException se doit d'tre fatale, quelque chose d'irrcuprable est arriv. Lancez cette exception lorsque quelque chose arrive et que vous souhaitez arrter le build. Par exemple, vous essayez d'crire sur le disque qui n'a plus d'espace libre ou que vous essayez de vous connecter un dpt distant qui ne rpond pas. Lancez donc MojoExecutionException si vous n'avez aucune chance que votre build puisse continuer correctement, lorsque quelque chose d'horrible est arriv et que vous voulez arrter le build et afficher l'utilisateur un message "BUILD ERROR". L'exception MojoFailureException correspond un vnement moins catastrophique, quelque chose qui ne doit pas dclencher la fin du build. Un test unitaire peut chouer, un checksum MD5 peut chouer, ces deux exemples sont des problmes, mais pas assez important pour arrter votre build. C'est dans ce type situation que vous devez utiliser MojoFailureException. Maven prvoit plusieurs comportements diffrents lorsqu'un projet choue. En voici les descriptions. Lorsque vous lancez un build Maven, vous pouvez invoquer une srie de projets qui peuvent chacun soit russir soit chouer. Vous pouvez dmarrer Maven sous trois modes diffrents : mvn -ff Mode fail-fast : Maven choue (s'arrte) au premier chec. mvn -fae Mode Fail-at-end : dans ce mode, Maven chouera la fin du build. Si un projet du reactor de Maven choue, Maven continuera l'excution de son build et n'affichera l'chec qu'en fin de build. mvn -fn Mode Fail never : Maven ne s'arrte pas en cas d'chec et ne reportera pas d'erreur. Vous pourrez vouloir ignorer les erreurs si vous excutez un build d'intgration continue et que vous voulez le poursuivre mme lorsque le build de l'un des projets choue. En tant que dveloppeur de plugin, vous devez prendre soin de lancer la bonne exception MojoExecutionException ou MojoFailureExeception en fonction de votre type d'erreur.
334
L'expression par dfaut pour ce paramtre est ${[Link]}. Cela veut dire que Maven essayera d'utiliser la valeur de la proprit [Link] pour affecter la valeur du message. Si cette proprit est nulle, le paramtre prendra la valeur dfinie grce l'attribut default-value de l'annotation @parameter. Au lieu d'utiliser la proprit [Link], vous pouvez configurer une valeur pour ce message directement partir du POM de votre projet. Plusieurs moyens existent pour renseigner la valeur du paramtre 'message' de notre EchoMojo. Premirement, vous pouvez passer une valeur partir de la ligne de commande en utilisant la syntaxe suivante ( supposer que vous ayez ajout [Link] votre pluginGroups) :
$ mvn first:echo -[Link]="Hello Everybody"
Vous pouvez galement spcifier la valeur de ce message en dfinissant une proprit dans votre POM ou dans votre fichier [Link].
<project> ... <properties> <[Link]>Hello Everybody</[Link]> </properties> </project>
Ce paramtre peut galement tre configur directement par l'intermdiaire d'une valeur de configuration de votre plugin. Si vous voulez personnaliser directement le paramtre 'message', vous pouvez utiliser la configuration suivante pour votre build. Celle-ci court-circuite la proprit [Link] et renseigne le paramtre du Mojo partir de la configuration du plugin.
<project> ... <build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>first-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <configuration> <message>Hello Everybody!</message> </configuration> </plugin> </plugins> </build> </project>
335
Si vous dsirez excuter votre EchoMojo deux fois dans diffrentes phases du cycle de vie, et si vous voulez configurer le paramtre 'message' avec deux valeurs diffrentes, vous pouvez configurer la valeur de ce paramtre partir de la balise execution dans votre POM de la manire suivante :
<build> <build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>first-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <executions> <execution> <id>first-execution</id> <phase>generate-resources</phase> <goals> <goal>echo</goal> </goals> <configuration> <message>The Eagle has Landed!</message> </configuration> </execution> <execution> <id>second-execution</id> <phase>validate</phase> <goals> <goal>echo</goal> </goals> <configuration> <message>${[Link]}</message> </configuration> </execution> </executions> </plugin> </plugins> </build> </build>
Mme si ce dernier exemple est assez verbeux, il illustre la flexibilit de Maven. Dans l'exemple prcdent, vous avez rattach l'EchoMojo aux phases validate et generate-resources du cycle de vie par dfaut. La premire balise execution est rattache la phase generate-resources, elle fournit la valeur suivante la proprit 'message' : "The Eagle has Landed!". La seconde balise execution est rattache la phase validate, elle fournit une rfrence la proprit ${[Link]}. Lorsque vous excutez la commande mvn install sur ce projet, vous verrez que le goal first:echo s'excute deux fois et affiche deux messages diffrents.
336
includes et excludes acceptent un tableau de String qui spcifient des paramtres d'inclusion et
l'exclusion pour crer le fichier ZIP. Exemple 17.7. Un plugin avec des paramtres multi-valeurs
package [Link] /** * Zips up the output directory. * @goal zip * @phase package */ public class ZipMojo extends AbstractMojo { /** * The Zip archiver. * @parameter \ expression="${[Link]#zip}" */ private ZipArchiver zipArchiver; /** * Directory containing the build files. * @parameter expression="${[Link]}" */ private File buildDirectory; /** * Base directory of the project. * @parameter expression="${basedir}" */ private File baseDirectory; /** * A set of file patterns to include in the zip. * @parameter alias="includes" */ private String[] mIncludes; /** * A set of file patterns to exclude from the zip. * @parameter alias="excludes" */ private String[] mExcludes; public void setExcludes( String[] excludes ) { mExcludes = excludes; } public void setIncludes( String[] includes ) { mIncludes = includes; } public void execute() throws MojoExecutionException { try { [Link]( buildDirectory, includes, excludes );
337
[Link]( new File( baseDirectory, "[Link]" ) ); [Link](); } catch( Exception e ) { throw new MojoExecutionException( "Could not zip", e ); } } }
Pour configurer un paramtre de Mojo multi-valeurs, vous pouvez utiliser une liste d'lments. Si le nom d'un paramtre multi-valeurs est includes, vous utiliserez une balise includes contenant des lments include. Si le paramtre multi-valeurs est excludes, vous utiliserez une balise excludes contenant des lments exclude. Pour configurer le ZipMojo pour qu'il ignore tous les fichiers .txt et tous les fichiers qui terminent par un tilde, vous pouvez utiliser la configuration de plugin suivante.
<project> ... <build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>zip-maven-plugin</artifactId> <configuration> <excludes> <exclude>**/*.txt</exclude> <exclude>**/*~</exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
338
Lorsque Maven instancie ce Mojo, il essaye de rcuprer le composant Plexus ayant le rle et le raccourci de rle spcifis. Dans cet exemple, le Mojo sera rattach au composant ZipArchiver. ce qui permettra notre ZipMojo de crer des fichiers ZIP.
Cette ligne a pour effet de rcuprer le composant ZipArchiver partir de Plexus. Il s'agit de l'Archiver qui correspond au role hint zip. An lieu d'injecter des composants, vous pouvez galement utiliser l'annotation @parameter en utilisant une expression :
339
@parameter expression="${[Link]#zip}"
Si ces deux annotations ont le mme comportement, l'annotation @component est privilgier pour configurer des dpendances sur des composants Plexus. @deprecated Indique que ce paramtre est dprci. Les utilisateurs peuvent continuer de configurer ce paramtre, mais un warning sera affich.
340
@execute phase="<phase>" Un cycle de vie alternatif, spcifi par la phase donne, sera excut en parallle avant de reprendre l'excution courante. @execute lifecycle="<lifecycle>" phase="<phase>" Cette annotation provoque l'excution du cycle de vie alternatif. Un cycle de vie personnalis peut tre dfini dans le fichier META-INF/maven/[Link].
Si vous voulez excuter la phase zipcycle au sein d'un autre build, vous pouvez crer un ZipForkMojo qui utilise l'annotation @execute pour demander Maven de traverser la phase zipcycle avant l'excution du build courant. Exemple 17.10. Fork d'un cycle de vie partir d'un Mojo
/** * Forks a zip lifecycle. * @goal zip-fork * @execute lifecycle="zipcycle" phase="package" */ public class ZipForkMojo extends AbstractMojo {
341
Excuter le ZipForkMojo lancera un fork du cycle de vie. Si vous avez configur votre plugin pour qu'il s'excuter avec le prfixe zip, l'excution de zip-fork devrait produire une sortie ressemblant cela.
$ mvn zip:zip-fork [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'zip'. [INFO] ---------------------------------------------------------------------[INFO] Building Maven Zip Forked Lifecycle Test [INFO] task-segment: [zip:zip-fork] [INFO] ---------------------------------------------------------------------[INFO] Preparing zip:zip-fork [INFO] [site:attach-descriptor] [INFO] [zip:zip] [INFO] Building zip: \ ~/maven-zip-plugin/src/projects/zip-lifecycle-test/target/[Link] [INFO] [zip:zip-fork] [INFO] doing nothing here [INFO] --------------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] --------------------------------------------------------------------[INFO] Total time: 1 second [INFO] Finished at: Sun Apr 29 16:10:06 CDT 2007 [INFO] Final Memory: 3M/7M [INFO] ---------------------------------------------------------------------
L'excution de zip-fork a cr un nouveau cycle de vie, Maven a ensuite excut le cycle de vie zipcycle et a affich le message contenu dans notre ZipFormMojo.
342
l'Exemple 17.11, Surcharge du cycle de vie par dfaut . Mettez le nom du type de packaging dans role-hint, et rattachez les goals aux phases en utilisant leurs coordonnes (sans la version). Vous pouvez associer plusieurs goals une phase en utilisant une liste spare par des virgules. Exemple 17.11. Surcharge du cycle de vie par dfaut
<component-set> <components> <component> <role>[Link]</role> <role-hint>zip</role-hint> <implementation> [Link] </implementation> <configuration> <phases> <process-resources> [Link]:maven-resources-plugin:resources </process-resources> <compile> [Link]:maven-compiler-plugin:compile </compile> <package>[Link]:maven-zip-plugin:zip</package> </phases> </configuration> </component> </components> </component-set>
Si vous crez un plugin qui dfinit un nouveau type de packaging et un nouveau cycle de vie, vous devez affecter la balise extensions true dans le POM de votre projet. Cela a pour effet de demander Maven de scanner votre plugin la recherche du fichier [Link] dans le rpertoire METAINF/plexus. Ainsi, votre nouveau type de packaging sera rendu disponible dans votre projet. Exemple 17.12. Configuration d'un plugin en Extension
<project> ... <build> ... <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>maven-zip-plugin</artifactId> <extensions>true</extensions> </plugin> </plugins> </build> </project>
343
Une fois que vous avez ajout le plugin avec sa balise extensions active, vous pourrez utiliser votre nouveau type de packaging. Votre projet pourra ainsi excuter le cycle de vie personnalit associ celui-ci.
344
[Link]
artifactId
Il d'agit de la version du projet que vous voulez crer (valeur par dfaut : 1.0-SNAPSHOT).
packageName
Lorsque le goal generate goal est excut dans ce mode, les paramtres lists prcdemment seront demands l'utilisateur les uns aprs les autres durant l'excution. Dans le cas contraire, le goal generate utilise les valeurs passes en la ligne de commande. Une fois que vous avez excut le goal generate avec la ligne de commande prcdente, un rpertoire quickstart contenant un nouveau projet Maven est cr. Cette ligne de commande est relativement difficile retenir. Dans la section suivante, nous gnrerons ce mme projet en utilisant le mode interactif.
346
6: internal -> appfuse-modular-jsf 7: internal -> appfuse-modular-spring 8: internal -> appfuse-modular-struts 9: internal -> appfuse-modular-tapestry 10: internal -> maven-archetype-j2ee-simple 11: internal -> maven-archetype-marmalade-mojo 12: internal -> maven-archetype-mojo 13: internal -> maven-archetype-portlet 14: internal -> maven-archetype-profiles 15: internal -> maven-archetype-quickstart 16: internal -> maven-archetype-site-simple 17: internal -> maven-archetype-site 18: internal -> maven-archetype-webapp 19: internal -> jini-service-archetype 20: internal -> softeu-archetype-seam 21: internal -> softeu-archetype-seam-simple 22: internal -> softeu-archetype-jsf 23: internal -> jpa-maven-archetype 24: internal -> spring-osgi-bundle-archetype 25: internal -> confluence-plugin-archetype 26: internal -> jira-plugin-archetype 27: internal -> maven-archetype-har 28: internal -> maven-archetype-sar 29: internal -> wicket-archetype-quickstart 30: internal -> scala-archetype-simple 31: internal -> lift-archetype-blank 32: internal -> lift-archetype-basic 33: internal -> cocoon-22-archetype-block-plain 34: internal -> cocoon-22-archetype-block 35: internal -> cocoon-22-archetype-webapp 36: internal -> myfaces-archetype-helloworld 37: internal -> myfaces-archetype-helloworld-facelets 38: internal -> myfaces-archetype-trinidad 39: internal -> myfaces-archetype-jsfcomponents 40: internal -> gmaven-archetype-basic 41: internal -> gmaven-archetype-mojo Choose a number: 15
Pour commencer, le goal archetype:generate en mode interactif affiche la liste des archtypes disponibles pour l'utilisateur. Le plugin Maven Archetype est founi avec un catalogue d'archtypes correspondants la plupart des types de projets standards (archtypes 10 18). Le catalogue d'archtypes du plugin peut galement tre complt par des archtypes tiers, comme des archtypes permettant de gnrer des projets AppFuse, des plugins Confluence ou Jira, des applications Wicket, des applications Scala, des projets Groovy, ... Vous pouvez consulter une liste non exhaustive des archtypes proposs par des tiers dans la partie Section 18.3.2, Archtypes tiers notables . Une fois que vous avez choisi un archtype, le plugin Maven Archetype tlcharge celui-ci et vous demande de fournir les valeurs suivantes pour gnrer votre nouveau projet : groupId artifactId
347
version package
[INFO] artifact [Link]:maven-archetype-quickstart: checking for updates from cen Downloading: [Link] 4K downloaded Define value for groupId: : [Link] Define value for artifactId: : quickstart Define value for version: 1.0-SNAPSHOT: : 1.0-SNAPSHOT Define value for package: [Link]: : [Link] Confirm properties configuration: groupId: [Link] artifactId: quickstart version: 1.0-SNAPSHOT package: [Link] Y: : Y
Une fois ceci fait, le plugin Maven Archetype gnre le projet dans le rpertoire que vous avez indiqu.
[INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO]
---------------------------------------------------------------------------Using following parameters for creating OldArchetype: maven-archetype-quickstart:RELEASE ---------------------------------------------------------------------------Parameter: groupId, Value: [Link] Parameter: packageName, Value: [Link] Parameter: basedir, Value: /Users/tobrien/tmp Parameter: package, Value: [Link] Parameter: version, Value: 1.0-SNAPSHOT Parameter: artifactId, Value: quickstart ********************* End of debug info from resources from generated POM ******************** OldArchetype created in dir: /Users/tobrien/tmp/quickstart -----------------------------------------------------------------------BUILD SUCCESSFUL -----------------------------------------------------------------------Total time: 1 minute 57 seconds Finished at: Sun Oct 12 15:39:14 CDT 2008 Final Memory: 8M/15M ------------------------------------------------------------------------
[Link] 3 [Link]
348
349
Application complte utilisant JSF (Java Server Faces) comme couche de prsentation.
appfuse-basic-spring et appfuse-modular-spring
Modle objet et sa couche de persistance sans couche prsentation. Les archtypes dont l'artifactId respecte le format appfuse-basic-* produisent une applications complte correspondant un unique projet Maven. Les archtypes dont l'artifactId respecte le format appfuse-modular-* produisent une applications complte sous la forme d'un projet Maven multimodule qui spare les objets du modle mtier, la couche de persistance et la couche prsentation. Voici un exemple permettant de gnrer une application web modulaire utilisant Spring MVC :
$ mvn archetype:generate \ -DarchetypeArtifactId=appfuse-modular-spring \
4
[Link] 5 [Link]
350
-DarchetypeGroupId=[Link] \ -DgroupId=[Link] \ -DartifactId=mod-spring \ -Dversion=1.0-SNAPSHOT \ -DinteractiveMode=false[INFO] Scanning for projects... ... [INFO] [archetype:generate] [INFO] Generating project in Batch mode [INFO] Archetype [[Link]:appfuse-modular-spring:RELEASE] found in catalog internal [INFO] ---------------------------------------------------------------------------[INFO] Using following parameters for creating OldArchetype: appfuse-modular-spring:RELEASE [INFO] ---------------------------------------------------------------------------[INFO] Parameter: groupId, Value: [Link] [INFO] Parameter: packageName, Value: [Link] [INFO] Parameter: basedir, Value: /Users/tobrien/tmp [INFO] Parameter: package, Value: [Link] [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: artifactId, Value: mod-spring ... [INFO] OldArchetype created in dir: /Users/tobrien/tmp/mod-spring [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL $ cd mod-spring $ mvn ... (an overwhelming amount of activity ~5 minutes) $ cd web $ mvn jetty:run-war ... (Maven Jetty plugin starts a Servlet Container on port 8080)
Il faut moins de cinq minutes entre la gnration du projet partir d'un archtype AppFuse et l'excution de cette application web avec son authentification et son systme de gestion des utilisateurs. Voici d'un bon exemple de la vritable force qu'apporte l'utilisation des archtypes Maven pour gnrer de nouvelles applications. Nous avons un peu simplifi le processus d'installation d'AppFuse, car nous avons oubli tout ce qui concerne le tlchargement et l'installation de la base de donnes MySQL. Mais cela n'a rien de trs compliqu au final, surtout si vous lisez "AppFuse Quickstart Documentation"6. [Link]. Plugins Confluence et JIRA Atlassian a cr quelques archtypes pour aider les personnes intresses dans le dveloppement de plugins Confluence ou JIRA. Confluence et JIRA sont respectivement un wiki et un gestionnaire d'anomalies. Ces deux produits ont acquis un grand nombre d'utilisateurs en distribuant des licences gratuites pour les projets open source. Les deux artefacts jira-plugin-archetype et confluencemaven-archetype ont le mme groupeId [Link]. Lorsque vous gnrez un plugin Confluence, l'archtype va crer un fichier [Link] qui contient les rfrences au dpt Atlassian et des dpendances sur l'artefact Confluence. Au final, le projet plugin Confluence disposera d'un exemple de macro et d'un descripteur [Link]. En utilisant l'archtype JIRA, vous crez un projet avec une classe MyPlugin vierge et un descripteur [Link] dans le rpertoire ${basedir}/src/main/resources.
6
[Link]
351
Pour plus d'information sur le dveloppement de plugin Confluence avec Maven 2, rfrez-vous la page "Developing Confluence Plugins with Maven 2"7 disponibles sur le wiki du projet. De mme, pour plus d'informations sur le dveloppement de plugins JIRA en utilisant Maven 2, rfrez-vous la page "How to Build and Atlassian Plugin"8 disponible sur l'Atlassian Developer Network. [Link]. Wicket Apache Wicket est un framework web orient composant. Il se focalise sur la gestion de l'tat de composants serveur crits en Java et en simple HTML. L o un framework comme Spring MVC ou Ruby on Rails se focalise sur la fusion d'objets d'une requte avec une srie de modles de page, Wicket se concentre plutt sur la capture des interactions et sur la structure de la page partir d'une srie de classes POJO Java. Vous pouvez gnrer un projet Wicket en utiliser le plugin Maven Archetype :
$ mvn archetype:generate ... (select the "wicket-archetype-quickstart" artifact from the interactive menu) ... ... (supply a groupId, artifactId, version, package) ... ... (assuming the artifactId is "ex-wicket") ... $ cd ex-wicket $ mvn install ... (a lot of Maven activity) ... $ mvn jetty:run ... (Jetty will start listening on port 8080) ...
Tout comme l'archtype AppFuse, cet archtype cre une application web directement excutable par le plugin Maven Jetty. Une fois lance, rendez-vous l'adresse [Link] pour consulter votre application web nouvellement produite.
Note
Pensez la puissance qu'apportent les archtypes Maven face une simple approche 'copier-coller' qui a caractris les dernires annes de dveloppement web. Il y a six ans, sans le plugin Maven Archetype, vous auriez du parcourir un livre sur AppFuse ou sur Wicket et apprendre comment bien utiliser ces frameworks avant de pouvoir en excuter le moindre bout de code dans un conteneur de servlets. Ou alors, vous auriez juste copi coll un projet existant et commenc le personnaliser selon vos besoins. Avec le plugin Maven Archetype, les dveloppeurs de framework peuvent vous fournir une application personnalise vos besoins en quelques minutes. Il s'agit d'un changement profond qui n'a pas encore atteint toutes les entreprises. On peut donc s'attendre voir se multiplier le nombre d'artefacts dans les prochaines annes.
7 8
[Link] [Link]
352
Pour gnrer un tel catalogue, vous devez parcourir un dpt Maven puis produire ce fichier XML catalogue. Le plugin Maven Archetype possde un goal nomm crawl qui effectue cela. En excutant le goal archetype:crawl partir de la ligne de commande sans argument, le plugin Maven Archetype va parcourir votre dpt local la recherche d'archtypes et crer un fichier [Link] dans le rpertoire ~/.m2/repository.
[tobrien@MACBOOK repository]$ mvn archetype:crawl [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'archetype'. [INFO] -----------------------------------------------------------------------[INFO] Building Maven Default Project
353
[INFO] task-segment: [archetype:crawl] (aggregator-style) [INFO] -----------------------------------------------------------------------[INFO] [archetype:crawl] repository /Users/tobrien/.m2/repository catalogFile null [INFO] Scanning /Users/tobrien/.m2/repository/ant/ant/1.5/[Link] [INFO] Scanning /Users/tobrien/.m2/repository/ant/ant/1.5.1/[Link] [INFO] Scanning /Users/tobrien/.m2/repository/ant/ant/1.6/[Link] [INFO] Scanning /Users/tobrien/.m2/repository/ant/ant/1.6.5/[Link] ... [INFO] Scanning /Users/tobrien/.m2/repository/xmlrpc/xmlrpc/1.2-b1/[Link] [INFO] Scanning /Users/tobrien/.m2/repository/xom/xom/1.0/[Link] [INFO] Scanning /Users/tobrien/.m2/repository/xom/xom/1.0b3/[Link] [INFO] Scanning /Users/tobrien/.m2/repository/xpp3/xpp3_min/[Link].O/xpp3_min-[Link].[Link] [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] -----------------------------------------------------------------------[INFO] Total time: 31 seconds [INFO] Finished at: Sun Oct 12 16:06:07 CDT 2008 [INFO] Final Memory: 6M/12M [INFO] ------------------------------------------------------------------------
Si vous tes intress par la cration d'un catalogue d'archtypes, c'est gnralement parce que vous tes un projet Open Source ou une socit qui dispose d'un ensemble d'archtypes partager. Ces archtypes sont probablement dj disponibles dans un dpt que vous avez besoin d'explorer pour gnrer un catalogue. En d'autres termes, vous aurez probablement envie de parcourir un rpertoire sur un dpt Maven existant et gnrer un fichier [Link] la racine du dpt. Pour cela, il vous faut passer le catalogue et le dpt en paramtre du goal archetype:crawl. La ligne de commande suivante permet de crer un fichier catalogue l'emplacement /var/www/html/ [Link], le dpt se trouve dans le rpertoire /var/www/html/maven2.
$ mvn archetype:crawl -Dcatalog=/var/www/html/[Link] \ [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'archetype'. [INFO] -----------------------------------------------------------------------[INFO] Building Maven Default Project [INFO] task-segment: [archetype:crawl] (aggregator-style) [INFO] -----------------------------------------------------------------------[INFO] [archetype:crawl] repository /Users/tobrien/tmp/maven2 catalogFile /Users/tobrien/tmp/[Link] [INFO] Scanning /Users/tobrien/tmp/maven2/com/discursive/cas/extend/cas-extend-client-java/2.1.1/cas[INFO] Scanning /Users/tobrien/tmp/maven2/com/discursive/cas/extend/cas-extend-client-java/2.2/cas-ex -Drepository=/var/www/html/maven2 ...
354
[Link]. Faire rfrence depuis le POM au dpt Flexmojos de Sonatype Flexmojos dpend de certains artefacts qui ne sont actuellement pas disponibles depuis le dpt central Maven. Ces artefacts sont disponibles depuis un dpt hberg par Sonatype. Pour utiliser Flexmojos, vous devrez faire rfrence ce dpt depuis le [Link] de votre projet. dans ce but, ajoutez l'lment repositories indiqu dans Exemple 19.1, Ajouter une rfrence au dpt Flexmojos de Sonatype au sein du POM dans le fichier [Link] de votre projet. Exemple 19.1. Ajouter une rfrence au dpt Flexmojos de Sonatype au sein du POM
<project> <modelVersion>4.0.0</modelVersion> <groupId>test</groupId> <artifactId>test</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>swc</module> <module>swf</module> <module>war</module> </modules> <repositories> <repository> <id>flexmojos</id> <url>[Link] </repository> </repositories> </project>
Le XML illustr dans Exemple 19.1, Ajouter une rfrence au dpt Flexmojos de Sonatype au sein du POM , ajoute ce dpt la liste des dpts consults par Maven quand il tente de tlcharger les artefacts et les plugins. [Link]. Utiliser Nexus comme dpt mandataire de Flexmojos de Sonatype Au lieu de pointer directement vers le dpt Flexmojos de Sonatype, Sonatype recommande d'installer un gestionnaire de dpt et de le mettre en proxy du dpt public de Sonatype. Quand vous mettez en place un proxy d'un dpt distant avec un gestionnaire de dpt comme Nexus, vous gagnez un niveau supplmentaire de contrle et de stabilit qu'il n'est pas possible d'atteindre lorsque votre build dpend directement de ressources externes. En plus de ce contrle et de cette stabilit, un gestionnaire de dpt fournit aussi une cible pour le dploiement des artefacts binaires produits par vos builds. Les instructions pour tlcharger, installer et configurer Nexus sont disponibles dans le Installation chapter in Repository Management with Nexus1. Une fois Nexus install et dmarr, effectuez les oprations suivantes pour lui ajouter une fonction de mandataire du dpt public de Sonatype.
1
[Link]
356
Pour ajouter un nouveau proxy d'un dpt, cliquez sur le lien Repositories sous Views/Repositories dans le menu Nexus de la partie gauche de l'interface utilisateur de Nexus. Ce click sur Repositories va charger le panneau Repositories. Dans ce panneau Repositories, cliquez sur le bouton Add.. et slectionnez Proxy Repository comme le montre la Figure 19.1, Ajout du proxy d'un dpt sur Sonatype Nexus .
Figure 19.1. Ajout du proxy d'un dpt sur Sonatype Nexus Une fois que vous avez cr ce nouveau dpt proxy, il vous faut le configurer pour qu'il pointe vers le dpt public Flexmojos de Sonatype. Slectionnez ce nouveau dpt puis l'onglet de Configuration en bas de la fentre. Remplissez les champs suivants avec les valeurs indiques comme le montre la Figure 19.2, Configuration du dpt Sonatype Flexmojos Proxy . Repository ID prend pour valeur "sonatype-flexmojos" Repository Name prend pour valeur "Sonatype Flexmojos Proxy" La "Remote Storage Location" prend pour valeur [Link] flexgroup/
357
Figure 19.2. Configuration du dpt Sonatype Flexmojos Proxy Une fois que vous avez rempli les champs prsents dans Figure 19.2, Configuration du dpt Sonatype Flexmojos Proxy cliquez sur le bouton Save pour enregistrer ce dpt et commencer l'utiliser comme proxy du dpt Sonatype Flexmojos. Nexus est fourni avec un groupe public de dpts, qui regroupe plusieurs dpts en un seul point d'entre pour les clients Maven. Pour complter la configuration de ce nouveau dpt mandataire, vous devez ajouter celui-ci au groupe Nexus Public Repositories. Pour ce faire, allez la liste des dpts qui devrait tre visible dans le haut du panneau Repositories comme le montre Figure 19.2, Configuration du dpt Sonatype Flexmojos Proxy . Cliquez sur le groupe Public Repositories puis sur l'onglet Configuration en bas du panneau Repository. Cliquer sur l'onglet Configuration fait apparatre le formulaire Group configuration comme le montre Figure 19.3, Ajout du proxy de Sonatype Flexmojos au groupe Public Repositories .
358
Figure 19.3. Ajout du proxy de Sonatype Flexmojos au groupe Public Repositories Pour ajouter le Sonatype Public Proxy au groupe Public Repositories faites un glisser/dposer du dpt Sonatype Public Proxy de la liste Available Repositories dans la liste Ordered Group Repositories. Cliquez sur le bouton Save et vous aurez ajout avec succs un proxy du dpt Sonatype Flexmojos votre installation de Nexus. chaque fois qu'un client va demander un artefact ce groupe de dpt, si Nexus ne l'a pas dj mis en cache il va le demander au dpt Sonatype Flexmojos situ http:// [Link]/content/groups/flexgroup/. Votre installation de Nexus maintient un cache local de tous les artefacts rcuprs depuis le dpt Sonatype Flexmojos. Ce cache local vous donne plus de contrle et rend l'environnement de build plus stable. Si vous montez une quipe de dveloppeurs qui dpend des artefacts du dpt public de Sonatype, vous aurez ainsi un environnement de build autonome qui ne dpendra pas de la disponibilit du dpt de Sonatype une fois que les artefacts ncessaires auront t mis en cache par votre instance de Nexus. La dernire tape consiste faire pointer votre installation de Maven vers l'instance de Nexus que vous venez de configurer. Vous devez donc modifier votre configuration Maven pour qu'il utilise le groupe du dpt Nexus comme miroir pour tous les dpts. Pour cela, vous devez diter votre fichier ~/.m2/ [Link] et lui ajouter le XML suivant.
359
Ce fichier XML configure Maven pour qu'il aille consulter le groupe de dpts publics plutt que les dpts d'artefacts et de plugins configurs par ailleurs. C'est une faon simple de garantir que toute demande d'artefact passe par le Nexus install.
360
Microsoft Windows FlexMojos tentera de lancer le binaire [Link]. Pour permettre l'excution des tests unitaires, ajoutez votre PATH le rpertoire contenant [Link], ou alors prcisez la localisation du binaire [Link] via l'option de ligne de commande Maven [Link]=${filepath}. Macintosh OSX FlexMojos tentera de lancer l'application "Flash Player". Pour permettre l'excution des tests unitaires, ajoutez le rpertoire contenant "Flash Player" votre PATH, ou alors prcisez le chemin de l'excutable via l'option de ligne de commande Maven -[Link]= ${filepath}. Unix (Linux, Solaris, etc.) FlexMojos tentera de lancer l'excutable flashplayer. Pour permettre l'excution des tests unitaires, ajoutez le rpertoire contenant flashplayer votre PATH, ou alors prcisez le chemin de l'excutable via l'option de ligne de commande Maven -[Link]= ${filepath}.
Note
Sur une machine Linux, il vous faudra installer un serveur X Virtual Frame Buffer (Xvfb) pour pouvoir lancer les tests unitaires sans interface graphique. Pour plus d'information, suivez le lien Xvfb2. Si vous avez dj dvelopp des applications Flash avec Adobe Flash CS4, Adobe Flex Builder ou si vous visionnez du contenu flash dans un navigateur, alors il est probable que Flash Player soit install sur votre station de travail. Bien qu'il soit possible de configurer Maven pour qu'il utilise l'un de ces players durant la campagne de tests unitaires Flex, vous prfrerez vous assurer que vous lancez bien la version debug de Flash Player. Pour minimiser les risques d'incompatibilit, vous devriez tlcharger l'un des Flash Players lists ci-dessous et l'installer sur votre station de travail. Pour tlcharger Flash Player selon l'environnement : Windows : flashplayer_10_sa_debug.exe3 [Link]
Mac OSX : [Link] flashplayer_10_sa_debug.app.zip4 Linux : [Link] 5 flash_player_10_linux_dev.[Link] Lancez la commande suivante pour installer ce player et l'ajouter votre PATH sur une machine OSX :
$ wget [Link]
flashplayer_10_sa_debug.[Link]
361
Plutt que d'ajouter en ligne de commande le chemin de Flash Player votre PATH, vous devriez configurer votre environnement. Sur OSX, il vous suffit d'ajouter cette dernire commande d'export votre fichier ~/.bash_profile.
Une fois que vous avez ajout ces groupes de plugins votre configuration Maven, vous pouvez invoquer les goals FlexMojos en utilisant le prfixe de plugin flexmojos. Sans cette configuration, invocation du goal flexbuilder ncessite la ligne de commande suivante :
$ mvn [Link]:flexmojos-maven-plugin:3.2.0:flexbuilder
Avec le groupe [Link] dans votre configuration Maven, le mme goal peut tre invoqu comme suit :
$ mvn flexmojos:flexbuilder
362
flexmojos-archetypes-modular-webapp Cre un projet multimodule qui prsente un projet qui produit un SWC qui est consomm par un projet pour produire un SWF lequel est affich dans uen application web produite par un dernier projet.
En regardant dans le rpertoire sample-library/, vous verrez que le projet prsente une arborescence comme dans la Figure 19.4, Arborescence de l'archtype de bibliothque Flexmojo .
363
Figure 19.4. Arborescence de l'archtype de bibliothque Flexmojo Le produit du seul archtype de bibliothque Flex contient trois fichiers : un POM, un fichier source et un fichier de test unitaire. Regardons chacun de ces trois fichiers. Premirement, le Project Object Model (POM). Exemple 19.4. POM d'un archtype pour projet de bibliothque Flex
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>sample-library</artifactId> <version>1.0-SNAPSHOT</version> <packaging>swc</packaging> <name>test Flex</name> <build> <sourceDirectory>src/main/flex</sourceDirectory> <testSourceDirectory>src/test/flex</testSourceDirectory> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>3.3.0</version> <extensions>true</extensions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>flex-framework</artifactId>
364
<version>3.2.0.3958</version> <type>pom</type> </dependency> <!-- flexmojos Unit testing support --> <dependency> <groupId>[Link]</groupId> <artifactId>flexmojos-unittest-support</artifactId> <version>3.3.0</version> <type>swc</type> <scope>test</scope> </dependency> </dependencies> </project>
L'Exemple 19.4, POM d'un archtype pour projet de bibliothque Flex est trs simple, le point cl de ce POM c'est la configuration de flexmojos-maven-plugin qui positionne extensions true. Cette configuration personnalise le cycle de vie pour le packaging swc qui est dfini dans le plugin flexmojos-maven-plugin. L'archtype inclut alors la dpendance flex-framework ainsi que la dpendance de type test flexmojos-unittest-support. La dpendance flex-framework est un POM qui contient les rfrences vers les bibliothques et les ressources ncessaires la compilation une application Flex. Dans l'Exemple 19.4, POM d'un archtype pour projet de bibliothque Flex , le packaging est primordial. Le type de packaging d'un POM contrle le cycle de vie qui est utilis pour produire le rsultat de build. La valeur swc dans l'lment packaging est l'indice qui indique le cycle de vie spcifique Flex dont les spcificits sont fournies par le plugin flexmojos-maven-plugin. L'autre partie importante de ce POM est l'lment build qui prcise l'emplacement du code source Flex ainsi que celui des tests unitaires. Maintenant, jetons un coup d'oeil l'Exemple 19.5, App, l'application exemple de l'archtype de bibliothque Flex qui contient l'exemple de code d'ActionScript cr par l'archtype. Exemple 19.5. App, l'application exemple de l'archtype de bibliothque Flex
package [Link] { public class App { public static function greeting(name:String):String { return "Hello, " + name; } } }
Bien que ce code soit trs simple, il apporte un exemple et un repre immdiat : "Ecriver le reste du code ici". Bien qu'il puisse sembler idiot de tester un code aussi simple, un exemple de test nomm [Link] est propos dans le rpertoire src/test/flex. Ce test est prsent dans l'Exemple 19.6, Test unitaire de la classe App pour l'archtype de bibliothque Flex . Exemple 19.6. Test unitaire de la classe App pour l'archtype de bibliothque Flex
package [Link] {
365
import [Link]; public class TestApp extends TestCase { /** * Tests our greeting() method */ public function testGreeting():void { var name:String = "Buck Rogers"; var expectedGreeting:String = "Hello, Buck Rogers"; var result:String = [Link](name); assertEquals("Greeting is incorrect", expectedGreeting, result); } } }
Pour excuter ce build, allez au rpertoire du projet sample-library et lancez la commande : run mvn install.
$ mvn install [INFO] Scanning for projects... [INFO] -----------------------------------------------------------------------[INFO] Building sample-library Flex [INFO] task-segment: [install] [INFO] -----------------------------------------------------------------------[INFO] [resources:resources] [INFO] [flexmojos:compile-swc] [INFO] flexmojos 3.3.0 - GNU GPL License (NO WARRANTY) - \ See COPYRIGHT file [WARNING] Nothing expecified to include. Assuming source and resources folders. [INFO] Flex compiler configurations: -[Link]-server=false -[Link]-all-type-selectors=false -[Link]-generated-actionscript=false -[Link]-path ~/.m2/repository/com/adobe/flex/framework/flex/\ 3.2.0.3958... -[Link] [Link] target/classes/configs/[Link] -[Link]=true -[Link]-path src/main/flex ... [INFO] [resources:testResources] [WARNING] Using platform encoding (MacRoman actually) to copy filtered \ resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory src/test/resources [INFO] [flexmojos:test-compile] [INFO] flexmojos 3.3.0 - GNU GPL License (NO WARRANTY) - \ See COPYRIGHT file [INFO] Flex compiler configurations: -[Link]-libraries ~/.m2/repository/org/sonatype/flexmojos/\ flexmojos-unittest-support... -[Link]-generated-actionscript=false
366
-[Link]-path ~/.m2/repository/com/adobe/flex/framework/flex 3.2.0.3958/flex-3.2.0.... -[Link]=true -[Link]-path src/main/flex target/test-classes src/test/flex -[Link]=true -target-player 9.0.0 -use-network=true -verify-digests=true -load-config= [INFO] Already trust on target/test-classes/[Link] [INFO] [flexmojos:test-run] [INFO] flexmojos 3.3.0 - GNU GPL License (NO WARRANTY) - \ See COPYRIGHT file [INFO] flexunit setup args: null [INFO] -----------------------------------------------------------------------[INFO] Tests run: 1, Failures: 0, Errors: 0, Time Elpased: 0 sec [INFO] [install:install]
Note
Pour pouvoir excuter les tests unitaires Flex il vous faudra configurer votre variable d'environnement PATH afin d'inclure le lecteur Flash Player. Pour plus d'information concernant la configuration de FlexMojos pour les tests unitaires, se rfrer la Section 19.2.2, Configuration de l'environnement pour les tests Flex Unit . Quand vous excutez la commande mvn install pour ce projet, vous pouvez noter dans l'output que Maven et le plugin Flexmojos prennent en charge la gestion de toutes les bibliothques et dpendances pour le compilateur Flex. De la mme faon que Maven est excellent pour aider les dveloppeurs Java grer le contenu d'un classpath Java, Maven peut aider les dveloppeurs Flex grer la complexit de gnration des paths. Vous avez peut-tre t surpris quand votre projet Flexmojos a dmarr un navigateur web ou un lecteur Flash Player et l'a utilis pour excuter l'application TestApp construite partir de votre code source.
367
Define value for artifactId: : sample-application Define value for version: 1.0-SNAPSHOT: : 1.0-SNAPSHOT Define value for package: [Link]: : [Link] Confirm properties configuration: groupId: [Link] artifactId: sample-library version: 1.0-SNAPSHOT package: [Link] Y: : Y [INFO] Parameter: groupId, Value: [Link] [INFO] Parameter: packageName, Value: [Link] [INFO] Parameter: basedir, Value: /Users/Tim/flex-sample [INFO] Parameter: package, Value: [Link] [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: artifactId, Value: sample-application [INFO] BUILD SUCCESSFUL
Si vous regardez dans le rpertoire sample-application/ vous verrez l'arborescence de fichiers illustre dans la Figure 19.5, Structure de fichiers issue de l'archtype Application Flex .
Figure 19.5. Structure de fichiers issue de l'archtype Application Flex La gnration d'une application Flex via l'archtype produit le POM suivant. Exemple 19.7. POM gnr par l'archtype Application Flex
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>sample-application</artifactId> <version>1.0-SNAPSHOT</version> <packaging>swf</packaging> <name>sample-application Flex</name>
368
<build> <sourceDirectory>src/main/flex</sourceDirectory> <testSourceDirectory>src/test/flex</testSourceDirectory> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>3.3.0</version> <extensions>true</extensions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>flex-framework</artifactId> <version>3.2.0.3958</version> <type>pom</type> </dependency> <!-- flexmojos Unit testing support --> <dependency> <groupId>[Link]</groupId> <artifactId>flexmojos-unittest-support</artifactId> <version>3.3.0</version> <type>swc</type> <scope>test</scope> </dependency> </dependencies> </project>
La diffrence entre l'Exemple 19.7, POM gnr par l'archtype Application Flex et l'Exemple 19.4, POM d'un archtype pour projet de bibliothque Flex se trouve dans le type de packaging : swf plutt que swc. En positionnant le packaging swf, le projet produira une application Flex, savoir l'application target/[Link]. L'application exemple produite par cet archtype affichera le texte "Hello World". Le fichier source [Link] se trouve dans src/ main/flex. Exemple 19.8. Application exemple [Link]
<mx:Application xmlns:mx="[Link] layout="absolute"> <mx:Text text="Hello World!"/> </mx:Application>
L'archtype produit galement un test unitaire FlexUnit simple qui ne fait rien d'autre que d'afficher un message de trace. L'exemple de test unitaire se trouve dans src/test/flex/org/sonatype/test. Exemple 19.9. Test unitaire de [Link]
package [Link]
369
{ import [Link]; import Main; public class TestApp extends TestCase { public function testNothing():void { //TODO un implemented trace("Hello test"); } } }
19.3.3. Creation d'un projet multimodule : Une application web avec une dpendance Flex
La ligne de commande suivante cre un projet multimodule contenant un projet de bibliothque Flex rfrence par une application Flex qui elle-mme est rfrence par une application web :
$ mvn archetype:generate \
370
Si vous regardez dans le rpertoire sample-multimodule/, vous verrez une arborescence qui contient trois projets swc, swf et war.
Figure 19.6. Arborescence de fichiers issue de l'archtype multimodule Flex Le POM parent du projet multimodule est simple comme vous pouvez le voir ci-dessous. Il est constitu de rfrences aux modules swc, swf et war. Exemple 19.10. POM parent produit par l'archtype multimodule Flex
<project xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <modelVersion>4.0.0</modelVersion> <groupId>[Link]</groupId> <artifactId>sample-multimodule</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>swc</module> <module>swf</module> <module>war</module> </modules> </project>
Le projet swc a un POM simple qui ressemble au POM illustr dans l'Exemple 19.4, POM d'un archtype pour projet de bibliothque Flex . Notez que l'artifactId de ce POM ne reflte pas le nom du module mais est swc-swc. Exemple 19.11. POM du module swc
<project> <modelVersion>4.0.0</modelVersion>
371
<parent> <groupId>[Link]</groupId> <artifactId>sample-multimodule</artifactId> <version>1.0-SNAPSHOT</version> </parent> <groupId>[Link]</groupId> <artifactId>swc-swc</artifactId> <version>1.0-SNAPSHOT</version> <packaging>swc</packaging> <name>swc Library</name> <build> <sourceDirectory>src/main/flex</sourceDirectory> <testSourceDirectory>src/test/flex</testSourceDirectory> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>3.3.0</version> <extensions>true</extensions> <configuration> <locales> <locale>en_US</locale> </locales> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>flex-framework</artifactId> <version>3.2.0.3958</version> <type>pom</type> </dependency> <!-- flexmojos Unit testing support --> <dependency> <groupId>[Link]</groupId> <artifactId>flexmojos-unittest-support</artifactId> <version>3.3.0</version> <type>swc</type> <scope>test</scope> </dependency> </dependencies> </project>
Le POM du module swf est semblable au POM de l'Exemple 19.7, POM gnr par l'archtype Application Flex avec une dpendance vers l'artefact swc-swc en plus. Notez que l'artifactId de ce POM ne reflte pas le nom du rpertoire qui contient le module ; l'artifactId dans le POM ci-dessous est swf-swf.
372
373
Avertissement
Dans l'Exemple 19.12, POM du module swf , la dpendance vers "swf-swc" doit tre change en "swc-swc". C'est un bug de l'archtype multimodule Flex qui est prsent dans la version 3.3.0 de FlexMojos. Il sera corrig dans la version FlexMojos 3.2.0. Quand vous dclarez une dpendance vers un SWC, vous devez prciser le type de dpendance afin que Maven puisse localiser les artefacts adquats dans le dpt distant ou local. Dans ce cas, le projet swf-swf dpend du SWC produit par le projet swc-swc. Quand vous ajoutez la dpendance au projet swf-swf, le plugin FlexMojos ajoutera le fichier SWC appropri dans le chemin des bibliothques de compilation Flex. Maintenant, jetez un coup d'oeil dans le POM simple du module war. Exemple 19.13. POM du module war
<project> <modelVersion>4.0.0</modelVersion> <parent> <artifactId>sample-multimodule</artifactId> <groupId>[Link]</groupId> <version>1.0-SNAPSHOT</version> </parent> <groupId>[Link]</groupId> <artifactId>war-war</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <build> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <goals> <goal>copy-flex-resources</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>[Link]</groupId>
374
<artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>[Link]</groupId> <artifactId>war-swf</artifactId> <version>1.0-SNAPSHOT</version> <type>swf</type> </dependency> </dependencies> </project>
Avertissement
Dans l'Exemple 19.13, POM du module war , la dpendance vers "war-swf" doit tre remplace par "swf-swf". C'est un bug dans l'archtype multimodule Flex qui est prsent dans la version 3.3.0 de FlexMojos. Il sera corrig dans la version FlexMojos 3.2.0. Le POM illustr dans l'Exemple 19.13, POM du module war configure le plugin FlexMojos pour excuter le goal copy-flex-resources pour ce projet. Le goal copy-flex-resources copiera l'application SWF la racine de l'application web. Dans ce projet, l'excution du build et la production du WAR copieront le fichier [Link] dans le rpertoire racine de l'application web target/war-war-1.0-SNAPSHOT. Pour construire l'application web multimodule, excutez mvn install depuis le rpertoire racine. Ceci doit gnrer les artefacts swc-swc, swf-swf et war-war et produire le fichier WAR /target/[Link] qui contient le [Link] la racine de l'application web.
Note
Pour pouvoir excuter les tests unitaires Flex, il vous faudra configurer votre variable d'environnement PATH afin d'inclure le lecteur Flash Player. Pour plus d'information concernant la configuration de FlexMojos pour les tests unitaires, se rfrer la Section 19.2.2, Configuration de l'environnement pour les tests Flex Unit .
375
Exemple 19.14. Configuration de l'lment extensions true pour un cycle de vie personnalis Flex
<build> <sourceDirectory>src/main/flex</sourceDirectory> <testSourceDirectory>src/test/flex</testSourceDirectory> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>3.3.0</version> <extensions>true</extensions> <configuration> <locales> <locale>en_US</locale> </locales> </configuration> </plugin> </plugins> </build>
swc lifecycle
376
Les goals FlexMojos participants sont les suivants : flexmojos:compile-swc Ce goal compile en une bibliothque SWC tous les fichiers ActionScript et MXML prsents dans le rpertoire sourceDirectory. Un fichier SWC est une bibliothque Adobe qui contient des composants et des ressources utilises dans des applications Flex. flexmojos:test-compile Ce goal compile tous les fichiers ActionScript et MXML qui se trouvent dans le rpertoire testSourceDirectory. flexmojos:test-run Ce goal excute les tests unitaires en utilisant le lecteur Flash Player. Ce goal ne peut s'excuter que sile Flash Player a t correctement configur comme dcrit dans la Section 19.2.2, Configuration de l'environnement pour les tests Flex Unit .
swf lifecycle
Figure 19.8. Cycle de vie SWF de FlexMojos Les goals FlexMojos participants sont les suivants :
377
flexmojos:compile-swf Ce goal compile en un fichier SWF tous les fichiers ActionScript et MXML du rpertoire sourceDirectory. Un fichier SWF est un fichier qui contient une application qui peut tre exectue dans le lecteur Flash Player or le l'environnement d'excution Adobe AIR. flexmojos:test-compile Ce goal compile tous les fichiers ActionScript et MXML du rpertoire testSourceDirectory. flexmojos:test-run Ce goal excute les tests unitaires en utilisant le lecteur Flash Player. Ce goal ne peut tre excut que si le lecteur Flash Player t a correctement configur comme dcrit dans la Section 19.2.2, Configuration de l'environnement pour les tests Flex Unit .
378
flexmojos:sources Gnre un JAR contenant toutes les sources du projet Flex flexmojos:test-compile Compile toutes les classes de test du projet Flex flexmojos:test-run Excute les tests unitaires en utilisant le lecteur Adobe Flash Player flexmojos:test-swc produit un fichier SWC contenant les classes de test du projet flexmojos:wrapper Gnre une page HTML qui encapsule l'application SWF
379
projet. Le goal test-compile est utilis pour compiler les tests unitaires. Dans les projets simples crs par les archtypes FlexMojos, les goals compile-swc et compile-swf sont invoqus parce que le projet personnalise le cycle de vie et rattache compile-swc ou compile-swf la phase de compilation et test-compile la phase test-compile. Si vous avez besoin de configurer les options du compilateur FlexMojos, vous le ferez travers les options de configuration du plugin FlexMojos. Par exemple, si vous voulez que l'application avec le POM illustr dans l'Exemple 19.7, POM gnr par l'archtype Application Flex ignore les alertes de compilation au niveau du code et utilise des polices personnalises, vous pouvez utiliser une configuration de plugin comme celle illustre dans l'Exemple 19.15, Configuration du plugin pour une compilation personnalise . Exemple 19.15. Configuration du plugin pour une compilation personnalise
<build> <sourceDirectory>src/main/flex</sourceDirectory> <testSourceDirectory>src/test/flex</testSourceDirectory> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>3.3.0</version> <extensions>true</extensions> <configuration> <configurationReport>true</configurationReport> <warnings> <arrayTostringChanges>true</arrayTostringChanges> <duplicateArgumentNames>false</duplicateArgumentNames> </warnings> <fonts> <advancedAntiAliasing>true</advancedAntiAliasing> <flashType>true</flashType> <languages> <englishRange>U+0020-U+007E</englishRange> </languages> <localFontsSnapshot> ${basedir}/src/main/resources/[Link] </localFontsSnapshot> <managers> <manager>[Link]</manager> </managers> <maxCachedFonts>20</maxCachedFonts> <maxGlyphsPerFace>1000</maxGlyphsPerFace> </fonts> </configuration> </plugin> </plugins> </build>
380
L'excution
de
ce
goal
produira
les
.settings/[Link], .flexLibProperties.
Quand vous excutez la commande mvn site, Maven gnrera cette documentation et la placera dans le menu "Project Reports" comme vous pouvez le voir dans la Figure 19.10, Documentation ActionScript incluse dans le site Maven .
381
Figure 19.10. Documentation ActionScript incluse dans le site Maven Si vous avez besoin de fournir des options de configuration au goal asdoc-report, il vous faudra ajouter un lment de configuration reportSets comme le montre l'Exemple 19.17, Configuration de asdoc-report . Exemple 19.17. Configuration de asdoc-report
<reporting> <plugins> <plugin> <groupId>[Link]</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>3.3.0</version> <reportSets> <reportSet> <id>flex-reports</id> <reports> <report>asdoc-report</report> </reports> <configuration> <windowTitle>My TEST API Doc</windowTitle> <footer>Copyright 2009 Sonatype</footer> </configuration> </reportSet> </reportSets> </plugin> </plugins> </reporting>
382
Figure 19.11. Le dpt Subversion de Flexmojos Si participer au projet Flexmojos vous intresse, vous rcuprerez probablement la version courante du projet sur votre machine. Pour rcuprer le code source Flexmojos en utilisant Subversion, saisissez la ligne de commande suivante :
$ svn co [Link] flexmojos A flexmojos ... $ ls COPYRIGHT flexmojos-sandbox [Link] flexmojos-archetypes flexmojos-super-poms src flexmojos-maven-plugin flexmojos-testing flexmojos-parent flexmojos-touchstone
383
xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] <localRepository>${[Link]}/.m2/repository</localRepository> <interactiveMode>true</interactiveMode> <usePluginRegistry>false</usePluginRegistry> <offline>false</offline> <pluginGroups> <pluginGroup>[Link]</pluginGroup> </pluginGroups> ... </settings>
Les balises simples de haut niveau sont : localRepository Cette valeur correspond au chemin du dpt local. Sa valeur par dfaut est ${[Link]}/.m2/ repository. interactiveMode true si Maven doit essayer d'intragir avec les entres de l'utilisateur, false sinon. Sa valeur par dfaut est true. usePluginRegistry true si Maven doit utiliser le fichier ${[Link]}/.m2/[Link] pour grer les versions des plugins, sa valeur par dfaut est false. offline
true si le systme de build doit fonctionner en mode hors connexion, sa valeur par dfaut est false. Cette balise est trs utilile pour les serveurs de build qui ne peuvent pas se connecter
des dpts distants, soit par ce qu'il ne dispose pas de rseau, soit pour des raisons de scurit. pluginGroups Cette balise contient un liste de balises pluginGroup, chaque balise contenant un groupId. La liste est utilise lorsqu'un plugin est lanc et que le son groupId n'est pas fournit par la ligne de commande. Cette liste contient [Link] par dfaut.
386
xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] ... <servers> <server> <id>server001</id> <username>my_login</username> <password>my_password</password> <privateKey>${[Link]}/.ssh/id_dsa</privateKey> <passphrase>some_passphrase</passphrase> <filePermissions>664</filePermissions> <directoryPermissions>775</directoryPermissions> <configuration></configuration> </server> </servers> ... </settings>
Les balises utilisables dans servers: id Il s'agit de l'id du serveur (ce n'est pas le login utilisateur) il correspond l'id de la balise distributionManagement du rpository. username, password Ces lments apparaissent sous la forme d'une paire indiquant l'identifiant et le mot de passe requis pour vous authentifier sur ce serveur. privateKey, passphrase Comme pour les deux lments prcdents, cette paire indique le chemin vers une cl prive (qui se trouve par dfaut dans ${[Link]}/.ssh/id_dsa) et une passphrase, si ncessaire. Les balises passphrase et password pourront tre externalises dans le futur, pour le moment leur valeur doit tre rentr en plain-text dans le fichier [Link]. filePermissions, directoryPermissions Lorsqu'un fichier ou un rpertoire est cr lors du dploiement dans un dpt, ces permissions sont utilises. Les valeurs autorises des nombres trois chiffres correspondant aux permissions fichiers *nix, comme 664 ou 775.
387
... <mirrors> <mirror> <id>[Link]</id> <name>PlanetMirror Australia</name> <url>[Link] <mirrorOf>central</mirrorOf> </mirror> </mirrors> ... </settings>
id, name Identifiant unique d'un mirroir. L'id est utilis pour diffrencier plusieurs miroirs. url L'URL de base de ce miroir. Le systme de build utilisera cette URL pour se connecter un dpt plutt que d'utiliser l'URL du serveur par dfaut. mirrorOf L'id du serveur dont ce miroir fait rfrence. Par exemple, utilisez cette balise pour pointer vers un miroir du serveur central Maven ([Link] Il ne doit pas s'agir de 'id du miroir.
id Identifiant unique du proxy. Celui-ci est utilis pour diffrencier les lments proxy.
388
active
true si ce proxy est activ. Vous pouvez ainsi configurer plusieurs proxy, mais d'en activer un
seul la fois la demande. protocol, host, port Les protocol://host:port d'un proxy. username, password Ces lments apparaissent sous la forme d'une paire indiquant l'identifiant et le mot de passe requis pour vous authentifier sur ce serveur proxy. nonProxyHosts Liste des Hosts pour lesquels il ne faut pas utiliser de proxy. L'exemple ci-dessus est dlimit par des pipes ('|'), il est galement possible des les dlimiter par des virgules.
389
<arch>x86</arch> <version>5.1.2600</version> </os> <property> <name>mavenVersion</name> <value>2.0.3</value> </property> <file> <exists>${basedir}/[Link]</exists> <missing>${basedir}/[Link]</missing> </file> </activation> ... </profile> </profiles> ... </settings>
L'activation d'un profil se produit lorsque les critres dfinis ont t atteints. Tous ne sont pas forcment ncessaires en mme temps. jdk L'activation a une vrification centre Java intgre dans la balise jdk. Celui se dclenchera si le test est excut avec un numro de version de JDK qui correspond au prfixe donn. Dans l'exemple ci-dessus, 1.5.0_06 correspondra. os La balise os peut dfinir des proprits spcifiques un systme d'exploitation. property Le profile s'activera si Maven dtecte la prsence d'une certaine proprit (une valeur qui peut tre rfrence dans un POM par ${name}) qui correspond une paire nom=valeur. file Enfin, un nom de fichier donn peut activer le profil en fonction de l'existence d'un fichier. La balise activation n'est pas le seul moyen d'activer un profil. La balise activeProfile du fichier [Link] peut contenir un id de profil. Ils peuvent galement tre activs partir de la ligne de commande en utilisant une liste spare par virgules aprs un flag P (Exemple : -P test). Pour voir quels profils sont activs sur un build, utiliser le maven-help-plugin :
mvn help:active-profiles
390
Ils existe cinq styles diffrents de proprits, qui sont tous disponibles partir du fichier [Link] :
env.X
Prfixer une variable avec env. retournera une variable d'environnement. Par exemple, ${[Link]} contient la valeur de la variable d'environnement $path. (%PATH% sous Windows.)
project.x
Permet de rfrencer un lment du fichier [Link]. Proprits systmes Java Toutes les proprits disponibles via la mthode [Link]() sont accessibles comme proprit de POM (Exemple : ${[Link]}).
x
Affect avec la balise properties ou un par l'intermdiaire d'un fichier externe, cet valeur peut tre utilise comme ${someVar}. Exemple A.7. Affecter la proprit ${[Link]} partir du fichier [Link]
<settings xmlns="[Link] xmlns:xsi="[Link] xsi:schemaLocation="[Link] [Link] ... <profiles> <profile> ... <properties> <[Link]>${[Link]}/our-project</[Link]> </properties> ... </profile> </profiles> ... </settings>
391
releases, snapshots Ce sont les policy pour chaque type d'artefact, release ou snapshot. Avec ces deux ensembles, un pom a le pouvoir de modifier les policy de chaque type au sein d'un rfrentiel unique. Un peut dcider d'activer seulement le tlchargement de snapshots, par exemple des fins de dveloppement. enabled
true ou false, permet de savoir si un dpt est activ pour un certain type (releases ou
snapshots). updatePolicy Cet lment spcifie la frquence des mises jour. Maven va comparer les timestamp des POMs locaux avec les POMs distants. Les choix possibles sont : always, daily (par dfaut), interval:X (o X reprsente un nombre de minute) ou never.
392
checksumPolicy Lorsque Maven dploie des fichiers dans le dpt, il dploie galement les fichiers checksum correspondants. Plusieurs options sont disponibles lorsqu'un checksum est manquant ou invalide : ignore, fail ou warn. layout Dans la description des dpts ci-dessus, il est mentionn que tous les dpts suivent un layout commun. Maven 2 a un layout par dfaut pour ses dpts, Maven 1.x en avait un diffrent. Utilisez cet lment pour prciser lesquels sont par dfaut ou legacy. Si vous tes pass de Maven 1 Maven 2 et que vous souhaitez utiliser le mme dpt, renseignez celui-ci comme legacy.
393
La dernire pice du puzzle du [Link] est la balise activeProfiles. Elle contient un ensemble de balises activeProfile, qui ont chacun pour valeur un id de profil. Tout profil dont l'id est prsente dans une balise activeProfile sera activ, quels que soient les paramtres d'environnement. Si aucun profil n'est trouv, rien ne se passera. Par exemple, si env-test est un activeProfile, un profile dans un [Link] (ou [Link]) sera activ. Si aucun profil n'est trouv, l'excution se poursuivra tout de mme normalement.
394
~/.m2
[Link] plain-text password
mvn
Server A
Maven Retrieves password for Server A from ~/.m2/settings. Maven sends the password to the remote server.
Figure A.1. Stockage de mot de passe non crypt dans les Settings Maven Maintenant, regardons comment Maven utilise des mots de passe chiffrs. La Figure A.2, Stockage d'un mot de passe crypt dans les Settings Maven prsente ce processus.
~/.m2
[Link] master password
mvn Server A
Maven Retrieves the Encrypted Password for Server A from ~/.m2/settings. Maven retreives the master password from ~/.m2/[Link] Maven decrypts the password and sends the decrypted password to the remote server.
Figure A.2. Stockage d'un mot de passe crypt dans les Settings Maven Pour configurer la fonctionnalit de chiffrage des mots de passe, crez le mot de passe matre en excutant l'une des commandes mvn -emp ou mvn --encrypt-master-password suivi par votre mot de passe matre.
$ mvn -emp mypassword {rsB56BJcqoEHZqEZ0R1VR4TIspmODx1Ln8/PVvsgaGw=}
Maven affiche alors une copie de la version chiffre du mot de passe sur la sortie stantard. Copiez celuici et collez-le dans le fichier ~/.m2/[Link] comme le montre l'exemple suivant.
395
Aprs avoir cr le mot de passe matre, vous pouvez commencer chiffrer vos mots de passe pour les utiliser dans vos settings. Pour chiffrer un mot de passe l'aide du mot de passe matre, utilisez l'une des commande mvn -ep ou mvn --encrypt-password. Imaginons que vous disposez d'un gestionnaire de dpt et que vous avez besoin d'un utilisateur "deployment" et d'un mot de passe "qualityFIRST" pour vous y connecter. Pour chiffrer ce mot de passe, utilisez la ligne de commande suivante :
$ mvn -ep qualityFIRST {uMrbEOEf/VQHnc0W2X49Qab75j9LSTwiM3mg2LCrOzI=}
Copiez ensuite le mot de passe chiffr affich sur la sortie standard et collez-le dans vos settings Maven. Exemple A.12. Stocker un mot de passe encrypt dans les Settings Maven (~/.m2/[Link])
<settings> <servers> <server> <id>nexus</id> <username>deployment</username> <password>{uMrbEOEf/VQHnc0W2X49Qab75j9LSTwiM3mg2LCrOzI=}</password> </server> </servers> ... </settings>
Lorsque vous excutez un build Maven qui a besoin d'interagir avec le gestionnaire de repository, Maven rcuprera le mot de passe principal partir du fichier ~/.m2/[Link] et utilisera celui-ci pour dchiffrer le mot de passe stock dans votre fichier ~/.m2/[Link]. Maven utilisera ce mot de passe dchiffr pour se connecter au serveur. Quels en sont les bnfices d'un tel mcanisme ? Il vous permet d'viter de stocker en clair vos mots de passe dans le fichier ~/.m2/[Link]. Notez que cette fonctionnalit ne prvoit pas le chiffrage du mot de passe lors de l'envoi de celui-ci sur le serveur distant. Il est toujours possible, pour une personne mal intentionne, de rcuprer vos mots de passe en analysant les flux rseau. Pour encore plus de scurit, vous pouvez demander vos dveloppeurs de stocker le mot de passe matre chiffr sur un priphrique de stockage amovible comme un disque dur USB. En utilisant cette mthode, un dveloppeur doit brancher son disque amovible sur sa station de travail lorsqu'il veut effectuer un dploiement ou une quelconque interaction avec un serveur distant. Pour cela, votre fichier ~/.m2/[Link] doit contenir une rfrence vers l'emplacement rel de votre fichier [Link]. Cette configuration passe par l'utilisation de la balise relocation.
396
Ainsi, le dveloppeur peut stocker son fichier [Link] sur son emplacement personnalis /Volumes/usb-key/[Link] et s'arranger pour que ce fichier ne soit disponible que s'il est assis devant sa station de travail.
397
Note
Tous les artefacts du tableau Tableau B.1, Autres implmentations des artefacts de Specs possdent le mme groupId : [Link]. Tableau B.1. Autres implmentations des artefacts de Specs Spcification Version Id de l'artefact de la Spec 1.0.2 1.1 1.0 1.1 2.3 3.0 2.1 3.0 1.0 3.0 1.5 1.1 1.0 1.0 1.1 1.4 1.1 geronimo-activation_1.0.2_spec geronimo-activation_1.1_spec geronimo-activation_1.0_spec geronimo-commonj_1.1_spec geronimo-corba_2.3_spec geronimo-corba_3.0_spec geronimo-ejb_2.1_spec geronimo-ejb_3.0_spec geronimo-el_1.0_spec geronimo-interceptor_3.0_spec geronimo-j2ee-connector_1.5_spec geronimo-j2ee-deployment_1.1_spec geronimo-j2ee-jacc_1.0_spec geronimo-j2ee-management_1.0_spec geronimo-j2ee-management_1.1_spec geronimo-j2ee_1.4_spec geronimo-jacc_1.1_spec Version de l'artefact 1.2 1.0.1 1.1 1.0 1.1 1.2 1.1 1.0 1.0 1.0 1.1.1 1.1 1.1.1 1.1 1.0 1.1 1.0
Activation Activation Activation CommonJ Corba Corba EJB EJB EL Interceptor J2EE Connector J2EE Deployment J2EE JACC J2EE Management J2EE Management J2EE JACC
Spcification
Version Id de l'artefact de la Spec 1.1MR3geronimo-javaee-deployment_1.1MR3_spec 1.3.1 1.4 1.0 1.1 1.1 3.0 2.0 2.1 geronimo-javamail_1.3.1_spec geronimo-javamail_1.4_spec geronimo-jaxr_1.0_spec geronimo-jaxrpc_1.1_spec geronimo-jms_1.1_spec geronimo-jpa_3.0_spec geronimo-jsp_2.0_spec geronimo-jsp_2.1_spec
Version de l'artefact 1.0 1.3 1.2 1.1 1.1 1.1 1.1 1.1 1.0 1.1.1 1.1 1.1 1.1 1.1.1 1.1.1 1.0.1 1.1.1
JEE Deployment JavaMail JavaMail JAXR JAXRPC JMS JPA JSP JSP JTA JTA QName SAAJ Servlet Servlet STaX API WS Metadata
1.0.1B geronimo-jta_1.0.1B_spec 1.1 1.1 1.1 2.4 2.5 1.0 2.0 geronimo-jta_1.1_spec geronimo-qname_1.1_spec geronimo-saaj_1.1_spec geronimo-servlet_2.4_spec geronimo-servlet_2.5_spec geronimo-stax-api_1.0_spec geronimo-ws-metadata_2.0_spec
Note
Ces versions d'artefacts seront probablement dpasses lorsque vous lirez ce livre. Pour vrifier les dernires versions disponibles, rendez visite l'adresse [Link] maven2/org/apache/geronimo/specs/ et cliquez sur l'artifactId que vous dsirez ajouter. Pour illustrer l'utilisation du tableau Tableau B.1, Autres implmentations des artefacts de Specs , si vous voulez crire du code dans votre projet qui ncessite les spcifications JTA 1.0.1B, ajoutez la dpendance suivante votre projet : Exemple B.1. Ajout de JTA 1.0.1B un projet MavenProject
<dependency> <groupId>[Link]</groupId> <artifactId>geronimo-jta_1.0.1B_spec</artifactId> <version>1.1.1</version> </dependency>
400
Notez que la version de cet artefact n'est pas aligne avec la version des spcifications. La dpendance prcdente ajoute la version 1.0.1B des spcifications JTA en utilisant la version 1.1.1. de l'artefact. Soyez conscients de cela lorsque vous rcuprez les dernires versions des artefacts, vrifiez qu'elle est compatible avec vos spcifications.
401