Sie sind auf Seite 1von 575

Thomas Locher (Credit Suisse), Tim O'Brien (Sonatype, Inc.), John Casey (Sonatype, Inc.

), Brian Fox (Sonatype, Inc.), Bruce Snyder (Sonatype, Inc.), Jason Van Zyl (Sonatype, Inc.), Eric Redmond ()

Copyright 2006-2008

Copyright ....................................................................................................... xii 1. Creative Commons BY-ND-NC ......................................................... xii Vorwort zur deutschen Ausgabe: 0.6-SNAPSHOT ...................................... xiv Vorwort ......................................................................................................... xvi 1. Anleitung zu diesem Buch ................................................................. xvi 2. Ihr Feedback ...................................................................................... xvii 3. Typographische Konventionen ........................................................xviii 4. Konventionen in Bezug auf Maven .................................................xviii 5. Danksagung ........................................................................................ xix 1. Einfhrung von Apache Maven ................................................................... 1 1.1. Maven ... Was ist das? ........................................................................ 1 1.2. Konvention ber Konfiguration ......................................................... 2 1.3. Die gemeinsame Schnittstelle ............................................................ 3 1.4. Universelle Wiederverwendung durch Maven-Plugins ..................... 5 1.5. Konzeptionelles Modell eines "Projekts" .......................................... 6 1.6. Ist Maven eine Alternative zu XYZ? ................................................. 8 1.7. Ein Vergleich von Maven und Ant .................................................... 9 1.8. Zusammenfassung ............................................................................ 14 2. Installieren und Ausfhren von Maven ...................................................... 15 2.1. berprfen der Java-Installation ...................................................... 15 2.2. Herunterladen von Maven ................................................................ 16 2.3. Installation von Maven ..................................................................... 16 2.3.1. Maven Installation unter Mac OSX ....................................... 17 2.3.2. Maven Installation unter Microsoft Windows ....................... 18 2.3.3. Maven Installation unter Linux .............................................. 19 2.3.4. Maven Installation unter FreeBSD oder OpenBSD ............... 19 2.4. Testen einer Maven Installation ....................................................... 19 2.5. Spezielle Installationshinweise ........................................................ 20 2.5.1. Benutzerdefinierte Konfiguration und-Repository ................ 21 2.5.2. Aktualisieren einer Maven-Installation .................................. 22 2.5.3. Upgrade einer Maven-Installation von Maven 1.x auf Maven 2.x ..................................................................................................... 23 2.6. Maven De-Installieren ...................................................................... 24 ii

Maven: The Definitive Guide 2.7. Hilfe bekommen beim Arbeiten mit Maven .................................... 24 2.8. Das Maven Hilfe Plugin ................................................................... 26 2.8.1. Beschreibung eines Maven Plugin ......................................... 27 2.9. Die Apache Software Lizenz ........................................................... 29 I. Maven by Example ..................................................................................... 31 3. Ein einfaches Maven Projekt .............................................................. 33 3.1. Einleitung .................................................................................. 33 3.1.1. Das Herunterladen der Beispiele dieses Kapitels ............ 33 3.2. Erstellen eines einfachen Projekts ............................................. 34 3.3. Der Aufbau eines einfachen Projekts ........................................ 36 3.4. Einfaches Projekt Objekt Modell (POM) .................................. 37 3.5. Kern Konzepte .......................................................................... 39 3.5.1. Maven Plugins und Ziele ................................................. 39 3.5.2. Maven Lifecycle .............................................................. 42 3.5.3. Maven Koordinaten ......................................................... 46 3.5.4. Maven Repositories ......................................................... 49 3.5.5. Maven Abhngigkeits-Management (Dependency Management) ............................................................................. 52 3.5.6. Site-Generierung und Reporting ..................................... 55 3.6. Zusammenfassung ..................................................................... 56 4. Anpassen eines Maven Projektes ........................................................ 57 4.1. Einleitung .................................................................................. 57 4.1.1. Herunterladen der Beispiele dieses Kapitels ................... 57 4.2. Eine kurze Einfhrung in das "Simple Weather" Projekt ......... 57 4.2.1. Yahoo! Wetter Dienst RSS ............................................. 58 4.3. Erstellen des "Simple Weather" Projektes ................................ 59 4.4. Anpassen der Projektinformationen .......................................... 60 4.5. Einfgen neuer Abhngigkeiten ................................................ 62 4.6. Quellcode von "Simple Weather" ............................................. 64 4.7. Resourcen Hinzufgen .............................................................. 71 4.8. Ausfhren des "Simple Weather" Programms .......................... 72 4.8.1. Das Exec Maven Plugin .................................................. 74 4.8.2. Erkundung der Projekt Abhngigkeiten .......................... 74 4.9. Erstellen von Unit-Tests ............................................................ 77 iii

Maven: The Definitive Guide 4.10. Hinzufgen von Gebietsbezogenen Unit Tests ....................... 80 4.11. Hinzufgen einer Unit-Test Ressource ................................... 81 4.12. Ausfhren von Unit-Tests ....................................................... 83 4.12.1. Ignorieren fehlgeschlagener Unit Tests ......................... 84 4.12.2. berspringen von Unit-Tests ........................................ 86 4.13. Builden einer paketierten, Befehlszeilen orientierten Anwendung ...................................................................................... 87 4.13.1. Anbinden des Assembly Goals zur Packetierungs Phase 89 5. Eine einfache Web-Anwendung ......................................................... 91 5.1. Einleitung .................................................................................. 91 5.1.1. Herunterladen der Beispiele dieses Kapitels ................... 91 5.2. Eine kurze Einfhrung in die "Simple Web" Anwendung ........ 91 5.3. Erstellen des "Simple Web" Projekts ........................................ 92 5.4. Konfigurieren des Jetty-Plugins ................................................ 93 5.5. Das Hinzufgen eines einfachen Servlets ................................. 96 5.6. Das Hinzufgen von J2EE-Abhngigkeiten ............................. 98 5.7. Zusammenfassung ................................................................... 100 6. Ein multi-modulares Projekt ............................................................. 101 6.1. Einleitung ................................................................................ 101 6.1.1. Herunterladen der Beispiele dieses Kapitels ................. 101 6.2. Das "Simple Parent" Projekt (parent=Elternteil) .................... 102 6.3. Das "Simple Weather" Modul ................................................. 103 6.4. Das "Simple-Web" Anwendungs-Modul ................................ 106 6.5. Erstellung des Multi-Projekt-Moduls ...................................... 109 6.6. Starten der Web-Anwendung .................................................. 110 7. Multi-module Enterprise Project ....................................................... 112 7.1. Einleitung ................................................................................ 112 7.1.1. Herunterladen der Beispiele dieses Kapitels ................. 112 7.1.2. Multi-Modul Enterprise Projekt .................................... 113 7.1.3. Technologie des Beispiels ............................................. 116 7.2. Das "Simple Parent" Projekt - Top Level ............................... 117 7.3. Das Simple Model" Modul - Das Objektmodell ..................... 119 7.4. Das "Simple Weather" Modul - Die Dienste .......................... 125 7.5. Das "Simple Persist" Modul - Die Datenabstraktion .............. 129 iv

Maven: The Definitive Guide 7.6. Das "Simple Web" Modul - Das Web-Interface ..................... 139 7.7. Aufrufen der Web-Anwendung ............................................... 153 7.8. Das "Simple Command" Modul - Das Kommandozeilen Modul ......................................................................................................... 154 7.9. Aufrufen der Kommandozeilen-Anwendung .......................... 162 7.10. Fazit ....................................................................................... 164 7.10.1. Programmierung gegen Interface-Projekte ................. 166 8. Optimierung und berarbeitung der POMs ...................................... 168 8.1. Einfhrung ............................................................................... 168 8.2. POM Bereinigung ................................................................... 169 8.3. Optimirung der Abhngigkeiten ............................................. 170 8.4. Optimirung der Plugins ........................................................... 176 8.5. Optimierung unter Zuhilfenahmen des Maven Dependency Plugin ......................................................................................................... 178 8.6. Abschliessende POMs ............................................................. 182 8.7. Fazit ......................................................................................... 190 II. Maven Reference ..................................................................................... 192 9. Das Projekt Objekt Modell (POM) ................................................... 193 9.1. Einfhrung ............................................................................... 193 9.2. Das Projekt Objekt Modell: POM ........................................... 193 9.2.1. Das Super POM ............................................................. 196 9.2.2. Das simpelste POM ....................................................... 200 9.2.3. Das tatschliche POM ................................................... 201 9.2.4. Echte POMs ................................................................... 202 9.3. POM Syntax ............................................................................ 202 9.3.1. Versionen von Projekten ............................................... 203 9.3.2. Referenzen auf Properties ............................................. 206 9.4. Projekt Abhngigkeiten (Dependencies) ................................. 209 9.4.1. Abhngigkeiten und Gltigkeitsbereich (Scope) .......... 210 9.4.2. Optionale Abhngigkeiten ............................................. 211 9.4.3. Abhngigkeitsspannen .................................................. 213 9.4.4. Transitive Abhngigkeiten ............................................ 215 9.4.5. Konfliktauflsung .......................................................... 217 9.4.6. Abhngigkeits Verwaltung /Dependency Management 220 v

Maven: The Definitive Guide 9.5. Projekt Beziehungen ............................................................... 222 9.5.1. Vertiefung von Koordinaten .......................................... 223 9.5.2. Multi-modulare Projekte ............................................... 225 9.5.3. Projekt Vererbung ......................................................... 227 9.6. POM Best Practices ................................................................. 230 9.6.1. Zusammenfassen von Abhngigkeiten .......................... 230 9.6.2. Multi-modular vs. Vererbung ........................................ 233 10. Der Build Lebenszyklus .................................................................. 241 10.1. Einfhrung ............................................................................. 241 10.1.1. Lebenszyklus: clean .................................................... 241 10.1.2. Standard Lebenszyklus: default .................................. 245 10.1.3. Lebenszyklus: site ....................................................... 247 10.2. Package-spezifische Lebenszyklen ....................................... 248 10.2.1. jar ................................................................................. 249 10.2.2. pom .............................................................................. 250 10.2.3. plugin ........................................................................... 250 10.2.4. ejb ................................................................................ 251 10.2.5. war ............................................................................... 252 10.2.6. ear ................................................................................ 252 10.2.7. Andere Packetierungs Typen ...................................... 253 10.3. Gebruchliche Lebenszyklus Goals ...................................... 255 10.3.1. Ressourcen Verarbeiten ............................................... 255 10.3.2. compile ........................................................................ 259 10.3.3. Verarbeiten von Test Ressourcen ................................ 261 10.3.4. Kompilieren der Test Klassen (testCompile) .............. 262 10.3.5. test ............................................................................... 262 10.3.6. install ........................................................................... 264 10.3.7. deploy .......................................................................... 264 11. Build-Profile .................................................................................... 266 11.1. Wozu sind sie ntzlich? ........................................................ 266 11.1.1. Was genau bedeutet Build Portabilitt ........................ 266 11.1.2. Auswahl eines geeigneten Mass der Portabilitt ......... 269 11.2. Portabilitt mittels Maven Profilen ....................................... 270 11.2.1. bersteuern eines Projekt Objekt Modelles ................ 273 vi

Maven: The Definitive Guide 11.3. Profil Aktivierung ................................................................. 274 11.3.1. Konfiguration der Aktivierung .................................... 276 11.3.2. Aktivierung wenn ein Property nicht vorhanden ist .... 278 11.4. Auflisten der aktuell aktiven Profile ..................................... 278 11.5. Tips und Tricks ..................................................................... 279 11.5.1. Gemeinsame Umgebungen ......................................... 279 11.5.2. Geheimnisse bewahren ................................................ 282 11.5.3. Plattform Klassifikatoren ............................................ 284 11.6. Zusammenfassung ................................................................. 287 12. Maven Assemblies .......................................................................... 288 12.1. Einfhrung ............................................................................. 288 12.2. Assembly Grundlagen ........................................................... 289 12.2.1. Vordefinierte Assembly Descriptoren (Archiv-Beschreibungen) ........................................................ 290 12.2.2. Erstellen eines Assembly ............................................ 292 12.2.3. Assemblies als Abhngigkeit ...................................... 295 12.2.4. Zusammenstellen von Assemblies mittels Assembly Abhngigkeiten ....................................................................... 296 12.3. bersicht eines Assembly Descriptors .................................. 301 12.4. Der Assembly Descriptor ...................................................... 303 12.4.1. Property Referenzen in Assembly Descriptoren ......... 303 12.4.2. Notwendige Basisinformationen fr Assemblies ........ 304 12.5. Bestimmen des Inhaltes eines Assemblies ............................ 306 12.5.1. Element files ............................................................ 306 12.5.2. Element fileSets ...................................................... 307 12.5.3. Standard Auschlussmuster in fileSets ...................... 311 12.5.4. Element dependencySets ........................................... 312 12.5.5. Element moduleSets .................................................. 327 12.5.6. Element Repositories ................................................... 336 12.5.7. Verwalten des Wurzelverzeichnisses des Assembly ... 338 12.5.8. componentDescriptors und containerDescriptorHandlers ............................................. 339 12.6. Best Practices ........................................................................ 340 12.6.1. Standardisierte, wiederverwendbare Assembly vii

Maven: The Definitive Guide Descriptoren ............................................................................ 341 12.6.2. Verteilung (Aggregierung) von Assemblies ............... 345 12.7. Zusammenfassung ................................................................. 350 13. Properties and Ressource Filterung ................................................. 352 13.1. Einleitung .............................................................................. 352 13.2. Maven Properties .................................................................. 352 13.2.1. Maven Projekt Einstellungen ...................................... 353 13.2.2. Properties der Maven Einstellungen (settings.xml) .... 356 13.2.3. Properties der Umgebungsvariablen ........................... 356 13.2.4. Java System Properties ................................................ 357 13.2.5. Benuzerdefinierte Properties ....................................... 359 13.3. Ressource Filterung ............................................................... 360 14. Maven in Eclipse: m2eclipse .......................................................... 365 14.1. Einfhrung ............................................................................. 365 14.2. m2eclipse ............................................................................... 365 14.3. Installation des m2eclipse Plugins ........................................ 366 14.3.1. Installieren der Voraussetzungen ................................ 367 14.3.2. Installation von m2eclipse ........................................... 369 14.4. Aufschalten der Maven Konsole ........................................... 370 14.5. Erstellen eines Maven Projekts ............................................. 371 14.5.1. Auschecken eines Maven Projektes von einem SCM Repository ............................................................................... 372 14.5.2. Erstellen eines Maven Projekts auf der Basis eines Maven Archetyps ................................................................................ 374 14.5.3. Erstellen eines Maven Moduls .................................... 378 14.6. Erstellen einer Maven POM Datei ........................................ 381 14.7. Importieren von Maven Projekten ........................................ 385 14.7.1. Importiren eines Maven Projektes ............................... 387 14.7.2. Materialisieren eines Maven Projektes ....................... 389 14.8. Starten von Maven Builds ..................................................... 393 14.9. Mit Maven Projekten arbeiten ............................................... 396 14.9.1. Zufgen und Updaten von Abhngigkeiten und Plugins 398 14.9.2. Erstellen eines Maven Modules .................................. 401 14.9.3. Herunterladen der Quelldatei(en) ................................ 401 viii

Maven: The Definitive Guide 14.9.4. ffnen von Projektseiten ............................................. 401 14.9.5. Auflsen von Abhngigkeiten ..................................... 402 14.10. Arbeiten mit den Maven Repositorien ................................ 402 14.10.1. Suchen von Maven Artefakten sowie Java Klassen .. 403 14.10.2. Indizierung von Maven Repositorien ........................ 408 14.11. Der neue graphische POM Editor ....................................... 412 14.12. Projektabhngigkeiten mit m2eclipse analysieren .............. 418 14.13. Maven Einstellungen ........................................................... 423 14.14. Zusammenfassung ............................................................... 431 15. Projekt-Site Erstellung .................................................................... 433 15.1. Einleitung .............................................................................. 433 15.2. Erstellen eines Projekt-Sites mit Maven ............................... 434 15.3. Anpassen des Site Descriptors .............................................. 436 15.3.1. Anpassen der Kopfzeilengraphiken ............................. 438 15.3.2. Anpassen des bersichtsmenues ................................. 439 15.4. Site-Verzeichnisstruktur ........................................................ 440 15.5. Erstellen einer Projekt-Dokumentation ................................. 442 15.5.1. Ein APT Beispiel ......................................................... 442 15.5.2. Ein FML Beispiel ........................................................ 443 15.6. Ausrollen eines Projekt-Sites ................................................ 444 15.6.1. Konfigurieren der Server Authentifizierung ............... 445 15.6.2. Konfigurieren der Datei und Verzeichnisrechte .......... 446 15.7. Anpassen des Site Auftritts ................................................... 447 15.7.1. Anpassen des Stylesheets site.css ................................ 447 15.7.2. Erstellen einer Sitevorlage .......................................... 448 15.7.3. Wiederverwendbare Website Skins ............................. 454 15.7.4. Erstellen einer Angepassten Themenvorlage (CSS) ... 456 15.7.5. Anpassen der Sitevorlage in einer Skin ....................... 458 15.8. Tips und Tricks ..................................................................... 459 15.8.1. Einfgen von XHTML in das Element HEAD ........... 459 15.8.2. Hinzufgen von Links zum Site Logo ........................ 460 15.8.3. Hinzufgen von Breadcrumbs zu Ihrem Site .............. 461 15.8.4. Hinzufgen der Projekt Version .................................. 461 15.8.5. Anpassen der Positionierung und des Formats des ix

Maven: The Definitive Guide Verffentlichungsdatums ........................................................ 463 15.8.6. Einsatz von Doxia Makros .......................................... 464 16. Repository Management mit Nexus ................................................ 467 17. Writing Plugins ............................................................................... 469 17.1. Introduction ........................................................................... 469 17.2. Programming Maven ............................................................. 469 17.2.1. What is Inversion of Control? ..................................... 470 17.2.2. Introduction to Plexus ................................................. 471 17.2.3. Why Plexus? ................................................................ 472 17.2.4. What is a Plugin? ......................................................... 473 17.3. Plugin Descriptor .................................................................. 474 17.3.1. Top-level Plugin Descriptor Elements ........................ 476 17.3.2. Mojo Configuration ..................................................... 477 17.3.3. Plugin Dependencies ................................................... 481 17.4. Writing a Custom Plugin ....................................................... 481 17.4.1. Creating a Plugin Project ............................................. 481 17.4.2. A Simple Java Mojo .................................................... 482 17.4.3. Configuring a Plugin Prefix ........................................ 484 17.4.4. Logging from a Plugin ................................................ 488 17.4.5. Mojo Class Annotations .............................................. 489 17.4.6. When a Mojo Fails ...................................................... 491 17.5. Mojo Parameters ................................................................... 492 17.5.1. Supplying Values for Mojo Parameters ...................... 492 17.5.2. Multi-valued Mojo Parameters .................................... 495 17.5.3. Depending on Plexus Components ............................. 497 17.5.4. Mojo Parameter Annotations ...................................... 497 17.6. Plugins and the Maven Lifecycle .......................................... 499 17.6.1. Executing a Parallel Lifecycle ..................................... 499 17.6.2. Creating a Custom Lifecycle ....................................... 500 17.6.3. Overriding the Default Lifecycle ................................ 502 18. Writing Plugins in Alternative Languages ...................................... 505 18.1. Writing Plugins in Ant .......................................................... 505 18.2. Creating an Ant Plugin .......................................................... 505 18.3. Writing Plugins in JRuby ...................................................... 508 x

Maven: The Definitive Guide 18.3.1. Creating a JRuby Plugin .............................................. 509 18.3.2. Ruby Mojo Implementations ....................................... 511 18.3.3. Logging from a Ruby Mojo ........................................ 514 18.3.4. Raising a MojoError .................................................... 515 18.3.5. Referencing Plexus Components from JRuby ............ 515 18.4. Writing Plugins in Groovy .................................................... 516 18.4.1. Creating a Groovy Plugin ............................................ 517 19. Einsatz von Maven Archetypen ...................................................... 519 19.1. Einfhrung in Maven Archetypen ......................................... 520 19.2. Einsatz von Archetypen ........................................................ 520 19.2.1. Einsatz eines Archetypen von der Befehlszeile .......... 520 19.2.2. Einsatz von der Befehlszeile: das Goal generate (interactiv) ............................................................................... 522 19.2.3. Einsatz eines Archetypen in m2eclipse ....................... 525 19.3. Verfgbare Archetypen ......................................................... 525 19.3.1. Die Standard Maven Archetypen ................................ 525 19.3.2. Verbreitete Third-Party Archetypen ............................ 526 19.4. Verffentlichen von Archetypen ........................................... 531 A. Appendix: Detailinformationen zur settings.xml-Datei .......................... 534 A.1. bersicht ....................................................................................... 534 A.2. Die Details der settings.xml Datei ................................................ 535 A.2.1. Einfache Wertangaben ........................................................ 535 A.2.2. Servers ................................................................................. 536 A.2.3. Spiegelrepositorien .............................................................. 537 A.2.4. Proxies ................................................................................. 538 A.2.5. Profiles ................................................................................ 540 A.2.6. Activation ............................................................................ 540 A.2.7. Properties ............................................................................. 542 A.2.8. Repositories ......................................................................... 543 A.2.9. Plugin Repositories ............................................................. 545 A.2.10. Aktive Profile .................................................................... 546 A.2.11. Verschlsseln von Passwrtern in den Maven Settings (ab Version 2.1.x) ................................................................................. 547 B. Appendix: Alternativen zu den Sun Spezifikationen .............................. 552 xi

Copyright
Copyright 2008 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.

1. Creative Commons BY-ND-NC


This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States license. For more information about this license, see http://creativecommons.org/licenses/by-nc-nd/3.0/us/. You are free to share, copy, distribute, display, and perform the work under the following conditions: You must attribute the work to Sonatype, Inc. with a link to http://www.sonatype.com. xii

Copyright You may not use this work for commercial purposes. You may not alter, transform, or build upon this work. If you redistribute this work on a web page, you must include the following link with the URL in the about attribute listed on a single line (remove the backslashes and join all URL parameters):
<div xmlns:cc="http://creativecommons.org/ns#" about="http://creativecommons.org/license/results-one?q_1=2&q_1=1\ &field_commercial=n&field_derivatives=n&field_jurisdiction=us\ &field_format=StillImage&field_worktitle=Maven%3A+\Guide\ &field_attribute_to_name=Sonatype%2C+Inc.\ &field_attribute_to_url=http%3A%2F%2Fwww.sonatype.com\ &field_sourceurl=http%3A%2F%2Fwww.sonatype.com%2Fbook\ &lang=en_US&language=en_US&n_questions=3"> <a rel="cc:attributionURL" property="cc:attributionName" href="http://www.sonatype.com">Sonatype, Inc.</a> / <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/us/"> 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-Noncommercial-No Derivative Works 3.0 license for the specific jurisdiction. If the Creative Commons Attribution-Noncommercial-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 http://creativecommons.org/international. 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 http://creativecommons.org/licenses/by-nc-nd/3.0/.

xiii

Vorwort zur deutschen Ausgabe: 0.6-SNAPSHOT


Vor Ihnen liegt die deutsche bersetzung der "Definitiv Guide to Apache Maven". Ein Werk das, wie das englische Original, zum Ziel hat Brcken zu schlagen. Brcken nicht nur zwischen Technikern und Techniken, sondern auch Brcken zwischen unseren verschiedenen Kulturen. In meiner tglichen Erfahrung gibt es eine grosse Zahl Arbeitsgruppen und Teams welche mehr als eine, oft sogar so viele Nationalitten wie Mitglieder umfassen. Das Kommunikationsmedium ist meist der kleinste gemeinsame Nenner: (Sowie-)Englisch. Wie oft habe ich nach tage- und nchtelangem Suchen feststellen mssen, dass der Fehler eigentlich ganz offensichtlich war, wenn Man(n) nur die (englische) Anleitung verstanden htte! Maven ist ein mchtiges Tool, hufiger missverstanden und nur rudimentr eingesetzt - insbesondere weil die Zusammenhnge unklar, die Dokumentation in Englisch schwierig und lckenhaft ist. Da ich vom Wert dieses Werkzeugs berzeugt bin habe ich alles gegeben dieses Werkzeug auch dem deutschen Sprachraum "native" zugnglich zu machen. Ich erhoffe mir hiervon auch, Entwickler zu ermutigen sich in der grossen bestehenden Maven Community einzubringen, Themen aufzugreifen und weiter zu fhren. Diesen Entwicklern mchte ich Sicherheit bieten indem ich Ihnen eine Referenz zur Seite stelle, die sie verstehen. Mit Blick auf unsere multinationalen Gruppen habe ich versucht das Werk so nahe am englischen Original zu belassen als mglich. Sie werden also auf Abschnittebene vergleichen knnen. Sollten Sie unsicher sein was Ihr Kollege tatschlich meint, so zcken Sie Ihr deutsches Exemplar, sehen nach welchen Abschnitt im englischen Original Ihr Kollege referenziert - et voil - lesen Sie in Ihrer Muttersprache was gemeint ist. Thomas Locher Zrich, im Januar 2008 xiv

Vorwort zur deutschen Ausgabe: 0.6-SNAPSHOT PS: Habe ich Ihnen bereits empfohlen die englische Originalausgabe zu kaufen?

xv

Vorwort
Maven is ein Build Werkzeug, ein Projekt Management Werkzeug ein abstrakter Container um Build Auftrge abzuarbeiten. Es stellt ein Werkzeug dar, welches unumgnglich ist fr alle Projekte welche ber die einfachsten Anforderungen hinauswachsen und sich pltzlich in der Lage finden konsistent eine grosse Zahl voneinander abhngiger Bibliotheken zu Builden, welche sich auf dutzende oder gar hunderte Komponenten (auch) von Drittparteien absttzen. Es ist ein Werkzeug, das dazu beigetragen hat einen Grossteil des Verwaltungsaufwandes fr Komponenten aus dem Alltag von Millionen von Fachspezialisten zu eliminieren. Es hat vielen Organisationen geholfen sich weiterzuentwickeln, hinweg ber die Phase des tglichen Kampf mit dem Build Management, hin zu einer neuen Phase in welcher der Aufwand einen Build zu erhalten und zu pflegen nicht mehr eine Grenzgrsse des Software Designs darstellt. Dieses Buch ist ein erster Versuch eines umfassenden Werkes bezglich Maven. Es baut auf die gesammelten Erfahrungen und der Arbeit aller Autoren vorgngiger Titel bezglich Maven auf und Sie sollten dieses Werk nicht als fertiges Werkstck ansehen sondern vielmehr als der erster Wurf einer langen Reihe von Updates welche dieser Ausgabe folgen werden. Auch wenn es Maven bereits einige Jahre gibt, so empfinden die Autoren dieses Werkes dennoch, dass Maven erst gerade begonnen hat die khnen Versprechen einzulsen welche auf den Weg gegeben wurden. Die Autoren -wie auch die Firma- welche hinter diesem Buch stehen, Sonatype glauben fest daran, dass dieses Werk dazu beitragen wird, eine neue Welle der Innovation und Entwicklung in Umfeld von Maven und dessen kosystem loszutreten.

1. Anleitung zu diesem Buch


Nehmen Sie dieses Buch in die Hand und lesen Sie einige Seiten des Textes. Am Ende der Seite werden Sie, sollten Sie die HTML Ausgabe lesen, entweder den Link zur nchsten Seite folgen wollen, oder im Fall der gedruckten Ausgabe werden Sie die Ecke heben und weiterblttern. Sollten Sie vor einem Computer xvi

Vorwort sitzen, so knnen Sie sicherlich das eine oder andere Beispiel durchspielen um dem Text zu folgen. Was Sie nicht tun sollten, auch nicht in Wut, ist das Buch in die Richtung eines Mitmenschen zu werfen - es ist einfach zu schwer! Dieses Buch gliedert sich in drei Abschnitte: eine Einfhrung, einen Beispielteil und eine Referenz. Die Einfhrung besteht aus zwei Kapiteln: Einfhrung und Installation. Der Beispielteil fhrt Maven ein, indem einige echte Anwendungsbeispiele eingefhrt werden und Ihnen anhand der Struktur der Beispiele weitere Motivation und Erklrung gegeben werden. Sollte Maven fr Sie neu sein, so fangen Sie an, den Beispielteil zu lesen. Die Referenz ist weniger als Einfhrung gedacht, sondern mehr als Nachschlagewerk. Jedes Kapitel des Referenzteils ziehlt genau auf ein Thema ab und geht hierbei auf die tiefstmglichen Details ein. So wird das Kapitel ber die Erstellung von Plugins anhand von einigen Beispielen und einer Anzahl Listen und Tabellen abgehandelt. Beide Abschnitte bieten Erklrungen und doch werden grundverschiedene Wege eingeschlagen. Whrend der beispielhafte Teil sich auf den Zusammenhang innerhalb des Maven Projekt sttzt, konzentriert sich der Referenzteil jeweils auf ein einziges Thema. Sie knnen natrlich auch im Buch herumspringen; der beispielhafte Teil ist in keiner Weise Voraussetzung fr den Referenzteil, aber Sie werden den Referenzteil besser verstehen, sollten Sie bereits den beispielhaften Teil gelesen haben. Maven wird am Besten anhand von Beispielen gelernt, sobald Sie die Beispiele durchgeabeitet haben werden Sie eine gute Referenzquelle brauchen, um sich Maven Ihren Bedrfnissen anzupassen.

2. Ihr Feedback
Wir haben dieses Buch nicht geschrieben, um unserem Herausgeber ein Word Dokument zu senden, eine Verffentlichung zu feiern und einander zu Beglckwnschen was fr eine gute Arbeit wir geleistet haben. Dieses Buch ist nicht "fertig", ja dieses Buch wird wohl nie "fertig" werden. Das behandelte Thema ndert sich stndig, weitet sich aus; und so verstehen wir dieses Buch als ein stndig weitergehender Dialog mit der Maven Community. Dieses Buch herauszugeben bedeutet, dass die wahre Arbeit erst gerade begonnen hat, und Sie, der Leser, spielen eine zentrale Rolle dieses Buch zu erweitern, verbessern und xvii

Vorwort aktuell zu halten. Sollten Sie etwas bemerken das fehlerhaft ist: ein Rechtschreibfehler, schlechter Code, eine offenkundige Lge, dann teilen Sie uns dies mit! Schreiben Sie uns eine Email an: book@sonatype.com. Die weitergehende Rolle dieses Buches ist abhngig von Ihrem Feedback. Wir sind interessiert daran zu erfahren, was funktioniert und was nicht. Wir wrden gerne erfahren, sollte dieses Buch Informationen enthalten welche Sie nicht verstehen. Ganz besonders wollen wir erfahren, sollten Sie den Eindruck haben dises Buch wre schrecklich. Positive und negative Rckmeldungen sind uns willkommen. Wir nehmen uns das Recht heraus nicht jeder Meinung zuzustimmen, aber in jedem Fall bekommen Sie eine gebhrende Antwort.

3. Typographische Konventionen
Dieses Buch verwendet die folgenden typographischen Konventionen: Kursiv Wird fr wichtige Begriffe, Programm- und Dateinamen, URLs, Ordner und Verzeichnispfade und zur Hervorhebung/Einfhrung von Begriffen verwendet.
Nichtproportonalschrift

Wird fr Programmcode verwendet (Java Klassennamen, -methoden, Variablen, Properties, Datentypen, Datenbank Elemente, und andere Codebeispiele welche in den Text eingestreut sind). Fette Nichtproportonalschrift Wird verwendet fr Befehle welche Sie auf der Kommandozeile eingeben, sowie um neue Codefragmente in fortlaufenden Beispielen hervorzuheben. Kursive Nichtproportonalschrift Wird verwendet um Ausgabetext zu kennzeichnen.

4. Konventionen in Bezug auf Maven


xviii

Vorwort Dieses Buch folgt gewissen Konventionen bezglich Namensgebung und Schriftsatz bezglich Apache Maven. Compiler Plugin Maven Plugins werden gross geschrieben.
Goal create

Maven Goal Namen werden in nichtproportionaler Schrift wiedergegeben. "plugin" Maven kreist stark um die Nutzung von Plugins, aber Sie werden keine umfassende Definition von Plugin in einem Wrterbuch finden. Dieses Buch benutzt den Terminus Plugin, da er einprgsam ist und auch weil er sich in der Maven Community so eingebrgert hat. Maven Lebenszyklus, Maven Standard Verzeichnis Layout, Maven Plugin, Projekt Objekt Modell Die Kernkonzepte von Maven werden im Text gross geschrieben, insbesondere wenn darauf Bezug genommen wird.
Goal Parameter

Ein Parameter eines Maven Goal wird in nichtproportionalschrift wiedergegeben.


Phase compile

Lebenszyklusphasen werden in nichtproportionalschrift wiedergegeben.

5. Danksagung
Sonatype mchte sich insbesondere bei allen Mitwirkenden bedanken: die folgende Liste ist in keiner Weise abschliessend oder vollstndig und alle haben mitgewirkt um die Qualitt dieses Werkes zu verbessern. Vielen Dank an Mangalaganesh Balasubramanian, Bertrand Florat, Chad Gorshing, Ali Colabawala, Bozhidar Batzov sowie Mark Stewart. Besonderen Dank auch an Joel Costigliola fr die Hilfe und Korrektur des Kapitels bezglich Spring Web. Stan Guillory war schon xix

Vorwort so etwas wie ein Teilautor, zhlt man die grosse Zahl der Korrekturen und Verbesserungsvorschlge welcher er einbrachte. Vielen Dank Stan. Speziellen Dank auch an Richard Coatsby von Bamboo der die Rolle des einstweiligen Grammatik-Beraters aufgenommen hat. Vielen Dank an alle partizipierenden Teilautoren einschliesslich Eric Redmond. Vielen Dank auch an die folgenden Mitwirkenden welche Fehler entweder in Form einer Email oder zum zugehrigen Get Satisfaction Site gemeldet haben: Paco Sobern, Ray Krueger, Steinar Cook, Henning Saul, Anders Hammar, "george_007", "ksangani", Niko Mahle, Arun Kumar, Harold Shinsato, "mimil", "-thrawn-", Matt Gumbley. Sollten Sie Ihren Get Satisfaction Benutzernamen in dieser Liste aufgefhrt sehen und wrden diesen gerne durch Ihren Namen ersetzt wissen, so senden Sie uns eine kurze Mail an book@sonatype.com.

xx

Chapter 1. Einfhrung von Apache Maven


Es gibt zwar schon eine Reihe Online Verffentlichungen zum Thema Apache Maven, aber was bis heute fehlt, ist eine umfassende, gut geschriebenen Einfhrung von Maven, welche zugleich als altgediente Referenz herhalten kann. Was wir hier versucht haben, ist eine solche gesamthafte Einfhrung gepaart mit einer umfassenden Referenz zu erstellen.

1.1. Maven ... Was ist das?


Die Antwort auf diese Frage hngt ganz von Ihrer Perspektive ab. Die groe Mehrheit der Benutzer wird Maven als "Build"-Werkzeug einordnen: ein Werkzeug um aus Quellcode einsatzfhige Artefakte (Programme) zu erzeugen. Build Ingenieure und Projektmanager mgen Maven als etwas umfassenderes sehen: ein (technisches) Projektmanagement-Tool. Wo liegt der Unterschied? Ein Build-Werkzeug wie Ant ist ausschlielich auf die Vorverarbeitung, Kompilierung, Prfung und Verteilung ausgelegt. Ein Projekt-Management-Tool wie Maven liefert eine Obermenge von Funktionen welche in einem Build- und Paketier-Werkzeug zur Anwendung kommen. Neben der Bereitstellung von Build Funktionalitten, bietet Maven auch die Mglichkeit Berichte/Auswertungen (Reports) anzufertigen, Websites zu generieren und den Kontakt zwischen den Mitgliedern einer Arbeitsgruppe/eines Teams zu ermglichen. Hier eine formale Definition von Apache Maven: Maven ist ein Projektmanagement-Tool welches ein umfassendes Projektmodell beinhaltet und eine Reihe von Normen bereitstellt. Darber hinaus verfgt es ber einen definierten Projekt-Lebenszyklus, ein Abhngigkeits-Management-System sowie Logik, welche die Ausfhrung von Plugin-Goals in definierten Phasen eines Lebenszykluses ermglicht. Wenn Sie Maven einsetzen, beschreiben Sie Ihr Projekt in einem genau definierten Projekt Objekt Modell, im weiteren Text POM genannt. Maven kann dann auf dieses Modell berspannende Regelwerke aus der Menge gemeinsam genutzter (oder auch massgeschneiderter) Plugins anwenden. Lassen Sie sich nicht von der Tatsache dass Maven ein "Projektmanagement" 1

Einfhrung von Apache Maven Werkzeug darstellt, erschrecken. Sollten Sie lediglich nach einem Build-Tool Ausschau gehalten haben, so wird Maven Ihnen dies ebenfalls bieten. In der Tat, die ersten Kapitel dieses Buches befassen sich mit dem hufigsten Anwendungsfall: Der Verwendung von Maven um Ihr Projekt zu kompilieren, testen und zu verteilen.

1.2. Konvention ber Konfiguration


Konvention ber Konfiguration ist ein einfaches Konzept: Systeme, Bibliotheken und Frameworks sollten von vernnftige Standardwerten ausgehen, ohne unntige Konfigurationen zu bentigen - Systeme sollten "einfach funktionieren". Gngige Frameworks wie Ruby on Rails und EJB3 haben damit begonnen, sich an diesen Grundstzen zu orientieren. Dies in Reaktion auf die Komplexitt der Konfiguration von Frameworks wie etwa der anfnglichen EJB 2.1 Spezifikationen. Das Konzept 'Konvention ber Konfiguration' wird am Beispiel der EJB 3 Persistenz schn veranschaulicht: alles, was Sie tun mssen, um ein bestimmtes Bean persistent zu speichern ist, dieses mit einer @Entitiy-Annotation zu versehen. Das Framework bernimmt Tabellen-und Spaltennamen basierend auf den Namen der Klasse und den Namen der Attribute. Es besteht die Mglichkeit, mittels sogenannter 'Hooks' - wenn ntig - die gesetzten Standardwerte zu bersteuern. In den meisten Fllen werden Sie feststellen, dass der Einsatz der vom Framework bereitgestellten Namen zu einer schnelleren Projektdurchfhrung fhrt. Maven greift dieses Konzept auf und stellt vernnftige Standard-Verhalten fr Projekte bereit. Ohne weitere Anpassungen, wird davon ausgegangen, dass sich Quellcode im Verzeichnis ${basedir}/src/main/java und Ressourcen sich im Verzeichnis ${basedir}/src/main/resources befinden. Von Tests wird davon ausgegangen, dass diese sich im Verzeichnis ${basedir}/src/test befinden, sowie ein Projekt standardmig ein JAR-Archive bereitstellt. Maven geht davon aus, dass Sie den kompilierten Byte-Code unter ${basedir}/target/classes ablegen wollen und anschlieend ein ausfhrbares JAR-Archive erstellen, welches im Verzeichnis ${basedir}/target abgelegt wird. Zwar mag diese Lsung trivial anmuten, jedoch bedenken Sie bitte die Tatsache, dass die meisten Ant-basierten Projekte die Lage dieser Verzeichnisse in jedem Teilprojekt festlegen mssen. Die 2

Einfhrung von Apache Maven Umsetzung von Konvention ber Konfiguration in Maven geht noch viel weiter als nur einfache Verzeichnis Standorte festzulegen, Maven-Core-Plugins kennen ein einheitliches System von Konventionen fr die Kompilierung von Quellcode, der Paketierung sowie Verteilung der Artefakten, der Generierung von (Dokumentations-) Web-Seiten, und vielen anderen Prozessen. Die Strke von Maven beruht auf der Tatsache, dass Maven mit einer 'vorbestimmten Meinung' ausgelegt ist: Maven hat einen definierten Lebenszyklus sowie eine Reihe von Plugins welche unter gemeinsamen Annahmen in der Lage sind, Software zu erstellen. Sollten Sie nach den Konventionen arbeiten, erfordert Maven fast keinen Aufwand - einfach Ihre Quellen in das richtige Verzeichnis legen - Maven kmmert sich um den Rest. Ein Nachteil der Verwendung von Systemen welche dem Grundsatz der Konvention ber Konfiguration folgen ist, dass Endbenutzer oftmals die Gefahr sehen, dass sie gezwungen werden eine bestimmte Methode anzuwenden - einem bestimmten Ansatz folgen mssen. Zwar ist es sicherlich richtig, dass der Kern von Maven auf einigen wenigen Grundannahmen basiert, welche nicht in Frage gestellt werden sollten, dennoch kann man die meisten Vorgaben auf die jeweilig vorherrschenden Bedrfnisse anpassen und konfigurieren. So kann zum Beispiel die Lage des Projekt-Quellcodes sowie dessen Ressourcen konfiguriert werden, oder die Namen der resultierenden JAR-Archive angepasst werden. Durch die Entwicklung von massgefertigten Plugins, kann fast jedes Verhalten an die Bedrfnisse Ihrer Umgebung angepasst werden. Sollten Sie der Konvention nicht folgen wollen, ermglicht Maven es Ihnen Voreinstellungen anzupassen um Ihren spezifischen Anforderungen Rechnung zu tragen.

1.3. Die gemeinsame Schnittstelle


In der Zeit vor Maven, das eine gemeinsame Schnittstelle fr den Build von Software bereitstellte, hatte gewhnlich jedes einzelne Projekt eine Person, welche sich der Verwaltung des vllig eigenen Build Systems widmete. Entwickler mussten einige Zeit aufwenden, um neben der tatschlichen Entwicklung herauszufinden, welche Eigenheiten beim Build einer neuen Software zu bercksichtigen waren, zu welcher sie beitragen wollten. Im Jahr 2001, gab es 3

Einfhrung von Apache Maven vllig unterschiedliche Build Konzepte/Systeme welche fr den Build eines Projekts wie Turbine, POI oder Tomcat zur Anwendung kamen. Jedesmal, wenn ein neues Source Code-Analyse-Tool zur statischen Analyse von Quellcode verffentlicht wurde, oder wenn jemand ein neues Unit-Test Framework herausgab welches man einsetzen wollte/sollte, musste man alles stehen und liegen lassen, um herauszufinden, wie dieses neue Werkzeug in das Projekt und dessen Build Umgebung einzupassen wre. Wie konnte man Unit-Tests laufen lassen? Es gab tausend verschiedene Antworten. Dieses Umfeld war geprgt von tausenden endlosen Auseinandersetzungen bezglich der 'richtigen' Werkzeuge und Build-Vorgehen. Das Zeitalter vor Maven war ein Zeitalter der Ineffizienz: das Zeitalter der "Build-Ingenieure". Heute setzen die meisten Open-Source-Entwickler bereits auf Maven, oder nutzen dieses um neue Software-Projekten aufzusetzen. Dieser bergang ist weniger ein Wechsel von einem Build Werkzeug zu einem anderen, sondern viel mehr eine Entwicklung, hin zum Einsatz einer gemeinsamen Build-Schnittstelle fr Projekte. So wie Software-Systeme modularer wurden, wurden Build Werkzeuge komplexer und die Zahl der (Teil-)Projekte wuchs in den Himmel. In der Zeit vor Maven, mussten Sie, wollten Sie etwa ein Projekt wie Apache ActiveMQ oder Apache ServiceMix aus Subversion auschecken und aus den Quellen erstellen, mit mindestens einer Stunde Aufwand rechnen, die Sie damit verbrachten herauszufinden, wie das Build-System des einzelnen Projekts funktionierte. Was waren die Voraussetzungen, um das Projekt zu builden? Welche Bibliotheken muss man herunterladen? Wo bekomme ich diese? Welche Targets kann ich im Build ausfhren? Im besten Fall dauerte es ein paar Minuten um herauszufinden wie ein neues Projekt zu builden war, - und im schlimmsten Fall (wie die alte Servlet-API-Umsetzung des Jakarta-Projekts), war ein Projekt aufbauen so schwierig, das es mehrere Stunden dauerte nur um an einen Punkt zu gelangen, an dem ein neuer Mitarbeiter den Quellcode bearbeiten konnte und das Projekt kompilierte. Heutzutage machen Sie einen Projekt Check-Out und fhren mvn install aus. Whrend Maven eine Reihe von Vorteilen einschlielich der Verwaltung von Abhngigkeiten und Wiederverwendung von gemeinsamer Logik zum Build durch Plugins bietet, ist der Hauptgrund fr den Erfolg der, dass es gelungen ist eine 4

Einfhrung von Apache Maven einheitliche Schnittstelle fr den Build von Software bereitzustellen. Wenn Sie sehen, dass ein Projekt wie Apache Wicket Maven verwendet, knnen Sie davon ausgehen, dass Sie in der Lage sein werden, Projekt ohne weiten Aufwand auszuchecken und aus den Quellen mittels mvn zu bauen und zu installieren. Sie wissen, wo der Zndschlssel hinkommt, Sie wissen, dass das Gas-Pedal auf der rechten Seite und die Bremse auf der Linken ist.

1.4. Universelle Wiederverwendung durch Maven-Plugins


Der Herzstck von Maven ist ziemlich dumm. Es weiss nicht viel mehr als ein paar XML-Dokumenten zu parsen sowie einen Lebenszyklus und ein paar Plugins zu verwalten. Maven wurde so konzipiert, dass die meiste Verantwortung auf eine Anzahl Maven-Plugins delegiert werden kann, welche den Lebenszyklus von Maven beeinflussen sowie gewisse Goals erreichen knnen. Der Groteil der Arbeit geschieht in Maven Goals. Hier passieren Dinge wie die Kompilierung von Quellcode, der Paketierung von Bytecode, die Erstellung von Websites, und jede andere Aufgabe die um einen Build zu erfllen notwenig ist. Die Maven Installation nach dem Download von Apache wei noch nicht viel ber die Paketierung eines WAR-Archivs oder dem Ausfhren eines JUnit-Tests; der grte Teil der Intelligenz von Maven ist in den Plugins enthalten und diese bezieht Maven aus dem Maven-Repository. In der Tat, das erste Mal, als Sie einen Aufruf wie z.B. mvn install auf Ihrer neuen Maven Installation absetzten, holte sich Maven die meisten der Core Maven Plugins aus dem zentralen Maven-Repository. Das ist mehr als nur ein Trick, um die Download-Gre von Maven in der Verteilung zu beeinflussen, dieses Verhalten ist es, das es erlaubt, durch die Erweiterung eines Plugins die Fhigkeiten des Builds zu verndern. Die Tatsache, dass Maven sowohl die Abhngigkeiten wie auch die Plugins aus einem Remote-Repository ldt ermglicht universelle Wiederverwendung von Build-Logik. Das Maven Surefire Plugin ist das Plugin, welches fr die Ausfhrung von Unit-Tests verantwortlich zeichnet. Irgendwo zwischen Version 1.0 und der aktuell 5

Einfhrung von Apache Maven verbreiteten Version hat jemand beschlossen, dieses neben der Untersttzung von JUnit auch um die Untersttzung fr das TestNG Unit-Test Framework zu erweitern. Dies geschah in einer Art und Weise, dass die Abwrtskompatibilitt erhalten blieb. Fr die Benutzer des Surefire Plugin im Einsatz von JUnit3 Tests vernderte sich nichts, weiterhin werden die Tests kompiliert und ausgefhrt, wie dies zuvor der Fall war. Aber Sie erhalten eine neue Funktionalitt, denn sollten Sie nun Unit Tests nach dem TestNG Framework ausfhren wollen, so haben Sie nun auch diese Mglichkeit, dank der Bemhungen der Maintainer des Surefire Plugin. Das Plugin erhielt auch die Fhigkeit annotierte JUnit4 Unit Tests zu untersttzen. Alle diese Erweiterungen wurden bereitgestellt, ohne dass Sie Maven aktiv aktualisieren, oder neue Software installieren mussten. Und ganz zentral, Sie mussten nichts an Ihrem Projekt ndern, abgesehen von einer Versionsnummer fr ein Plugin in einem POM. Es ist dieser Mechanismus welche sich auf wesentlich mehr als nur das Surefire Plugin auswirkt: Projekte werden mittels einem Compiler Plugin kompiliert, mittels JAR-Plugin in JAR-Archive gepackt, es gibt es Plugins zum Erstellen von Berichten, Plugins zur Ausfhrung von JRuby und Groovy-Code, sowie Plugins zum Verffentlichen von Websites auf Remote-Servern. Maven hat gemeinsame Aufgaben in Plug-Ins herausgelst welche zentral gewartet sowie universell eingesetzt werden. Wann immer Vernderungen in einem Bereich des Buildens umgesetzt werden, wann immer ein neues Unit-Test Framework freigegeben oder ein neues Werkzeug bereit gestellt wird. Sie sind nicht gezwungen, diese nderungen in ihren Build einzupflegen um dies zu untersttzen. Sie profitieren von der Tatsache, dass Plugins von einem zentral gewarteten Remote-Repository heruntergeladen werden. Das ist die wahre Bedeutung von universeller Wiederverwendung durch Maven Plugins.

1.5. Konzeptionelles Modell eines "Projekts"


Maven unterhlt ein (abstraktes) Modell eines Projekts, Sie verarbeiten also nicht nur Quellcode Dateien in Binrdateien, Sie entwickeln zugleich eine Beschreibung des Software-Projekts und ordnen diesem eine Reihe einzigartiger Koordinaten zu. Sie beschreiben die Attribute des Projekts: Wie ist die Projektlizenzierung 6

Einfhrung von Apache Maven geregelt? Wer entwickelt und trgt zum Projekt bei? Zu welchen anderen Projekten bestehen Abhngigkeiten? Maven ist mehr als nur ein "Build-Tool", es ist mehr als nur eine Verbesserung von Werkzeugen wie make und Ant; es ist eine Plattform, umfasst eine neue Semantik bezglich Software-Projekten und Software-Entwicklung. Diese Definition eines Modells fr jedes Projekt ermglicht Funktionen wie: Dependency Management / Abhngigkeits Verwaltung Da ein Projekt einzigartig mittels einer Gruppenkennung (groupId), Artefaktenkennung (artifactId) und Version (version) identifiziert wird, ist nun mglich, diese Koordinaten zur Abhngigkeitsverwaltung einzusetzen. Remote-Repositories Mit Blick auf das Abhngigkeitsmanagement ist es nun mglich diese im Maven Projekt Objekt Modell eingefhrten Koordinaten einzusetzen um Maven Repositorien aufzubauen. Universelle Wiederverwendung der Build-Logik Plugins werden ausgerichtet auf das Projekt Objekt Model (POM) gebaut, sie sind nicht dafr ausgelegt auf bestimmte Dateien an bestimmten Orten zuzugreifen. Alles wird in das Modell abstrahiert, Plugin-Konfiguration und Anpassung geschieht im Modell. Tool Portabilitt / Integration Werkzeuge wie Eclipse, NetBeans oder IntelliJ haben jetzt einen gemeinsamen Ort um auf Projektinformationen zuzugreifen. Vor dem Aufkommen von Maven, gab es fr jede IDE eine spezifische Art und Weise in welcher diese Daten abgelegt wurden, was im Wesentlichen einem benutzerdefinierten POM entspricht. Maven standardisiert diese Beschreibung und whrend jeder IDE weiterhin deren eigenes Datenablagesystem unterhalten kann, lsst sich dieses nun leicht aus dem Modell heraus generieren. Einfache Suche und Filterung von Projekt-Artefakten Werkzeuge wie Nexus ermglichen es Ihnen schnell und einfach Archive auf der Basis der im POM enthaltenen Daten zu indexieren und zu durchsuchen. 7

Einfhrung von Apache Maven Maven hat eine Grundlage fr die Anfnge einer konsistenten semantischen Beschreibung eines Software-Projekts geschaffen.

1.6. Ist Maven eine Alternative zu XYZ?


Natrlich, Maven stellt eine Alternative zu Ant dar, aber Apache Ant ist nach wie vor ein groartiges, weit verbreitetes Werkzeug. Es stellt seit Jahren den amtierende Champion der Java Build Tools, und Sie knnen auch weiterhin Ant-Build-Skripte einfach in Ihr Maven Projekt integrieren. Das ist auch eine gebruchliche Art, Maven einzusetzen. Andererseits, jetzt da mehr und mehr Open-Source-Projekte sich auf Maven zubewegen und Maven als Projekt Management Plattform einsetzen, haben aktive Entwickler begonnen zu erkennen, dass Maven nicht nur die Aufgabe der Build Verwaltung untersttzt, sondern insgesamt zur Frderung einer gemeinsamen Schnittstelle zwischen Entwicklern und Software Projekte beitrgt. Maven hat viele Ausprgungen eine Plattform als nur eines Werkzeugs. Wenn Sie die Auffassung vertreten wrden, Maven als eine Alternative zu Ant anzusehen, so wrden Sie pfel mit Birnen vergleichen. Maven umfasst mehr als nur ein einen Werkzeugkasten um Projekte zu Builden. Dies ist das zentrale Argument, welches alle Vergleiche der Art Maven/Ant, Maven/Buildr, Maven/Gradle unerheblich macht. Maven ist nicht bestimmt von der Mechanik Ihres Build-Systems, es fusst nicht auf dem Skripting der verschiedenen Aufgaben Ihres Builds, sondern es geht weit mehr um die Frderung einer Reihe von Standards, einer gemeinsamen Schnittstelle, eines Leben-Zykluses, einem Standard-Repository Format, einem Standard-Verzeichnis Layout, usw. Es geht sicherlich nicht darum, welches POM-Format zum Einsatz kommt, ob XML, YAML, Ruby oder Maven. Maven bietet weit mehr als dies: Maven und bezieht sich auf viel mehr als nur das Werkzeug. Wenn dieses Buch von Maven spricht, so bezieht sich dies auf die Zusammenstellung von Software, Systemen und Standards, welche Maven untersttzt. Buildr, Ivy, Gradle alle diese Werkzeuge interagieren mit den Repository-Format welches zu definieren Maven beigetragen hat. Sie knnten genauso einen Build auf der Basis von Buildr einzig unter Zuhilfenahme von einem Tool wie Nexus aufbauen, Nexus wird in vorgestellt in Kapitel 16: Repository-Manager. 8

Einfhrung von Apache Maven Whrend Maven eine Alternative fr viele dieser Tools darstellt, muss die Gemeinschaft der Open Source Entwickler darber hinaus kommen knnen, Technologie als ein kontinuierliches Nullsummenspiel zwischen unfreundlichen Konkurrenten in einer kapitalistischen Wirtschaft zu sehen. Dies mag im Wettbewerb von Grounternehmen und Ihrem Bezug zu einander sinnvoll erscheinen, hat aber wenig Relevanz auf die Art und Weise, wie Open-Source-Communities arbeiten. Die berschrift "Wer gewinnt? Ant oder Maven?" ist nicht sehr konstruktiv. Zwingen Sie uns, diese Frage zu beantworten, werden wir uns definitiv auf die Seite von Maven schlagen und darlegen, dass Maven eine gegenber Ant berlegene Alternative darstellt die darberhinaus die Grundlage fr eine Technologie des Buildes legt. Gleichzeitig bitten wir zu bercksichtigen, dass die Grenzen von Maven in stndiger Bewegung sind, die Maven Gemeinde ist immerzu versucht, neue Wege zu mehr kumene, mehr Interoperabilitt, grerer Gemeinschaft zu schaffen. Die Kernkomponenten von Maven sind der deklarative Build, die Abhngigkeitsverwaltung (Dependency Management), Repository Verwaltung und breite Wiederverwendbarkeit durch den Einsatz von Plugins. Es sind aber die spezifische Inkarnationen dieser Ideen zu einem gegebenen Zeitpunkt weniger wichtig, als das Ziel dass die Open-Source-Community in Zusammenarbeit zur Verringerung der Ineffizienz von "Enterprise Scale Builds" beizutragen.

1.7. Ein Vergleich von Maven und Ant


Whrend der vorangegangene Abschnitt Ihnen verstndlich gemacht haben sollte, dass die Autoren dieses Buches keinerlei Interesse an der Schaffung oder Vertiefung einer Fehde zwischen Apache Ant und Apache Maven haben, ist uns die Tatsache bewusst, dass die meisten Organisationen eine Entscheidung zwischen Ant und Maven treffen (mssen). In diesem Abschnitt werden wir daher diese beiden Werkzeuge gegenberstellen. Ant luft beim Build-Prozess zu seiner vollen Grsse auf: Es ist ein Build-System nach dem Vorbild von make mit Targets und Abhngigkeiten. Jeder Target besteht aus einer Reihe von Anweisungen, die in XML beschrieben werden. Es gibt eine Task copy, eine Task javac sowie eine Task JAR. Wenn Sie Ant benutzen, mssen 9

Einfhrung von Apache Maven Sie Ant mit der speziellen, spezifischen Anweisungen fr die Zusammenstellung und dem Packaging Ihres Projektes aufrufen. Sehen Sie sich das folgende Beispiel einer einfachen Ant build.xml-Datei an: Example 1.1. Eine einfache Ant build.xml-Datei
<project name="my-project" default="dist" basedir="."> <description> simple example build file </description> <!-- set global properties for this build --> <property name="src" location="src/main/java"/> <property name="build" location="target/classes"/> <property name="dist" location="target"/> <target name="init"> <!-- Create the time stamp --> <tstamp/> <!-- Create the build directory structure used by compile --> <mkdir dir="${build}"/> </target> <target name="compile" depends="init" description="compile the source " > <!-- Compile the java code from ${src} into ${build} --> <javac srcdir="${src}" destdir="${build}"/> </target> <target name="dist" depends="compile" description="generate the distribution" > <!-- Create the distribution directory --> <mkdir dir="${dist}/lib"/> <!-- 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>

An diesem einfachen Beispiel eines Ant Skriptes, knnen Sie sehen, wie genau man definieren muss, was man von Ant erwartet. Ein Target ist javac, hier werden 10

Einfhrung von Apache Maven die Quelldateien in Binrdaten verarbeitet, dabei ist es wichtig, dass man genau angibt, wo die Quell- sowie Zieldateien abgelegt werden (/src/main/java resp. /target/classes). Ebenfalls mssen Sie Ant anweisen, aus den resultierenden Dateien ein JAR-Archiv zu erstellen. Whrend einige der neueren Entwicklungen dazu beitragen, dass Ant weniger prozedural orientiert arbeitet, ist die Entwickler-Erfahrung dennoch die, einer in XML abgefassten prozeduralen Programmiersprache. Vergleichen Sie das Vorgehen von Maven mit dem vorigen Beispiel: In Maven, um ein JAR-Archive aus einer Reihe von Java Quellcode Dateien zu erstellen, ist alles, was Sie tun mssen, ein einfaches POM (pom.xml Datei) zu generieren. Platzieren Sie den Quellcode in ${basedir}/src/main/java und fhren Sie dann mvn install von der Befehlszeile aus . Das Beispiel der Maven pom.xml Datei, welches zum selben Ergebnis fhrt wie zuvor das Ant-Skript sehen Sie unten. Example 1.2. Muster einer Maven pom.xml-Datei
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>my-project</artifactId> <version>1.0</version> </project>

Das ist alles was Sie in der zugehrigen pom.xml Datei bentigen. Der Aufruf von mvn install wird die Resourcen sowie Quelldateien kompilieren, bestehende Unit-Tests ausfhren, JAR-Archive erstellen und dieses in einem lokalen Repository anderen Projekten zur Verfgung stellen. Ohne die pom.xml Datei abzundern, knnen Sie durch den Aufruf von mvn site im Zielverzeichnis eine index.html wiederfinden, welche den Link zu einer Dokumentations-Web-Seite auf der Basis von JavaDoc sowie einigen Standard Reports bereitstellt. Zugegeben, dies ist das einfachste, mgliche Beispiel-Projekt. Ein Projekt, das nur Quellcode enthlt und ein JAR-Archive erzeugt. Ein Projekt welches der Maven Konvention unterliegt und keinerlei Abhngigkeiten oder Anpassungen bercksichtigt. Sobald wir die Verhaltensweisen der Plugins anpassen wird unsere pom.xml Datei wachsen. In den grssten Projekten werden Sie komplexe Maven 11

Einfhrung von Apache Maven POMs finden, welche eine grosse Anzahl Plugin-Anpassungen sowie Abhngigkeitserklrungen enthalten. Aber, selbst wenn das POM Ihres Projekts erheblich wchst, enthlt dies eine ganz andere Art von Daten und Informationen denn das Skript einer entsprechenden Ant-Datei. Maven POMs enthalten Deklarationen wie: "Dies ist eine JAR-Projekt", und "Der Quellcode ist unter /src/main/java abgelegt". Wohingegen Ant-Build-Dateien explizite Anweisung enthalten: "Dies ist ein Projekt", "Die Quelle ist in /src/main/java", "javac gegen dieses Verzeichnis ausfhren", "Ablegen der Ergebnisse in /target/classses", "Erstellen eines JAR-Archives aus der. ...". Wo Ant genauen Prozess-Anweisungen bedurfte, gab es etwas innerhalb des Maven Builds, das einfach "wusste", wo der Quellcode zu finden ist und wie dieser zu verarbeiten ist. Die Unterschiede zwischen den Ant und Maven in diesem Beispiel sind: Apache Ant Ant kennt keine formalen Konventionen bezglich einer gemeinsamen Projekt Verzeichnis-Struktur. Sie mssen Ant genau sagen, wo sich die Quelldateien befinden und wo die Ausgabe abgelegt werden soll. Informelle Konventionen haben sich im Laufe der Zeit herausgebildet, aber diese wurden nicht im Produkt kodifiziert. Ant ist Prozedural, Sie mssen Ant genau sagen, was zu tun ist und wann dies zu tun. Sie mussten definieren: erst kompilieren, dann kopieren, dann paketieren. Ant kennt keinen Lebenszyklus, Sie mussten Targets definieren und deren Abhngigkeiten. Sie mussten die Abfolge der Schritte manuell fr jeden Target festlegen. Apache Maven Maven arbeitet nach Konventionen. Da Sie diese beachteten, wusste Maven wo Ihr Quellcode sich befand. Es stellt den Bytecode unter target/classes und es erzeugte ein JAR-Archive in /target. 12

Einfhrung von Apache Maven Maven ist deklarative. Alles was Sie tun musste, war eine pom.xml Datei zu erzeugen sowie Ihre Quelle im Standard-Verzeichnis ablegen. Maven kmmerte sich um den Rest. Maven kennt einen Lebenszyklus, welchen Sie mit dem Aufruf von mvn install angestossen haben. Dieser Aufruf bringt Maven dazu, eine Abfolge von Schritten abzuarbeiten, bis das Ende des Lebenszykluses erreicht ist. Als Nebeneffekt dieser Reise durch den Lebenszyklus fhrt Maven eine Reihe von Standard-Plugin-Goals aus, diese erledigen Arbeiten wie z.B. kompilieren oder dem Erstellen eines JAR-Archives. Maven hat eine eingebaute Intelligenz bezglich der gemeinsamen Projektaufgaben in Form von Maven-Plugins. Sollten Sie Unit Tests ausfhren wollen, ist alles was Sie tun mssen, die Tests zu schreiben und unter ${basedir}/src/test/java abzulegen, fhren Sie eine Test bezogene Abhngigkeit zu entweder TestNG oder JUnit ein, und starten Sie mvn test. Sollten Sie anstelle eines JAR-Archives eine Web Anwendung erstellen, so ist alles was Sie tun mssen den Projekttyp auf "war" umstellen und Ihr Applikationsverzeichnis (docroot) auf ${basedir}/src/main/webapp setzen. Klar, knnen Sie all dies auch mit Ant bewerkstelligen, aber Sie werden alle Anweisungen von Grund auf festhalten. In Ant wrden Sie erst einmal herausfinden, wo die JUnit-JAR-Datei sich befindet, dann mssten Sie einen Klassenpfad erstellen welcher auch die JUnit-Archive Datei enthlt, und anschliessend Ant mitteilen wo sich der Quellcode befindet. Schliesslich wrden Sie einen Target erstellen die Quellen der Test Dateien zu kompilieren und zu guter Letzt die Tests mit JUnit auszufhren. Ohne Untersttzung von Technologien wie antlibs und Ivy (und auch mit diesen untersttzenden Technologien) stellt sich bei Ant das Gefhl eines prozeduralen Build Ablaufs ein. Eine effiziente Zusammenstellung einiger Maven POMs in einem Projekt welches sich an die Maven-Konventionen hlt erzeugt berraschend wenig XML im Vergleich zur Ant-Alternative. Ein weiterer Vorteil von Maven ist die Abhngigkeit von weithin benutzten Maven-Plugins. Heutzutage benutzt jeder das Maven Surefire Plugin fr Unit-Tests, sobald jemand ein weiteres Unit Test Framework einbindet, knnen Sie neue Fhigkeiten in Ihrem eigenen Build durch 13

Einfhrung von Apache Maven die einfache nderung der Version eines einzelnen, bestimmten Maven Plugins nutzen. Die Entscheidung ber die Verwendung Maven oder Ant ist heutzutage nicht binr. Ant hat noch immer einen Platz in in komplexen Builds. Wenn Ihr aktueller Build-Prozess einige sehr individuelle Prozesse enthlt, oder wenn Sie etliche Ant-Skripte geschrieben haben um einen bestimmten Prozess in einer bestimmten Weise, die sich nicht an die Normen Maven hlt, abzudecken, knnen Sie diese Skripte dennoch mit Maven abarbeiten. Ant wird als Kernkomponente in Form eines Plugins von Maven zur Verfgung gestellt. Benuzerdefinierte Maven-Plugins knnen in Ant geschrieben werden und Maven Projekte knnen so konfiguriert werden, das Ant-Skripte innerhalb des Maven-Projekt-Lebenszykluses abgearbeitet werden.

1.8. Zusammenfassung
Diese Einfhrung wurde absichtlich kurz gehalten. Wir haben Ihnen umrissen, was Maven ist und wie es zu einem guten Build-Prozess beitrgt, sowie ber die Zeit hinweg diesen verbessern hilft. Im nchste Kapitel werden wir am Beispiel eines einfachen Projektes aufzeigen welche phnomenalen Aufgaben mit dem kleinstmglich Aufwand an Konfiguration geleistet werden knnen.

14

Chapter 2. Installieren und Ausfhren von Maven


Dieses Kapitel enthlt detaillierte Anweisungen fr die Installation von Maven auf einer Reihe von unterschiedlichen Plattformen. Statt ein bestimmtes Mass der Vertrautheit mit der Installation von Software und dem Einstellen von Umgebungsvariablen vorauszusetzen, haben wir uns entschieden, so detailliert wie mglich zu sein, um Probleme welche von unvollstndigen Installation herrhren von vornherein zu minimieren. die einzige Voraussetzung welche angenommen wird ist die, einer bestehenden, geeigneten und vollstndigen Java Umgebung, eines Java Development Kit (JDK). Sollten Sie nur Interesse an der Installation haben, so knnen Sie nach dem Lesen der Abschnitte "2.2 Herunterladen von Maven" sowie "2.3 Installation von Maven" zu den weiterfhrenden Kapiteln des Buches bergehen. Wenn Sie an einer detaillierten Beschreibung interessiert sind, so gibt Ihnen dieses Kapitel die entsprechenden Informationen sowie eine Erklrung der Bedeutung der Apache Software License, Version 2.0.

2.1. berprfen der Java-Installation


Obschon Maven auch auf Java 1.4 untersttzt ist, geht dieses Buch davon aus, dass sie mindestens auf Java 5 aufsetzen. Whlen Sie den neusten stabilen JDK welcher fr Ihre Plattform erhltlich ist. Alle in diesem Buch aufgefhrten Beispiele sind unter Java 5 oder Java 6 lauffhig.
java -version java version "1.6.0_02" Java(TM) SE Runtime Environment (build 1.6.0_02-b06) Java HotSpot(TM) Client VM (build 1.6.0_02-b06, mixed mode, sharing)
%

Maven ist unter allen Java-kompatibel zertifiziert Entwicklungsumgebungen, sowie einigen weiteren, nicht-zertifizierten Implementierungen von Java lauffhig. Die Beispiele in diesem Buch wurden gegen die offizielle Java Development Kit Implementation wie diese von Sun Microsystems Webseite (http://java.sun.com) 15

Installieren und Ausfhren von Maven heruntergeladen werden kann, geschrieben und getestet. Sollten Sie mit einer Linux-Distribution arbeiten, mssen Sie eventuell die Java Entwicklungsumgebung selbst herunterladen und installieren. Bitte stellen Sie sicher, dass diese auch zum Einsatz kommt: durch Aufruf von "java -fullversion ". Nun, da Sun Microsystem den Quellcode von Java unter einer Open Source Lizenz offengelegt hat, tritt diesbezglich hoffentlich schon bald eine Besserung ein und es werden auch auf puristisch Linux-Distributionen die originalen Sun JRE sowie JDKs installiert. Bis zu diesem Tag mssen Sie selbst Hand anlegen, Java herunterladen und installieren.

2.2. Herunterladen von Maven


Sie knnen Maven von der Apache Maven-Projekt-Website unter http://maven.apache.org/download.html herunterladen. Beim Herunterladen von Maven, whlen Sie die neuste Version von Apache Maven vom Website. Die aktuell neuste Version zur Zeit als dieses Buch geschrieben wurde war Maven 2.0.9. Sollten Sie die Apache Software Lizenz noch nicht kennen, so machen sie sich - vor dem Einsatz des Produktes - mit deren Bedingungen vertraut. Weitergehende Informationen diesbezglich finden Sie in Abschnitt "2.8 Die Apache Software Lizenz".

2.3. Installation von Maven


Die Unterschiede zwischen den Betriebssystemen wie Mac OS X und Microsoft Windows sind gross, daneben gibt auch subtile Unterschiede zwischen den verschiedenen Versionen von Windows oder Varianten von Linux zu beachten. Zum Glck ist der Prozess der Installation von Maven auf all diesen Betriebssystemen relativ einfach und schmerzlos. Die folgenden Abschnitte geben einen berblick ber die empfohlene Best-Practice der Installation von Maven unter einer Vielzahl von Betriebssystemen.

16

Installieren und Ausfhren von Maven

2.3.1. Maven Installation unter Mac OSX


Am Anfang bentigen Sie zunchst die Software, diese bekommen Sie unter: http://maven.apache.org/download.html. Laden Sie die aktuelle Version von Maven in einem fr Sie passenden Format herunter. Whlen Sie einen geeigneten Platz als "Heimat" und entpacken Sie das Archiv dort. Wenn Sie zum Beispiel das Verzeichnis /usr/local/apache-maven-2.0.9 gewhlt haben, so macht es Sinn einen symbolischen Link zu erzeugen. Dies erleichtert die Arbeit und erspart die Anpassung von Umgebungsvariablen im Falle eines Upgrades der Version.
/usr/local /usr/local /usr/local /usr/local % % % % cd /usr/local ln -s apache-maven-2.0.9 maven export M2_HOME=/usr/local/maven export PATH=${M2_HOME}/bin:${PATH}

Ist Maven einmal installiert ist, mssen Sie noch ein paar Schritte unternehmen, damit Maven korrekt funktionieren kann. Zu aller erst sollten Sie das bin-Verzeichnis Ihrer Maven Distribution (in diesem Beispiel /usr/local/Apache-Maven/bin) in den Befehlspfad aufnehmen. Ausserdem sollten Sie noch die Umgebungsvariable M2_HOME auf das Maven-Top-Level-Verzeichnis setzen (in diesem Beispiel /usr/local/Maven). Note Installations-Anweisungen sind die gleichen fr OSX Tiger und OSX Leopard. Es wurde berichtet, dass Maven 2.0.6 mit einer Vorschau-Version von XCode ausgeliefert wird. Sollten Sie XCode installiert haben, fhren Sie mvn von der Befehlszeile aus, und berprfen Sie die Verfgbarkeit. XCode installiert Maven unter /usr/share/Maven. Wir empfehlen die Installation der jngsten Version von Maven 2.0.9, da hier eine Reihe von Bugfixes und Verbesserungen eingeflossen sind. Um die Konfiguration beider Umgebungsvariablen bei jedem Start zu setzen, ist es notwendig diese in einem Skript abzulegen welches bei jedem Systemstart abgearbeitet wird. Fgen Sie daher die folgenden Zeilen der Datei .bash_login an:
export M2_HOME=/usr/local/maven

17

Installieren und Ausfhren von Maven


export PATH=${M2_HOME}/bin:${PATH}

Mit dem Anfgen dieser Zeilen wird Maven Ihrer Umgebung zugefgt, und Sie bekommen die Mglichkeit Maven von der Kommandozeile zu starten. Note Diese Installationsanleitung geht davon aus, dass Sie unter der bash-Shell arbeiten.

2.3.1.1. Maven Installation unter Mac OSX mit MacPorts Sollten Sie MacPorts einsetzen, so knnen Sie Maven installieren, indem Sie die folgenden Befehle auf der Kommandozeile eingeben:

$ sudo port install maven2 Password: ****** ---> Fetching maven2 ---> Attempting to fetch apache-maven-2.0.9-bin.tar.bz2 from http://www.apache.org/dist/mav ---> Verifying checksum(s) for maven2 ---> Extracting maven2 ---> Configuring maven2 ---> Building maven2 with target all ---> Staging maven2 into destroot ---> Installing maven2 2.0.9_0 ---> Activating maven2 2.0.9_0 ---> Cleaning maven2

Fr weiterfhrende Informationen bezglich der Maven 2 Portierung verweisen wir auf Portfile. Bezglich weiterfhrender Informationen zu MacPorts und wie dies zu installieren ist: MacPorts Projekt Seite (Engl.).

2.3.2. Maven Installation unter Microsoft Windows


Die Installation von Maven unter Windows ist sehr hnlich wie jene unter Mac OSX, die wichtigsten Unterschiede finden sich bezglich des Installationsortes und der Festlegung der Umgebungsvariablen. Dieses Buch geht von einem Maven Installations-Verzeichnis von "C:\Program Files\Maven-2.0.9" aus, aber es wird keinen Unterschied machen, sollten Sie Maven in ein anderes Verzeichnis installieren, solange Sie die Umgebungsvariablen entsprechend anpassen. Nach 18

Installieren und Ausfhren von Maven dem Entpacken des Maven Installationspaketes mssen Sie zwei Umgebungsvariablen - PATH und M2_HOME - setzen. Um dies zu bewerkstelligen, geben Sie auf der Kommandozeile folgende Befehlen ein:
C:\Users\tobrien > set M2_HOME=c:\Program Files\apache-maven-2.0.9 C:\Users\tobrien > set PATH=%PATH%;%M2_HOME%\bin

Das Setzen der Umgebungsvariablen in der Kommando-Zeile erlaubt Ihnen die Ausfhrung von Maven whrend Ihrer aktuellen Sitzung und zwingt Sie diese bei jedem Neustart erneut zu setzen. Sie sollten diese Variablen daher den Systemeinstellungen zufgen, ffnen Sie hierzu das Menue "Systemeinstellungen" von dort "System" und whlen Sie "".

2.3.3. Maven Installation unter Linux


Zur Installation von Maven auf einer Linux-Maschine, folgen Sie der Vorgehensweise in Abschnitt 2.3.2: "Installation von Maven auf Mac OSX".

2.3.4. Maven Installation unter FreeBSD oder OpenBSD


Zur Installation von Maven auf einem FreeBSD oder OpenBSD Maschine, folgen Sie der Vorgehensweise in Abschnitt 2.3.2: "Installation von Maven auf Mac OSX"

2.4. Testen einer Maven Installation


Ist Maven erst einmal installiert, knnen Sie die Version berprfen, indem Sie mvn -v in der Befehlszeile eingeben. Bei einer korrekten Installation von Maven sollte eine Ausgabe wie folgt erscheinen:
$ mvn -v Maven 2.0.9

Sollten Sie diese Ausgabe erhalten, wissen Sie dass Maven verfgbar und bereit ist um eingesetzt zu werden. Wenn nicht, hat Ihr Betriebssystem den mvn Befehl nicht gefunden. berprfen Sie ob die PATH-Umgebungsvariable sowie M2_HOME 19

Installieren und Ausfhren von Maven (Gross/Kleinschreibung beachten!) richtig gesetzt sind.

2.5. Spezielle Installationshinweise


Das herunter zu ladende Maven Paket hat eine Grsse von etwa 1,5 MiB [1], diese Schlankheit hat es erreicht, da der Kern von Maven mit dem Ziel entwickelt wurde, Plugins und Abhngigkeiten von einem Remote-Repository dynamisch und auf Abruf zuzuladen. Wenn Sie Anfangen mit Maven zu arbeiten, ldt Maven zunchst Plugins in ein lokales Repository. Dieses wird im Abschnitt 2.5.1 "Benutzerdefinierte Konfiguration und -Repository" beschrieben. Im Fall, dass Sie neugierig sind, lassen Sie uns einen Blick darauf werfen, was sich im Maven Installationsverzeichnis befindet. 1
/usr/local/maven $ ls -p1 LICENSE.txt NOTICE.txt README.txt bin/ boot/ conf/ lib/

Die Datei LICENSE.txt enthlt die Software-Lizenz fr Apache Maven. Diese Lizenz ist in einigen Details in Abschnitt 2.8 "ber die Apache Software Lizenz" beschrieben. NOTICE.txt enthlt einige Hinweise zu Abhngigkeiten von Bibliotheken, von denen Maven abhngig ist. README.txt enthlt Installationsanweisungen. Das Verzeichnis /bin enthlt das "mvn"-Skript, mit welchem Maven aufgerufen wird. /boot enthlt eine JAR-Datei (classworlds-1.1.jar), welche den Class-Loader unter welchem Maven ausgefhrt wird bereitstellt. /conf enthlt eine Datei settings.xml, diese wird eingesetzt um globale Einstellungen festzulegen um das Verhalten von Maven zu definieren und anzupassen. Sollten Sie Maven Ihren Gegebenheiten anpassen
1

Haben Sie je eine 200-GB-Festplatte gekauft, nur um herauszufinden, dass diese weniger als 200 GiB fasst, wenn Sie diese installiert haben? Computer verstehen Gibibytes, aber Einzelhndler verkaufen Produkte mit Gigabyte. MiB steht fr die Mebibyte und ist definiert als 2^20 oder 1024^2. Diese binre Prfix Standards sind von der IEEE, CIPM, und und IEC bernommen. Fr weitere Informationen ber Kibibytes, Mebibytes, Gibibytes und Tebibytes siehe auch http://en.wikipedia.org/wiki/Mebibyte.

20

Installieren und Ausfhren von Maven mssen, hat es sich herausgebildet, dass man die Einstellungen der settings.xml durch eine Datei settings.xml im Verzeichnis ~/.m2 bersteuert. /lib enthlt eine einzige JAR-Datei (Maven-2.0.9-uber.jar), welche die Hauptimplementierung (Core) von Maven enthlt. Note Mit der Ausnahme einer shared Unix Installation, sollten Sie auf die Anpassung der settings.xml unter M2_HOME/conf vermeiden. Die Anpassung der globalen settings.xml-Datei der eigentlichen Maven Installation ist gewhnlich unntig und erschwert den upgrade zwischen den Maven Installationen unntigerweise, da Sie daran denken mssen, die angepasste settings.xml wieder von der bisherigen zur neuen Maven Installation zurckzukopieren. Sollten Sie dennoch gezwungen sein, die settings.xml anzupassen, so sollten Sie die 'persnliche' settings.xml unter ~/.m2/settings.xml anpassen.

2.5.1. Benutzerdefinierte Konfiguration und-Repository


Sobald Sie beginnen sich mit Maven ausgiebig auseinander zu setzen, werden Sie feststellen, dass Maven einige lokale, benutzerspezifische Konfigurationsdateien und ein lokales Archiv in Ihrem Home-Verzeichnis angelegt hat. Unter ~/.m2 befinden sich: ~/.m2/settings.xml Eine Datei mit der benutzerspezifischen Konfiguration der Authentifizierung, Repositorien und anderen Informationen, um das Verhalten von Maven zu steuern. ~/.m2/repository/ Dieses Verzeichnis enthlt Ihr lokales Maven-Repository. Wenn Sie eine Abhngigkeit von einem Remote-Maven-Repository herunterladen, so wird diese in ihrem lokalen Repository zwischengespeichert.

21

Installieren und Ausfhren von Maven Note Unter Unix (und OSX), bezeichnet die Tilde "~" Ihr Home-Verzeichnis (d.h. ~/bin bezieht sich auf /home/tobrien/bin). Unter Windows, werden wir uns ebenfalls mit ~ auf Ihr Home-Verzeichnis beziehen. Unter Windows XP ist Ihr Home-Verzeichnis C:\Dokumente und Einstellungen\<Benutzername>, unter Windows Vista wird Ihr Home-Verzeichnis mit C:\Users\<Benutzername> bezeichnet. Im Folgenden bitten wir Sie entsprechend Ihres Systems den Pfad anzupassen.

2.5.2. Aktualisieren einer Maven-Installation


So Sie unter Unix/OSX arbeiten und die Installation wie oben unter Abschnitt 2.3.2 "Installation von Maven auf Mac OSX" oder Abschnitt 2.3.3 "Installation von Maven auf Linux" beschrieben ausgefhrt haben, so ist es ein Kinderspiel eine Maveninstallation zu Aktualisieren: Installieren Sie einfach die neuere Version von Maven (/usr/local/maven-2.future) neben der bestehenden Version von Maven (/usr/local/maven-2.0.9). ndern Sie dann den symbolischen Link /usr/local/Maven von /usr/local/maven-2.0.9/ auf /usr/local/maven-2.future. Fertig! Da Ihre M2_HOME Variable bereits auf /usr/local/Maven zeigt, mssen keine weiteren Anpassungen ausgefhrt werden. Unter Windows, entpacken Sie einfach die neue Version von Maven unter C:\Program Files\Maven-2.future und aktualisieren Sie Ihre M2_HOME Variable ber die Systemsteuerungen. Note Sollten Sie die globale Datei settings.xml von /M2_HOME/conf angepasst haben, so mssen Sie diese nderungen in das /conf-Verzeichnis der neuen Installation bertragen.

22

Installieren und Ausfhren von Maven

2.5.3. Upgrade einer Maven-Installation von Maven 1.x auf Maven 2.x
Beim Upgrade von <term>Maven 1</term> auf <term>Maven 2</term> werden Sie eine ganz neue POM Struktur sowie ein neues Repository benutzen. Haben Sie bereits ein benutzerspezifisches Maven 1 Repository fr massgeschneiderte Artefakte erstellt, so knnen Sie mit Hilfe des Nexus Repository Manager diese so darstellen, dass sie von Maven 2 Anwendungen benutzt werden kann. Bezglich weiterer Informationen zum Nexus Repository Manager verweisen wir auf Kapitel 16: Repository Manager. Zustzlich zum Einsatz von Werkzeugen wie Nexus, knnen Sie Referenzen auf Repositorien so einstellen, dass diese das vorgngige Format untersttzen. Bezglich weiterer Informationen zum Konfiguration einer Referenz auf ein Maven 1 Repository siehe auch Abschnitt A.2.8: "Repositorien". Sollten Sie eine Anzahl bestehender Maven 1 Projekte unterhalten, interessieren Sie sich bestimmt fr das Maven One Plugin. Das Plugin wurde entworfen, um Projekte von Maven 1 auf Maven 2 zu portieren. Ein bestehendes Maven 1 Projekt knnen sie portieren in dem Sie das Goal one:convert wie folgt aufrufen:
$ cd my-project $ mvn one:convert

one:convert wird eine Maven 1 project.xml Datei einlesen und in eine pom.xml-Datei konvertieren welches zu Maven 2 kompatibel ist. Sollten Sie allerdings ein Maven 1 Build Skript mittels Jelly angepasst haben, so mssen Sie andere Wege gehen. Whrend Maven 1 Jelly basierte Anpassungen favorisierte, ist der bevorzugte Weg der Anpassung von Maven 2 Skripten mittels benutzerdefinierten Plugins, skriptbaren Plugins oder dem Maven Antrun Plugin. Das Wichtigste was es bei der Migration von Maven 1 auf Maven 2 zu beachten gilt ist, dass Maven 2 auf einem grundstzlich verschiedenen Unterbau aufbaut. Maven 2 setzt auf Lebenszyklusphasen und definiert das Verhltnis zwischen Plugins auf eine andere Art und Weise. Sollten Sie eine derartige Migration 23

Installieren und Ausfhren von Maven vornehmen, so mssen Sie Zeit einplanen, um sich mit den Unterschieden der zwei Versionen vertraut machen. Obschon es nahe liegt sich mit der neuen POM Struktur auseinanderzusetzen, sollten Sie sich zunchst auf das Lebenszykluskonzept konzentrieren. Sobald Sie das Lebenszykluskonzept verstanden haben, steht Ihnen nichts mehr im Weg, Maven zur vollen Strke einzusetzen.

2.6. Maven De-Installieren


Die meisten Installationsanleitungen fr Maven beinhalten das Entpacken des Maven Bndel in ein Verzeichnis und das Setzen einiger Umgebungsvariablen. Sollten Sie also Maven von Ihrem Arbeitsplatz entfernen mssen, so mssen Sie lediglich das Maven Installationsverzeichnis lschen und die Umgebungsvariablen entfernen. Sie sollten ebenfalls das Verzeichnis ~/.m2 entfernen, da dies Ihr lokales Repository enthlt.

2.7. Hilfe bekommen beim Arbeiten mit Maven


Whrend dieses Buch das Ziel hat, ein umfassendes Nachschlagewerk zu sein, wird es Themen geben welche wir verpasst haben oder besondere Umstnde und Situationen sowie Tipps, welche nicht abgedeckt werden. Der Kern von Maven ist sehr einfach, die eigentliche Arbeit geschieht in den Maven Plugins; und deren gibt es zu viele um alle in diesem Buch abdecken zu knnen. Sie werden zwangslufig auf Schwierigkeiten stoen und Eigenheiten finden, welche in diesem Buch nicht bercksichtigt wurden. In diesen Fllen empfehlen wir Ihnen die Suche nach Antworten an folgenden Orten: http://maven.apache.org Dies sollte der erste Ausgangspunk einer jeden Suche sein. Der Maven-Website enthlt eine Flle von Informationen und Dokumentation. Jedes offizielle Plugin hat ein paar Seiten Dokumentation und es gibt eine Reihe von "Quick Start"-Dokumenten, die zustzlich zum Inhalt dieses Buches hilfreich sein 24

Installieren und Ausfhren von Maven werden. Whrend die Maven Website eine Flle von Informationen enthlt, kann es aber auch frustrierend, verwirrend und berwltigend sein, dort zu suchen. Die Seite enthlt ein spezielles Google-Suchfeld welches die wichtigsten Informationsquellen bezglich Maven durchsucht. Diese Suchmaske liefert bessere Ergebnisse als eine generische Google-Suche. Maven User Mailing List Die Maven User Mailing List ist der Ort fr Nutzer um Fragen zu stellen. Bevor Sie sich mit einer Frage an die User Mailing List wenden, durchsuchen Sie bitte vorangegangene Diskussionen zum betreffenden Thema. Es zeugt von schlechtem Stil eine Frage stellen, die bereits zuvor gestellt wurde, ohne vorher zu prfen, ob in den Archiven bereits eine Antwort schlummert. Es gibt eine Reihe von ntzlichen Mailing-List Archiv Browsern um Ihnen die Arbeit zu erleichtern. Fr unsere Recherchen hat sich Nabble als am ntzlichsten erwiesen. Sie knnen die User Mailing List Archive hier finden: http://www.nabble.com/Maven---Users-f178.html. Eine Beschreibung, wie Sie der User Mailingliste beitreten knnen finden sie hier http://maven.apache.org/mail-lists.html. http://www.sonatype.com Sonatype unterhlt eine Online-Kopie dieses Buches und andere Tutorials im Zusammenhang mit Apache Maven. Note Trotz der grten Bemhungen von einigen sehr engagierten Maven Mitwirkenden, ist die Maven Website schlecht organisiert und voller unvollstndiger (und manchmal) irrefhrender Auszgen und Dokumentationen. In der Gemeinschaft der Maven Entwickler gibt es leider einen Mangel gemeinsamer Standards der Plugin-Dokumentation. Einige Plugins sind sehr gut dokumentiert, whrend andere nicht einmal die elementarsten Anweisungen fr den Gebrauch ausweisen. Oft der erfolgversprechendste Ansatz die Suche nach einer Lsung in den Archiven der User Mailing Lists. Und wenn Sie wirklich helfen wollen unterbreiten Sie einen Patch der Maven Website (oder diesem Buch). 25

Installieren und Ausfhren von Maven

2.8. Das Maven Hilfe Plugin


Im Laufe des Buches werden wir Maven-Plugins Einfhren, sprechen von Maven Project Object Model (POM)-Dateien, Einstellungen und Profilen. Es werden Zeiten kommen, in denen Sie ein Werkzeug bentigen, um Ihnen dabei zu helfen, den Sinn einiger in Maven genutzter Modelle zu erkennen sowie die Zielsetzungen bestimmter Plugins nachzuvollziehen. Das Maven Hilfe Plugin ermglicht Ihnen die in Maven aktiven Profile auszugeben, das tatschlich aktive Projekt Objekt Modell (POM) anzusehen sowie die Attribute der Maven Plugins darzustellen. Note Fr einen konzeptionellen berblick ber das POM und Plug-Ins verweisen wir Sie auf Kapitel 3, Ein einfaches Maven-Projekt. Das Hilfe-Maven Plugin hat vier Goals. Die ersten drei Goals: -active-profiles, effective-pom, sowie effective-settings beschreiben je ein bestimmtes Projekt und mssen daher im Hauptverzeichnis des Projekts aufgerufen werden. Das letzte Goal - describe - ist etwas komplexer, es gibt Informationen ber ein Plug-In oder dessen Zielsetzung aus. help:active-profiles Gibt die Profile (project, user, global) aus, welche fr diesen Build aktiv sind help:effective-pom Zeigt das tatschlich eintretende POM fr den gegenwrtigen Build unter Bercksichtigung der aktiven Profile aus help:effective-settings Gibt die Einstellungen des Projekts wieder, unter Bercksichtigung von Profilerweiterungen sowie der Vererbung aus den globalen Einstellungen auf die Benutzer spezifischen Einstellungen help:describe Beschreibt die Attribute eines Plugins. Dieses Goal muss einzig nicht unter 26

Installieren und Ausfhren von Maven einem bestehendes Projekt Verzeichnis aufgerufen werden. Es muss mindestens die groupId und artifactId des Plugin welches Sie beschreiben wollen gegeben werden

2.8.1. Beschreibung eines Maven Plugin


Sobald Sie beginnen mit Maven zu arbeiten, werden Sie die meiste Zeit damit verbringen zu versuchen mehr Informationen zu Maven-Plugins zu bekommen: Wie funktionieren Plugins? Was sind die Konfigurations-Parameter? Was sind die Goals? Das Goal help:describe werden Sie regelmssig benutzen um an diese Informationen zu gelangen. Mit dem plugin-Parameter knnen Sie spezifizieren welches Plugin Sie untersuchen mchten. Hierzu geben sie entweder das Plugin-Prefix an (z.B. maven-help-plugin als help) oder die groupId:artifact[:version], wobei die Version optional ist. hier ein Beispiel; der folgende Befehl verwendet das Hilfe Plugin Goal describe um Informationen ber das Maven Hilfe Plugin auszugeben.
$ mvn help:describe -Dplugin=help ... Group Id: org.apache.maven.plugins 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. ...

Die Ausgabe des Goals describe mit dem Plugin-Parameter gibt die Koordinaten des Plugins aus, dessen Goal, Prefix und eine kurze Beschreibung. Obwohl diese Daten hilfreich sind, werden Sie in der Regel ausfhrlichere Informationen suchen. Um dies zu erreichen, fhren Sie das Goal help:describe mit dem Parameter full aus, wie im folgenden beschrieben:
$ mvn help:describe -Dplugin=help -Dfull ... Group Id: org.apache.maven.plugins Artifact Id: maven-help-plugin

27

Installieren und Ausfhren von Maven


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: org.apache.maven.plugins.help.ActiveProfilesMojo Language: java Parameters: ----------------------------------------------[0] Name: output Type: java.io.File Required: false Directly editable: true Description: 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: java.util.List 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 ...

Diese Option ist ideal um alle Goals eines Plugins zu finden, sowie deren 28

Installieren und Ausfhren von Maven Parameter. Aber manchmal ist dies weit mehr Informationen als notwendig. Um Informationen ber ein einziges Goal zu erlangen, setzen Sie mit dem Plugin-Parameter auch den mojo-Parameter zu. Der folgende Aufruf listet alle Informationen ber das Goal compile des Compiler-Plugins.
$ mvn help:describe -Dplugin=compiler -Dmojo=compile -Dfull

Note Was? Ein Mojo? In Maven, ein Plugin Goal ist bekannt als "Mojo".

2.9. Die Apache Software Lizenz


Apache Maven ist unter der Apache Software Lizenz, Version 2.0 freigegeben. Wenn Sie die Lizenz lesen mchten, lesen Sie diese Lizenz abgelegt in ${M2_HOME}/LICENSE oder lesen Sie diese auf der Webseiten der Open-Source-Initiative http://www.opensource.org/licenses/apache2.0.php nach. Es gibt eine gute Chance, dass Sie, wenn Sie dieses Buch lesen, kein Rechtsanwalt sind. Wenn Sie sich fragen, was die Apache Lizenz, Version 2.0 bedeutet, dann hat die Apache Software Foundation hat eine sehr hilfreich "Hufig gestellte Fragen (FAQ)"- Seite bezglich der Lizenz zusammengestellt. Sie finden diese unter http://www.apache.org/foundation/licence-FAQ.html. Da die FAQ in Englisch gefasst sind, hier nur eine Beispielhafte bersetzung der Frage "Ich bin kein Jurist. Was bedeutet das alles ?" Die Apache Lizenz, Version 2.0, Erlaubt Ihnen die Apache Software kostenlos herunterladen und zu verwenden. Ganz oder teilweise, fr persnliche, Firmen-interne oder kommerzielle Nutzung einzusetzen. Apache Software in oder-Distributionen oder Pakete welche Sie erstellen einzusetzen Verbietet Ihnen: 29

Installieren und Ausfhren von Maven Apache Software oder davon abgeleitete Software ohne korrekte Angabe der Herkunft zu verbreiten; die Benutzung jeglicher Marken der Apache Software Stiftung in einer solchen Weise zu dass daraus abzuleiten ist, dass die Stiftung Ihr Produkt untersttzt die Benutzung jeglicher Marken der Apache Software Stiftung in einer solchen Weise zu dass daraus abzuleiten ist, dass Sie die Apache Software erschaffen haben. Zwingt Sie nicht die Source der Apache Software selbst, oder irgendwelcher davon abgeleiteten Produkte welche Sie daraus hergestellt haben einer Distribution oder einem Produkt welches Sie zusammengestellt haben beizulegen. nderungen welche sie an der Software der Apache Software Stiftung angebracht haben dieser zurckzugeben (Solcher Feedback wird ermutigt)

30

Part I. Maven by Example


Das erste Buch zum Thema Maven welches erschienen ist, war das "Maven Developer's Notebook" von O'Reilly, dieses Buch, fhrte Maven in einer Reihe von einfachen Schritten ein. Die Idee hinter dem Developer's Notebook-Serie war, dass Entwickler am Besten lernen, wenn sie neben einem anderen Entwickler sitzen, und dem Denkprozess folgen, welcher ein anderer Entwickler beschreitet um sich eine neue Materie anzueignen und zu nutzen. Obschon die Serie der Developer's Notebooks erfolgreich war, gibt es eine entscheidende Kehrseite am Notebook-Format: Notebooks sind, par Definition, Ziel orientiert. Sie geleiten durch eine Abfolge von Schritten zu einem bestimmten Ziel. Grere Nachschlagewerke oder "Animal" Bcher sind dazu da, eine umfassende Materialsammlung ber das gesamte Thema darzustellen. Beide Bcher haben Vor-und Nachteile, aber die Verffentlichung des einen ohne das andere ist ein Rezept fr zuknftige Probleme. Zur Verdeutlichung des Problems, nehmen Sie einmal an, dass zehntausend Menschen nachdem sie "A Developer's Notebook" gelesen haben, alle wissen werden, wie man ein einfaches Projekt aufsetzt, dem Beispiel halber ein Maven Projekt welches aus einer Reihe von Quelldateien ein WAR-Archive generiert. Aber, sobald diese Personen tiefer gehende Informationen nachschlagen mchten oder die eine oder andere Besonderheit zum Beispiel des "Assembly" Plugins erfahren wollen, stecken sie in so etwas wie einer Sackgasse. Da es kein gut geschriebenes Referenzmanual fr Maven gibt, mssen sie nun auf die Plugin-Dokumentation auf dem Maven Site zurckgreifen oder alternativ sich durch eine Reihe von Mailinglisten qulen. Wenn die Leute erst einmal in der Maven Dokumentation graben, fangen sie an, tausende von schlecht geschrieben HTML-Dokumente des Maven Websites zu lesen, geschrieben von Hunderten von verschiedenen Entwicklern, jeder mit einer anderen Vorstellung davon, was es bedeutet, ein Plugin zu dokumentieren: Hunderte von Entwicklern mit unterschiedlichen sprachlichen Stilen, Ausdrcken und Muttersprachen. Trotz der grten Bemhungen von Hunderten von gut meinenden Freiwilligen, ist die Lektre der Plugin-Dokumentation auf der Website Maven, ist im besten Fall frustrierend - und im schlimmsten Fall ein Grund Maven aufzugeben. Oftmals 31

bleiben Maven Nutzer stecken, nur weil sie auf dem Maven Site schlicht keine Antwort auf ihr Problem finden knnen. Whrend das erste Maven Developer's Notebook neue Benutzer zu Maven hinzog, und diese mit grundlegenden Kenntnissen zur Nutzung von Maven ausstattete, wuchs schon bald Frustration in dieser Gruppe, denn sie konnten beim besten Willen kein prgnantes, gut geschriebenes Referenz-Handbuch finden. Dieser Mangel eines aussagekrftiges (oder definierenden) Referenz-Handbuches hat Maven fr einige Jahre zurckgehalten; es wurde etwas wie eine dmpfende Kraft in der Maven User-Community. Dieses Buch zielt darauf ab, diese Situation zu ndern, indem sie sowohl ein Update des ursprnglichen Maven Entwickler Notebook in Teil I, "Maven by Example" darstellt, und auch den ersten Versuch eines umfassenden Nachschlagewerks in Teil II, "Maven-Referenz". Was haben Sie in Ihren Hnden halten, (oder auf dem Bildschirm sehen) sind eigentlich zwei Bcher in einem. In diesem Teil des Buches, werden wir den erzhlenden, fortschreitenden Stil des Developer's Notebooks beibehalten, denn es ist wertvolles Material, welches dem Einsteiger hilft, anhand von Beispielen zu lernen, eben "Maven by Example". In der ersten Hlfte des Buches wird Maven an Hand von Beispielen eingefhrt, um dann in Teil II, der "Maven-Referenz" Lcken zu schliessen, uns in Details zu ergeben und fortgeschrittene Themen einzufhren welche sonst unter Umstnden den neuen Benutzer von Maven irritieren und vom Weg abbringen knnte. Whrend Teil II: Maven-Referenz auf einen Tabellenverweis oder einem vom Beispiel entkoppelten Programmausdruck setzt, setzt Teil I: Maven by Example auf die Kraft einer guten Vorbildwirkung sowie einer durchgehenden Storyline. Mit Abschluss von Teil I: Maven by Example, sollten Sie das Rstzeug haben, das Sie brauchen, um mit Maven fr ein paar Monate auszukommen. Wahrscheinlich werden sie nur auf Teil II: Maven-Referenz zurckkommen, um eine Anpassung eines Maven-Plugins vorzunehmen, oder wenn Sie weitere Details zu den einzelnen Plugins bentigen.

32

Chapter 3. Ein einfaches Maven Projekt


3.1. Einleitung
In diesem Kapitel fhren wir ein einfaches Projekt ein, welches wir von Grund auf mit dem Maven Archetype Plugin erstellen. Diese Anwendung bietet uns die Gelegenheit einige grundlegende Konzepte von Maven einzufhren, whrend Sie einfach der Entwicklung des Projektes folgen. Sollten Sie bereits zuvor Maven eingesetzt haben, werden Sie festgestellt haben, dass Maven mit sehr wenigen Details gut zurecht kommt. Ihr Build wird "einfach funktionieren", und Sie brauchen sich nur um Details zu kmmern, wenn es notwendig ist, das Standardverhalten zu ndern oder ein angepasstes Plugin zu erstellen. Allerdings, sollten Sie gezwungen sein sich um die Details von Maven zu kmmern, so ist ein gutes Verstndnis der grundlegenden Konzepte von wesentlicher Bedeutung. Dieses Kapitel zielt darauf ab, das einfachste mgliche Maven-Projekt einzufhren und daran Ihnen einige der grundlegenden Konzepte, welche die Maven zu einer soliden Build Plattform machen, vorzustellen. Nach dem Lesen dieses Kapitels werden Sie ein grundlegendes Verstndnis des Build Lifecycles, des Maven Repositories, der Abhngigkeits-Verwaltung (Dependency Management) und dem Projekt Objekt Modell (POM) haben.

3.1.1. Das Herunterladen der Beispiele dieses Kapitels


Dieses Kapitel entwickelt ein sehr einfaches Beispiel, welches dazu dient einige Kern-Konzepte von Maven vorzustellen. Indem Sie den Schritten des Kapitels folgen, sollte es nicht notwendig werden die Beispiel herunterzuladen um den von Maven erstellten Quellcode einzusehen. Um dieses Beispiel zu erstellen werden wir das Archetype Maven Plugin einsetzen. Dieses Kapitel ndert das Projekt in keiner Weise. Sollten Sie es vorziehen, dieses Kapitel anhand der letzendlichen Quellcode-Beispiele zu lesen, so kann das Beispielprojekt dieses Kapitels zusammen mit den anderen Beispielen dieses Buchs von http://books.sonatype.com/maven-book/mvn-examples-1.0.zip oder 33

Ein einfaches Maven Projekt http://books.sonatype.com/maven-book/mvn-examples-1.0.tar.gz heruntergeladen werden. Entpacken Sie das Archiv in ein beliebiges Verzeichnis, und gehen Sie dann zum Verzeichnis /ch03. Darin finden Sie ein Verzeichnis mit dem Namen /simple welches den Quellcode fr dieses Kapitel enthlt.

3.2. Erstellen eines einfachen Projekts


Um ein neues Projekt unter Maven zu beginnen, setzen Sie das Archetype Maven-Plugin von der Befehlszeile aus ein.
$ mvn archetype:create -DgroupId=org.sonatype.mavenbook.ch03 \ -DartifactId=simple \ -DpackageName=org.sonatype.mavenbook [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'archetype'. [INFO] artifact org.apache.maven.plugins:maven-archetype-plugin: checking for updates from central [INFO] ----------------------------------------------------------------------[INFO] Building Maven Default Project [INFO] task-segment: [archetype:create] (aggregator-style) [INFO] -------------------------------------------------------------------[INFO] [archetype:create] [INFO] artifact org.apache.maven.archetypes:maven-archetype-quickstart: \ checking for updates from central [INFO] Parameter: groupId, Value: org.sonatype.mavenbook.ch03 [INFO] Parameter: packageName, Value: org.sonatype.mavenbook [INFO] Parameter: basedir, Value: /Users/tobrien/svnw/sonatype/examples [INFO] Parameter: package, Value: org.sonatype.mavenbook [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: artifactId, Value: simple [INFO] * End of debug info from resources from generated POM * [INFO] Archetype created in dir: /Users/tobrien/svnw/sonatype/examples/simple

mvn ist der Aufruf von Maven2; archetype:create bezeichnet ein Maven Goal. So Sie Ant kennen, ist ein Maven Goal gleichbedeutend mit einem Ant Target. Beide beschreiben eine Arbeitseinheit eines Builds. Die -Dname=wert Wertepaare stellen Argumente dar, welche an das Goal weitergereicht werden und nehmen die Form von -D Eigenschaft an, hnlich deren welche Sie der Java Virtual Machine ber die Befehlszeile weitergeben. Der Zweck des Goals archetype:create ist, schnell ein Projekt auf der Grundlage eines Archetypen zu erstellen. Ein Archetyp in diesem Kontext ist definiert als "ein originalgetreues Modell oder Typmuster nach dem andere, hnliche Dinge gemustert sind, ein Prototyp" [1][2]. Von Maven 34

Ein einfaches Maven Projekt werden etliche Archetypen bereitgehalten, diese reichen von der einfachen Swing Anwendung bis hin zur komplexen Web-Applikation. In diesem Kapitel werden wir den aller einfachsten Archtetypen nutzen um ein einfaches Gerst eines Starter-Projekts zu erstellen. Das Plugin hat das Prfix "archetype" und das entsprechende Goal ist "create". Sobald wir das Projekt generiert haben, sehen Sie sich das Verzeichnis /simple und die von Maven darin generierte Verzeichnisstruktur nher an:
simple/ simple/pom.xml /src/ /src/main/ /main/java /src/test/ /test/java

Der erzeugte Verzeichnisbaum hlt sich an das Maven Standard Layout, wir werden spter auf die Einzelheiten eingehen, aber fr den Moment konzentrieren wir uns auf die wenigen grundstzlichen Verzeichnisse: Das Archetype Maven Plugin erstellt ein Verzeichnis, das mit der artifactId einhergeht: /simple. Dieses Verzeichnis ist bekannt als das Projekt Basis-Verzeichnis. Jedes Maven-Projekt bentigt was als als Projekt Objekt Modell (POM) bekannt ist, in einer Datei mit dem Namen pom.xml. Diese Datei beschreibt das Projekt, konfiguriert Plugins, und definiert Abhngigkeiten. Unser Projekt-Quellcode und zugehrige Ressourcen werden unter /src/main abgelegt. Im Falle unseres einfachen Java-Projekt wird dies aus ein paar Java-Klassen und einigen Property-Dateien bestehen. In einem anderen Projekt knnte dies das Root-Dokument einer Web-Anwendung sein, oder Konfigurationsdateien fr einen Applikations-Server. In einem Java-Projekt werden die Java-Klassen in /src/main/java sowie Ressoucen in /src/main/resources abgelegt. Unsere Projekt-Testflle befinden sich unter /src/test. In diesem Verzeichnis werden Java-Klassen wie z.B. JUnit oder TestNG Tests (/src/test/java) abgelegt, sowie Klassenpfad relevante Ressourcen fr Tests unter /src/test/resources. 35

Ein einfaches Maven Projekt Das Maven Archetype Plugin erzeugt eine einzige Klasse com.sonatype.maven.App. Dies ist eine dreizeilige Java-Klasse mit einer statischen main()-Funktion welche eine Nachricht ausgibt:
package org.sonatype.mavenbook; /** * Hello world! * */ public class App { public static void main( String[] args ) { System.out.println( "Hello World!" ); } }

Der einfachste Maven Archetyp generiert das einfachst mgliche Programm: ein Programm, welches "Hallo Welt!" auf der Standard-Ausgabe ausgibt.

3.3. Der Aufbau eines einfachen Projekts


Sobald Sie das Projekt mit dem Maven Archetype Plugin erstellt haben, indem Sie die Anweisungen aus Abschnitt 3.2: Erstellen eines einfachen Projekts ausfhren, werden Sie es builden und als Anwendung paketieren wollen. Um dies zu bewerkstelligen, rufen Sie im Verzeichnis in welchem sich die pom.xml-Datei befindet den Befehl mvn install von der Befehlszeile auf.
$ mvn install [INFO] Scanning for projects... [INFO] ---------------------------------------------------------------------[INFO] Building simple [INFO] task-segment: [install] [INFO] ---------------------------------------------------------------------[INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:compile] [INFO] Compiling 1 source file to /simple/target/classes [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:testCompile] [INFO] Compiling 1 source file to /simple/target/test-classes [INFO] [surefire:test] [INFO] Surefire report directory: /simple/target/surefire-reports

36

Ein einfaches Maven Projekt


------------------------------------------------------T E S T S ------------------------------------------------------Running org.sonatype.mavenbook.AppTest 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/simple-1.0-SNAPSHOT.jar [INFO] [install:install] [INFO] Installing /simple/target/simple-1.0-SNAPSHOT.jar to \ ~/.m2/repository/com/sonatype/maven/ch03/simple/1.0-SNAPSHOT/ \ simple-1.0-SNAPSHOT.jar

Sie haben soeben das einfachste mgliche Maven Projekt erstellt, kompiliert, getestet, paketiert und installiert. Um sich zu berzeugen, dass die Anwendung tatschlich lauffhig ist, starten Sie sie von der Befehlszeile:
$ java -cp target/simple-1.0-SNAPSHOT.jar org.sonatype.mavenbook.App Hello World!

3.4. Einfaches Projekt Objekt Modell (POM)


Bei der Ausfhrung von Maven richtet dieses sich nach dem Projekt Objekt Modell (POM), um an Informationen ber das Projekt zu gelangen. Das POM liefert Antworten auf Fragen wie: Welche Art von Projekte ist es? Wie lautet der Projektname? Gibt es irgendwelche Anpassungen am Build bezglich diesem Projekt? Hier die grundlegende pom.xml-Datei wie sie vom Archetype Maven Plugin Goal create erstellt wurde. Example 3.1. Einfachstes Projekt pom.xml Datei
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook.ch03</groupId> <artifactId>simple</artifactId>

37

Ein einfaches Maven Projekt


<packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>simple</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>

Diese pom.xml-Datei stellt das elementarste POM dar mit welchem Sie je in einem Maven Projekt zu tun haben werden. In der Regel ist eine POM-Datei wesentlich komplexer: Abhngigkeiten werden definiert und Plugin Verhalten angepasst. Die ersten Elemente- groupId, artifactId, packaging sowie version sind als Maven-Koordinaten bekannt. Sie sind der eindeutigen Identifizierung eines Projekts gewidmet. name und url sind beschreibende Elemente des POM, welche in einer einfach lesbare Art den Namen des Projektes sowie einer zugeordneten Projekt-Website wiedergeben. Zuletzt wird im dependency Element eine einzige Beziehung als "Test-Scoped" Abhngigkeit zum JUnit-Test Framework unter dem Namen JUnit definiert. Diese Themen werden im Abschnitt 3.5: "Kernkonzepte" ausgefhrt. Zum jetzigen Zeitpunkt ist alles was sie wissen mssen, dass die pom.xml-Datei Maven zum Leben erweckt. Bei der Ausfhrung von Maven wird dieses gesteuert durch eine Kombination von Einstellungen innerhalb der pom.xml-Datei, einer Art "Super"-POM welche sich im Installationsverzeichnis von Maven befindet, sowie (mglicherweise) einigen benutzerspezifischen Einstellungen. Um sich das "tatschliche" POM, oder das POM, gegen welches Maven ausgefhrt wird anzusehen, geben Sie im Stammverzeichnis Ihres Projekts den folgenden Befehl ein:
$ mvn help:effective-pom

Mit der Ausfhrung bekommen Sie ein wesentlich umfangreicheres POM, das auch die Maven Standardeinstellungen enthlt

38

Ein einfaches Maven Projekt

3.5. Kern Konzepte


Nachdem Sie nun zum ersten Mal Maven eingesetzt haben, ist ein guter Zeitpunkt gekommen einige der Kernkonzepte von Maven einzufhren. Im vorigen Beispiel haben Sie, aufbauend auf ein einfaches POM, ein einfaches Projekt generiert, welches im Standard Layout von Maven (der Konvention folgend) strukturiert die Quelldateien abgelegt hat. Sie haben dann Maven mit einer Lebenszyklusphase als Argument aufgerufen und damit ausgelst, dass Maven eine Anzahl Plugin Goals abgearbeitet hat. Zuletzt haben Sie einen Maven Artifact in Ihr lokales Repository installiert. Moment! Was ist ein "Lebenszyklus"? Was ist ein "lokales Repository"? Die folgenden Abschnitte beschreiben einige der fr Maven zentralen Konzepte.

3.5.1. Maven Plugins und Ziele


Im vorigen Abschnitt haben wir Maven mit zwei unterschiedlichen Kommandozeilen-Argumenten aufgerufen. Der erste Befehl war ein einziges Plugin Goal, das Goal create des Archetype Maven Plugin. Der zweite Aufruf von Maven war hingegen gekoppelt mit einer Lifecycle-Phase - install. Um ein einzelnes (bestimmtes) Maven Plugin Goal auszufhren, benutzten wir die Syntax mvn archetype:create, hierbei ist archetype die Kennung eines Plugins und create die Kennung eines Goals. Wann immer Maven ein Plugin Goal ausfhrt, gibt es die Plugin- sowie die Goal-Kennung auf der Standardausgabe aus:
$ mvn archetype:create -DgroupId=org.sonatype.mavenbook.ch03 \ -DartifactId=simple \ -DpackageName=org.sonatype.mavenbook ... [INFO] [archetype:create] [INFO] artifact org.apache.maven.archetypes:maven-archetype-quickstart: \ checking for updates from central ...

Ein Maven-Plugin ist eine Sammlung von einem oder mehreren Goals. Beispiele von Maven-Plugins sind einfache Core-Plugins wie das JAR-Plugin welches das Goal zur Erzeugung von JAR-Archiven beinhaltet; das Compiler-Plugin mit den Goals Source Code kompilieren oder Unit Test Quellcode zu kompilieren oder das Surefire Plugin welches Goals zum Abarbeiten von Unit Tests sowie der Report 39

Ein einfaches Maven Projekt Generierung diesbezglich beinhaltet. Andere, strker spezialisierte Maven-Plugins sind z. B. das Hibernate3 Plugin zur Integration mit der beliebten Hibernate Persistenz Bibliothek, dem JRuby Plugin, welches erlaubt Ruby als Teil des Builds auszufhren sowie Maven Plugins in Ruby zu schreiben. Maven sieht auch vor benutzerdefinierte Plugins einzubinden. Ein benutzerdefiniertes Plugin kann in Java geschrieben sein, oder aber auch in einer von vielen anderen Sprachen darunter Ant, Groovy, BeanShell, und, wie bereits erwhnt, Ruby.

Figure 3.1. Ein Plugin enthlt Goals Ein Goal ist eine spezifische Aufgabe, welche alleinstehend, oder zusammen mit anderen Goals als Teil eines greren Builds ausgefhrt werden kann. Ein Goal ist eine "Arbeitseinheit" in Maven. Beispiele von Goals sind das Goal compile des Compiler-Plugin, es kompiliert den gesamten Quellcode fr ein Projekt, oder das Goal test des Surefire Plugin welches Unit-Tests ausfhren kann. Goals werden durch Konfigurations-Parameter bestimmt, welche erlauben das Verhalten anzupassen. Ein Beispiel, das Goal compile des Compiler-Plugin definiert eine Reihe von Konfigurations-Parameter, mit denen Sie die gewnschte JDK-Version Version bestimmen, sowie ber den Einsatz von Compiler-Optimierungen bestimmen knnen. Im vorigen Beispiel haben wir ber die Befehlszeile die Parameter groupId und artifactId an das Goal create des Archetype Plugin weitergegeben (-DgroupId=com.sonatype.maven.ch03 sowie -DartifactId=simple). Darber hinaus haben wir den Parameter packageName als com.sonatype.maven an das Goal create weitergegeben. Htten wir den Parameter packageName ausgelassen, wre die Voreinstellung com.sonatype.maven.ch03 40

Ein einfaches Maven Projekt zum Zug gekommen. Note Im weiteren Text werden wir hufig, wenn wir auf ein Plugin Goal verweisen eine verkrzte Notation benutzen: pluginId:goalId; Ein Beispiel: um sich auf das Goal create des Archetype Maven Plugin zu beziehen schreiben wir archetype:create. Goals legen Parameter fest, fr welche vernnftige Standardwerte definiert sein knnen. Im vorangehenden Beispiel archtetype:create, wurde der Archetype nicht spezifiziert, es wurde lediglich eine groupId sowie eine artifactId weitergegeben. Hier kommen wir das erste mal mit Konvention vor Konfiguration in Berhrung. Die Konvention, oder der Standard, des Goals create ist die Generierung eines einfachen Projektes namens Quickstart. Das Goal create definiert einen Parameter archetype:artifactId welcher auf den Standardwert maven-archetype-quickstart gesetzt ist. Der Archetyp 'Quickstart' erzeugt eine minimale Projekthlse, mit zugehrigem POM sowie einer einzigen Klasse. Das Archetype Plugin ist wesentlich mchtiger als dieses Beispiel andeutet, jedoch ist es eine gute Mglichkeit, um neue Projekte schnell zu starten. Spter in diesem Buch, zeigen wir Ihnen, wie das Archetype Plugin benutzt werden kann, um komplexere Projekte wie Web-Anwendungen zu generieren, und wie Sie das Archetype Plugin benutzen knnen um Ihren eigenen Satz von Projekten zu definieren. Der Kern von Maven hat nur wenig zu tun mit den spezifischen Aufgaben welche am Build Ihres Projektes beteiligt sind. Von sich aus weiss Maven nicht wie man Ihre Quelldateien kompiliert oder gar ein JAR-Archive packt. Maven delegiert all diese Arbeiten an Maven-Plugins wie das Compiler Plugin oder das JAR-Plugin. Diese knnen, sobald sie gebraucht werden, aus dem zentralen Maven Repository heruntergeladen und periodisch aktualisiert werden. Wenn Sie Maven herunterladen, so bekommen Sie lediglich den Kern oder Core von Maven. Dieser besteht aus einer sehr grundlegenden Shell, welche nur in der Lage ist die Befehlszeile zu analysieren, den Klassenpfad zu verwalten, eine POM-Datei zu analysieren und nach Bedarf Plugins herunterzuladen. Indem das Compiler Plugin 41

Ein einfaches Maven Projekt vom Core getrennt gehalten wurde und ber einen Update Mechanismus verfgt, ist es ein Leichtes fr den Benutzer, auch die neusten Compiler Optionen zum Einsatz zu bringen. Auf diese Weise ermglichen Maven-Plugins universelle Wiederverwendbarkeit von bergreifender Buildlogik, Sie definieren nicht einen Kompilierungs-Task innerhalb des Builds, Sie benutzen das Compiler Plugin wie es von jedem Maven Benutzer eingesetzt wird. Wird das Plugin weiterentwickelt, kann jedes Projekt auf der Basis von Maven sofort den Nutzen daraus ziehen (und sollten Sie das Compiler Plugin nicht mgen, so knnen Sie es bersteuern und Ihr eigenes zum Einsatz bringen!).

3.5.2. Maven Lifecycle


Der zweite Aufruf des vorangegangenen Abschnitts war mvn package. Bei diesem Aufruf wurde kein Plugin Goal angegeben, statt dessen wurde eine Lebenszyklusphase angegeben. Eine Phase ist ein Schritt in dem was Maven den "Build Lifecycle" nennt. Der Build Lebenszyklus ist eine geordnete Folge von Phasen welche am Aufbau eines Projekts beteiligt sind. Maven untersttzen kann eine Reihe ganz unterschiedlicher Lebenszyklen. Der am hufigsten zum Einsatz kommende ist der Standard-Lebenszyklus. Dieser beginnt mit eine Phase der Validierung der grundlegenden Integritt des Projekts und endet mit einer Phase der Bereitstellung von einem Projekt fr die Produktion. Lifecycle Phasen sind bewusst vage gehalten, im einzelnen lediglich definiert als Validierung, Test oder Verteilung kann eine Phase fr verschiedene Projekte ganz unterschiedliche Bedeutung haben. Zur Verdeutlichung ein Beispiel: die Phase package bedeutet in einem Projekt welches ein JAR-Archive erstellt: 'erstelle ein JAR-Archive', hingegen in einem Projekt welches eine Webanwendung zum Ziel hat: 'Erstelle ein WAR-Archive'. Abbildung 3.2 "Ein Lebenszyklus besteht aus einer Abfolge von Phasen" zeigt eine vereinfachte Darstellung des Maven Standard Lebenszykluses. Plugin-Goals knnen an Lebenszyklus-Phasen gebunden werden. Mit dem Durchschreiten des Lebenszykluses arbeitet Maven die Goals der einzelnen Phasen ab. An jeder Phase knnen keine (0) oder mehrere Goals gebunden sein. Im vorangegangenen Abschnitt, beim Aufruf von mvn package, haben Sie vielleicht bemerkt, dass mehr als ein Ziel ausgefhrt wurde. Sehen Sie sich die Ausgabe nach 42

Ein einfaches Maven Projekt dem Ausfhren von mvn package genau an, Sie werden sehen, dass verschiedene Goals ausgefhrt wurden. Als dieses einfache Beispiel die Phase package erreichte, fhrte es das Goal jar des Jar Plugins aus. Da unser einfaches Schnellstart-Projekt (standardmig) den Paketierungstyp jar setzt, wird das Goal jar:jar an die Phase package gebunden.

Figure 3.2. Ein Goal wird an eine Phase gebunden Wir wissen nun, dass die Phase package fr ein Projekt mit jar-Paketierung ein JAR-Archive erstellen wird. Aber wie steht es um die vorangehenden Goals, deren wie etwa compiler:compile und surefire:test? Diese Goals werden von Maven beim Durchschreiten der vorhergehenden Phasen des Lebenszykluses abgearbeitet. Der Aufruf einer bestimmten Phase lst aus, dass alle vorgngigen Phasen in entsprechender Reihenfolge abgearbeitet werden. Mit dem Abschluss der spezifizierten Phase endet die Bearbeitung. Jede Phase entspricht keinem oder mehreren abzuarbeitenden Goals, und da wir keine weitere Plugin-Konfiguration oder Anpassung durchgefhrt haben, bindet dieses Beispiel lediglich eine Reihe von Standard-Plugin-Goals an den Standard-Lebenszyklus. Luft Maven entlang des definierten Standard-Lebenszykluses bis zur Phase package, werden die folgenden Goals in der angegebenen Reihenfolge ausgefhrt:
resources:resources

Das Goal resources des Resouces Plugin wird an die Phase resources gebunden. Dieses Goal kopiert alle Ressourcen von /src/main/resources und allen anderen, konfigurierten Ressource- Verzeichnissen in das Ausgabe-Verzeichnis.
compiler:compile

43

Ein einfaches Maven Projekt Das Goal compile des Compiler Plugin wird an die Phase compile gebunden. Dieses Ziel kompiliert den gesamten Quellcode von /src/main/java oder jedem anderen konfigurierten Quellen-Verzeichnisse in das Ausgabe-Verzeichnis.
resources:testResources

Das Goal testResources des Resources Plugin wird an die Phase test-resources gebunden. Dieses Goal kopiert alle Ressourcen von /src/test/resources und jedem anderen, konfigurierten Test-Ressource Verzeichnis in ein Test Ausgabe Verzeichnis.
compiler:testCompile

Das Goal testCompile des Compiler-Plugin wird an die Phase test-compile gebunden. Dieses Goal kompiliert die Testflle von /src/test/java und allen anderen konfigurierten Test-Quellen-Verzeichnissen in ein Test Ausgabe Verzeichnis.
surefire:test

Das Goal test des Surefire Plugin wird an die Phase test gebunden. Dieses Ziel fhrt alle Tests aus und generiert Ausgabedateien der detaillierten Ergebnissen. Standardmig wird dieses Goal den Build beenden, sollte ein Test scheitern.
jar:jar

Das Goal jar des JAR-Plugin wird an die Phase package gebunden. Dieses Goal paketiert das Ausgabeverzeichnis und erstellt ein JAR-Archiv.

44

Ein einfaches Maven Projekt

45

Ein einfaches Maven Projekt Figure 3.3. Gebundene Goals werden mit den zugehrigen Phasen ausgefhrt. (Anmerkung: Es bestehen mehr Phasen als oben abgebildet, dies ist ein Auszug der Mglichkeiten) Wir fassen zusammen: beim Ausfhren von mvn package durchluft Maven alle Lebenszyklus Phasen bis und mit package, und fhrt hierbei in Abfolge alle Goals aus, welche zugehrig an Phasen gebunden sind. Anstelle der Angabe eines Maven Lifecycle Goals, knnen Sie das gleiche Ergebnis erreichen, indem Sie eine Abfolge von Plugin Goals angeben:
mvn resources:resources \ compiler:compile \ resources:testResources \ compiler:testCompile \ surefire:test \ jar:jar \ install:install

Die Ausfhrung der Phase package ist der Verwaltung aller beteiligten Goals eines bestimmten Builds vorzuziehen. Ein derartiges Vorgehen erlaubt den Projekten auch die Einhaltung genau definierter Standards. Es ist der Lebenszyklus, welcher einem Entwickler erlaubt von von einem Maven-Projekt zu einem anderen zu springen, ohne sich um die Details der einzelnen Builds zu kmmern. Schaffen Sie es ein Maven-Projekt zu builden, so schaffen Sie dies fr alle!

3.5.3. Maven Koordinaten


Das Archetype Plugin erstellte ein Projekt mit einer Datei namens pom.xml. Dies ist das Projekt Objekt Modell (POM), eine deklarative Beschreibung eines Projekts. Wenn Maven ein Goal ausfhrt hat jedes Goal Zugang zu den im Projekt POM definierten Informationen. Wenn das Goal jar:jar ein JAR-Archive erstellen soll, sieht es in der POM Datei nach um herauszufinden wie das JAR-Archive heissen soll. Soll das Goal compiler:compiler Java Quelldateien kompilieren greift das Goal auf die POM Dateien zurck, um zu sehen ob dort Compiler Eigenschaften definiert sind. Goals werden immer im Kontext eines POMs ausgefhrt. Goals sind Aktionen welche wir auf ein Projekt anwenden mchten, 46

Ein einfaches Maven Projekt und Projekte sind in POM Dateien abgebildet. Das POM bezeichnet ein Projekt, stellt einen Satz von Identifikationsmerkmale (Koordinaten) fr ein Projekt, und definiert die Beziehungen zwischen diesem Projekt und andern Projekten durch die Angabe von Abhngigkeiten, Eltern und Voraussetzungen. Ein POM kann auch Plugin-Verhalten beeinflussen sowie Informationen ber die Entwicklergemeinde und an einem Projekt beteiligten Entwicklern bereitstellen. Maven Koordinaten stellen eine Anzahl Identifikatoren, welche zur eindeutigen Identifikation eines Projekts, einer Abhngigkeit oder eines Maven Plugins genutzt werden knnen. Werfen Sie einen Blick auf das folgende POM.

Figure 3.4. Maven Projekt Koordinaten Wir haben die Maven Koordinaten fr dieses Projekt: groupId, artifactId, version und packaging vorgestellt. Die Einheit dieser Identifikatoren bildet die Koordinaten eines Projekts[3]. Genau wie in jedem anderen Koordinatensystem, fixieren diese Koordinaten einen bestimmten Punkt im Raum: vom Allgemeinen zum Spezifischen. Maven bestimmt ein Projekt mit dessen Koordinaten, so sich ein 47

Ein einfaches Maven Projekt Projekt auf ein anderes bezieht, entweder als Abhngigkeit, Plugin oder auch elterliche Projekt Referenz. Maven Koordinaten werden gewhnlich durch einen Doppelpunkt getrennt in folgender Form wiedergegeben: groupId:artifactId:version:packaging. Die Koordinate des im obigen Beispiel einer pom.xml-Datei eines Projektes sind daher folgendermassen wiedergegeben: mavenbook:my-app:jar:1.0-SNAPSHOT. Diese Notation gilt auch fr Projekt-Abhngigkeiten; unser Projekt basiert auf JUnit Version 3.8.1, es enthlt daher eine Abhngigkeit zu junit:junit:jar:3.8.1 . 1
groupId

Die "Gruppe" (Firma, Team, Organisation, Projekt, oder anderweitige Gruppe). Es gilt die ungeschriebene Regel, dass die groupId in der Reverse-Domain-Name Notation der Organisation die das Projekt erstellt, wiedergegeben wird. Projekte von Sonatype htte eine groupId welche mit com.sonatype beginnt, Projekte der Apache Software Foundation htte eine groupId welche mit org.apache beginnt.
artifactId

Eine eindeutige hierarchische Kennung unter der groupId, identifiziert ein einzelnes Projekt.
version

Eine bestimmte Version eines Projekts. Freigegebene Projekte haben eine bestimmte, festgelegte Versionskennung. Diese bezieht sich immer auf genau eine Version des Projekts. Projekte in der aktiven Entwicklung knnen eine spezielle Kennung bekommen, diese markiert die angegebene Version als eine "Momentaufnahme". Der Identifikator packaging ist ebenfalls ein wichtiger Bestandteil der Maven Koordinaten, aber nicht Teil der eindeutigen Projektkennung. Eine Projektdarstellung der Art groupId:artifactId:version bezeichnet ein Projekt einzigartig (kanonisch). Es ist nicht mglich ein weiteres Projekt mit dem gleichen
1

Es gibt eine weitere, fnfte Koordinate: classifier. Diese kommt nur selten zum Einsatz und wir werden die Einfhrung daher auf spter im Buch zurckstellen. Nehmen Sie sich die Freiheit diese Koordinate im Moment zu ignorieren.

48

Ein einfaches Maven Projekt Bezeichnern zu erstellen.


packaging

Die Art in welcher das Projekt 'gepackt' ist, dies ist auf den Standardwert 'jar' gesetzt. Ein Projekt vom Packaging Typ 'jar' wird als JAR-Archive bereitgestellt, eines des Types 'war' in Form eines WAR-Archives. Diese vier Elemente bestimmen den Schlssel um ein Projekt eindeutig im weiten Raum "mavenisierter" Projekte aufzufinden. Maven-Repositories (ffentliche, private und lokale) sind nach diesen Identifikatoren organisiert. Sobald ein Projekt im lokalen Maven-Repository eingestellt ist, steht es augenblicklich fr alle weiteren Projekte (welche gegen dieses Repository arbeiten) bereit, eingebunden zu werden. Alles was zu tun bleibt, ist die Koordinaten in einem anderen Projekt als Abhngigkeit einzutragen.

Figure 3.5. Der 'Maven'-Raum stellt ein Koordinatensystem fr Projekte

3.5.4. Maven Repositories


Beim ersten Ausfhren von Maven, werden Sie feststellen, dass Maven eine Reihe von Dateien von einem Maven Remote Repository herunterldt. Sollte die 49

Ein einfaches Maven Projekt Erstellung des einfhrenden Projektes das erste Mal sein, dass Sie Maven aufrufen, so ist das erste was passiert, dass Maven die neuste Version des Resource Plugins herunterldt, ausgelst durch das Goal resources:resource. Maven ldt Artefakte und Plugins aus einem Remote Repository sobald diese bentigt werden. Einer der Grnde, weshalb der Maven Download ist so klein ist (1,5 MiB) ist, dass Maven nicht mit allerlei Plugins ausgeliefert wird. Ausgeliefert wird nur das Allerntigste, alles weitere holt sich Maven bei Bedarf aus einem Remote-Repository. Maven kommt hierzu mit einer Standardeinstellung eines Remote Repositories (http://repo1.maven.org/maven2) von welchem es versuchen wird die Core Maven-Plugins und deren Abhngigkeiten herunterzuladen. Oftmals werden Sie an einem Projekt arbeiten, welches auf Bibliotheken aufbaut, welche weder frei noch ffentlich zu verbreiten sind. In einem solchen Fall mssen Sie entweder ein benutzerdefiniertes Repository innerhalb Ihrer Organisation aufbauen oder die Abhngigkeiten manuell herunterladen und installieren. Die Standard (Remote) Repositorien knnen durch Verweise auf benutzerdefinierte Maven Repositorien ersetzt oder ergnzt werden. Es gibt eine Reihe Produkte welche Organisationen dabei untersttzen eigene Repositorien zu verwalten sowie Spiegel-Repositorien von ffentlichen Maven-Repositorien zu erstellen. Was macht ein Maven Repository zu einem Maven Repository? Ein Maven-Repository zeichnet sich durch seine Struktur aus, ein Repository ist eine Sammlung von Projekt Artefakten in einer Struktur und Form welche fr Maven leicht leicht nachvollziehbar ist. Die Artefakte in einem Maven-Repository sind in einer Verzeichnis-Struktur abgelegt, welche eng mit den Maven Projekt Koordinaten korrespondieren. Sie knnen sich diese Struktur ansehen: ffnen Sie mit einem Web-Browser das zentrale Maven Repository auf http://repo1.maven.org/maven2/. Sie knnen dort ein Artefakt mit den Koordinaten org.apache.commons:commons-email:1.1 im Verzeichnis /org/apache/commons/commons-email/1.1/ in einer Datei namens "commons-email.jar" vorfinden. Der Standard fr ein Maven-Repository ist es, einen Artefakten in folgender Struktur relativ zum Wurzelverzeichnis des Repositories abzulegen:
/<groupId>/<
artifactId>/<version>/< artifactId>-<version>.<packaging>

50

Ein einfaches Maven Projekt Maven ldt Artefakte und Plugins von einem Remote-Repository auf Ihren lokalen Rechner herunter und speichert diese Artefakte in Ihrem lokalen Maven-Repository. Ist ein Artefakt einmal von einem Remote Repository in das lokale Repository heruntergeladen, so wird Maven kein weiteres mal auf das Remote Repository zugreifen, da Maven immer zuerst auf das lokale Repository zugreifen wird, vor es anderswo sucht. Unter Windows XP befindet sich Ihr lokales Repository wahrscheinlich unter C:\Dokumente und Einstellungen\Benutzername\.m2\Repository, unter Windows Vista befindet sich Ihr lokales Repository unter C:\Benutzer\Benutzername\.m2\Repository auf Unix-Systemen werden Sie Ihr lokales Maven-Repository unter ~/.m2/repository wiederfinden. Sobald Sie ein Projekt wie das aus dem vorherigen Abschnitt erstellen, wird in der Phase install ein Goal ausgefhrt welches den neuen Artifakten in Ihrem lokalen Maven Repository ablegt. Sie sollten nun in der Lage sein, das Artefakt Ihres eingngigen Projektes in Ihrem lokalen Maven Repository wiederzufinden. Beim Aufruf von mvn install installiert Maven den Projekt Artefakt in Ihrem lokalen Repository. Probieren Sie es aus.
$ mvn install ... [INFO] [install:install] [INFO] Installing .../simple-1.0-SNAPSHOT.jar to \ ~/.m2/repository/com/sonatype/maven/simple/1.0-SNAPSHOT/ \ simple-1.0-SNAPSHOT.jar ...

Betrachten Sie die Ausgabe dieses Befehls, Sie knnen sehen, wie Maven unseres Projekt's JAR-Archiv im lokalen Maven-Repository ablegt. Maven nutzt das lokale Repository um Artefakte zwischen lokalen Projekten zu teilen. Sagen wir, Sie entwickeln zwei Projekte, Projekt A und Projekt B, dabei ist Projekt B von einem Artefakt von Maven-Projekt A abhngig. So wird Maven den Artefakt beim Build von Projekt B aus Ihrem lokalen Repository holen. Maven Repositorien sind beides, ein lokaler Zwischenspeicher (Cache) von Artefakten welche von einem Remote Repository heruntergeladen wurden, wie auch ein Mechanismus welcher erlaubt, dass Ihre Projekte zueinander abhngig sein knnen.

51

Ein einfaches Maven Projekt

3.5.5. Maven Abhngigkeits-Management (Dependency Management)


In dem einfachen Beispiel dieses Kapitels, lst Maven die Koordinaten der JUnit-Abhngigkeit junit:junit:3.8.1 in einen Pfad /junit/junit/3.8.1/junit-3.8.1.jar des Maven Repositories auf. Die Mglichkeit, Artefakte in einem Repository basierend auf Maven Koordinaten zu lokalisieren gibt uns die Mglichkeit Abhngigkeiten in einem Projekt POM zu definieren. Sehen Sie sich die pom.xml-Datei genauer an. Sie werden einen Abschnitt finden, welcher sich mit den Abhngigkeiten (dependencies) befasst, dieser Abschnitt enthlt eine einzige Abhngigkeit: JUnit. Ein komplexeres Projekt wrde mehr als eine einzelne Abhngigkeit beinhalten, oder auch Abhngigkeiten welche von anderen Artefakten abhngen. Dies ist eine der mchtigsten Funktionen von Maven: die Untersttzung von transitiven Abhngigkeiten. Nehmen wir an, Ihr Projekt hngt von einer Bibliothek ab, welche wiederum von fnf oder zehn anderen Bibliotheken abhngig ist (etwa wie Spring oder Hibernate). Statt alle diese Abhngigkeiten nachzuverfolgen und in Ihrem pom.xml explizit aufzulisten knnen Sie schlicht diejenige Abhngigkeit aufnehmen, welche Sie beabsichtigen. Maven wird die implizit abhngigen Bibliotheken fr Sie auflsen. Maven wird auch auftretende Konflikte auflsen, diesbezglich bietet Maven die Mglichkeit das Verhalten anzupassen sowie gewisse transitive Abhngigkeiten auszuschliessen. Werfen wir einen Blick auf eine Abhngigkeit, welche im vorangegangenen Beispiel in Ihr lokales Repository heruntergeladen wurde. Sehen Sie in Ihrem lokalen Repository-Pfad unter ~/.m2/repository/junit/junit/3.8.1/ nach. Wie Ihnen nach der Lektre des Kapitels bekannt ist, gibt es eine Datei junit-3.8.1.jar sowie eine junit-3.8.1.pom-Datei und zustzlich eine Anzahl Dateien; Prfsummen welche Maven nutzt, um die Echtheit eines heruntergeladenen Artefakts zu berprfen. Beachten Sie, dass Maven nicht nur das JUnit JAR-Archive herunterldt. Maven ldt zustzlich das POM des Artefakts herunter. Die Tatsache, dass Maven zustzlich zum Artefakt auch die zugehrige POM Dateien herunterldt ist von zentraler Bedeutung fr die Untersttzung von transitiven Abhngigkeiten durch Maven. 52

Ein einfaches Maven Projekt Sie werden feststellen, dass Maven bei der Installation Ihres Projekt-Artefaktes in das lokale Maven-Repository zugleich eine leicht modifizierte Version der zugehrigen pom.xml-Datei im selben Verzeichnis des JAR-Archives ablegt. Zugleich eine POM-Datei im Repository abzulegen gibt anderen Projekten Informationen zu diesem Projekt, als Wichtigstes dessen Abhngigkeiten. Projekt B, abhngig von Projekt A, hngt auch von den Abhngigkeiten des Projekts A ab. Wenn Maven eine Abhngigkeit zu einem Artefakt anhand einer Reihe von Artefaktkoordinaten auflst, so ruft Maven die POM-Dateien auf und nimmt sich deren Abhngigkeiten an, um bestehende transitive Abhngigkeiten aufzulsen. Jene transitiven Abhngigkeiten werden sodann den Projektabhngigkeiten zugefgt. Eine Abhngigkeit in Maven ist nicht nur eben ein JAR-Archiv. Es ist eine POM-Datei, welche weitere Abhngigkeiten von anderen Artefakten erklren kann. Solche Abhngigkeiten der Abhngigkeiten nennt man transitive Abhngigkeiten und sie werden durch die Tatsache, dass das Maven-Repository mehr als nur den Bytecode speichert ermglicht. Maven speichert Meta-Daten bezglich der Artefakte. Die folgende Abbildung zeigt ein mgliches Szenario transitiver Abhngigkeiten.

53

Ein einfaches Maven Projekt

Figure 3.6. Wie Maven transitive Abhngigkeiten auflst / Resolving transitive Dependencies In der vorangegangenen Abbildung, ist ein Projekt abhngig von den Projekten B und C. Projekt B baut auf Projekt D auf, Projekt C baut auf Projekt E auf. Die Gesamtmenge aller Abhngigkeiten von A sind Projekte B, C, D, E, jedoch musste Projekt A lediglich die Projekte B und C deklarieren. Transitive Abhngigkeiten knnen sich immer dann als ntzlich erweisen, wenn Ihr Projekt sich auf ein anderes Projekt absttzt, welches weitere Abhngigkeiten deklariert (z.B. Hibernate, Apache Struts, oder das Spring Framework). Maven bietet Ihnen auch die Mglichkeit, transitive Abhngigkeiten von der Aufnahme in den Klassenpfad auszuschliessen. Maven kennt auch das Konzept des Gltigkeitsbereichs (Scope). Die pom.xml-Datei des Beispielprojektes kennt nur eine einzige Abhngigkeit junit:junit:jar:3.8.1 in einem Gltigkeitsbereich test. Wenn eine Abhngigkeit bezglich eines Gltigkeitsbereich test definiert ist, so bedeutet dies, dass diese nicht dem Goal compile des Compiler Plugins zur Verfgung steht. 54

Ein einfaches Maven Projekt Die Abhngigkeit wird dem Klassenpfad nur fr die Goals compiler:testCompile sowie surefire:test zugefgt. Bei der Erstellung eines JAR-Archivs fr ein Projekt werden Abhngigkeiten nicht mit eingeschlossen, es wird lediglich gegen diese kompiliert. Beim Erstellen eines WAR- oder EAR-Archives knnen Sie konfigurieren, ob Sie Abhngigkeiten in den erstellten Artefakt einschliessen mchten. Ebenfalls mglich ist der Ausschluss bestimmter Abhngigkeiten abhngig vom gewhlten Gltigkeitsbereich. Der Gltigkeitsbereich provided bestimmt, dass die Abhngigkeit bentigt wird um zu kompilieren, aber nicht in den Erstellten Artefakt eingebunden werden soll. Dieser Gltigkeitsbereich (provided) ist ntzlich, wenn Sie eine Web Applikation erstellen; Sie mssen z.B. gegen die Servlet Spezifikation kompilieren, jedoch werden Sie vermeiden, das Servlet API JAR-Archiv in das /WEB-INF/lib Verzeichnis Ihrer Webanwendung abzulegen.

3.5.6. Site-Generierung und Reporting


Eine weitere wichtige Mglichkeit ist die Fhigkeit von Maven Dokumentationen und Reports zu Generieren. Fhren Sie im Stammverzeichnis der Beispielanwendung folgenden Aufruf aus:
$ mvn site

Der Aufruf wird Lebenszyklus Phase site auslsen. Im Gegensatz zu den Standard-Build Lifecycle Phasen welche sich mit der Verwaltung von Codegeneration, der Manipulation von Ressourcen, Kompilierung, Packetierung und so weiter befassen betrifft diese Phase ausschlielich die Bearbeitung von Website-Content im Rahmen des /src/site Verzeichnisses und der Generierung von Reports. Nach Abschluss diesen Befehls, sollten Sie einen Projekt-Website im Verzeichnis /target/site vorfinden. Nach dem Laden der Datei /target/site/index.html sollten Sie das Skelett eines Projekt (Web-)Sites sehen. Diese Shell enthlt bereits einige Berichte unter der Rubrik "Projekt Reports" der linken Navigation im Men, sowie Informationen ber das Projekt, dessen Abhngigkeiten und der Entwickler im Zusammenhang mit dem Projekt in der Rubrik "Projekt-Information". Die Projekt-Website dieses Beispiels ist grtenteils 55

Ein einfaches Maven Projekt leer, da das POM nur sehr wenige Informationen ber die reinen Koordinatenpunkte hinaus enthlt: den Namen und die URL des Projektsites sowie der einzigen Test Abhngigkeit. Sie werden feststellen, dass auf dieser Website bereits einige Standard-Berichte bereitstehen, so gibt es einen Bericht, welcher den Ausgang der Unit-Tests zusammenfasst. Dieser Report spiegelt alle im Projekt erfolgten Unit Tests wieder, sowie im einzelnen deren Erfolg oder Misserfolg. Ein weiterer Report erzeugt die JavaDoc des Projekt API's. Maven bietet eine vollstndige Palette von konfigurierbaren Reports, wie zum Beispiel dem Clover Report, welcher Aufschluss ber die erfolgte Testabdeckung gibt, der JXR Report, ein Report welcher querverweisende HTML-Seiten generiert und speziell fr Code-Reviews ntzlich ist, der PMD Report, welcher, aufbauend auf eine Quellcodeanalyse, Aufschluss ber eine Reihe von problematischen Kodierungen gibt, sowie der JDepend Report, welcher die Abhngigkeiten zwischen verschiedenen Packages einer Quellcodebasis analysiert. Die Reports der Website werden in der pom.xml Datei eines Builds konfiguriert.

3.6. Zusammenfassung
Wir haben ein einfaches Projekt erstellt, in ein JAR-Archive gepackaged und diese JAR-Archive im lokalen Repository installiert um es anderen Projekten zur Verfgung zu stellen; sodann haben wir eine Projektwebsite der zugehrigen Dokumentation generiert. Wir konnten das alles bewerkstelligen, ohne auch nur einen einzige Zeile Code zu schreiben. Darberhinaus haben wir Zeit aufgewandt einige der Kernkonzepte von Maven zu erlutern. Im nchsten Kapitel werden wir damit beginnen, die pom.xml-Datei anzupassen, weitere Abhngigkeiten einzufgen sowie einige Unit Tests zu konfigurieren.

56

Chapter 4. Anpassen eines Maven Projektes


4.1. Einleitung
Dieses Kapitel baut auf das vorangehende Kapitel (3), insbesondere auf das eingefhrte "Simple Maven Projekt" auf. Wir erstellen mit dem Archetype Maven Plugin ein einfaches Projekt, fgen einige Abhngigkeiten ein, erstellen Quellcode und passen das Projekt unseren Bedrfnissen an. Am Ende dieses Kapitels, werden Sie wissen, wie man es am besten angeht, reale Projekte mit Maven zu erstellen.

4.1.1. Herunterladen der Beispiele dieses Kapitels


In diesem Kapitel werden wir mit Ihnen ein einfaches, ntzliches Programm zur Interaktion mit einem Yahoo! Wetter Web-Service erstellen. Whrend Sie in der Lage sein sollten, der Entwicklung dieses Kapitels ohne Beispiel-Quellcode zu folgen, empfehlen wir das Herunterladen einer Kopie der Quellcodes als Referenz. Das Beispielprojekt dieses Kapitel zusammen mit den anderen Beispielen dieses Buchs kann von http://books.sonatype.com/maven-book/mvn-examples-1.0.zip oder http://books.sonatype.com/maven-book/mvn-examples-1.0.tar.gz heruntergeladen werden. Entpacken Sie das Archiv in ein beliebiges Verzeichnis, und gehen Sie dann zum Unterverzeichnis /ch04. Darin befindet sich ein Verzeichnis mit dem Namen /simple weather welches den Quellcode fr dieses Kapitel enthlt.

4.2. Eine kurze Einfhrung in das "Simple Weather" Projekt


Bevor wir loslegen, lassen Sie uns einen Schritt zurcktreten und das Wetter Projekt vorstellen. Was ist das, das 'Simple Weather' Projekt? Das einfache 57

Anpassen eines Maven Projektes Wetterdienst-Projekt ist ein Beispiel, das speziell konstruiert wurde um einige der Funktionen von Maven vorzustellen. Es handelt sich um eine Anwendung, welche beispielhaft die Art der Anwendung vorstellt, welche Sie zu bauen angefragt werden. Die 'Simple Weather' Anwendung ist ein ein grundlegendes Beispiel einer befehlszeilenorientierten Anwendung, welche auf eine angegebene Postleitzahl Daten vom Yahoo! RSS WetterDienst abruft. Die Anwendung analysiert den Rckgabewert und gibt diesen auf der Konsole aus. Es gab eine Reihe von Grnden welche uns bewogen dieses Beispiel auszuwhlen: zum einen ist es unkompliziert, der Benutzer macht eine Eingabe ber die Befehlszeile; diese nehmen wir auf, schicken die Anfrage an den Yahoo! Wetter Dienst (RSS), analysieren das Ergebnis und geben zuletzt einige Daten auf den Bildschirm aus. Dieses Beispiel besteht aus einer einfachen main()-Klasse und einigen Hilfsklassen, es gibt kein Enterprise Framework einzufhren, lediglich einfaches XML-Parsen sowie einige Logging-Anweisungen. Zum anderen gibt dieses Beispiel uns eine gute Gelegenheit einige interessante Bibliotheken wie Velocity, Dom4J und Log4J einzufhren - Obwohl dieses Buch sich auf die Einfhrung von Maven konzentriert, werden wir uns nicht scheuen, die Gelegenheit zur Einfhrung interessanter Utilities wahrzunehmen. Schlielich ist es ein Beispiel, das in einem einzigen Kapitel eingefhrt, entwickelt, und deployed werden kann.

4.2.1. Yahoo! Wetter Dienst RSS


Bevor Sie diese Anwendung bauen, sollten Sie etwas mehr ber die Yahoo! Wetter Dienste (RSS-Feeds) erfahren. Allem voraus weisen wir darauf hin, dass der Dienst unter den folgenden Konditionen angeboten wird: "Die Datendienste werden zur Nutzung von Einzelpersonen sowie Non-Profit-Organisationen kostenlos, im Rahmen von persnlichen, nicht kommerziellen Anwendungen angeboten. Sie sind angehalten auf die Nutzung der Yahoo! Wetter Dienste im Rahmen Ihres Angebotes hinzuweisen." Mit anderen Worten, wenn Sie daran dachten, diese Dienste in Ihren 58

Anpassen eines Maven Projektes kommerziellen Webauftritt zu integrieren, dann gehen Sie bitte noch einmal ber die Bcher: die Nutzung der Dienste ist lediglich fr den privaten, nicht kommerziellen Gebrauch gestattet. Die Nutzung zu welcher wir in diesem Kapitel anregen ist beschrnkt auf die persnliche Weiterbildung. Weitere Informationen bezglich der Yahoo! Wetter Dienst Konditionen finden Sie in der Yahoo Wetter! API-Dokumentation: http://developer.yahoo.com/weather/.

4.3. Erstellen des "Simple Weather" Projektes


In einem ersten Schritt, lassen Sie uns mit Hilfe des Archetype Maven Plugin ein grundlegendes Skelett der Anwendung erstellen. Fhren Sie den folgenden Aufruf aus, um ein neues Projekt zu generieren:
$ mvn archetype:create -DgroupId=org.sonatype.mavenbook.ch04 \ -DartifactId=simple-weather \ -DpackageName=org.sonatype.mavenbook \ -Dversion=1.0 [INFO] [archetype:create] [INFO] artifact org.apache.maven.archetypes:maven-archetype-quickstart: \ checking for updates from central [INFO] -----------------------------------------------------------------[INFO] Using following parameters for creating Archetype: \ maven-archetype-quickstart:RELEASE [INFO] -----------------------------------------------------------------[INFO] Parameter: groupId, Value: org.sonatype.mavenbook.ch04 [INFO] Parameter: packageName, Value: org.sonatype.mavenbook [INFO] Parameter: basedir, Value: ~/examples [INFO] Parameter: package, Value: org.sonatype.mavenbook [INFO] Parameter: version, Value: 1.0 [INFO] Parameter: artifactId, Value: simple-weather [INFO] *** End of debug info from resources from generated POM *** [INFO] Archetype created in dir: ~/examples/simple-weather

Sobald das Archetype Maven Plugin das Projekt erstellt hat, wechseln Sie in das Verzeichnis der "Simple Weather" Anwendung und werfen Sie einen Blick auf die pom.xml Datei. Sie sollten das folgende XML-Dokument vorfinden: Example 4.1. Erstes POM des "Simple Weather" Projekts
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0

59

Anpassen eines Maven Projektes


http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook.ch04</groupId> <artifactId>simple-weather</artifactId> <packaging>jar</packaging> <version>1.0</version> <name>simple-weather2</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project>

Bitte beachten Sie, dass wir den Parameter version und das Goal archetype:create bergeben haben. Hiermit wird der Standardwert des 1.0-SNAPSHOT berschrieben. In diesem Projekt entwickeln wir die Version 1.0 des "Simple Weather" Beispielprogramms, wie Sie leicht am Element version der pom.xml-Datei ablesen knnen.

4.4. Anpassen der Projektinformationen


Bevor wir mit dem Schreiben von Quellcode loslegen, Lassen Sie uns die Projektinformationen ein wenig Anpassen. Wir wollen etliche Informationen bezglich der Lizenzrechte, der Organisation sowie der beteiligten Entwickler einfgen. Dies alles sind Standard-Informationen welche wir erwarten, dass diese in den meisten Projekten gebraucht werden. Die folgende Auflistung zeigt den 60

Anpassen eines Maven Projektes Ausschnitt der XML-Datei, der die Informationen zur Organisation, der Lizenzierung sowie bezglich der Entwickler bereitstellt. Example 4.2. Informationen bezglich der Organisation, rechtlicher Belange sowie der Entwickler in der pom.xml-Datei
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> ... <name>simple-weather</name> <url>http://www.sonatype.com</url> <licenses> <license> <name>Apache 2</name> <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> <distribution>repo</distribution> <comments>A business-friendly OSS license</comments> </license> </licenses> <organization> <name>Sonatype</name> <url>http://www.sonatype.com</url> </organization> <developers> <developer> <id>jason</id> <name>Jason Van Zyl</name> <email>jason@maven.org</email> <url>http://www.sonatype.com</url> <organization>Sonatype</organization> <organizationUrl>http://www.sonatype.com</organizationUrl> <roles> <role>developer</role> </roles> <timezone>-6</timezone> </developer> </developers> ... </project>

Die Auslassungspunkte ("...") in Beispiel 4.2, "Informationen bezglich der Organisation, rechtlicher Belange sowie der Entwickler in der pom.xml-Datei" 61

Anpassen eines Maven Projektes sind eine Abkrzung fr ein stark gekrztes Listing. Wenn Sie in diesem Buch auf eine pom.xml Datei stossen, welche direkt hinter dem Element-Tag project mit "..." beginnt und mit "..." direkt vor dem Element project aufhrt, so zeigt dies an, dass wir nicht die gesamte pom.xml-Datei wiedergeben. In diesem Fall wurden die Tag-Elemente licenses, organization und developers vor dem Element dependencies eingefgt.

4.5. Einfgen neuer Abhngigkeiten


Die einfache "Simpel Weather" Anwendung umfasst folgende drei Aufgaben: Abrufen von XML-Daten vom Yahoo! Wetter Dienst, analysieren des zurckgegebenen XML von Yahoo und schliesslich die formatierte Ausgabe auf der Konsole. Um diese Aufgaben zu erledigen, mssen wir einige neue Abhngigkeiten zu unserem Projekt pom.xml hinzufgen. Um die XML-Antwort des Yahoo! Dienstes zu analysieren werden wir <term>Dom4J</term> und <term>Jaxen</term> einsetzen. Um die Ausgabe des Kommandozeilenprogramms zu formatieren setzen wir <term>Velocity</term> ein und es ist ebenfalls notwendig, eine Abhngigkeit zu <term>Log4J</term> hinzuzufgen, um Ereignisse zu loggen. Nachdem wir diese Abhngigkeiten einbringen, sieht unsere Beispiel pom.xml-Datei wie folgt aus: Example 4.3. Hinzufgen der Abhngigkeiten von Dom4J, Jaxen, Velocity und Log4J
<project> [...] <dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version>

62

Anpassen eines Maven Projektes


</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>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>

Wie Sie sehen, haben wir zum bestehenden Element der Test bezogenen Abhngigkeit JUnit, vier weitere Elemente dependency eingefgt. Nach dem Einfgen der Abhngigkeiten sowie dem Aufruf von mvn install werden Sie sehen, wie Maven diese Abhngigkeiten wie auch eine Reihe transitiver Abhngigkeiten in Ihr lokales Maven Repository herunterldt. Nun wie wussten wir die Koordinaten dieser Abhngigkeiten? "Weiss" man schlicht die entsprechenden Werte fr groupId und artifactId? Manche Artefakte sind so weit verbreitet (z.B. Log4J), dass Sie, wann immer Sie sie brauchen, sich an die Werte der groupId und artifactId erinnern werden. Velocity, Dom4J und Jaxen haben wir unter Einsatz einer hilfreichen Website (http://www.mvnrepository.com) aufgelst. Diese Website bietet eine Maske zur Suche ber das Maven-Repository an. Sie knnen die Site benutzen um Abhngigkeiten herauszufinden. Um dies zu verifizieren, versuchen Sie es selbst: laden Sie die Seite http://www.mvnrepository.com und suchen Sie nach einigen hufig verwendeten 63

Anpassen eines Maven Projektes Bibliotheken wie Hibernate oder dem Spring Framework. Wenn Sie auf dieser Site nach einem Artefakt suchen, werden Ihnen der artefactId-Wert sowie alle im zentralen Repository verfgbaren version-Werte ausgegeben. Ein Klick auf die Details einer bestimmten Version ldt eine Seite, welche das Element dependency wiedergibt, dieses knnen Sie kopieren und in die pom.xml Datei Ihres eigenen Projekt einfgen. Wenn Sie eine Abhngigkeit finden mssen, so lohnt es sich, mvnrepository.com zu benutzen. Auch werden Sie dann werden festestellen, dass bestimmte Bibliotheken ber mehr als eine groupId verfgen. Dieses Werkzeug wird Ihnen helfen das Maven-Repository zu verstehen.

4.6. Quellcode von "Simple Weather"


Das "Simple Weather" Beispielprogramm besteht aus fnf Java-Klassen:
org.sonatype.mavenbook.weather.Main

Diese Klasse enthlt eine statische main()-Funktion, es ist der Ausgangspunkt fr dieses System.
org.sonatype.mavenbook.weather.Weather

Die Weather-Klasse ist ein einfaches Java-Bean, welches die Koordinaten unseres Wetterberichtes, sowie eine Anzahl wichtiger Daten wie z.B Temperatur und Luftfeuchtigkeit vorhlt.
org.sonatype.mavenbook.weather.YahooRetriever

Die YahooRetriever Klasse stellt eine Verbindung zum Yahoo! Wetter Dienst her und liefert einen InputStream der Daten des Dienstes.
org.sonatype.mavenbook.weather.YahooParser

Die YahooParser Klasse analysiert das zurckgegebene XML vom Yahoo! Wetter Dienst und wandelt es in ein Weather-Objekt um.
org.sonatype.mavenbook.weather.WeatherFormatter

Die WeatherFormatter Klasse setzt auf einem Weather Objekt auf, erstellt einen VelocityContext, und fhrt ein Velocity Template (Vorlage) daruaf aus. 64

Anpassen eines Maven Projektes Wir wollen an diese Stelle nicht nher auf den Quellcode des Beispiels eingehen, werden aber alle erforderlichen Quellen des Beispiels im Buch bereitstellen, so dass Sie "Simple Weather" zum Laufen bekommen. Wir gehen davon aus, dass die meisten von Ihnen den Quellcode heruntergeladen haben, wollen aber mit den Beispielen des Buches aber auch jene Leser bercksichtigen, welche den Beispielen innerhalb des Kapitels Schritt-fr-Schritt folgen. Die folgenden Abschnitte legen den Quellcode der Klassen des "Simple Weather" Projekt dar. Diese Klassen sollten alle in das gleiche Paket com.sonatype.maven.weather abgelegt werden. Lassen Sie uns die App sowie die AppTest Klassen welche das Goal archetype:create erzeugt hat, entfernen und unsere neuen Klassen dem Package zufgen. In einem Maven-Projekt, liegen alle Quellen eines Projektes unter /src/main/java. Aus dem Basis-Verzeichnis des neuen Projekts heraus, fhren Sie die folgenden Befehle aus:
$ $ $ $ $ $ $ cd src/test/java/org/sonatype/mavenbook rm AppTest.java cd ../../../../../.. cd src/main/java/org/sonatype/mavenbook rm App.java mkdir weather cd weather

Sie haben ein neues Paket com.sonatype.maven.weather erstellt. Nun sollten wir etliche Klassen in diesem Verzeichnis erstellen. Benutzen Sie hierfr Ihren Lieblings-Text-Editor und erstellen Sie eine neue Datei mit dem Namen Weather.java mit folgendem Inhalt: Example 4.4. "Simple Weather" Wetter Objekt Modell
package org.sonatype.mavenbook.weather; public class Weather { private String city; private String region; private String country; private String condition; private String temp; private String chill; private String humidity;

65

Anpassen eines Maven Projektes


public Weather() {} public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getRegion() { return region; } public void setRegion(String region) { this.region = region; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getCondition() { return condition; } public void setCondition(String condition) { this.condition = condition; } public String getTemp() { return temp; } public void setTemp(String temp) { this.temp = temp; } public String getChill() { return chill; } public void setChill(String chill) { this.chill = chill; } public String getHumidity() { return humidity; } public void setHumidity(String humidity) { this.humidity = humidity; } }

Die Wetter Klasse definiert ein einfaches Bean, welches die Informationen vorhlt, welche aus den vom Yahoo! Wetter-Dienst zurckgegebenen Daten geparsed werden. Der Yahoo! Wetter-Dienst bietet eine Flle an Informationen, ausgehend von den Sonnenaufgangs und -untergangszeiten, bis hin zur Windrichtung sowie -geschwindigkeit. Im Ansinnen, die Beispiele des Buchs so einfach wie mglich zu gestalten, enthlt unser Weeather-Objekt-Modell nur die Temperatur, Chill, Feuchtigkeit und sowie eine textuelle Beschreibung der gegenwrtigen Bedingungen. Im gleichen Verzeichnis erstellen Sie nun eine Datei mit dem Namen Main.java. Diese Haupt-Klasse wird die statische main()-Funktion beinhalten, welche der Einstiegspunkt dieses Beispiels ist. Example 4.5. Einfache Weather-Hauptklasse
package org.sonatype.mavenbook.weather; import java.io.InputStream; import org.apache.log4j.PropertyConfigurator;

66

Anpassen eines Maven Projektes


public class Main { public static void main(String[] args) throws Exception { // Configure Log4J PropertyConfigurator.configure(Main.class.getClassLoader() .getResource("log4j.properties")); // 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) { this.zip = 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 System.out.print( new WeatherFormatter().format( weather ) ); } }

Die oben gezeigte main()-Funktion konfiguriert Log4J indem es eine Ressource (log4j.properties) auf dem Klassenpfad sucht, um anschliessend einen ZIP-Code/eine Postleitzahl von der Befehlszeile zu lesen. Wird eine whrend des Leseversuchs eine Exception geworfen, wird standardmssig auf die Postleitzahl 60202 zurckgegriffen. Sobald dem Programm eine Postleitzahl zugefhrt wird, wird main() instanziert und deren start()-Methode aufgerufen. Die start()-Methode ruft die YahooRetriever Klasse auf, um das XML-Wetter abzurufen. Die Klasse YahooRetriever liefert einen InputStream, welcher an die Klasse YahooParser weitergeleitet wird. YahooParser analysiert das zurckgegebene Yahoo! Wetter XML und erstellt ein Weather-Objekt. Schlielich nimmt der WeatherFormatter 67

Anpassen eines Maven Projektes das Weather Objekt und spuckt eine formatierte Zeichenfolge aus, welche auf der Standardausgabe ausgegeben wird. Erstellen Sie nun im gleichen Verzeichnis eine Datei mit dem Namen YahooRetriever.java mit folgendem Inhalt: Example 4.6. "Simple Weather" YahooRetriever Klasse
package org.sonatype.mavenbook.weather; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import org.apache.log4j.Logger; public class YahooRetriever { private static Logger log = Logger.getLogger(YahooRetriever.class); public InputStream retrieve(int zipcode) throws Exception { log.info( "Retrieving Weather Data" ); String url = "http://weather.yahooapis.com/forecastrss?p=" + zipcode; URLConnection conn = new URL(url).openConnection(); return conn.getInputStream(); } }

Diese einfache Klasse ffnet eine URLConnection auf die Yahoo! Wetter-API und liefert einen InputStream. Um den InputStream verarbeiten zu knnen mssen wir im gleichen Verzeichnis eine Datei YahooParser.java erstellen. Example 4.7. "Simple Weather" YahooParser Klasse
package org.sonatype.mavenbook.weather; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import import import import org.apache.log4j.Logger; org.dom4j.Document; org.dom4j.DocumentFactory; org.dom4j.io.SAXReader;

public class YahooParser {

68

Anpassen eines Maven Projektes


private static Logger log = Logger.getLogger(YahooParser.class); public Weather parse(InputStream inputStream) throws Exception { Weather weather = new Weather(); log.info( "Creating XML Reader" ); SAXReader xmlReader = createXmlReader(); Document doc = xmlReader.read( inputStream ); log.info( "Parsing XML Response" ); weather.setCity( doc.valueOf("/rss/channel/y:location/@city") ); weather.setRegion( doc.valueOf("/rss/channel/y:location/@region") ); weather.setCountry( doc.valueOf("/rss/channel/y:location/@country") ); weather.setCondition( doc.valueOf("/rss/channel/item/y:condition/@text") ); weather.setTemp( doc.valueOf("/rss/channel/item/y:condition/@temp") ); weather.setChill( doc.valueOf("/rss/channel/y:wind/@chill") ); weather.setHumidity( doc.valueOf("/rss/channel/y:atmosphere/@humidity") ); return weather; } private SAXReader createXmlReader() { Map<String,String> uris = new HashMap<String,String>(); uris.put( "y", "http://xml.weather.yahoo.com/ns/rss/1.0" ); DocumentFactory factory = new DocumentFactory(); factory.setXPathNamespaceURIs( uris ); SAXReader xmlReader = new SAXReader(); xmlReader.setDocumentFactory( factory ); return xmlReader; } }

Der YahooParser ist die komplexeste Klasse in diesem Beispiel. Wir werden nicht in die Einzelheiten von Dom4J oder Jaxen eingehen, aber die Klasse bentigt dennoch ein wenig Erklrung. Die parse()-Methode von YahooParser nimmt einen InputStream auf und gibt ein Weather-Objekt zurck. Um dies zu tun, muss sie das XML-Dokument per DOM4J analysieren. Da wir an Elementen des Yahoo!Wetter Namespaces interessiert sind, ist es notwendig einen Namespace bewussten SAXReader in der Methode createXmlReader() zu erstellen. Sobald wir diesen Reader erstellt haben und damit das Dokument analysiert haben, bekommen wir ein org.dom4j.Document-Objekt zurck. Statt durch alle Kind-Elemente zu iterieren, adressieren wir die fr uns relevanten Informationen direkt mit Hilfe 69

Anpassen eines Maven Projektes eines XPath-Ausdrucks. Dom4J liefert in diesem Beispiel das XML-Parsing und Jaxen die XPath-Funktionalitt. Haben wir einmal ein Weather-Objekt erzeugt, mssen wir unsere Ausgabe fr den Gebrauch lesbar formatieren. Erstellen Sie im Verzeichnis der andern Klassen eine Datei mit dem Namen WeatherFormatter.java. Example 4.8. "Simple Weather" WeatherFormatter Klasse
package org.sonatype.mavenbook.weather; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringWriter; import org.apache.log4j.Logger; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; public class WeatherFormatter { private static Logger log = Logger.getLogger(WeatherFormatter.class); public String format( Weather weather ) throws Exception { log.info( "Formatting Weather Data" ); Reader reader = new InputStreamReader( getClass().getClassLoader() .getResourceAsStream("output.vm")); VelocityContext context = new VelocityContext(); context.put("weather", weather ); StringWriter writer = new StringWriter(); Velocity.evaluate(context, writer, "", reader); return writer.toString(); } }

Die Klasse WeatherFormatter verwendet Velocity, um basierend auf einer Vorlage, die Ausgabe darzustellen. Die format()-Methode nimmt eine Weather Bean auf und gibt eine formatierte Zeichenkette zurck. Das erste, was die format()-Methode macht, ist eine Velocity Vorlage namens poutput.vm vom Klassenpfad zu laden. Wir erstellen dann einen VelocityContext welcher mit einem einzigen Weather Objekt namens weather bestckt wird. Ein StringWriter wird erstellt, um die Ergebnisse mit der Vorlage zu fusionieren. Die Vorlage wird mit 70

Anpassen eines Maven Projektes einem Aufruf an Velocity.evaluate() ausgewertet und die Ergebnisse als String zurckgegeben. Bevor wir dieses Beispiel ausfhren knnen, mssen wir noch einige Ressourcen auf unserem Klassenpfad erstellen.

4.7. Resourcen Hinzufgen


Dieses Projekt hngt von zwei Klassenpfad Ressourcen ab: Die main()-Klasse konfiguriert Log4J mit log4j.properties vom Klassenpfad, und die WeatherFormatter Klasse greift auf eine Velocity Vorlage namens output.vm zurck. Beide Ressourcen mssen im Standard-Package (oder dem Wurzelverzeichnis des Klassenpfades) vorhanden sein. Um diese Ressourcen zuzufgen, mssen wir im Wurzelverzeichnis ein neues Verzeichnis /project-src/main/resources erstellen. Da das Verzeichnis nicht nicht vom Goal archetype:create geschaffen wurde, mssen wir dieses durch folgende Befehle aus dem Projekt Verzeichnis heraus erstellen:
$ cd src/main $ mkdir resources $ cd resources

Sobald das Ressourcen-Verzeichnis erstellt ist, knnen wir die beiden Ressourcen zufgen. Zunchst fgen Sie die Datei log4j.properties in das Ressourcen-Verzeichnis ein. Example 4.9. "Simple Weather" Log4J Konfigurationsdatei
# Set root category priority to INFO and its only appender to CONSOLE. log4j.rootCategory=INFO, CONSOLE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Threshold=INFO log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%-4r %-5p %c{1} %x - %m%n

Diese Datei log4j.properties konfiguriert Log4J alle Log-Nachrichten mit 71

Anpassen eines Maven Projektes einem PatternLayout an die Standard-Ausgabe zu senden. Schlielich brauchen wir eine Velocity Vorlage output.vm um die Ausgabe der Applikation darzustellen. Erstellen Sie output.vm im Ressourcen-Verzeichnis. Example 4.10. "Simple Weather" Output-Velocity-Template
********************************* Current Weather Conditions for: ${weather.city}, ${weather.region}, ${weather.country} Temperature: ${weather.temp} Condition: ${weather.condition} Humidity: ${weather.humidity} Wind Chill: ${weather.chill} *********************************

Diese Vorlage enthlt eine Reihe von Verweisen auf eine Variable namens weather. Die Variable weather ist das Weather Bean, welches an den WeatherFormatter gegeben wurde, die Syntax ${weather.temp} ist eine Kurzform um die Werte der Weather Bean aufzurufen und anzuzeigen. Nun, da wir allen Projekt-Code an den richtigen Stellen haben, knnen wir Maven benutzen, um dieses Beispiel aufzurufen.

4.8. Ausfhren des "Simple Weather" Programms


Mit dem Exec Maven Plugin des Codehouse-Mojo-Projekts knnen wir das Programm ausfhren. Um die main()-Klasse auszufhren, geben Sie den folgenden Befehl aus dem Projekt-Basis-Verzeichnis ein:
$ mvn install /$ mvn exec:java -Dexec.mainClass=org.sonatype.mavenbook.weather.Main ... [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:

72

Anpassen eines Maven Projektes


Evanston, IL, US Temperature: 45 Condition: Cloudy Humidity: 76 Wind Chill: 38 ********************************* ...

We didnt supply a command-line argument to the Main class, so we ended up with the default zip code, 60202. To supply a zip code, we would use the -Dexec.args argument and pass in a zip code:
$ mvn exec:java -Dexec.mainClass=org.sonatype.mavenbook.weather.Main -Dexec.args="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 ...

Da wir kein Kommandozeilen-Argument angegeben haben, wurde die Anwendung mit der Standard-Postleitzahl "60202" ausgefhrt. Wie Sie sehen knnen, haben wir das "Simple Weather" Tool erfolgreich aufgerufen, Daten von Yahoo! Wetter abgerufen, das Ergebnis analysiert, formatiert und die sich daraus ergebenden Daten mit Hilfe von Velocity ausgegeben. Wir haben all dies erreicht, ohne dabei viel mehr zu tun als unseres Projekt's Source-Code erstellen, sowie minimale Konfiguration an der pom.xml vorzunehmen. Beachten Sie, dass kein "Build-Prozess" beteiligt war. Wir mussten nicht festlegen wie oder wo die Java-Compiler unseren Quellecode kompiliert, wir haben nichts zu tun, um das Build-System zu finden, anzugeben wie der Bytecode ausgefhrt werden soll um die Beispiel-Anwendung auszufhren. Alles, was notwendig war, um etliche Abhngigkeiten einzufgen war, die entsprechenden Maven Koordinaten zu finden 73

Anpassen eines Maven Projektes und in der pom.xml Datei einzutragen.

4.8.1. Das Exec Maven Plugin


Der Exec-Plugin ermglicht Ihnen die Ausfhrung von Java-Klassen und andere Skripten. Es ist keines der Kern- oder Core-Maven Plugins, aber es steht Ihnen vom Mojo Projekt gehostet von Codehaus zur Verfgung. Fr eine vollstndige Beschreibung der Exec-Plugins, fhren Sie:
$ mvn help:describe -Dplugin=exec -Dfull

aus Es wird alle Goals, welche das Exec Maven Plugin zur Verfgung stellt, auflisten. Das Help Plugin, wird auch alle gltigen Parameter des Exec-Plugins aufzeigen, sollten Sie dessen Verhalten anpassen wollen. Um dem Exec Plugin Kommandozeilenargumente mitzugeben, sehen Sie in der Dokumentation des Plugins nach, welche von help:describe wiedergegeben wird. Obschon das Exec-Plugin ntzlich ist, solltens Sie es nicht ausserhalb der laufenden Tests whrend der Entwicklungsphase zur Ausfhrung von Anwendungen benutzen. Als robustere Lsung, verwenden Sie das Maven Plugin Assembly welches im Abschnitt 4.13: "Erstellen einer packetierten Kommandozeilen Anwendung" eingefhrt wird.

4.8.2. Erkundung der Projekt Abhngigkeiten


Das Exec-Plugin ermglicht es uns, die Anwendung auszufhren, ohne die Abhngigkeiten explizit in den Klassenpfad aufzunehmen. In jedem anderen Build-System, wre es notwendig geworden, alle Abhngigkeiten in eine Art /lib-Verzeichnis zu kopieren, welches eine Sammlung von JAR-Dateien enthlt. Dann htten wir ein einfaches Skript, welches den Bytecode des Programms sowie alle unsere Abhngigkeiten in den Klassenpfad einschliesst. Nur dann knnten wir java com.sonatype.maven.weather.Main ausfhren. Das Exec Plugin nutzt die Tatsache, dass Maven bereits um die Erstellung und Verwaltung Ihres Klassenpfades und der Abhngigkeiten weiss. 74

Anpassen eines Maven Projektes Whrend dies ist zwar bequem ist, ist es dennoch schn zu wissen, was genau in Ihren Klassenpfad eingeschlossen wird. Whrend des Projekt direkt nur von wenigen Bibliotheken wie Dom4J, Log4J, Jaxen, und Velocity abhngt, sttzen diese sich auf weitere, transitive Abhngigkeiten. Um herauszufinden, wie Ihr Klassenpfad tatschlich aussieht, knnen Sie das Dependency Maven Plugin zur Ausgabe einer Liste der aufgelsten Abhngigkeiten benutzen. Um die Liste der Abhngigkeiten des "Simple Weather" Projekts auszugeben, fhren Sie das Goal dependency:resolve aus.
$ mvn dependency:resolve ... [INFO] [dependency:resolve] [INFO] [INFO] The following files have been resolved: [INFO] com.ibm.icu:icu4j:jar:2.6.1 (scope = compile) [INFO] commons-collections:commons-collections:jar:3.1 (scope = compile) [INFO] commons-lang:commons-lang:jar:2.1 (scope = compile) [INFO] dom4j:dom4j:jar:1.6.1 (scope = compile) [INFO] jaxen:jaxen:jar:1.1.1 (scope = compile) [INFO] jdom:jdom:jar:1.0 (scope = compile) [INFO] junit:junit:jar:3.8.1 (scope = test) [INFO] log4j:log4j:jar:1.2.14 (scope = compile) [INFO] oro:oro:jar:2.0.8 (scope = compile) [INFO] velocity:velocity:jar:1.5 (scope = compile) [INFO] xalan:xalan:jar:2.6.0 (scope = compile) [INFO] xerces:xercesImpl:jar:2.6.2 (scope = compile) [INFO] xerces:xmlParserAPIs:jar:2.6.2 (scope = compile) [INFO] xml-apis:xml-apis:jar:1.0.b2 (scope = compile) [INFO] xom:xom:jar:1.0 (scope = compile)

Wie Sie sehen, hat unser Projekt eine groe Zahl von Abhngigkeiten. Auch wenn wir nur direkte Abhngigkeiten von vier Bibliotheken angegeben haben, scheinen insgesamt 15 Abhngigkeiten zu bestehen. Dom4J hngt von Xerces und dem XML-Parser-APIs ab, Jaxen hngt davon ab, dass Xalan sich im Klassenpfad befindet. Das Dependency Maven Plugin wird ihnen die endgltige Kombination von Abhngigkeiten unter welchen Ihr Projekt kompiliert wird ausgeben. Wollen Sie den gesamten Baum aller Abhngigkeiten sehen, so knnen Sie das Goal dependency:tree aufrufen:
$ mvn dependency:tree ... [INFO] [dependency:tree] [INFO] org.sonatype.mavenbook.ch04:simple-weather:jar:1.0 [INFO] +- log4j:log4j:jar:1.2.14:compile

75

Anpassen eines Maven Projektes


[INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] ... +| +| | | | | | +| | | +\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 \- com.ibm.icu: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 org.apache.commons:commons-io:jar:1.3.2:test junit:junit:jar:3.8.1:test

Sollten Sie wirklich abenteuerlich sein, oder einfach nur die volle Liste der Abhngigkeiten sehen wollen, einschliesslich aller Artefakte, die aufgrund von Konflikten oder anderen Grnden abgelehnt wurden, fhren Sie Maven mit dem Debug-Flag aus.
$ mvn install -X ... [DEBUG] org.sonatype.mavenbook.ch04: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] com.ibm.icu: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)

In der Debug-Ausgabe sehen wir die Eingeweide des Abhngigkeit-Management-Systems bei der Arbeit. Was Sie hier sehen, ist der vollstndige Baum aller Abhngigkeiten fr dieses Projekt. Maven listet die vollen 76

Anpassen eines Maven Projektes Maven Koordinaten fr alle Ihre Projekt-Abhngigkeiten und die Abhngigkeiten derer Abhngigkeiten (und die Abhngigkeiten der Abhngigkeiten der Abhngigkeiten). Sie knnen ersehen, dass "Simple Weather" von Jaxen abhngt, welches von xom abhngig ist was wiederum auf icu4j aufbaut. Aus dieser Ausgabe knnen Sie erkennen, dass Maven einen Graphen der Abhngigkeiten erstellt, hierbei Duplikate eliminiert und etwaige Versionskonflikte lst. Sollten Sie bezglich Abhngigkeiten auf Probleme stossen, so ist es oft hilfreich ein wenig tiefer im Baum den Abhngigkeiten zu schrfen. Durch Einschalten der Debugausgabe knnen Sie den Maven Abhngigkeits-Mechanismus bei der Arbeit sehen.

4.9. Erstellen von Unit-Tests


Maven hat eine eingebaute Untersttzung fr Unit-Tests. Testen ist ein Teil des ursprnglichen Maven Lebenszyklus. Lassen Sie uns ein paar Unit-Tests zum "Simple Weather" Projekt hinzufgen. Zuerst werden wir ein Package com.sonatype.maven.weather unter /src/test/java erstellen.
$ $ $ $ cd src/test/java cd org/sonatype/mavenbook mkdir -p weather/yahoo cd weather/yahoo

An dieser Stelle werden wir zwei Unit-Tests erstellen. Der erste Unit Test wird die Klasse YahooParser, der zweite die WeatherFormatter Klasse testen. Erstellen Sie eine Datei mit dem Namen YahooParserTest.java mit folgendem Inhalt im Package weather: Example 4.11. "Simple Weather" YahooParserTest Unit-Test
package org.sonatype.mavenbook.weather.yahoo; import java.io.InputStream; import junit.framework.TestCase; import org.sonatype.mavenbook.weather.Weather; import org.sonatype.mavenbook.weather.YahooParser;

77

Anpassen eines Maven Projektes


public class YahooParserTest extends TestCase { public YahooParserTest(String name) { super(name); } public void testParser() throws Exception { InputStream nyData = getClass().getClassLoader().getResourceAsStream("ny-weather.xml"); Weather weather = new YahooParser().parse( nyData ); assertEquals( "New York", weather.getCity() ); assertEquals( "NY", weather.getRegion() ); assertEquals( "US", weather.getCountry() ); assertEquals( "39", weather.getTemp() ); assertEquals( "Fair", weather.getCondition() ); assertEquals( "39", weather.getChill() ); assertEquals( "67", weather.getHumidity() ); } }

Dieser YahooParserTest erweitert die von JUnit definierte Klasse TestCase. Es folgt das bliche Muster fr einen JUnit-Test: ein Konstruktor, der ein einziges String Argument annimmt und den Konstruktor der Superklasse aufruft und eine Reihe von public Methoden welche im Namen mit "test" beginnen, welche als Unit-Tests aufgerufen werden. Wir definieren ein einfaches Testvorgehen: testParser, welches den YahooParser berprft, indem es ein XML-Dokument mit bekannten Werten auswertet. Das Test XML-Dokument heisst ny-weather.xml und wird aus dem Klassenpfad geladen. Wir fgen Test Ressourcen in Abschnitt 4.11: "Hinzufgen von Unit Test Ressourcen" an. In unserem Verzeichnisaufbau des Maven-Projekts befindet sich die Datei ny-weather.xml im Verzeichnis der Test-Ressourcen -- ${basedir}/src/test/resources unter /com/sonatype/maven/wetter/yahoo/ny-weather.xml . Die Datei wird als InputStream eingelesen und an die parse()-Methode des YahooParser geleitet. Die parse()-Methode liefert ein Weather Objekt zurck,welches ber eine Anzahl von assertEquals() Aufrufen, eine innerhalb der Klasse TestCase definierte Methode, geprft wird. Im gleichen Verzeichnis erstellen Sie eine Datei mit dem Namen WeatherFormatterTest.java.

78

Anpassen eines Maven Projektes Example 4.12. "Simple Weather" WeatherFormatterTest Unit-Test
package org.sonatype.mavenbook.weather.yahoo; import java.io.InputStream; import org.apache.commons.io.IOUtils; import org.sonatype.mavenbook.weather.Weather; import org.sonatype.mavenbook.weather.WeatherFormatter; import org.sonatype.mavenbook.weather.YahooParser; import junit.framework.TestCase; public class WeatherFormatterTest extends TestCase { public WeatherFormatterTest(String name) { super(name); } public void testFormat() throws Exception { InputStream nyData = getClass().getClassLoader().getResourceAsStream("ny-weather.xml"); Weather weather = new YahooParser().parse( nyData ); String formattedResult = new WeatherFormatter().format( weather ); InputStream expected = getClass().getClassLoader().getResourceAsStream("format-expected.dat"); assertEquals( IOUtils.toString( expected ).trim(), formattedResult.trim() ); } }

Der zweite Unit Test dieses einfachen Projekts testet die Klasse WeatherFormatter. Wie bereits die Klasse YahooParserTest, erweitert auch die Klasse WeatherFormatterTest die Klasse TestCase des JUnit Frameworks. Die einzige Testfunktion liest die gleiche Testressource von ${basedir}/src/test/resources umter dem /com/sonatype/Maven/Wetter/yahoo-Verzeichnis unter Einbezug des Unit Test Klassenpfades. Wir fgen Test Ressourcen wie im Abschnitt 4.11: "Hinzufgen Unit Test Ressourcen" beschrieben an. WeatherFormatterTest zieht diese Beispiel-Eingabedatei durch den YahooParser an, welcher ein Weather Objekt zurckgibt an, dieses Objekt wird dann mit dem WeatherFormatter ausgegeben. Da WeatherFormatter eine Zeichenkette ausgibt, mssen wir gegen eine gesetzte Eingabe testen. Unser "gesetzter" Input wurde einer Text-Datei mit 79

Anpassen eines Maven Projektes dem Namen format-expected.dat erfasst, welche sich im gleichen Verzeichnis wie ny-weather.xml befindet. Um die Test-Ausgabe mit der erwarteten Ausgabe zu vergleichen, wird diese als InputStream eingelesen und unter Einbezug der Klasse IOUtils aus Apache Commons IO in einen String umgewandelt. Diese Zeichenfolge wird dann mittels assertEquals() mit der Testausgabe verglichen.

4.10. Hinzufgen von Gebietsbezogenen Unit Tests


In der Klasse WeatherFormatterTest benutzten wir ein Dienstprogramm aus Apache Commons IO- die Klasse IOUtils. IOUtils bietet eine Reihe von hilfreichen statische Funktionen, welche den Grossteil der Arbeit der Input/Output-Operationen bernehmen. In diesem speziellen Unit Test benutzen wir IOUtils.toString() um die format-expected.dat Klassenpfadressource in einen String zu verwandeln. Wir htten dies auch ohne den Einsatz von Commons IO bewerkstelligen knnen, aber es htte zustzliche sechs oder sieben Zeilen Code bedingt um mit den verschiedenen InputStreamReader- und StringWriter-Objekten umzugehen. Der Hauptgrund fr den Einsatz der Commons IO Bibliothek war, uns eine Ausrede zu geben, Test-scoped (abgegrenzte) Abhngigkeiten am Beispiel von Commons IO einzufhren. Eine Test-scoped Abhngigkeit ist eine Abhngigkeit, welche nur auf whrend der Testkompilierung und Testausfhrung auf dem Klassenpfad eingeschlossen ist. Sollte Ihr Projekt als war- oder ear-Archiv packetiert werden, so wrde eine Test-scoped Abhngigkeit nicht in das Projekt-Output-Archiv einbezogen werden. Um eine Test-scoped Abhngigkeit zu erstellen, fgen Sie das folgende dependency-Element in Ihrem Projekt in das Element dependencies ein . Example 4.13. Das Hinzufgen einer Test-scoped Abhngigkeit
<project> ... <dependencies> ... <dependency> <groupId>org.apache.commons</groupId>

80

Anpassen eines Maven Projektes


<artifactId>commons-io</artifactId> <version>1.3.2</version> <scope>test</scope> </dependency> ... </dependencies> </project>

Nachdem Sie diese Abhngigkeit der pom.xml Datei zugefgt haben, fhren Sie mvn dependency:resolve aus: Sie sollten sehen, dass commons-io nun als eine Abhngigkeit mit Gebietsbezug test aufgefhrt wird. Noch eine Kleinigkeit wird bentigt, bevor wir bereit sind diese Projekt Unit-Tests auszufhren. Wir mssen die Klassenpfad Ressourcen erstellen, von welchen diese Unit-Tests abhngen. Geltungsbereiche werden ausfhrlich im Abschnitt 9.4.1: "Geltungsbereiche von Abhngigkeiten" dargestellt.

4.11. Hinzufgen einer Unit-Test Ressource


Ein Unit Test hat Zugriff auf eine Reihe von testspezifischen Ressourcen. Hufig werden Sie Dateien mit den erwarteten Ergebnissen und Dummy-Dateien mit Eingabetexten auf dem Testklassenpfad ablegen. In diesem Projekt legen wir ein Test XML-Dokument fr den YahooParserTest namens ny-weather.xml sowie eine Datei mit der erwarteten Ausgabe des WeatherFormatter unter format-expected.dat ab. Um Test Ressourcen einzufgen, mssen Sie zunchst das Verzeichnis /src/test/resources erstellen. Dies ist das Standard-Verzeichnis, in welchem Maven nach Unit-Test Ressourcen sucht. Erstellen Sie dieses Verzeichnis indem Sie die folgenden Befehle aus Ihrem Projekt-Basis-Verzeichnis heraus ausfhren.
$ cd src/test $ mkdir resources $ cd resources

Sobald Sie das Ressourcen-Verzeichnis erstellt haben, erstellen Sie eine Datei mit dem Namen format-expected.dat in diesem Verzeichnis.

81

Anpassen eines Maven Projektes Example 4.14. "Simple Weather" WeatherFormatterTest erwartete Ausgabe
********************************* Current Weather Conditions for: New York, NY, US Temperature: 39 Condition: Fair Humidity: 67 Wind Chill: 39 *********************************

Diese Datei sollte vertraut aussehen. Es ist die gleiche Ausgabe, welche generiert wurde, als Sie das "Simple Weather" Projekt mit dem Exec Maven Exec starteten. Die zweite Datei welche Sie bentigen werden und daher im Ressourcen-Verzeichnis erstellen sollten ist ny-weather.xml. Example 4.15. "Simple Weather" YahooParserTest XML-Eingabe
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"> <channel> <title>Yahoo! Weather - New York, NY</title> <link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/</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>http://weather.yahoo.com/</link> <url>http://l.yimg.com/us.yimg.com/i/us/nws/th/main_142b.gif</url> </image> <item> <title>Conditions for New York, NY at 8:51 pm EDT</title>

82

Anpassen eines Maven Projektes


<geo:lat>40.67</geo:lat> <geo:long>-73.94</geo:long> <link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/\</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="http://l.yimg.com/us.yimg.com/i/us/we/52/33.gif" /><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>

Diese Datei enthlt ein Test XML-Dokument fr den YahooParserTest. Wir speichern diese Datei, um den YahooParser zu testen ohne eine XML-Antwort vom Yahoo! Wetterdienst abzurufen.

4.12. Ausfhren von Unit-Tests


Nun, da die Unit Tests zu Ihrem Projekt bestehen, fhren wir diese aus! Sie brauchen nichts weiter zu tun um die Unit Tests anzustossen: die Testphase ist ein normaler Bestandteil des Maven Lifecycles. Die Maven Tests werden automatisch ausgefhrt sobald Sie mvn package oder mvn install aufrufen. Wenn Sie mchten, dass alle Phasen des Lebenszyklus bis einschlielich der Testphase ausgefhrt werden, rufen Sie mvn test auf.
$ mvn test ... [INFO] [surefire:test] [INFO] Surefire report directory: ~/examples/simple-weather/target/\ surefire-reports

83

Anpassen eines Maven Projektes


------------------------------------------------------T E S T S ------------------------------------------------------Running org.sonatype.mavenbook.weather.yahoo.WeatherFormatterTest 0 INFO YahooParser - Creating XML Reader 177 INFO YahooParser - Parsing XML Response 239 INFO WeatherFormatter - Formatting Weather Data Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.547 sec Running org.sonatype.mavenbook.weather.yahoo.YahooParserTest 475 INFO YahooParser - Creating XML Reader 483 INFO YahooParser - Parsing XML Response Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.018 sec Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

Der Aufruf von mvn test von der Befehlszeile veranlasst Maven zur Ausfhrung aller Phasen des Lebenszyklus' bis und mit der Testphase. Das Surefire Maven Plugin hat ein Goal test, welches an die Testphase gebunden ist. Dieses Goal test fhrt alle Unit-Tests des Projektes aus, welche sich unter /src/test/java befinden und einen Dateinamen von **/Test*.java, **/*Test.java sowie **/*TestCase.java haben. Fr unser Projekt knnen Sie sehen, dass das Surefire Plugin mit dem Goal test die Unittests WeatherFormatterTest und YahooParserTest ausgefhrt hat. Bei der Ausfhrung des Surefire Maven Plugins werden nicht nur die Tests ausgefhrt, es werden auch XML- und Text-Berichte erzeugt und unter dem Verzeichnis ${basedir}/target/surefire-reports abgelegt. Sollten Ihre Tests fehlschlagen, so knnen Sie in diesem Verzeichnis von den Unit Tests angelegte Detailsangaben wie Fehlermeldungen oder Stack Traces der Unit Tests finden.

4.12.1. Ignorieren fehlgeschlagener Unit Tests


Oft werden Sie an einem System arbeiten dessen Unit Tests scheitern. Sollten Sie Test-Driven Development (TDD) praktizieren, so ist die Anzahl der gescheiterten Tests ein Mass dafr, wie nahe der Vollendung Ihr Projekt ist. Sollten Sie trotz gescheiterter Unit-Tests dennoch gerne ein Produkt erstellen, so mssen Sie Maven anweisen, diese Unit Tests zu ignorieren. Das Standardverhalten von Maven ist es, nach einem gescheiterten Test den Build abzubrechen. Um den Build auch bei 84

Anpassen eines Maven Projektes auftreten gescheiterter Tests weiterzufhren, mssen sie den Konfigurationseintrag testFailureIgnore des Surefire Maven Plugins auf "true" setzen. Example 4.16. Ignorieren von gescheiterten Unit-Test Fllen
<project> [...] <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> </plugins> </build> [...] </project>

Die Plugin Dokumentation (http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html) zeigt, dass dieser Parameter einen Ausdruck erklrt: Example 4.17. Plugin-Parameter-Ausdrcke
testFailureIgnore Set this to true to ignore a failure during \ testing. Its use is NOT RECOMMENDED, but quite \ convenient on occasion.

* Type: boolean * Required: No * Expression: ${maven.test.failure.ignore}

// testFailureIgnore Setzen Sie diesen Parameter auf "true" um scheiternde Testflle // Die Benutzung des Parameters wird NICHT EMPFOHLEN, kann aber zu Zeiten recht ntz

Dieser Ausdruck kann von der Befehlszeile mit dem 'D-Parameter' gesetzt werden:
$ mvn test -Dmaven.test.failure.ignore=true

85

Anpassen eines Maven Projektes

4.12.2. berspringen von Unit-Tests


Sie knnen Maven auch so konfigurieren dass bestimmte Unit Tests ganz bersprungen werden. Vielleicht arbeiten Sie an einem sehr groen System, in welchem die Unit-Tests Minuten in Anspruch nehmen und Sie wollen nicht warten bis alle Unit-Tests abgeschlossen sind, um ein Produkt zu erstellen. Mglicherweise mssen Sie mit einem Legacy-System arbeiten, welches eine Reihe von scheiternden Unit-Tests umfasst. Anstelle der Behebung der Unit-Test Fehlern mchten Sie lediglich ein JAR-Archive erstellen. Maven sieht fr diese Flle vor, und stellt die Fhigkeit mit dem Parameter skip des Surefire Plugins zum berspringen von Unit-Tests bereit. Um beim Aufruf von der Befehlszeile die Unit Tests zu berspringen, fgen Sie einfach den Parameter maven.test.skip Ihrem angestrebten Goal an:
$ mvn install -Dmaven.test.skip=true ... [INFO] [compiler:testCompile] [INFO] Not compiling test sources [INFO] [surefire:test] [INFO] Tests are skipped. ...

Wenn das Surefire Plugin das Goal test erreicht, berspringt es die Unit-Tests, sollte der Parameter maven.test.skip auf "true" gesetzt sein. Eine weitere Art Maven zu konfigurieren Unit Tests zu berspringen ist, diese Konfiguration in Ihrer Projekt pom.xml-Datei vorzunehmen. Um dies zu tun, wrde man ein Element plugin Ihrer Build Konfiguration zufgen. Example 4.18. berspringen von Unit-Tests
<project> [...] <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> </plugins>

86

Anpassen eines Maven Projektes


</build> [...] </project>

4.13. Builden einer paketierten, Befehlszeilen orientierten Anwendung


In Abschnitt 4.8, "Ausfhren des "Simple Weather" Programms", haben wir die "Simple Weather" Anwendung unter Verwendung des Exec Maven Plugins ausgefhrt. Auch wenn das Exec Plugin die Anwedung ausgefhrt und und Ausgaben erzeugt hat, sollte man Maven nicht als Container zur Ausfhrung Ihrer Anwendungen ansehen. Sollten Sie Ihre Anwendung an andere weitergeben wollen, so werden sie dies sicher als JAR-Archive, oder als Archiv in ZIP oder GZIP Format tun wollen. Das folgende Vorgehen gibt einen berblick ber den Prozess mit Hilfe einer vordefinierter Assembly Definitionsdatei sowie dem Assembly Maven Plugin ein verteilbares JAR Archive zu erstellen, welches den Anwendungs-(Byte) Code sowie alle notwendigen Abhngigkeiten enthlt. Das Assembly Maven Plugin ist ein Plugin welches Sie zur Zusammenstellung beliebiger Pakete zur Verteilung Ihrer Anwendung benutzen knnen. Sie knnen das Assembly Plugin dazu einsetzen, das Resultat in beliebiger Form zusammenzustellen, indem Sie eine darauf zugeschnittene Assembly Definitionsdatei erstellen. In einem spteren Kapitel werden wir Ihnen zeigen wie man eine zugeschnittene Assembly Definitionsdatei erstellt, um die "Simple Weather" in einem komplexeren Archiv zu deployen. In diesem Kapitel werden wir das vordefinierte Format jar-with-dependencies einsetzen. Um das Assembly Maven Plugin einzusetzen, mssen wir die folgende Anpassung an der bestehenden Konfiguration in der pom.xml-Datei vornehmen: Example 4.19. Konfigurieren der Assembly Maven Definition
<project> [...] <build> <plugins>

87

Anpassen eines Maven Projektes


<plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build> [...] </project>

Sobald Sie die Konfigurationsnderung hinzugefgt haben, starten Sie den Build mit dem Aufruf mvn assembly:assembly.
$ mvn install assembly:assembly ... [INFO] [jar:jar] [INFO] Building jar: ~/examples/simple-weather/target/simple-weather-1.0.jar [INFO] [assembly:assembly] [INFO] Processing DependencySet (output=) [INFO] Expanding: \ .m2/repository/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar into \ /tmp/archived-file-set.1437961776.tmp [INFO] Expanding: .m2/repository/commons-lang/commons-lang/2.1/\ commons-lang-2.1.jar into /tmp/archived-file-set.305257225.tmp ... (Maven Expands all dependencies into a temporary directory) ... [INFO] Building jar: \ ~/examples/simple-weather/target/\ simple-weather-1.0-jar-with-dependencies.jar

Nach dem Abarbeiten befindet sich unser Ergebnis im Verzeichnis /target in der Datei simple-weather-1.0-jar-with-dependencies.jar. Wieder knnen wir die main()-Klasse ausfhren. Um die "Simple Weather" aufzurufen, geben sie folgenden Befehl auf der Kommandozeile im Projekt-Basis-Verzeichnis ein:
$ cd target $ java -cp simple-weather-1.0-jar-with-dependencies.jar \ org.sonatype.mavenbook.weather.Main 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

88

Anpassen eines Maven Projektes


Temperature: 44 Condition: Fair Humidity: 40 Wind Chill: 40 *********************************

Das Format 'jar-with-dependencies' erstellt ein einziges JAR-Archiv, welches allen Bytecode der "Simple Weather" Anwendung sowie den entpackten Bytecode aller Abhngigkeiten enthlt. Dieses etwas unkonventionelle Format eines Archivs kommt in einer 9 MiB Datei mit rund 5290 Klassen daher, aber dies ist ein einfaches Format, um Anwendungen welche Sie mit Maven entwickelt haben zu verteilen. Spter in diesem Buch, werden wir Ihnen zeigen, wie Sie eine benutzerdefinierte Assembly Definitionsdatei erstellen um eine gewhnliche Standard-Distribution zu erstellen.

4.13.1. Anbinden des Assembly Goals zur Packetierungs Phase


Unter Maven 1 wurde ein Build massgeschneidert indem man eine Anzahl von Plugin Goals direkt aneinanderknpfte. Jedes Plugin Goal hatte Vorbedingungen und definierte einen Bezug zu anderen Plugin Goals. Mit der Ankunft von Maven 2 wurde das Lebenszykluskonzept eingefhrt, und Plugin Goals sind nun zu einer Anzahl Phasen zugeordnet, welche in einem Standard Lebenszyklus bestehen. Das Lebenszykluskonzept ist eine solide Grundlage, welche es vereinfacht, die Abfolge der Plugin Goals zu bestimmen und zu koordinieren welche Goals in einem bestimmten Build ausgefhrt werden. Unter Maven 1 war der Bezug zwischen den Goals direkt, unter Maven 2 besteht der Bezug von Plugin Goals immer zu einer Menge von gemeinsamen Lebenszyklus Phasen. Obschon es zulssig ist, ein Goal direkt - wie beschrieben - von der Kommandozeile auszufhren, steht es eher im Einklang mit der Architektur von Maven 2, das Assembly mit dem Aufruf des Goals assembly:assembly whrend einer Phase des Maven Lebenszykluses aufzurufen. Die folgenden Plugin-Konfiguration konfiguriert das Maven Plugin Assembly, um das angefgte Goal whrend der Phase package des Maven Standard 89

Anpassen eines Maven Projektes Lebenszykluses auszufhren. Das angefgte Goal fhrt das gleiche aus, wie schon das Goal assembly. Um das Goal assembly:attached der Phase package zuzuordnen benutzen wir das Element executions innerhalb des Elements plugin der Sektion build des Projekt POMs. Example 4.20. Anbinden des Assembly Goals zur Packetierungs Phase
<project> [...] <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> <executions> <execution> <id>simple-command</id> <phase>package</phase> <goals> <goal>attached</goal> </goals> </execution> </executions> </plugins> </build> [...] </project>

Sobald Sie diese nderung Ihres POMs angefgt haben mssen Sie nur noch mvn package aufrufen, um Ihr Assembly zu generieren. Die Konfiguration der execution wird sicherstellen, dass das Goal assembly:attached ausgefhrt wird, sobald Maven in die Lebenszyklusphase package eintritt.

90

Chapter 5. Eine einfache Web-Anwendung


5.1. Einleitung
In diesem Kapitel erstellen wir mit Hilfe des Archetype Maven Plugin eine einfache Web-Anwendung. Wir fhren diese Web-Applikation ein, benutzen hierfr einen Servlet-Container Jetty, fgen einige Abhngigkeiten ein, schreiben ein einfaches Servlet und erzeugen ein WAR-Archiv. Am Ende dieses Kapitels, werden Sie in der Lage sein Maven zur Beschleunigung der Entwicklung von Web-Applikationen einzusetzen.

5.1.1. Herunterladen der Beispiele dieses Kapitels


Das Beispiel in diesem Kapitel wird mit dem Archetype Maven Plugin erzeugt. Whrend Sie in der Lage sein sollten, der Entwicklung dieses Kapitels ohne Beispiel-Quellcode zu folgen, empfehlen wir das Herunterladen einer Kopie der Quellcodes als Referenz. Das Beispielprojekt dieses Kapitel zusammen mit den anderen Beispielen dieses Buchs kann von http://books.sonatype.com/maven-book/mvn-examples-1.0.zip oder http://books.sonatype.com/maven-book/mvn-examples-1.0.tar.gz heruntergeladen werden. Entpacken Sie das Archiv in ein beliebiges Verzeichnis, und gehen Sie dann zum Verzeichnis /ch05. Darin finden Sie ein Verzeichnis mit dem Namen /simple web welches den Quellcode fr dieses Kapitel enthlt.

5.2. Eine kurze Einfhrung in die "Simple Web" Anwendung


Wir haben dieses Kapitel gezielt auf Plain-Old Web Applikationen (POWA) konzentriert - ein Servlet und eine JSP-Seite. Wir werden Ihnen in den nchsten 20 Seiten sicher nicht zeigen wie Sie Ihre Struts 2, Tapestry, Wicket, JSF, oder Waffle Anwendung erstellen, auch nicht wie Sie die Integration eines IoC Containers wie 91

Eine einfache Web-Anwendung Plexus, Guice oder Spring Framework bewerkstelligen. Das Ziel dieses Kapitels ist es, Ihnen die grundlegenden Mglichkeiten welche Maven zur Entwicklung von Web-Anwendungen bietet vorzustellen. Nicht mehr und nicht weniger! Spter in diesem Buch, werden wir einen Blick auf die Entwicklung von zwei Web-Anwendungen werfen: einer, welche Hibernate, Velocity sowie das Spring Framework nutzt, und eine andere unter Verwendungen von Plexus.

5.3. Erstellen des "Simple Web" Projekts


Um das Web Applikationsprojekt zu erstellen, fhren Sie mvn archetype:create mit einer artifactId und einer groupId aus. Whlen Sie die archetypeArtifactId maven-archetype-webapp. Bei der Ausfhrung wird die entsprechende Verzeichnis-Struktur und das grundlegende Maven POM erstellt.
~/examples$ mvn archetype:create -DgroupId=org.sonatype.mavenbook.ch05 \ -DartifactId=simple-webapp \ -DpackageName=org.sonatype.mavenbook \ -DarchetypeArtifactId=maven-archetype-webapp [INFO] [archetype:create] [INFO] ---------------------------------------------------------------------[INFO] Using parameters for creating Archetype: maven-archetype-webapp:RELEASE [INFO] ---------------------------------------------------------------------[INFO] Parameter: groupId, Value: org.sonatype.mavenbook.ch05 [INFO] Parameter: packageName, Value: org.sonatype.mavenbook [INFO] Parameter: basedir, Value: ~/examples [INFO] Parameter: package, Value: org.sonatype.mavenbook [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: artifactId, Value: simple-webapp [INFO] *************** End of debug info from resources from generated POM ** [INFO] Archetype created in dir: ~/examples/simple-webapp

Sobald das Archetype Maven Plugin das Projekt erstellt hat, gehen Sie in das Verzeichnis /simple-web und werfen Sie einen Blick auf die dort abgelegte pom.xml-Datei. Sie sollten das folgenden XML-Dokument vorfinden: Example 5.1. Erstes POM des "Simple Web" Projekt
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion>

92

Eine einfache Web-Anwendung


<groupId>org.sonatype.mavenbook.ch05</groupId> <artifactId>simple-webapp</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>simple-webapp Maven Webapp</name> <url>http://maven.apache.org</url> <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>

Beachten Sie dass das Element packaging den Wert 'war' enthlt. Ein Projekt des Types war package, wird eine WAR-Datei im Zielverzeichnis erstellen, das standardmig den Namen ${artifactId}-${version}.war trgt. Fr dieses Projekt, wird das standardmige WAR in /target/simple-webapp-1.0-SNAPSHOT.war abgelegt. Im "Simple Web" Projekt haben wir den Namen der WAR-Datei vorbestimmt, indem wir ein Element finalName in die Projekt Build Konfiguration eingefgt haben. Mit dem finalName von 'simple-webapp' generiert die Phase package ein WAR-Archiv in /target/simple-webapp.war.

5.4. Konfigurieren des Jetty-Plugins


Sobald Sie Ihre Web Anwendung kompiliert, getestet und verpackt haben, werden Sie sie wahrscheinlich einen Servlet-Container einsetzen wollen und diese mit der 93

Eine einfache Web-Anwendung vom Archetype Maven Plugin erstellten index.jsp-Datei testen wollen. Normalerweise wre der Ablauf hierzu entsprechend: Herunterladen eines Containers wie etwas Jetty oder Apache Tomcat, Auspacken einer Distribution, Kopieren Ihres Anwendungs WAR-Archivs in ein /webapp-Verzeichnis, schliesslich starten des Containers. Obschon man das alles tun kann, gibt es keine Notwendigkeit, dies zu tun. Stattdessen knnen Sie das Jetty Maven Plugin einsetzen, und Ihre Web-Applikation aus Maven heraus starten. Um dies zu tun, mssen wir das Jetty Maven Plugin in unserem Projekt POM konfigurieren. Fgen Sie das folgende Plugin-Element Ihrer Projekt Build Konfiguration an: Example 5.2. Konfigurieren des Jetty-Plugins
<project> [...] <build> <finalName>simple-webapp</finalName> <plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins> </build> [...] </project>

Nachdem Sie das Jetty Plugin in der Projekt pom.xml-Datei konfiguriert haben. knnen Sie das Goal jetty:run aufrufen, um Ihre Web Anwendung im Jetty Container zu starten. Rufen sie mvn jetty:run wie folgt auf:
~/examples$ mvn jetty:run ... [INFO] [jetty:run] [INFO] Configuring Jetty for project: simple-webapp Maven Webapp [INFO] Webapp source directory = \ ~/svnw/sonatype/examples/simple-webapp/src/main/webapp [INFO] web.xml file = \ ~/svnw/sonatype/examples/simple-webapp/src/main/webapp/WEB-INF/web.xml [INFO] Classes = ~/svnw/sonatype/examples/simple-webapp/target/classes 2007-11-17 22:11:50.532::INFO: Logging to STDERR via org.mortbay.log.StdErrLog [INFO] Context path = /simple-webapp [INFO] Tmp directory = determined at runtime

94

Eine einfache Web-Anwendung


[INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml [INFO] Web overrides = none [INFO] Webapp directory = \ ~/svnw/sonatype/examples/simple-webapp/src/main/webapp [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@0.0.0.0:8080 [INFO] Started Jetty Server

Nach erfolgreichem Starten des Servlet-Containers durch Maven, laden Sie die URL http://localhost:8080/simple-webapp/ in einen Web-Browser. Die durch Archetype generierte index.jsp-Datei ist trivial: sie enthlt eine berschrift mit dem Text: "Hallo Welt!". Maven erwartet, dass das Document Root der Web-Applikation in /src/main/webapp liegt. In diesem Verzeichnis finden Sie auch die Datei index.jsp welche im Beispiel 5.3: "Inhalt von /src/main/webapp/index.jsp" aufgelistet wird. Example 5.3. Inhalt von /src/main/webapp/index.jsp
<html> <body> <h2>Hello World!</h2> </body> </html>

Unter /src/main/webapp/WEB-INF finden Sie den kleinsten mglichen Web-Applikations Beschrieb; der web.xml. Example 5.4. Inhalt von src/main/webapp/WEB-INF/web.xml
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> </web-app>

95

Eine einfache Web-Anwendung

5.5. Das Hinzufgen eines einfachen Servlets


Eine Web-Applikation mit einer einzigen JSP-Seite und keinen konfigurierten Servlets ist so gut wie nutzlos. Lassen Sie uns ein einfaches Servlet hinzufgen und die entsprechenden nderungen in der pom.xml- sowie der web.xml-Datei vornehmen. Zu Beginn mssen wir ein neues Package namens com.sonatype.maven.web im Verzeichnis /src/main/java erstellen
$ mkdir -p src/main/java/org/sonatype/mavenbook/web $ cd src/main/java/org/sonatype/mavenbook/web

Sobald Sie dieses Package kreiert haben, wechseln Sie in das Verzeichnis (/src/main/java/com/sonatype/maven/web) und erstellen Sie eine Klasse SimpleServlet in einer Datei SimpleServlet.java, welche den folgenden Quellcode enthlt. Example 5.5. SimpleServlet Klasse
package org.sonatype.mavenbook.web; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class SimpleServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println( "SimpleServlet Executed" ); out.flush(); out.close(); } }

Unsere Klasse SimpleServlet ist eben dies, ein einfaches Servlet, welches eine einfache Nachricht auf den responseWriter schreibt. Um dieses Servlet Ihrer Web-Anwendung hinzuzufgen und auf einen Anfragepfad abzubilden, fgen Sie die folgenden Servlet-und Servlet-Mapping-Elemente zu Ihrer Projekt 96

Eine einfache Web-Anwendung web.xml-Datei an. Die web.xml-Datei finden Sie unter /src/main/webapp/WEB-INF. Example 5.6. Mapping the Simple Servlet
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>simple</servlet-name> <servlet-class>org.sonatype.mavenbook.web.SimpleServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>simple</servlet-name> <url-pattern>/simple</url-pattern> </servlet-mapping> </web-app>

Nun ist alles vorhanden, um das Servlet zu testen, die Klasse befindet sich unter /src/main/java und die web.xml-Datei wurde aktualisiert. Bevor wir das Jetty-Plugin starten, kompilieren Sie Ihr Projekt, durch den Aufruf von mvn compile:
~/examples$ mvn compile ... [INFO] [compiler:compile] [INFO] Compiling 1 source file to ~/examples/ch05/simple-webapp/target/classes [INFO] -----------------------------------------------------------------------[ERROR] BUILD FAILURE [INFO] -----------------------------------------------------------------------[INFO] Compilation failure /src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[4,0] \ package javax.servlet does not exist /src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[5,0] \ package javax.servlet.http does not exist /src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[7,35] \ cannot find symbol symbol: class HttpServlet public class SimpleServlet extends HttpServlet { /src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[8,22] \

97

Eine einfache Web-Anwendung


cannot find symbol symbol : class HttpServletRequest location: class org.sonatype.mavenbook.web.SimpleServlet /src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[9,22] \ cannot find symbol symbol : class HttpServletResponse location: class org.sonatype.mavenbook.web.SimpleServlet /src/main/java/org/sonatype/mavenbook/web/SimpleServlet.java:[10,15] \ cannot find symbol symbol : class ServletException location: class org.sonatype.mavenbook.web.SimpleServlet

Die Erstellung schlgt fehl, Ihr Maven-Projekt weist keine Abhngigkeit zum Servlet-API aus. Im nchsten Abschnitt werden wir diese hinzufgen und das Servlet-API in das Projekt POM eintragen.

5.6. Das Hinzufgen von J2EE-Abhngigkeiten


Um ein Servlet zu schreiben bentigen Sie die Servlet-API-Spezifikation. Um die Servlet-API-Spezifikation als eine Abhngigkeit zu Ihrem Projekt POM hinzuzufgen, fgen Sie das folgende dependency Element Ihrer pom.xml an. Example 5.7. Einfgen der Servlet-Spezifikation 2.4 als Abhngigkeit
<project> [...] <dependencies> [...] <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> </dependencies> [...] </project>

Es ist auch darauf hinzuweisen, dass wir fr diese Abhngigkeit den Geltungsbereich provided verwendet haben. Dies sagt Maven, dass das Archiv 98

Eine einfache Web-Anwendung seitens des Containers bereitgestellt wird, und nicht in das war-Archiv einfliessen soll. Wenn Sie daran interessiert waren, ein benutzerdefiniertes JSP-Tag fr dieses einfache Web-Anwendung zu erstellen, so bruchten Sie eine Abhngigkeit zur JSP-Spezifikation 2.0. Verwenden Sie die folgende Konfiguration, um diese Abhngigkeit zu schaffen. Example 5.8. Hinzufgen der 2.0 JSP-Spezifikation als Abhngigkeit
<project> [...] <dependencies> [...] <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies> [...] </project>

Sobald Sie die Servlet Spezifikationsimplementierung als Abhngigkeit hinzugefgt haben, fhren Sie mvn clean install gefolgt von mvn jetty:run aus.
[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 clean install jetty:run

jetty-6.1.6rc1 No Transaction manager found Started SelectChannelConnector@0.0.0.0:8080

An diesem Punkt sollten Sie in der Lage sein, die Ausgabe des SimpleServlet zu erhalten. Von der Befehlszeile knnen Sie mittels curl die Ausgabe des Servlet zur Standard-Ausgabe umleiten:
~/examples$ curl http://localhost:8080/simple-webapp/simple SimpleServlet Executed

99

Eine einfache Web-Anwendung

5.7. Zusammenfassung
Nach dem Lesen dieses Kapitels sollten Sie in der Lage sein eine einfache Web-Applikation zu erstellen. In diesem Kapitel wurde nicht nher auf die Millionen verschiedener Mglichkeiten eingegangen wie man eine komplette Web-Anwendung erschafft. Weitere Kapitel werden einen umfassenderen berblick ber Projekte geben, bei denen einige der populren Web-Frameworks und Technologien zum Einsatz kommen.

100

Chapter 6. Ein multi-modulares Projekt


6.1. Einleitung
In diesem Kapitel werden wir ein Multi-Modul Projekt erstellen, welches die Beispiele der beiden vorangegangenen Kapitel verbindet. Die "Simple Weather" Anwendung von Chapter 4, Anpassen eines Maven Projektes (Kapitel 4: "Anpassen eines Maven Projekts") wird verbunden mit der "Simple Web" Applikation von Chapter 5, Eine einfache Web-Anwendung (Kapitel 5: "Eine einfache Web-Anwendung"), mit dem Ergebnis einer Web Anwendung welche die Wetterdaten zu einer gegebenen Postleitzahl abruft und die Wettervorhersage auf einer Webseite darstellt. Am Ende dieses Kapitels werden Sie in der Lage sein, unter Verwendung von Maven komplexe, multi-modulare Projekte zu entwickeln.

6.1.1. Herunterladen der Beispiele dieses Kapitels


Das multi-modulare Projekt welches wir in diesem Kapitel erstellen werden, besteht aus modifizierten Versionen der Projekte der vorhergehenden Kapitel: 4 (Kapitel 4: "Anpassen eines Maven Projekts") sowie 5 (Kapitel 5: "Eine einfache Web-Anwendung"). Wir werden dieses multi-modulare Projekt nicht mit dem Archetype Maven Plugin generieren. Wir empfehlen Ihnen eine Kopie der Beispiel-Code als zustzliche Referenz beim Lesen der Inhalte in diesem Kapitel herunterzuladen. Das Beispielprojekt dieses Kapitels zusammen mit den anderen Beispielen aus diesem Buch kann von http://books.sonatype.com/maven-book/mvn-examples-1.0.zip oder http://books.sonatype.com/maven-book/mvn-examples-1.0.tar.gz heruntergeladen werden. Entpacken Sie das Archiv in ein beliebiges Verzeichnis, und gehen Sie dann zum Verzeichnis /ch06. Darin finden Sie ein Verzeichnis mit dem Namen /simple-parent welches das multi-modulare Projekt dieses Kapitels enthlt. Innerhalb des Verzeichnisses /simple-parent werden Sie auf eine pom.xml-Datei sowie zwei Unterverzeichnisse /simple weather und /simple web app stossen welche den Quellcode fr dieses Kapitel enthalten. 101

Ein multi-modulares Projekt

6.2. Das "Simple Parent" Projekt (parent=Elternteil)


Ein multi modulares Projekt wird durch ein "Eltern"-POM und dessen referenzierende Submodule definiert. Im Verzeichnis /simple-parent finden Sie die "Eltern" POM Datei pom.xml, auch das 'top-level' POM genannt, Example 6.1. simple-parent Projekt POM
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook.ch06</groupId> <artifactId>simple-parent</artifactId> <packaging>pom</packaging> <version>1.0</version> <name>Chapter 6 Simple Parent Project</name> <modules> <module>simple-weather</module> <module>simple-webapp</module> </modules> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</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>

102

Ein multi-modulares Projekt


</dependency> </dependencies> </project>

Wie Sie sehen, definiert das top-level POM die Maven Koordinaten groupId als com.sonatype.maven, artifactId als simple-parent und version als 1.0. Das top level POM definiert keinen Ausgabetyp JAR- oder WAR-Archiv wie das bislang der Fall, sondern bezieht sich auf andere Maven Projekte. Das entsprechende Element package eines top level POM welches lediglich ein Projekt Objekt Modell darstellt, ist 'pom'. Der nchste Abschnitt in der pom.xml-Datei fhrt die Sub-Module auf. Diese Module werden im Element module aufgefhrt, und befinden sich je in einem eigenen Unterverzeichnis. Maven kennt diese Struktur und sucht in den Unterverzeichnissen nach weiteren pom.xml-Dateien. Diese werden dann in die Liste der Maven Projekte des Builds aufgenommen. Zuletzt setzen wir eine Anzahl Einstellungen welche von allen Untermodulen geerbt werden. Das "Simple Parent" Modul setzt die Zielplattform aller Untermodule als Java 5 Plattform. Da das Compiler-Plugin standardmssig an den Lebenszyklus gekettet ist, knnen wir den Abschnitt pluginManagement hierzu benutzen. Wir werden pluginManagement spter im Detail beleuchten, fr den Moment ist es einfacher, diese Trennung zwischen Bereitstellung von Plugin Standard-Konfigurationen und dem tatschlichen 'binden' der Plugins darzustellen wenn sie auf diese Weise getrennt werden. Das Element dependency fgt als globale Abhngigkeiten JUnit 3.8.1 ein. Sowohl die Konfiguration sowie die Abhngigkeiten werden von allen Untermodulen geerbt. Der Einsatz der POM Vererbung erlaubt es Ihnen, gemeinsam genutzte Abhngigkeiten, wie z.B. JUnit oder Log4J, universell zu definieren.

6.3. Das "Simple Weather" Modul


Das erste Untermodul welches wir uns genauer ansehen wollen, ist das Untermodul "Simple Weather". Dieses Modul enthlt alle Klassen, welche zum Abrufen und Verarbeiten des Yahoo! Wetterdienstes bentigt werden. 103

Ein multi-modulares Projekt Example 6.2. POM des Untermodul "Simple-Weather"


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch06</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-weather</artifactId> <packaging>jar</packaging> <name>Chapter 6 Simple Weather API</name> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> </plugins> </pluginManagement> </build> <dependencies> <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>velocity</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency>

104

Ein multi-modulares Projekt


<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> <scope>test</scope> </dependency> </dependencies> </project>

Im POM des Moduls "Simple Weather" sehen wir, wie dieses Modul die elterlichen Koordinaten in Form von Maven Koordianten referenziert. Das elterliche POM enthielt die Koordinaten groupId com.sonatype.maven, artifactId simple-parent sowie version 1.0 Beachten Sie hier, dass wir weder die Koordinate groupID noch version definieren mssen, diese sind bereits im "elterlichen" POM definiert. Example 6.3. Die Klasse WeatherService
package org.sonatype.mavenbook.weather; import java.io.InputStream; 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 ); } }

Die Klasse WeatherService ist unter definiert, und ruft lediglich die drei in Chapter 4, Anpassen eines Maven Projektes (Kapitel 4: "Anpassen eines Maven Projekts") definierten Objekte auf. Im Beispiel dieses Kapitels, erstellen
/src/main/java/de/sonatype/Maven/Weather

105

Ein multi-modulares Projekt wir ein separates Projekt, welches Service-Objekte bereitstellt, die vom Web-Applikations Projekt angesprochen werden. Dies ist ein gewhnliches Pattern von Enterprise Anwendungen. Oftmals besteht eine komplexe Anwendung aus weit mehr als einer einzigen (einfachen) Web-Applikation. Eine solche Anwendung knnte aus einer Reihe von Web Anwendungen sowie weiteren Befehlszeilenanwendungen bestehen. Sie werden in diesem Fall die gemeinsame Logik in einer Service Klasse zusammenfassen und fr eine Anzahl Projekte als Dienst bereitstellen. Dies gibt uns eine Rechtfertigung fr die Erstellung einer Klasse WeatherService. Sie knnen daran sehen, wie die "Simple Web" Anwendung auf die bereitgestellten Service Objekte welche in "Simple Weather" bereitgestellt werden zugreift. Die Methode retrieveForecast() hat einen Parameter Postleitzahl. Dieser wird an die Methode retrieve() der Klasse YahooRetriever gegeben, welche das entsprechende XML-Fragment beim Yahoo Wetter Dienst einholt. Das erhaltene XML wird an die Methode parse() bergeben, welche ein Objekt Weather zurckgibt. Das Objekt Weather wird dann in Form einer lesbaren, formatierten Zeichenkette ausgegeben.

6.4. Das "Simple-Web" Anwendungs-Modul


Das Untermodul "Simple Web" ist das zweite, referenzierte Sub-Modul des Projekts. Das darin enthaltene Web-Anwendungsprojekt ist vom Untermodul WeatherService abhngig und es enthlt einige einfache Servlets zur Prsentation der Ergebnisse der Yahoo! Wetterdienst Abfrage. Example 6.4. POM des Untermodul "Simple-Webapp"
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch06</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent>

106

Ein multi-modulares Projekt


<artifactId>simple-webapp</artifactId> <packaging>war</packaging> <name>simple-webapp Maven Webapp</name> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.sonatype.mavenbook.ch06</groupId> <artifactId>simple-weather</artifactId> <version>1.0</version> </dependency> </dependencies> <build> <finalName>simple-webapp</finalName> <plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins> </build> </project>

Das "Simple Web" Modul definiert ein einfaches Servlet, welches eine Postleitzahl aus einem HTTP-Request ausliest, den weatherService aus Example 6.3, Die Klasse WeatherService (Beispiel 6.3: "Die klasse WeatherService") aufruft, und das Resultat auf den Writer schreibt. Example 6.5. Simple-Webapp WeatherServlet
package org.sonatype.mavenbook.web; import import import import org.sonatype.mavenbook.weather.WeatherService; java.io.*; javax.servlet.*; javax.servlet.http.*;

public class WeatherServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String zip = request.getParameter("zip" ); WeatherService weatherService = new WeatherService();

107

Ein multi-modulares Projekt


PrintWriter out = response.getWriter(); try { out.println( weatherService.retrieveForecast( zip ) ); } catch( Exception e ) { out.println( "Error Retrieving Forecast: " + e.getMessage() ); } out.flush(); out.close(); } }

Im WeatherServlet, instanziieren wir die Klasse "SimpleWeather" des SimpleWeather Projekts. Die Postleitzahl welche in den Anfrage-Parametern bermittelt wird, geht an die Methode retrieveForecast(), der zurckgegebene Text wird auf den Writer geleitet. Schlussendlich besteht die web.xml-Datei der "Simple Web" Anwendung, welche unter /src/main/webapp/WEB-INF zu finden ist, und alles zusammenbindet. Die Servlet-und Servlet-Mapping-Elemente definieren hierbei einen Pfad von /weather auf das WeatherServlet. Example 6.6. web.xml der Simple-Webapp
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>simple</servlet-name> <servlet-class>org.sonatype.mavenbook.web.SimpleServlet</servlet-class> </servlet> <servlet> <servlet-name>weather</servlet-name> <servlet-class>org.sonatype.mavenbook.web.WeatherServlet</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>

108

Ein multi-modulares Projekt

6.5. Erstellung des Multi-Projekt-Moduls


Mit dem "Simple Weather" Projekt welches den allgemeinen Code zur Interaktion mit dem Yahoo! Wetterdienst erstellt, sowie der "Simple Web" Anwendung welche die Webanwendung in Form eines Servlets bereitstellt, es ist an der Zeit, zu Kompilieren und Packetieren, sowie Bereitstellen der Anwendung in Form eines WAR-Archivs. Um das zu bewerkstelligen, mssen Sie die beiden Projekte in der richtigen Reihenfolge kompilieren und installieren. Da "Simple Web" von "Simple Weather" abhngig ist, muss diese zuerst kompiliert werden und als JAR-Archive bereitgestellt werden. Tun Sie dies durch den Aufruf von mvn clean install aus dem Verzeichnis der Mutterapplikation heraus auf der Befehlszeile.
~/examples/ch06/simple-parent$ mvn clean install [INFO] Scanning for projects... [INFO] Reactor build order: [INFO] Simple Parent Project [INFO] simple-weather [INFO] simple-webapp Maven Webapp [INFO] ---------------------------------------------------------------------[INFO] Building simple-weather [INFO] task-segment: [clean, install] [INFO] ---------------------------------------------------------------------[...] [INFO] [install:install] [INFO] Installing simple-weather-1.0.jar to simple-weather-1.0.jar [INFO] ---------------------------------------------------------------------[INFO] Building simple-webapp Maven Webapp [INFO] task-segment: [clean, install] [INFO] ---------------------------------------------------------------------[...] [INFO] [install:install] [INFO] Installing simple-webapp.war to simple-webapp-1.0.war [INFO] [INFO] ---------------------------------------------------------------------[INFO] Reactor Summary: [INFO] ---------------------------------------------------------------------[INFO] Simple Parent Project ............................... SUCCESS [3.041s] [INFO] simple-weather ...................................... SUCCESS [4.802s] [INFO] simple-webapp Maven Webapp .......................... SUCCESS [3.065s] [INFO] ----------------------------------------------------------------------

Wenn Maven gegen ein Projekt mit Submodulen ausgefhrt wird, ldt Maven zunchst das hchststehende POM, dann lokalisiert es alle abhngigen POM-Dateien. Maven bringt alle Komponenten POM-Inhalte in das, was man den 109

Ein multi-modulares Projekt Maven Reaktor nennt, innerhalb werden die Komponenten POM auf deren Abhngigkeiten analysiert. Der Reaktor definiert die Reihenfolge der Komponenten und stellt deren Abarbeitung und Installation sicher. Note Der Reaktor wird die Reihenfolge der Module gem der Definition in der POM erhalten, soweit dies mglich ist. Eine hilfreiches mentales Modell hierfr ist das Bild, dass Module mit Abhngigkeiten von Geschwister-Projekten solange in der Reihenfolge "nach hinten" gerckt werden, bis deren Abhngigkeitsverhltnisse befriedigt sind. In seltenen Fllen kann es ntzlich sein, in die Reihenfolge der Module einzugreifen, - zum Beispiel, wenn Sie ein hufig instabiles Modul gegen Anfang des Build abarbeiten mchten. Nachdem der Reaktor ausgearbeitet hat, in in welcher Reihenfolge die Projekte abgearbeitet werden mssen, fhrt Maven die angegebenen Goals fr die jeweiligen Module des Multi-Moduls aus. In diesem Beispiel knnen Sie erkennen, wie Maven "Simple Weather" vor "Simple Web" stellt, und auf dem jeweiligem Modul einen Befehl mvn clean install abarbeitet. Note Beim Ausfhren von Maven von der Befehlszeile sollten Sie die Lebenszyklusphase clean vor allen anderen Phasen spezifizieren. Mit dem Aufruf von clean stellen Sie sicher, dass alle alten Output-Artefakte gelscht werden, vor die Anwendung kompiliert und paketiert wird. clean auszufhren ist nicht notwendig, aber es stellt sicher dass Sie einen "sauberen Build" erstellen.

6.6. Starten der Web-Anwendung


Nach der Installation des Multi-Modul-Projekts mittels mvn clean install aus dem Stammverzeichnis von "Simple Project" heraus, knnen Sie direkt in das 110

Ein multi-modulares Projekt Unterverzeichnis /Simple aufrufen:


Web wechseln

und dort das Goal run des Jetty Plugins

~/examples/ch06/simple-parent/simple-webapp $ mvn jetty:run [INFO] ---------------------------------------------------------------------[INFO] Building simple-webapp Maven Webapp [INFO] task-segment: [jetty:run] [INFO] ---------------------------------------------------------------------[...] [INFO] [jetty:run] [INFO] Configuring Jetty for project: simple-webapp Maven Webapp [...] [INFO] Webapp directory = ~/examples/ch06/simple-parent/\ simple-webapp/src/main/webapp [INFO] Starting jetty 6.1.6rc1 ... 2007-11-18 1:58:26.980::INFO: jetty-6.1.6rc1 2007-11-18 1:58:26.125::INFO: No Transaction manager found 2007-11-18 1:58:27.633::INFO: Started SelectChannelConnector@0.0.0.0:8080 [INFO] Started Jetty Server

Sobald Jetty mit dem Startvorgang abgeschlossen hat, laden Sie http://localhost:8080/simple-webapp/weather?zip=01201 in einen Browser und Sie sollten sehen, wie die Wettervorhersage formatiert ausgegeben wird.

111

Chapter 7. Multi-module Enterprise Project


7.1. Einleitung
In diesem Kapitel werden wir, aufbauend auf die Beispiele der Kapitel 6: Ein Multi-Projekt-Modul sowie Kapitel 5. Eine einfache Web-Anwendung, ein Multi-Modul-Projekt entwickeln. In dieses Beispiel werden wir das Spring Framework und auch Hibernate einbinden, um eine einfache Web-Anwendung und gleichzeitig ein einfaches Befehlszeilen-Dienstprogramm zum Lesen von Daten des Yahoo! Wetter Dienstes zu erstellen. Den Quellcode des "Simple Weather" Beispiels aus Chapter 4, Anpassen eines Maven Projektes (Kapitel 4: Anpassen eines Maven Projekts) werden wir mit dem Quellcode aus Chapter 5, Eine einfache Web-Anwendung (Kapitel 5: Eine einfache Web-Anwendung) kombinieren. Im Laufe der Entwicklung dieses Multi Modul Projekts werden wir Fragenstellungen bezglich des Einsatzes von Maven errtern und verschiedene Mglichkeiten der Umsetzung darlegen, um den Aufbau modularer Projekte zu frdern und die Wiederverwendung von Komponenten aufzuzeigen.

7.1.1. Herunterladen der Beispiele dieses Kapitels


Das multi-modulare Projekt welches wir in diesem Kapitel erstellen werden, besteht aus modifizierten Versionen der Projekte der vorhergehenden Kapitel; Chapter 4, Anpassen eines Maven Projektes (Kapitel 4: Anpassen eines Maven Projekts) sowie Chapter 5, Eine einfache Web-Anwendung (Kapitel 5: Eine einfache Web-Anwendung). Wir werden dieses multi-modulare Projekt nicht mit dem Archetype Maven Plugin generieren. Wir empfehlen Ihnen eine Kopie der Beispiel-Code als zustzliche Referenz beim Lesen der Inhalte in diesem Kapitel herunterzuladen. Das Beispielprojekt dieses Kapitel zusammen mit den anderen Beispielen dieses Buchs kann von http://www.sonatype.com/book/mvn-examples-1.0.zip oder http://books.sonatype.com/maven-book/mvn-examples-1.0.tar.gz heruntergeladen werden. Entpacken Sie das Archiv in ein beliebiges Verzeichnis, und gehen Sie 112

Multi-module Enterprise Project dann zum Verzeichnis /ch07. Darin finden Sie ein Verzeichnis mit dem Namen /simple-parent welches das multi modulare Projekt dieses Kapitels enthlt. Innerhalb des Verzeichnisses /simple-parent werden Sie auf eine pom.xml-Datei sowie zwei Unterverzeichnisse /simple weather und /simple web app stossen welche den Quellcode fr dieses Kapitel enthalten.

7.1.2. Multi-Modul Enterprise Projekt


Die Komplexitt einer extensiven Enterprise Applikation aufzuzeigen wrde den Rahmen dieses Buches bei weitem sprengen. Solche Projekte sind gekennzeichnet durch den Einsatz mehrerer Datenbanken, der Integration externer Systeme und Teilprojekte welche weiter z.B. nach Abteilungen aufgeteilt werden. Solcherlei Projekte beinhalten in der Regel tausende von Zeilen Quellcode, und reflektieren die Arbeit von Dutzenden oder Hunderten von Software-Entwicklern. Da ein solches Beispiel den Rahmen des Buches sprengen wrde, knnen wir Ihnen hier lediglich anhand eines Beispielprojekts die Komplexitten grerer Enterprise-Anwendungen aufzeigen. Im Abschluss geben wir einige Ratschlge der modularen Strukturierung welche ber dieses Kapitel hinausgehen. In diesem Kapitel wenden wir uns einem Multi Modul Projekt zu, welches zwei Benutzerschnittstellen definiert: ein Befehlszeilen-Abfrage-Tool fr die Yahoo! Wetter-Dienste, sowie eine Web-Anwendung welche auf diese Dienste aufbaut. Beide Anwendungen speichern die Resultate der Abfragen in einer eingebetteten Datenbank. Beide Anwendungen erlauben es dem Benutzer auf historisierte Abfragewerte der eingebetteten Datenbank zuzugreifen. Beide Anwendungen teilen sich die Anwendungslogik und auch eine Persistenz Bibliothek. Dieses Kapitel baut auf den Code zur Auswertung des Yahoo! Wetter Dienstes auf, welcher in Chapter 4, Anpassen eines Maven Projektes (Kapitel 4 Anpassen eines Maven Projekts) eingefhrt wurde. Dieses Projekt gliedert sich in fnf Untermodule wie in Figure 7.1, Beziehungen der Module einer komplexen Enterprise Anwendung (Abbildung 7.1: "Beziehungen der Module einer komplexen Enterprise Anwendung") veranschaulicht wird.

113

Multi-module Enterprise Project

Figure 7.1. Beziehungen der Module einer komplexen Enterprise Anwendung Aus Figure 7.1, Beziehungen der Module einer komplexen Enterprise Anwendung (Abbildung 7.1: "Beziehungen der Module einer komplexen Enterprise Anwendung") sehen Sie, dass es fnf Untermodule des "Eltern"-Projekt gibt. Diese sind: simple-model Dieses Modul definiert ein einfaches Objektmodell, welches die vom Yahoo! Wetter-Dienst zurckgegebenen Daten abbildet. Dieses Objektmodell beinhaltet die Objekte Weather, Condition, Atmosphere, Location und Wind (Wetterlage, Zustand, Atmosphre, Ort sowie Windrichtung). Beim parsen der vom Yahoo! Wetter Dienst zurckgegebenen XML-Antwort werden weather Objekte erstellt, welche an die Anwendung weitergegeben werden. Dieses Projekt beinhaltet Objekte welche mit Hibernate 3 Annotations versehen sind um die Zuordnung eines jeden Objektes zu einem Datensatz in der Datenbank sicherzustellen.

114

Multi-module Enterprise Project simple-weather Dieses Modul enthlt alle Logik welche erforderlich ist, um Daten des Yahoo! Wetter-Dienstes anzuziehen und das zurckgegebene XML auszuwerten. Aus dem zurckgegebenen XML werden anschliessend Objekte wie diese in "Simple Model" definiert wurden, erstellt. Das "Simple Weather"-Modul ist abhngig vom Modul "Simple Model". "Simple Weather" stellt einen Dienst bereit ("WeatherService"), welcher sowohl von "Simple Command" wie auch von "Simple Web" konsumiert wird. simple-persist Dieses Modul enthlt einige Data Access Objekte (DAO). Konfiguriert, um Weather Objekte in einer eingebetteten Datenbank abzuspeichern. Beide Benutzerschnittstellen dieser multi-modularen Anwendung (Web/Befehlszeile) bauen auf einfache DAOs (Data Access Objekts=Datenzugriffsobjekte) auf, welche zur Speicherung (speichern=to persist) herangezogen werden. Die Modellobjekte welche in "Simple Model" bereitgestellt werden, knnen von den DAOs sowohl verstanden wie auch zurckgegeben werden. "Simple Persist" ist direkt von "Simple Model" abhngig und definiert weitere Abhngigkeiten zu den Modellobjekten, gekennzeichnet durch Hibernate Annotations. simple-webapp Das Web-Anwendungs Projekt definiert zwei Spring MVC-Controller-Implementierungen welche unter Verwendung des WeatherService definiert werden, sowie die DAOs aus "Simple Persist". "Simple Web" verfgt ber eine direkte Abhngigkeit zu "Simple Weather" sowie eine transitive Abhngigkeit zu "Simple Model". simple-command Dieses Modul enthlt eine einfache Befehlszeilen-Anwendung welche dazu eingesetzt werden kann, die Yahoo! Wetter-Dienste abzufragen. Das Modul enthlt eine statisch definierte Klasse main() welche mit WeatherService aus "Simple Weather" sowie der DAOs welche in "Simple Persist" definiert wurden arbeitet. "Simple Command" hat eine direkte Abhngigkeit zu "Simple 115

Multi-module Enterprise Project sowie "Simple Persist"; es besteht eine transitive Abhngigkeit zu "Simple Model". Hiermit ist das Beispiel in diesem Kapitel vorgestellt; es ist einfach genug um es in einem Lehrbuch einzufhren, und doch komplex genug um eine Aufspaltung in fnf Untermodule zu rechtfertigen. Whrend unser knstliches Beispiel ein Modell-Projekt von fnf Klassen, eine Persistenz-Bibliothek mit zwei Service-Klassen und eine Parsing-Bibliothek mit fnf oder sechs Klassen hat, kann ein tatschliches "Reale-Welt-System" leicht ein Modell-Projekt mit hunderten von Klassen, mehrere Persistenz- und Service-Bibliotheken welche ber mehrere Bereiche reichen, umfassen. Whrend wir versucht haben sicherzustellen, dass der Quellcode des Beispiels einfach genug ist, um diesen in einer Sitzung zu verstehen, haben wir uns ebenso bemht ein modulares Beispiel zu erstellen. Es wre nachvollziehbar, wrden Sie nach der Betrachtung des Quellcodes, sich von Maven abwenden und den Eindruck mitnehmen, Maven ermuntere dazu Komplexitt einzufhren, da das Beispiel lediglich fnf Klassen umfasst. Jedoch sollten Sie immer bedenken, dass wir keine Mhen scheuten, das einfache Beispiel anzureichern, um die Mglichkeiten zur Bearbeitung komplexer Fragestellungen beispielhaft aufzuzeigen und darzustellen, insbesondere die von Maven gegebenen Multi-Modul-Funktionalitten.
Weather"

7.1.3. Technologie des Beispiels


Die in diesem Kapitel eingesetzten Technologien umfassen solche, welche zwar populr sind, aber nicht in direktem Zusammenhang mit dem Einsatz von Maven stehen. Die angedeuteten Technologien sind: das Spring Framework und Hibernate. Das Spring Framework stellt einen 'Inversion of Control (IoC) Container' bereit, sowie eine Reihe von Frameworks welche auf die Vereinfachung der Interaktion mit verschiedenen J2EE-Bibliotheken abzielen. Mit dem Spring Framework als Fundament der Anwendungsentwicklung erhalten Sie Zugriff auf eine Reihe von hilfreichen Abstraktionen, welche Ihnen einen Groteil der mhseligen Fummelei im Umgang mit z.B. Persistenz Frameworks wie Hibernate oder iBatis oder auch Enterprise-APIs wie JDBC, JNDI und JMS nehmen. Das Spring Framework hat in den vergangenen Jahren stark an Popularitt gewonnen, insbesondere als Alternative zu den schwergewichtigen Enterprise Standards aus 116

Multi-module Enterprise Project dem Hause Sun Microsystems. Hibernate ist ein weit verbreitetes Object-Relational-Mapping- (ORM-) Framework, das eine Interaktion mit relationalen Datenbanken bereitstellt, als ob es sich um eine Sammlung von Java-Objekten handele. Dieses Beispiel konzentriert sich auf den Aufbau einer einfachen Web-Anwendung und eines Befehlszeilen-Programms, welche, aufbauend auf das Spring Framework und Hibernate, eine Reihe von wiederverwendbaren Komponenten bereitstellt, welche es erlauben die bestehenden Wetter-Daten in einer eingebettete Datenbank abzulegen (persistieren). Wir haben uns entschlossen diese Frameworks einzubinden, um Ihnen am Beispiel aufzuzeigen, wie man beim Einsatz von Maven diese Technologien einbinden kann. Obschon es in das Kapitel eingestreut kurze Einfhrungen zu diesen Technologien gibt, so ist es nicht das erklrte Ziel dieses Kapitels diese Technologien im Detail darzustellen. Bezglich weiterfhrender Dokumentation dieser Frameworks verweisen wir: bezglich Spring auf die Projekt Website http://www.springframework.org, bezglich Hibernate auf den Projekt Website http://www.hibernate.org. Dieses Kapitel setzt als eingebettete Datenbank auf HSQLDB, weitere Informationen zu dieser Datenbank finden Sie auf der Projekt Website http://hsqldb.org.

7.2. Das "Simple Parent" Projekt - Top Level


Das "Simple Parent" Hauptmodul hat ein POM welches auf fnf Untermodule verweist: (simple-command), (simple-model), (simple-weather), (simple-persist) und (simple-webapp). Das Top-Level POM (pom.xml-Datei) ist im Example 7.1, Simple Parent POM Projekt (Beispiel 7.1, "Simple Parent POM Projekt") dargestellt. Example 7.1. Simple Parent POM Projekt
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion>

117

Multi-module Enterprise Project


<groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-parent</artifactId> <packaging>pom</packaging> <version>1.0</version> <name>Chapter 7 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>org.apache.maven.plugins</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 Sollten Sie bereits mit Maven POMs vertraut sein, so werden Sie jetzt bemerken, dass dieses top level POM kein Element dependencyManagement definiert. Das Element dependencyManagement erlaubt es Ihnen, Abhngigkeitsversionen in einem einzigen top-level POM zu definieren und wird in Chapter 8, Optimierung und 118

Multi-module Enterprise Project berarbeitung der POMs (Kapitel 8: Optimieren und Refaktorieren von POMs) eingefhrt. Bemerken Sie bitte die hnlichkeiten dieses Hauptmodul POMs zu jenem Hauptmodul POM des Projekts in Example 6.1, simple-parent Projekt POM (Kapitel 6.1: "Simple Parent Projekt POM"). Der einzige, wirkliche Unterschied zwischen diesen beiden POMs ist die Liste der Untermodule. Wo das vorangegangene Beispiel nur zwei Untermodule auffhrte, hat dieses Hauptmodul deren fnf. In den nchsten Abschnitten wird jedes dieser fnf Untermodule in einigen Details dargestellt. Da unsere Beispiel Java-Annotationen einsetzt, haben wir es so konfiguriert, dass der Compiler auf die Java 5 Virtual Machine (JVM) aufsetzt.

7.3. Das Simple Model" Modul - Das Objektmodell


Das erste, was die meisten Enterprise Projekte bentigen, ist ein Objekt-Modell. Ein Objekt-Modell erfasst die Grundmenge aller Domain-Objekte eines Systems. Ein Banken-System knnten ein Objekt-Modell haben, welches aus einem Konto, Kunden- und Transaktions-Objekt besteht, ein System zum Erfassen und Verbreiten von Sportergebnisse bessse ein Mannschafts- und ein Spiel-Objekt. Was auch immer Ihr Projekt umfasst, die Chancen stehen gut, dass Sie die entsprechenden Konzepte Ihres Systems in einem Objekt-Modell erfasst haben. Eine gngige Praxis im Umgang mit Maven ist es, dieses Modul separate auszulagern um es fortan als hufig referenziertes Modul weiterzufhren. In unserem System erfassen wir jede Abfrage des Yahoo! Wetter-Dienstes mit einem Objekt, das Objekt weather, welches weitere vier Objekte referenziert: Windrichtung, Chill und Geschwindigkeit werden in einem Objekt Wind erfasst. Standortdaten einschlielich der Postleitzahl, Stadt, Region und Land sind in einer Klasse Location zusammengefasst. Die atmosphrischen Bedingungen wie die Feuchtigkeit, maximale Sichtbarkeit, Luftdruck, und ob der Druck steigt oder fllt, wird in einer Klasse Atmosphere gehalten. Eine textuelle Beschreibung der 119

Multi-module Enterprise Project Zustnde, der Temperatur, und die Daten der Beobachtung werden einer Klasse Condition zusammengefasst.

Figure 7.2. Einfaches Objektmodell fr Wetter-Daten Die pom.xml-Datei fr dieses schlichte Modell hat nur eine Abhngigkeitsdefinition welche der Erluterung bedarf: Unser Objekt-Modell wird mit Hibernate Annotations realisiert. Wir verwenden Annotations um die Modell-Objekte auf Tabellen einer relationalen Datenbank abzubilden. Die Abhngigkeit besteht zu org.hibernate: hibernate-annotaions: 3.3.0.ga. Werfen Sie einen Blick in diese pom.xml sowie einige der kommenden Beispiele worin dies verdeutlicht wird: Example 7.2. pom.xml des Projektmoduls: simple-model
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-parent</artifactId>

120

Multi-module Enterprise Project


<version>1.0</version> </parent> <artifactId>simple-model</artifactId> <packaging>jar</packaging> <name>Simple Object Model</name> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.0.ga</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>3.3.0.ga</version> </dependency> </dependencies> </project>

Unter /src/main/java/de/sonatype/Maven/weather/model liegt Weather.java welche das annotierte Wetter-Objekt-Modell beinhaltet. Das Weather-Objekt ist ein einfaches Java Bean. Das bedeutet, es werden private Member Variablen gesetzt (id, location, condition, wind, amosphere und date) welche durch public Getter und Setter-Methoden offengelegt werden. Dabei wird folgende Regel umgesetzt: gibt es ein String-Property mit dem Namen "name" so wird eine public Getter-Methode ohne Argumente namens getName() gesetzt, sowie eine public Setter Methode mit einem Argument setName(String name); analog fr andere Typen. Whrend wir hier die Getter und Setter-Methode fr das id-Property zeigen, haben wir die Mehrheit der anderen Properties ausgelassen um an dieser Stelle einer Anzahl Bume das Leben zu wahren.

Example 7.3. Annotiertes Wetter Modell Objekt


package org.sonatype.mavenbook.weather.model; import javax.persistence.*; import java.util.Date; @Entity @NamedQueries({ @NamedQuery(name="Weather.byLocation",

121

Multi-module Enterprise Project


query="from Weather w where w.location = :location") }) public class Weather { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; @ManyToOne(cascade=CascadeType.ALL) private Location location; @OneToOne(mappedBy="weather",cascade=CascadeType.ALL) private Condition condition; @OneToOne(mappedBy="weather",cascade=CascadeType.ALL) private Wind wind; @OneToOne(mappedBy="weather",cascade=CascadeType.ALL) private Atmosphere atmosphere; private Date date; public Weather() {} public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } // Alle weiteren getter/setter Methoden ausgelassen... }

In der Klasse Weather, setzen wir auf Hibernate Annotationen, um dem "simple persist" Projekt Anleitung zu geben. Diese Annotationen werden von Hibernate benutzt, um ein Objekt auf eine Tabelle einer relationalen Datenbank abzubilden. Whrend eine ausfhrliche Einfhrung in die Hibernate Annotationen weit ber den Rahmen dieses Kapitels hinausgeht, hier eine kurze Erklrung fr Neugierige: Die Annotation @Entity bezeichnet diese Klasse als zu persistierende Einheit, die @Table Annotation haben wir ausgelassen, Hibernate wird daher den Klassennamen als Tabellennamen einsetzen und so das Objekt Weather auf eine Tabelle Weather abbilden. Die @NamedQueries Annotation definiert eine Abfrage, welche vom WeatherDAO aus dem "Simple Persist" Projekt verwendet wird. Die Abfragesprache, welche von der @NamedQuery Annotation benutzt wird ist Hibernate Query Language (HQL). Jede Variable wird mit Annotationen versehen welche den Typ, die Spalte sowie jegliche Beziehungen der Spalte zu anderen 122

Multi-module Enterprise Project Spalten definiert:


Id

Das Property id wird mit @Id gekennzeichnet. Dies zeichnet das Property id als das Property aus, welches den Primrschlssel bezglich der Tabelle in der Datenbank trgt. Die Kennzeichnung @GeneratedValue bestimmt wie neue Primrschlssel generiert werden. Im Falle von id, bestimmen wir den GenerationType IDENTITY, welcher auf die Verwendung des Datenbank eigenen Generierungsalgoryhtmus aufsetzt.
Location

Jede Instanz eines Wetter-Objekts (Weather) ist an eine Instanz eines Standort Objekts (Location) gebunden. Ein Standort Objekt reprsentiert eine Postleitzahl und die Kennzeichnung @ManyToOne stellt sicher, dass Wetter-Objekte, welche an den selben Standort gebunden sind auch auf dieselbe Instanz zeigen. Das Attribut cascade der Annotation @ManyToOne stellt sicher, dass wir bei jedem persistieren des Wetter Objekts auch das zugehrige Standort Objekt persistieren.
Condition, Wind, Atmosphere

Jedes dieser Objekte wird mit einer Kennzeichnung von @OneToOne und dem CascadeType ALL abgebildet. Dies bedeutet, dass jedes Mal, wenn wir ein Wetter-Objekt speichern, eine Zeile in der Tabelle Weather, aber auch in den Tabellen Condition, Wind und Atmosphere erzeugt wird.
Date

Das Property date ist nicht annotiert, das bedeutet, dass Hibernate in Bezug auf die Spalten alle Standardwerte benutzt um diese Zuordung zu definieren. Der Spaltenname wird als date gesetzt, und der Datentyp der Spalte auf den entsprechenden Typ um dem date-Objekt zu entsprechen. Note Sollten Sie ein Property in der Abbildung nicht bercksichtingen, so wrden Sie dieses Property mit @Transient annotieren.

123

Multi-module Enterprise Project Next, take a look at one of the secondary model objects, Condition, shown in Example 7.4, 'Condition' Modell Objekt des Projektes "simple-model". This class also resides in src/main/java/org/sonatype/mavenbook/weather/model. Als nchstes, schauen Sie sich das weiterfhrende Objekt Modell Condition an. Diese Klasse ist ebenfalls unter /src/main/java/de/sonatype/maven/weather/model abgelegt. Example 7.4. 'Condition' Modell Objekt des Projektes "simple-model"
package org.sonatype.mavenbook.weather.model; import javax.persistence.*; @Entity public class Condition { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; private private private private String String String String text; code; temp; date;

@OneToOne(cascade=CascadeType.ALL) @JoinColumn(name="weather_id", nullable=false) private Weather weather; public Condition() {} public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } // Alle weiteren getter/setter Methoden ausgelassen... }

Die Klasse Condition entspricht der Klasse weather. Sie wird mit @Entity annotiert, und hat eine gleichartige Kennzeichnung des Properties id. Die Properties text, code, temp sowie date werden alle auf Standardwerten belassen, das Property weather ist mit der Kennzeichnung @OneToOne versehen sowie einer weiteren Annotation welche das entsprechende Objekt Weather mit dem Fremdschlssel des Namens weather_id in Verbindung bringt. 124

Multi-module Enterprise Project

7.4. Das "Simple Weather" Modul - Die Dienste


Das nchste Modul welches wir betrachten werden, ist so etwas wie ein "Dienst". Das "Simple Weather" Modul ist das Modul, das alle fr den Abruf und die Analyse der Daten vom Yahoo! Wetter Dienst notwendige Logik enthlt. Obwohl das "Simple Weather" Modul aus drei Java-Klassen und einem JUnit-Test besteht, stellt es eine einzige Komponente WeatherService, dar. Dieser wird sowohl durch "Simple Web" der Webapplikation, und auch "Simple Command" konsumiert. Hufig enthalten Enterprise Projekte ein oder mehrere API-Module welche kritische Business-Logik oder Logik zur Interaktion mit externen Systemen beinhalten. Ein Banken System knnten ein Modul beinhalten, welches Daten eines externen Providers abruft und analysiert; ein System zur Anzeige von Sportergebnisse knnte einen XML-Datenstrom verarbeiten um in Echtzeit die Ergebnisse von Basketball oder Fuball darzustellen. In unserem Beispiel kapselt dieses Modul alle notwendigen Netzwerk-Aktivitten sowie das XML-Parsing zur Interaktion mit dem Yahoo! Wetter Dienst. Andere Module knnen auf dieses Modul aufbauen, Sie rufen einfach die Methode retrieveForecast() der Klasse WeatherService auf. Diese nimmt als Argument eine Postleitzahl und liefert ein Weather-Objekt zurck. Example 7.5. POM des simple-weather Moduls
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-weather</artifactId> <packaging>jar</packaging> <name>Simple Weather API</name> <dependencies> <dependency> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-model</artifactId>

125

Multi-module Enterprise Project


<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>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> <scope>test</scope> </dependency> </dependencies> </project>

Das "Simple Weather" POM erweitert das darberliegende (elterliche) POM, setzt das Packaging auf jar und fgt die folgenden Abhngigkeiten ein:
org.sonatype.mavenbook.ch07:simple-model:1.0

"Simple-Weather" analysiert den Yahoo! Wetter Dienst (RSS) und verpackt dieses in ein Objekt Weather. Es verfgt ber eine direkte Abhngigkeit zum "Simple Model" Modul.
log4j:log4j:1.2.14

"Simple Weather" setzt auf die Bibliothek Log4J zum Ausgeben von Log-Nachrichten auf.
dom4j:dom4j:1.6.1 and jaxen:jaxen:1.1.1

Diese Beide Abhngigkeiten sind notwendig um das vom Yahoo! Wetter Dienst zurckgegebene XML zu verarbeiten.

126

Multi-module Enterprise Project


org.apache.commons:commons-io:1.3.2 (scope=test)

Diese Abhngigkeit mit Gltigkeitsbereich test wird von der Klasse YahooParserTest bentigt. Next is the WeatherService class, shown in Example 7.6, Die Klasse WeatherService. This class is going to look very similar to the WeatherService class from Example 6.3, Die Klasse WeatherService. Although the WeatherService is the same, there are some subtle differences in this chapters example. This versions retrieveForecast() method returns a Weather object, and the formatting is going to be left to the applications that call WeatherService. The other major change is that the YahooRetriever and YahooParser are both bean properties of the WeatherService bean. Als nchstes betrachten wir die Klasse WeatherService (Example 7.6, Die Klasse WeatherService), diese Klasse ist sehr hnlich zur Klasse WeatherService aus Example 6.3, Die Klasse WeatherService (Beispiel 6.3: Die WeatherService Klasse). Whrend die Klasse WeatherService die Gleiche ist, gibt es in diesem Kapitel einige subtile Unterschiede des Beispiels zu beachten. Diese Version der Methode retrieveForecast() liefert ein Objekt Weather zurck und berlsst die Formatierung der aufrufenden Anwendungen. Die andere groe nderung ist, dass die Klassen YahooRetriever und YahooParser beide Bean Properties des Beans WeatherService sind. Example 7.6. Die Klasse WeatherService
package org.sonatype.mavenbook.weather; import java.io.InputStream; import org.sonatype.mavenbook.weather.model.Weather; public class WeatherService { private YahooRetriever yahooRetriever; private YahooParser yahooParser; public WeatherService() {} public Weather retrieveForecast(String zip) throws Exception { // Daten holen InputStream dataIn = yahooRetriever.retrieve(zip);

127

Multi-module Enterprise Project


// Daten auswerten Weather weather = yahooParser.parse(zip, dataIn); return weather; } public YahooRetriever getYahooRetriever() { return yahooRetriever; } public void setYahooRetriever(YahooRetriever yahooRetriever) { this.yahooRetriever = yahooRetriever; } public YahooParser getYahooParser() { return yahooParser; } public void setYahooParser(YahooParser yahooParser) { this.yahooParser = yahooParser; } }

Schlussendlich haben wir in diesem Projekt eine XML-Datei. Diese wird vom Spring Framework benutzt, um den so genannten ApplicationContext zu erstellen. Zunchst einige Erluterungen: unsere beiden Anwendungen, die Web-Anwendung und das Befehlszeilen-Dienstprogramm, mssen mit der Klasse WeatherService interagieren. Sie tun dies indem sie aus dem Spring ApplicationContext eine Instanz der Klasse mit dem Namen WeatherService holen. Unsere Web-Applikation, verwendet einen Spring MVC-Controller welcher einer Instanz des WeatherService zugeordnet ist, und unsere Dienstprogramm ldt die Klasse WeatherService von einem Spring ApplicationContext in einer statischen Methode main(). Um die Wiederverwendbarkeit zu frdern, haben wir unter /src/main/resources eine Datei applicationContext-weather.xml beigefgt, welche im Klassenpfad zur Verfgung steht. Module, welche eine Abhngigkeit zum "Simple Weather" Modul haben, knnen diesen Context mit dem ClasspathXmlApplicationContext des Spring Framework laden. Hierauf knnen Sie auf eine benannte Instanz der Klasse WeatherService namens weatherService zugreifen.

128

Multi-module Enterprise Project Example 7.7. Spring Application Context fdes simple-weather Moduls
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd default-lazy-init="true"> <bean id="weatherService" class="org.sonatype.mavenbook.weather.WeatherService"> <property name="yahooRetriever" ref="yahooRetriever"/> <property name="yahooParser" ref="yahooParser"/> </bean> <bean id="yahooRetriever" class="org.sonatype.mavenbook.weather.YahooRetriever"/> <bean id="yahooParser" class="org.sonatype.mavenbook.weather.YahooParser"/> </beans>

Diese Konfiguration definiert drei Beans: yahooParser, yahooRetriever und weatherService. Das Bean weatherService ist eine Instanz von WeatherService, und das XML-Dokument belegt die Properties yahooParser und yahooRetriever mit Verweisen auf benannten Instanzen der entsprechenden Klassen. Sehen Sie in der Datei applicationContext-weather.xml die Definition der Architektur eines Teilsystems in diesem Multi-Modul-Projekt. Projekte wie "Simple Web" oder "Simple Command" knnen diesen Context referenzieren, und somit eine Instanz des WeatherService abrufen welcher bereits in Bezug zu Instanzen von YahooRetriever und YahooParser steht.

7.5. Das "Simple Persist" Modul - Die Datenabstraktion


Dieses Modul definiert zwei sehr einfache Daten Zugriffsobjekte (Data Access Objects: DAO). Ein DAO ist ein Objekt, das eine Schnittstelle fr die Persistenz bereitstellt. 129

Multi-module Enterprise Project Note Warum Persistenz und nicht Speicherung? Persistenz ist der allgemeine Begriff, whrend Speicherung sich hinlnglich auf ein lokales Medium bezieht, was in keinem Fall gegeben sein muss. In einer Anwendung welche auf Object-Relational-Mapping (ORM) Werkzeuge wie Hibernate zur Abbildung aufbaut, werden in der Regel DAOs um die zu persistierenden Objekte erstellt. In diesem Projekt definieren wir zwei DAO-Objekte: WeatherDAO und LocationDAO. Die Klasse WeatherDAO erlaubt es uns, Wetter-Objekte in einer Datenbank abzuspeichern bzw. Wetter-Objekte anhand eines Schlssels (weatherId) oder auch zu einem bestimmten Standort abzurufen. Das LocationDAO besitzt eine Methode, welche es uns erlaubt zu einer gegebenen Postleitzahl das entspreche Standort-Objekt zu holen. Lassen Sie uns einen Blick auf die "Simple Persist" POM werfen: Example 7.8. POM des "simple-persist" Moduls
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch07</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>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-model</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.2.5.ga</version>

130

Multi-module Enterprise Project


<exclusions> <exclusion> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.0.ga</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>3.3.0.ga</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> </dependencies> </project>

Diese POM-Datei referenziert "Simple Parent" als darberliegendes, elterliches POM, sowie eine Anzahl Abhngigkeiten. Im Rahmen des "Simple Persist" Moduls sind diese:
org.sonatype.mavenbook.ch07:simple-model:1.0

Genau wie bereits im "Simple Weather" Modul, wird hier eine Abhngigkeit zum grundlegenden Objekt Modell wie es in "Simple Model" definiert ist, beschrieben.
org.hibernate:hibernate:3.2.5.ga

Wir definieren eine Abhngigkeit zu Hibernate Version 3.2.5.ga, aber wie Sie richtig bemerkt haben, wird eine (transitive) Abhngigkeit von Hibernate ausgeschlossen. Wir tun dies, da die Abhngigkeit javax.transaction:javax 131

Multi-module Enterprise Project nicht im ffentlichen Maven-Repository verfgbar ist. Diese Abhngigkeit ist eine dieser Abhngigkeiten zu Sun Microsystems Quellcode, welche es noch nicht in die freien zentralen Maven-Repositories geschafft hat. Um zu verhindern, dass ein immer eine rgerlicher Meldung uns auf den notwendigen Download dieser (unfreien) Abhngigkeit hinweist, schliessen wir diese einfach aus, und fgen eine neue Abhngigkeit hinzu ...
javax.servlet:servlet-api:2.4

Da das Projekt ein Servlet beinhaltet, mssen wir das Servlet API version 2.4 einschliessen.
org.springframework:spring:2.0.7

Dies umfasst das gesamte Spring Framework als Abhngigkeit . Note Es ist generell besser, eine Abhngigkeit zu den Komponenten von Spring zu definieren, zu denen diese tatschlich besteht. Das Spring Framework-Projekt kommt Ihnen hier sehr entgegen, indem es genau definierende Artefakte wie z.B. spring-hibernate3 erschaffen hat.) Warum sich von Spring abhngig machen? Bei der Integration von Hibernate, erlaubt uns der Einsatz von Spring Helfer-Klassen wie die Klasse HibernateDaoSupport auszuntzen. Um Ihnen ein Beispiel dafr zu geben, was unter Einsatz des HibernateDaoSupport mglich ist, werfen Sie einen Blick auf den Quellcode fr das WeatherDAO: Example 7.9. WeatherDAO Klasse des "simple persist" Moduls
package org.sonatype.mavenbook.weather.persist; import java.util.ArrayList; import java.util.List; import import import import org.hibernate.Query; org.hibernate.Session; org.springframework.orm.hibernate3.HibernateCallback; org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import org.sonatype.mavenbook.weather.model.Location;

132

Multi-module Enterprise Project


import org.sonatype.mavenbook.weather.model.Weather; public class WeatherDAO extends HibernateDaoSupport# { public WeatherDAO() {} public void save(Weather weather) {# getHibernateTemplate().save( weather ); } public Weather load(Integer id) {# return (Weather) getHibernateTemplate().load( Weather.class, 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("Weather.byLocation"); query.setParameter("location", location); return new ArrayList<Weather>( query.list() ); } }); } }

Das ist alles! Nein wirklich, das ist die gesamte Klasse mit welcher Sie neue Zeilen einfgen, anhand von Primrschlsseln Werte suchen, oder auch alle Zeilen in der Weather-Tabelle finden welche eine Referenz auf einen Ort setzen. Sie werden verstehen, dass wir an dieser Stelle nicht einfach das Buch schliessen knnen um die notwendigen fnfhundert Seiten Erklrung der Feinheiten des Hibernate Frameworks einzuschieben, aber was wir tun knnen ist, Ihnen ein paar kurze Erklrungen geben: Die Klasse leitet sich von HibernateDaoSupport ab. Das bedeutet, dass die Klasse mit einer Hibernate SessionFactory verbunden ist, welche zum Einsatz kommt Hibernate Session Objekte zu erstellen. In Hibernate wird jeder Aufruf ber ein Session-Objekt ausgefhrt. Eine Session vermittelt Zugang zu der zugrunde liegenden Datenbank und kmmert sich um die Verwaltung der Verbindung zur JDBC-Datenquelle. Die Erweiterung von HibernateDaoSupport bedeutet auch, dass wir Zugriff auf 133

Multi-module Enterprise Project mittels getHibernateTemplate() haben. Um Ihnen ein Beispiel davon zu geben, was mit HibernateTemplates mglich ist ... ...die Methode save() nimmt sich einer Instanz eines Wetter Objekts an, und ruft die Methode save() eines HibernateTemplate auf. Das HibernateTemplate verwandelt den Aufruf in einfache Hibernate Operationen um, und wandelt jegliche Datenbank spezifische Exeptions in entsprechende Runtime-Exceptions um. In diesem Fall rufen wir save() auf, um einen Datensatz in der Datenbank, in der Tabelle Weather abzulegen. Alternativen zu diesem Aufruf wren update() sollten wir einen Eintrag aktualisieren, oder saveOrUpdate(), welches den Datensatz entweder anlegt oder aktualisiert, abhngig von der Anwesenheit eines Properties id des Objekts Weather, das nicht Null sein darf. Die Methode load() ist ein weiterer Einzeiler, welcher lediglich eine Methode einer Instanz des HibernateTemplates aufruft. Die Methode load() des HibernateTemplates hat zwei Parameter eine Klasse sowie eine serialisierbares Objekt. In diesem Fall entspricht das serialisierbare Objekt dem Wert der id des Objekts Weather welches geladen werden soll. Diese letzte Methode recentForLocation() beruft sich auf ein NamedQuery das im Wetter-Objekt-Modell festgelegt wurde. Sollten Sie sich erinnern, wir haben im Wetter-Objekt-Modell eine Abfrage "Weather.byLocation" in der Form "from Weather w where w.location = :location" definiert. Wir Laden dieses NamedQuery mit einem Verweis auf ein Hibernate Session-Objekt in einem HibernateCallback der ausgefhrt wird, indem die Methode execute() eines HibernateTemplate aufgerufen wird. In dieser Methode sehen Sie, wie wir die benannten Parameter mit dem Parameter des Aufrufs der Methode recentForLocation() bevlkern. Now is a good time for some clarification. HibernateDaoSupport and HibernateTemplate are classes from the Spring Framework. They were created by the Spring Framework to make writing Hibernate DAO objects painless. To support this DAO, well need to do some configuration in the simple-persist Spring ApplicationContext definition. The XML document shown in Example 7.10, Spring Application Context Definition fr das "simple-persist" Modul is stored in src/main/resources in a file named applicationContext-persist.xml.
HibernateTemplates

134

Multi-module Enterprise Project Es ist an der Zeit fr einige Klarstellungen: HibernateDaoSupport und HibernateTemplate sind Klassen des Spring Framework. Sie wurden von den Entwicklern des Spring Framework bereitgestellt, um das Bearbeiten von Hibernate DAO-Objekte schmerzloser zu gestalten. Um dieses DAO zu untersttzen, mssen wir noch einige wenige Einstellungen in der Definition des Spring ApplicationContext von "Simple Persist" vornehmen. Das folgende XML-Dokument ist unter /src/main/resources in einer Datei mit dem Namen applicationContext-persist.xml abgelegt. Example 7.10. Spring Application Context Definition fr das "simple-persist" Modul
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" default-lazy-init="true"> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="annotatedClasses"> <list> <value>org.sonatype.mavenbook.weather.model.Atmosphere</value> <value>org.sonatype.mavenbook.weather.model.Condition</value> <value>org.sonatype.mavenbook.weather.model.Location</value> <value>org.sonatype.mavenbook.weather.model.Weather</value> <value>org.sonatype.mavenbook.weather.model.Wind</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.transaction.factory_class"> org.hibernate.transaction.JDBCTransactionFactory </prop> <prop key="hibernate.dialect"> org.hibernate.dialect.HSQLDialect </prop> <prop key="hibernate.connection.pool_size">0</prop> <prop key="hibernate.connection.driver_class"> org.hsqldb.jdbcDriver </prop> <prop key="hibernate.connection.url"> jdbc:hsqldb:data/weather;shutdown=true </prop> <prop key="hibernate.connection.username">sa</prop>

135

Multi-module Enterprise Project


<prop key="hibernate.connection.password"></prop> <prop key="hibernate.connection.autocommit">true</prop> <prop key="hibernate.jdbc.batch_size">0</prop> </props> </property> </bean> <bean id="locationDAO" class="org.sonatype.mavenbook.weather.persist.LocationDAO"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="weatherDAO" class="org.sonatype.mavenbook.weather.persist.WeatherDAO"> <property name="sessionFactory" ref="sessionFactory"/> </bean> </beans>

Dieser ApplicationContext erreicht eine Anzahl verschiedener Dinge: zunchst wird ein SessionFactory Bean bereitgestellt, ein Bean von welchem die DAOs die Hibernate Session Objekte beziehen. Dieses Bean ist eine Instanz des AnnotatedServiceFactoryBean und wird mit einer Anzahl annotatedClasses bereitgestellt. Hier sei bemerkt, dass die Liste der bereitgestellten annotierten Klassen die Liste der Klassen darstellt, welche in unserem Modul "Simple Model" definiert wurden. Als nchstes wird die sessionFactory entsprechend einer Reihe von Hibernate Konfigurationseigenschaften (hibernateProperties) konfiguriert. In diesem Beispiel definieren die HibernateProperties eine Reihe von Einstellungen:
hibernate.dialect

Diese Einstellung definiert, welcher SQL-Dialekt fr unsere Datenbank generiert wird. Da wir als Datenbank HSQLDB einsetzen, ist der gewhlte Datenbank Dialekt org.hibernate.dialect.HSQLDialect. Hibernate untersttzt die SQL-Dialekte aller wichtigen Datenbank Systeme wie Oracle, MySQL, PostgreSQL und SQL Server.
hibernate.connection.*

In diesem Beispiel werden die JDBC-Verbindungsparameter aus der Spring Konfiguration heraus gesetzt. Unsere Anwendungen sind so konfiguriert, dass sie gegen eine HSQLDB unter dem Verzeichnis ./data/weather arbeiten. In 136

Multi-module Enterprise Project einer echten Enterprise Applikation ist es wahrscheinlicher, dass Sie die Datenbankkonfiguration mittles JNDI externalisieren und somit von Ihrem Quellcode trennen. Schlielich werden in der Definitionsdatei der Bean die beiden DAO-Objekte des "Simple Persist" Moduls erstellt und mit einer Referenz auf die eben erstellte sessionFactory Bean versehen. Genau wie im Spring Applikations- Context von "Simple Weather" definiert diese Datei applicationContext-persit.xml die Architektur eines Submoduls einer grsseren Anwendung. Sollten Sie mit einer grsseren Anzahl von Persistenzklassen arbeiten, bietet es sich unter Umstnden an, diese in einem eigenen applicationContext ausserhalb Ihrer Anwendung zusammenzufassen. Theres one last piece of the puzzle in simple-persist. Later in this chapter, were going to see how we can use the Maven Hibernate3 plugin to generate our database schema from the annotated model objects. For this to work properly, the Maven Hibernate3 plugin needs to read the JDBC connection configuration parameters, the list of annotated classes, and other Hibernate configuration from a file named hibernate.cfg.xml in src/main/resources. The purpose of this file (which duplicates some of the configuration in applicationContext-persist.xml) is to allow us to leverage the Maven Hibernate3 plugin to generate Data Definition Language (DDL) from nothing more than our annotations. See Example 7.11, hibernate.cfg.xml des "simple-persist" Moduls. Als letztes Puzzleteil des "Simple Persist" Beispiels werden wir spter im Kapitel erfahren, wie wir mit der Hilfe des Hibernate3 Maven Plugins aus den annotierten Modellobjekten unser Datenbankschema erzeugen knnen. Damit dies funktioniert, muss das Hibernate3 Maven Plugin die Parameter der JDBC-Verbindungskonfiguration, die Liste der kommentierten Klassen und andere Hibernate-Konfigurations Parameter aus einer Datei mit dem Namen hibernate.cfg.xml unter /src/main/resources auslesen knnen. Der Zweck dieser Datei (welche einige Konfigurationen der applicationContext-persist.xml dupliziert) ist es, das Hibernate3 Maven Plugin so zu nutzen, dass wir aus nichts weiter als unseren annotierten Klassen die gesamte DDL erstellen knnen. 137

Multi-module Enterprise Project Example 7.11. hibernate.cfg.xml des "simple-persist" Moduls


<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- SQL Dialekt --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <!-- Datenbank Verbindungsparamenter --> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:data/weather</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <property name="connection.shutdown">true</property> <!-- JDBC connection pool (den gestellten pool benutzen) --> <property name="connection.pool_size">1</property> <!-- Aktivierung des automatischen Hibernate Session Context Management --> <property name="current_session_context_class">thread</property> <!-- Deaktivierung des second Level Cache --> <property name="cache.provider_class"> org.hibernate.cache.NoCacheProvider </property> <!-- Ausgabe allen SQL auf stdout --> <property name="show_sql">true</property>

<!-- deaktivierung der Batch funktionalitt von HSQLDB um Fehler korrekt weiterzugeben <property name="jdbc.batch_size">0</property> <!-- Auflisten aller bestehender Property Dateien --> <mapping class="org.sonatype.mavenbook.weather.model.Atmosphere"/> <mapping class="org.sonatype.mavenbook.weather.model.Condition"/> <mapping class="org.sonatype.mavenbook.weather.model.Location"/> <mapping class="org.sonatype.mavenbook.weather.model.Weather"/> <mapping class="org.sonatype.mavenbook.weather.model.Wind"/> </session-factory> </hibernate-configuration>

Die Inhalte von Example 7.10, Spring Application Context Definition fr das "simple-persist" Modul (Beispiel 7.10: "'Simple Persist' Spring Application 138

Multi-module Enterprise Project Context") und Example 7.1, Simple Parent POM Projekt (Beispiel 7.1: "Simple Parent POM Project" ) sind redundant. Whrend die Datei SpringApplicationContext.xml von der Web- sowie der Befehlszeilen-Anwendung benutzt wird, findet die Datei hibernate.cfg.xml nur Einsatz zur Untersttzung des Hibernate3 Maven Plugins. Spter in diesem Kapitel werden wir sehen, wie man mittels der Datei hibernate.cfg.xml und dem Hibernate3 Maven Plugin ein Datenbank-Schema, basierend auf dem kommentierten Objektmodell wie dieses in "Simple Model" besteht, generieren kann. Es ist die Datei hibernate.cfg.xml welche die Eigenschaften der JDBC-Verbindung konfiguriert und die annotierten Modelklassen in form einer Aufzhlung dem Hibernate3 Maven Plugin bereitstellt.

7.6. Das "Simple Web" Modul - Das Web-Interface


Die Web-Anwendung wird in einem einfachen Web Applikations Projekt definiert. Dieses einfache Web Applikations Projekt definiert zwei Spring MVC Controller Objekte: WeatherController und HistoryController. Beide Controller werden auf Komponenten der "Simple Weather" und "Simple Persist" Module abgebildet. Der Spring Container wird in der zu dieser Applikation zugehrigen Datei web.xml konfiguriert. Diese referenziert die Datei applicationContext-weather.xml unter "Simple Weather" sowie die Datei applicationContext-persist.xml in "Simple Persist". Die Komponenten-Architektur von dieser einfachen Web-Anwendung ist in Figure 7.3, Abhngigkeiten des Spring MVC Controllers zu den Komponenten aus 'Simple Weather' sowie 'Simple Persist' (Abbildung 7.3: "Abhngigkeiten des Spring MVC Controllers zu den Komponenten aus 'Simple Weather' sowie 'Simple Persist' ") dargestellt.

139

Multi-module Enterprise Project

Figure 7.3. Abhngigkeiten des Spring MVC Controllers zu den Komponenten aus 'Simple Weather' sowie 'Simple Persist' Das POM des Moduls "Simple Webapp" wird unten aufgefhrt: Example 7.12. POM fder simple-webapp
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-webapp</artifactId> <packaging>war</packaging> <name>Simple Web Application</name> <dependencies>

140

Multi-module Enterprise Project


<dependency> # <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-weather</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-persist</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> </dependencies> <build> <finalName>simple-webapp</finalName> <plugins> <plugin> # <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <dependencies># <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> </dependencies> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> # <artifactId>hibernate3-maven-plugin</artifactId> <version>2.0</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> # </component> </components> </configuration>

141

Multi-module Enterprise Project


<dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>

Mit dem fortschreiten des Buches werden Sie festellen, dass die Datei pom.xml an Lnge gewinnt. In diesem POM werden wir vier Abhngigkeiten und zwei Plugins konfigurieren. Lassen Sie uns Schritt fr Schritt das POM durchgehen und die fr die Konfiguration wichtigen Punkte genauer erlutern: Das "Simple Web" Applikationsmodul definiert vier Abhngigkeiten: die Servlet-Spezifikation 2.4, die "Simple Weather" Dienste, die "Simple Persist" Applikations-Bibliothek sowie das gesamte Spring Framework 2.0.7. Das Jetty Maven Plugin knnte nicht einfacher in dieses Projekt einzufgen sein: wir fgen einfach ein Plugin-Element, welches die entsprechenden Koordinaten groupId und artifactId setzt, ein. Die Tatsache, dass dieses Plugin so trivial zu konfigurieren ist bedeutet, dass die Plugin-Entwickler einen guten Dienst getan haben. Es wurden sinnvolle Standardwerte gesetzt, welche wir in den meisten Fllen nicht bersteuern mssen. Sollten Sie dennoch die Standardeinstellungen bersteuern wollen/mssen, so tun Sie dies indem Sie ein Konfigurationselement mit den entsprechenden Werten einfgen. In unserer Build Konfiguration werden wir das Hibernate3 Maven Plugin so konfigurieren, dass dieses gegen eine eingebettete Instanz einer HSSQL Datenbank luft. Damit das Hibernate3 Maven Plugin auf die Datenbank zugreifen kann, muss diese einen Verweis auf die JDBC-Treiber der HSSQL-Datenbank im Klassenpfad bekommen. Um diese Abhngigkeit eines Plugins bereitzustellen, erklren wir diese direkt im Plugin-Element. Hier referenzieren wir hsqldb:hsqldb:1.8.0.7. Das Hibernate Plugin 142

Multi-module Enterprise Project bentigt die JDBC-Treiber ebenfalls, um die Datenbank zu erstellen. Aus diesem Grund haben wir diese dort ebenfalls referenziert. Es ist hier im Hibernate Maven Plugin ist, wo dieses POM anfngt interessant zu werden: Im nchsten Abschnitt werden wir das Goal hbm2ddl ausfhren, um die HSQLDB Struktur zu erstellen. In dieser Datei pom.xml schliessen wir ebenfalls eine Referenz auf die Version 2.0 des Hibernate3 Maven Plugin von Codehouse MoJo ein. Das Hibernate3 Maven Plugin kann auf verschiedenerlei Wegen an die Hibernate Mapping Informationen gelangen; abhngig vom jeweiligen Einsatzszenario des Hibernate Plugins. Sollten sie Hibernate Mapping XML(.hbm.xml)-Dateien einsetzen und htten vor, Modellklassen mit Hilfe des Goals hbmjava zu generieren, so wrden Sie Ihre Implementierung auf configuration stellen. Wrden Sie jedoch Hiberante3 einsetzen um eine bestehende Datenbank zu re-engineeren, um daraus die entsprechenden .hbm.xml Dateien zu generieren und die Klassen dann daraus abzuleiten, so wrden Sie die Implementierung jdbcconfiguration whlen. In unserem Fall benutzen wir einfach ein annotiertes Objekt Modell um eine Datenbank zu generieren. In anderen Worten, wir haben bereits unser Hibernate Mapping, jedoch keine bestehende Datenbank. In diesem Fall ist whlen wir annotationconfiguration. Das Hiberante3 Maven Plugin wird unter Section 7.7, Aufrufen der Web-Anwendung (Abschnitt 7.7: "Aufrufen der Web-Anwendung") nher beleuchtet. Note Ein hufiger auftretender Fehler ist die Verwendung der extensions-Konfiguration um Abhngigkeiten von Plugins zu definieren. Wir raten von dieser Praxis dringend ab, denn dies kann dazu fhren, dass Ihr Klassenpfad -neben anderen unschnen Nebeneffektenprojektweit "verschmutzt" wird. Auerdem wird in der Version 2.1 genau diese Funktionalitt stark berarbeitet werden, was bedeutet, dass Sie hier in jedem Fall noch einmal Hand anlegen mssten. Die einzige "normale" Nutzung fr Extensions ist die, eine neue Paketdefinition zu erstellen.

143

Multi-module Enterprise Project Nun werden wir uns den beiden Spring MVC Controllern und deren Konfiguration zuwenden. Beide dieser Controller beziehen sich auf Beans welche in "Simple Weather" bzw "Simple Persist" definiert wurden. Example 7.13. simple-webapp WeatherController
package org.sonatype.mavenbook.web; import import import import import import org.sonatype.mavenbook.weather.model.Weather; org.sonatype.mavenbook.weather.persist.WeatherDAO; org.sonatype.mavenbook.weather.WeatherService; javax.servlet.http.*; org.springframework.web.servlet.ModelAndView; org.springframework.web.servlet.mvc.Controller;

public class WeatherController implements Controller { private WeatherService weatherService; private WeatherDAO weatherDAO; public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { String zip = request.getParameter("zip"); Weather weather = weatherService.retrieveForecast(zip); weatherDAO.save(weather); return new ModelAndView("weather", "weather", weather); } public WeatherService getWeatherService() { return weatherService; } public void setWeatherService(WeatherService weatherService) { this.weatherService = weatherService; } public WeatherDAO getWeatherDAO() { return weatherDAO; } public void setWeatherDAO(WeatherDAO weatherDAO) { this.weatherDAO = weatherDAO; } }

Die Klasse WeatherController implementiert das Spring MVC Controller Interface, welches die Existenz einer Methode handleRequest() in der oben angegebenen 144

Multi-module Enterprise Project Form vorschreibt. Wenn Sie das Innenleben dieser Methode betrachten, so werden Sie feststellen, dass diese die Methode retrieveForecast() der Instanzvariablen weatherService aufruft. Anders als im vorgehenden Beispiel in welchem die Klasse WeatherService durch ein Servlet instanziert wurde, ist weatherController ein Bean, mit einem weatherService Property. Es liegt in der Verantwortung des Spring IoC Containers die Verdrahtung der Komponennte weatherService bereitzustellen. Darber hinaus werden Sie bemerkt haben, dass wir in dieser Implementierung auf den weatherFormatter verzichten, an dessen Statt geben wir das Objekt Weather, welches von retrieveForecast() zurckgegeben wird an den Konstruktor von ModelAndView. Die Klasse ModelAndView werden wir benutzen um Velocity Templates darzustellen, welche eine Referenz zu einer Variablen ${weather} halten. Das zugehrige Template weather.vm liegt unter /src/main/webapp/WEB-INF/vm abgelegt und wird in ??? (Beispiel 7.14) ausgefhrt. In the WeatherController, before we render the output of the forecast, we pass the Weather object returned by the WeatherService to the save() method on WeatherDAO. Here we are saving this Weather objectusing Hibernateto an HSQLDB database. Later, in HistoryController, we will see how we can retrieve a history of weather forecasts that were saved by the WeatherController. Innerhalb des WeatherController, geben wir das vom WeatherService zurckgegebene Objekt Weather an die Methode save() des WeatherDAO. Dort wird das Objekt Weather mit Hilfe von Hibernate in der HSQLDB abgespeichert. Spter im HistoryController werden wir sehen wie man die Vergangenheit bezglich einer Wettervorhersage welche von HSQLDB gespeichert wurde, zurckgeholen kann. Example 7.14. Die von WeatherController wiedergegebene Vorlage weather.vm
<b>Derzeitiges Wetter von: ${weather.location.city}, ${weather.location.region}, ${weather.location.country}</b><br/> <ul> <li>Temperatur: ${weather.condition.temp}</li> <li>Wetterlage: ${weather.condition.text}</li>

145

Multi-module Enterprise Project


<li>Feuchtigkeit: ${weather.atmosphere.humidity}</li> <li>Wind Chill Faktor: ${weather.wind.chill}</li> <li>Datum: ${weather.date}</li> </ul>

Die Syntax der Velocity Vorlagen ist einfach, Variablen werden durch vorangestelltes Dollarzeichen in geschwungenen Klammern markiert ${Variable}. Der Ausdruck zwischen den geschweiften Klammern verweist auf ein Property, oder ein Property eines Properties der Variable weather, welche durch den WeatherController an das Template weitergegeben wurde. Der HistoryController wird eingesetzt, um auf Prognosen aus der Vergangenheit zuzugreifen welche zuvor vom WeatherController angefragt wurden. Immer, wenn wir wieder eine Prognose mittels dem WeatherController abrufen, speichert der Controller das Objekt Weather mittels dem WeatherDAO in der Datenbank. Das WeatherDAO nutzt Hibernate um das Objekt Weather in eine Reihe von Zeilen zu zerlegen und in eine Anzahl in Relation stehende Datenbanktabellen abzuspeichern. Der HistoryController ist im Example 7.15, simple-web HistoryController (Beispiel 7.15: "Simple Web" HistoryController) ausgefhrt. Example 7.15. simple-web HistoryController
package org.sonatype.mavenbook.web; import import import import import import java.util.*; javax.servlet.http.*; org.springframework.web.servlet.ModelAndView; org.springframework.web.servlet.mvc.Controller; org.sonatype.mavenbook.weather.model.*; org.sonatype.mavenbook.weather.persist.*;

public class HistoryController implements Controller { private LocationDAO locationDAO; private WeatherDAO weatherDAO; public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { String zip = request.getParameter("zip"); Location location = locationDAO.findByZip(zip); List<Weather> weathers = weatherDAO.recentForLocation( location ); Map<String,Object> model = new HashMap<String,Object>();

146

Multi-module Enterprise Project


model.put( "location", location ); model.put( "weathers", weathers ); return new ModelAndView("history", model); } public WeatherDAO getWeatherDAO() { return weatherDAO; } public void setWeatherDAO(WeatherDAO weatherDAO) { this.weatherDAO = weatherDAO; } public LocationDAO getLocationDAO() { return locationDAO; } public void setLocationDAO(LocationDAO locationDAO) { this.locationDAO = locationDAO; } }

Der HistoryController ist mit zwei in "Simple Persist" definierten DAO-Objekten verdrahtet. Dabei sind die DAOs Bean-Properties des HistoryControllers: WeatherDAO und LocationDAO. Die Aufgabe des HistoryController ist, eine Liste von Weather Objekten entsprechend einer bestimmten Postleitzahl zurckzugeben. Wenn das WeatherDAO ein Objekt Weather in die Datenbank speichert, so legt es nicht eine Postleitzahl ab, sonder es speichert zustzlich eine Referenz auf ein Objekt Location welches an das Objekt Weather gebunden ist, wie in "Simple Model" definiert. Um eine Liste von Weather-Objekte abzurufen, ruft der HistoryController zunchst das Objekt Lokation auf, welches der Postleitzahl entspricht. Dies wird durch den Aufruf der Methode findByZip() des LocationDAO bewerkstelligt. Nachdem ein Objekt Lokation abgerufen wurde, versucht der HistoryController die vorgngigen Weather Objekte mit Referenz auf das Objekt Lokation abzurufen. Das Ergebnis, welches in in der Form List<Weather> besteht, wird dann in eine HashMap von zwei Variablen der Velocity Vorlage history.vm wie im ??? (Beispiel 7.16: "history.vm dargestellt vom HistoryController") dargestellt, umgewandelt. 147

Multi-module Enterprise Project Example 7.16. history.vm dargestellt vom HistoryController


<b> Derzeitige Wetterlage von: ${location.city}, ${location.region}, ${location.country} </b> <br/> #foreach( $weather in $weathers ) <ul> <li>Temperatur: $weather.condition.temp</li> <li>Zustand: $weather.condition.text</li> <li>Feuchtigkeit: $weather.atmosphere.humidity</li> <li>Wind Chill Faktor: $weather.wind.chill</li> <li>Datum: $weather.date</li> </ul> #end

Die Vorlage history.vm is unter /src/main/webapp/WEB-INF/vm abgelegt und verweist auf die Variable location um Angaben zum Standort/Lokation der Prognose, welche vom WeatherDAO zurckgegeben wurde auszugeben. Diese Vorlage unterliegt einer Velocity Kontrollstruktur, #foreach, welche sicherstellt, dass durch alle Elemente der Variablen weathers geschlauft wird. Jedes Element in weathers wird einer Variable weather zugeordnet und mit der Vorlage welche sich zwischen #foreach und #end befindet, verknpft und ausgegeben. You've seen these Controller implementations, and you've seen that they reference other beans defined in simple-weather and simple-persist, they respond to HTTP requests, and they yield control to some mysterious templating system that knows how to render Velocity templates. All of this magic is configured in a Spring application context in src/main/webapp/WEB-INF/weather-servlet.xml. This XML configures the controllers and references other Spring-managed beans, it is loaded by a ServletContextListener which is also configured to load the applicationContext-weather.xml and applicationContext-persist.xml from the classpath. Let's take a closer look at the weather-servlet.xml shown in ???. Sie haben nun die Controller-Implementierung gesehen, und Sie haben gesehen, dass sich deren Implementierung auf weitere Beans welche in "Simple Weather" sowie "Simple Persist" definiert sind, sttzt. Sie reagieren auf HTTP-Anfragen, 148

Multi-module Enterprise Project und bernehmen die Kontrolle eines misterisen Templating-Systems welches wei, wie man Velocity-Vorlagen verarbeitet. Diese ganze Magie wurde im Spring applicationContext definiert, welcher sich unter /src/main/webapp/WEB-INF/weather-servlet.xml befindet. Diese XML-Konfiguration konfiguriert die Controller und definiert weitere Referenzen zu Beans welche von Spring verwaltet werden. die Datei weather-servlet.xml wird von einem ServletContextListener geladen, welcher zugleich so konfiguriert ist, dass er die Datei applicationContext-weather.xml sowie applicationContext-persist.xml vom Klassenpfad ldt. Lassen Sie uns die datei weather-servlet.xml einmal genauer anschauen. Example 7.17. Spring Controller Konfiguration weather-servlet.xml
<beans> <bean id="weatherController" # class="org.sonatype.mavenbook.web.WeatherController"> <property name="weatherService" ref="weatherService"/> <property name="weatherDAO" ref="weatherDAO"/> </bean> <bean id="historyController" class="org.sonatype.mavenbook.web.HistoryController"> <property name="weatherDAO" ref="weatherDAO"/> <property name="locationDAO" ref="locationDAO"/> </bean> <!-- Sie knnen mehr als einen Controller definieren --> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="urlMap"> <map> <entry key="/weather.x"> # <ref bean="weatherController" /> </entry> <entry key="/history.x"> <ref bean="historyController" /> </entry> </map> </property> </bean>

<bean id="velocityConfig" # class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="resourceLoaderPath" value="/WEB-INF/vm/"/> </bean>

149

Multi-module Enterprise Project


<bean id="viewResolver" # class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="cache" value="true"/> <property name="prefix" value=""/> <property name="suffix" value=".vm"/> <property name="exposeSpringMacroHelpers" value="true"/> </bean> </beans>

Die Datei weather-servlet.xml definiert die beiden Controller als Spring-verwaltete Beans. weatherController besitzt zwei Properties, welche Verweise auf weatherService und weatherDAO darstellen; historyController verweist auf die Beans weatherDAO und locationDAO. Wenn dieser ApplicationContext erstellt wird, so geschieht dies in einem Umfeld, welches den Zugang zu den ApplicationContexten definiert, sowohl zum "Simple Persist" wie auch zum "Simple Weather" Application Context. Im ??? Beispiel werden Sie sehen, wie man Spring konfigurieren kann, um mehrere Komponenten aus verschiedenen Spring Konfigurations-Dateien zusammenzufhren. Das Bean urlMapping definiert URL-Muster, welche den WeatherController und den HistoryController aufrufen. In diesem Beispiel benutzen wir SimpleUrlHandlerMapping und bilden /weather.x auf den WeatherController sowie /history.x auf den HistoryController ab. Da wir mit der Velocity-Templating-Engine arbeiten, sind wir gezwungen etliche Konfigurations-Optionen weiterzugeben. Hierzu weisen wir in der Datei velocityConfig.xml Velocity an, Vorlagen immer unter /WEB-INF/vm zu suchen. Zuletzt wird der viewResolver mit der Klasse VelocityViewResolver konfiguriert. Es gibt bereits eine Reihe von Implementierungen des ViewResolvers in Spring; diese reichen von einem Standard-ViewResolver um JSTL/JSP-Seiten zu generieren, und reicht bis zu solchen welcher Freemaker Templates erstellen knnen. In unserem Beispiel werden wir die Velocity-Templating-Engine konfigurieren, sowie die Standard-Prfix und Suffixe setzen, welche automatisch an die Namen der Vorlagen angefgt werden und an ModelAndView weitergegeben werden. 150

Multi-module Enterprise Project Finally, the simple-webapp project was a web.xml which provides the basic configuration for the web application. The web.xml file is shown in ???. Schlielich ist das "Simple Web" Projekt eine Webanwendung, und bentigt somit eine Datei web.xml als Basiskonfiguration der Anwendung. Die zugehrige Datei web.xml ist ??? (7.18: "web.xml von 'Simple Web' ") wiedergegeben. Example 7.18. web.xml von 'Simple Web'
<web-app id="simple-webapp" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Simple Web Application</display-name> <context-param> # <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext-weather.xml classpath:applicationContext-persist.xml </param-value> </context-param> <context-param> # <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/log4j.properties</param-value> </context-param> <listener> # <listener-class> org.springframework.web.util.Log4jConfigListener </listener-class> </listener> <listener> <listener-class> # org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> # <servlet-name>weather</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> #

151

Multi-module Enterprise Project


<servlet-name>weather</servlet-name> <url-pattern>*.x</url-pattern> </servlet-mapping> </web-app>

Hier ein kleines Kusntstck das uns die Wiederverwendung des applicationContext-weather.xml sowie applicationContest.persist.xml innerhalb dieses Projekts erlaubt. Die contextConfigLocation wird vom ContextLoaderListener zur Erstellung eines ApplicationContext benutzt. Beim Erstellen des Weather Servlets wird die Datei weather-servlet.xml -wie in ??? (Beispiel 7.17: Spring Controller Konfiguration weather-servlet.xml) dargestellt - im Zusammenhang mit dem applicationContext welcher aus der contextConfigLocation geladen wird, ausgewertet. Auf diese Weise knnen Sie in einem anderen Projekt eine Anzahl Beans definieren und auf diese ber den Klassenpfad zugreifen. Da sowohl "Simple Persist" als auch "Simple Weather" als JAR-Archiv unter /WEB-INF/lib verfgbar sein werden, mssen wir nur noch das Prfix classpath: benutzen, um diese Dateien zu referenzieren. (Eine andere Mglichkeit wre gewesen, diese Dateien nach /WEB-INF zu kopieren, um sie dort mit einem Konstrukt wie etwa /WEB-INF/applicationContext-persist.xml zu referenzieren). Die log4jConfigLocation wird verwendet, um dem Log4JConfigListener mitzuteilen, wo dieser die Log4J Logging-Konfiguration finden kann. In diesem Beispiel weisen wir log4J an, unter /WEB-INF/log4j.properties zu suchen. Hiermit stellen wir sicher, dass das Log4J Subsystem konfiguriert ist, sobald die Web-Applikation gestartet wird. Es ist wichtig, den Log4JConfigListener vor dem ContextLoaderListener zu platzieren, da Sie anderenfalls unter Umstnden wichtige Logging-Nachrichten verpassen, welche auf Probleme hinweisen knnen, die den ordungsgemssen Start der Anwendung verhindern. Insbesondere wenn Sie eine besonders groe Anzahl Beans unter der Verwaltung von Spring haben, und eines der Beans beim Applikationsstart umfllt, wird Ihre Anwendung scheitern. Haben Sie dann bereits zuvor das Logging initialisiert, so haben Sei vielleicht die Mglichkeit 152

Multi-module Enterprise Project eine Warnung oder eine Fehlermeldung aufzufangen; andernfalls werden Sie wohl keinerlei Ahnung haben warum Ihnen der Anwendungsstart misglckt ist. Der ContextLoaderListener ist im Wesentlichen der Spring Container. Beim Start einer Anwendung erstellt dieser Listner einen ApplicationContext aus dem Wert des contextConfigLocation Parameters. Wir definieren ein Spring MVC DispatcherServlet mit dem Namen weather. Hierdurch wird Spring unter /WEB-INF/weather-servlet.xml nach einer Spring Konfigurationsdatei suchen. Sie knnen so viele DispatcherServlets erstellen, wie Sie bentigen, ein DispatcherServlet kann eine oder mehrere Spring MVC-Controller-Implementierungen enthalten Alle in der Endung ".x" endenden Anfragen werden zum Weather Servlet geleitet. Wir mchten hier darauf hinweisen, dass die Endung ".x" keine tiefere Bedeutung hat, es ist eine willkrliche Auswahl welche Sie mit jedem beliebigen URL-Muster ersetzen knnen.

7.7. Aufrufen der Web-Anwendung


Um die Web-Anwendung aufrufen zu knnen mssen Sei zunchst mittels dem Hibernate3 Maven Plugin die Datenbank erstellen. Um dies zu tun, geben Sie bitte das folgende Kommando auf der Befehlszeile im Verzeichnis des "Simple Web" Projekts ein :
$ mvn hibernate3:hbm2ddl [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'hibernate3'. [INFO] org.codehaus.mojo: checking for updates from central [INFO] -----------------------------------------------------------------------[INFO] Building Chapter 7 Simple Web Application [INFO] task-segment: [hibernate3:hbm2ddl] [INFO] -----------------------------------------------------------------------[INFO] Preparing hibernate3:hbm2ddl ... 10:24:56,151 INFO org.hibernate.tool.hbm2ddl.SchemaExport - export complete [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------

153

Multi-module Enterprise Project Nach Abschluss der Ausfhrung sollte ein Verzeichnis ${basedir}/data erstellt sein welches die HSQLDB Datenbank enthlt. Um die Web Applikation nun zu starten geben Sie folgenden Befehl ein:
$ mvn jetty:run [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'jetty'. [INFO] -----------------------------------------------------------------------[INFO] Building Chapter 7 Simple Web Application [INFO] task-segment: [jetty:run] [INFO] -----------------------------------------------------------------------[INFO] Preparing jetty:run ... [INFO] [jetty:run] [INFO] Configuring Jetty for project: Chapter 7 Simple Web Application ... [INFO] Context path = /simple-webapp [INFO] Tmp directory = determined at runtime [INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml [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@0.0.0.0:8080 [INFO] Started Jetty Server

Nach dem Start von Jetty, knnen Sie mit dem Aufruf http://localhost:8080/simple-webapp/weather.x?zip=60202 das Wetter von Evanston, IL aufrufen. Mit der nderung der Postleitzahl sollte es Ihnen mglich sein Ihren eigenen Wetterbericht abzurufen.
Derzeitige Wetterlage von: Evanston, IL, US * * * * * Temperatur: 42 Zustand: Partly Cloudy Feuchtigkeit: 55 Wind Chill Faktor: 34 Datum: Tue Mar 25 10:29:45 CDT 2008

7.8. Das "Simple Command" Modul - Das Kommandozeilen Modul


154

Multi-module Enterprise Project Das "Simple Command" Modul ist die Befehlszeilen-Version der "Simple Web" Anwendung. Es ist ein Dienstprogramm, das auf den selben Abhngigkeiten aufbaut: "Simple Weather" und "Simple Persist". Statt der Interaktion ber einen Web-Browser, rufen Sie fr diese Anwendung ein Dienstprogramm 'simple-command' von der Befehlszeile aus auf.

Figure 7.4. Dienstprogramm aufbauend auf die Modue Simple-Weather und Simple-Persist

Example 7.19. POM des Simple-Command Moduls


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version>

155

Multi-module Enterprise Project


</parent> <artifactId>simple-command</artifactId> <packaging>jar</packaging> <name>Simple Command Line Tool</name> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</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> <plugin> <groupId>org.codehaus.mojo</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>1.8.0.7</version> </dependency> </dependencies> </plugin> </plugins>

156

Multi-module Enterprise Project


</build> <dependencies> <dependency> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-weather</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.sonatype.mavenbook.ch07</groupId> <artifactId>simple-persist</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> </dependencies> </project>

Dieses POM wird die Erstellung eines JAR files veranlassen, welches die Klasse org.sonatype.mavenbook.weather.Main beinhaltet. Diese Klasse wird in Example 7.20, Klasse Main des Simple-Command Moduls (Beispiel 7.20:"Klasse Main des Simple-Command Moduls" dargestellt. In dieser pom.xml-Datei werden wir das Maven Plugin Assembly um einen bereits mitgelieferten "Assembly Beschrieb" mit dem Namen "jar-with-dependencies" konfigurieren. Dieses Plugin wird sodann ein JAR- Archive erstellen, welches allen Bytecode beinhaltet welcher gebraucht wird, um das Projekt auszufhren, wie auch alle weitergehenden Abhngigkeiten. Example 7.20. Klasse Main des Simple-Command Moduls
package org.sonatype.mavenbook.weather; import java.util.List; import org.apache.log4j.PropertyConfigurator; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;

157

Multi-module Enterprise Project


import import import import org.sonatype.mavenbook.weather.model.Location; org.sonatype.mavenbook.weather.model.Weather; org.sonatype.mavenbook.weather.persist.LocationDAO; org.sonatype.mavenbook.weather.persist.WeatherDAO;

public class Main { private WeatherService weatherService; private WeatherDAO weatherDAO; private LocationDAO locationDAO; public static void main(String[] args) throws Exception { // Configure Log4J PropertyConfigurator.configure(Main.class.getClassLoader().getResource( "log4j.properties")); // Read the Zip Code from the Command-line (if none supplied, use 60202) String zipcode = "60202"; try { zipcode = args[0]; } catch (Exception e) { } // Read the Operation from the Command-line (if none supplied use weather) String operation = "weather"; try { operation = args[1]; } catch (Exception e) { } // Start the program Main main = new Main(zipcode); ApplicationContext context = new ClassPathXmlApplicationContext( new String[] { "classpath:applicationContext-weather.xml", "classpath:applicationContext-persist.xml" }); main.weatherService = (WeatherService) context.getBean("weatherService"); main.locationDAO = (LocationDAO) context.getBean("locationDAO"); main.weatherDAO = (WeatherDAO) context.getBean("weatherDAO"); if( operation.equals("weather")) { main.getWeather(); } else { main.getHistory(); } } private String zip; public Main(String zip) { this.zip = zip; }

158

Multi-module Enterprise Project


public void getWeather() throws Exception { Weather weather = weatherService.retrieveForecast(zip); weatherDAO.save( weather ); System.out.print(new WeatherFormatter().formatWeather(weather)); } public void getHistory() throws Exception { Location location = locationDAO.findByZip(zip); List<Weather> weathers = weatherDAO.recentForLocation(location); System.out.print(new WeatherFormatter().formatHistory(location, weathers)); } }

Die Klasse Main hlt eine Referenz auf die Klassen WeatherDAO, LocationDAO und WeatherService. Folgende Aufgaben werden durch deren statische Methode main() wahrgenommen: Die Postleitzahl aus dem ersten Argument ([0]) der Befehlszeile auslesen Das Kommando aus dem zweiten Argument ([1]) der Befehlszeile auslesen. Ist das Kommando "weather", so werden die aktuellen Wetterdaten vom Webservice angefragt. Ist das Kommando "history" so werden die Wetterdaten aus der lokalen Datenbank abgerufen. Laden des Spring ApplicationContext unter Bezug auf zwei XML Dateien, welche von den Modulen "Simple Persist" und "Simple Weather" geladen wurden. Instanzieren der Klasse Main Befruchten von WeatherService, WeatherDAO sowie LocationDAO mit Beans aus dem Spring ApplicationContext Aufrufen der entsprechenden Methode getWeather() oder getHistory() entsprechend dem bergebenen Kommando Als Teil der Web Applikation benutzen wir Spring VelocityViewResolver um eine Velocity Vorlage darzustellen. Fr die befehlszeilenorientierte Applikation ist es notwendig eine einfache Klasse zu erstellen, welche unsere Wetterdaten mit 159

Multi-module Enterprise Project Hilfe einer Velocity Vorlage darstellt. Example 7.21, WeatherFormatter stellt Wetterdaten unter Einbezug einer Velocity Vorlage dar (Beispiel 7.21: "WeatherFormatter stellt Wetterdaten unter Einbezug einer Velocity Vorlage dar") ist der Auszug der Klasse WeatherFormatter, einer Klasse mit zwei Methoden welche den Wetterbericht und die Wettergeschichte darstellen. Example 7.21. WeatherFormatter stellt Wetterdaten unter Einbezug einer Velocity Vorlage dar
package org.sonatype.mavenbook.weather; import import import import java.io.InputStreamReader; java.io.Reader; java.io.StringWriter; java.util.List;

import org.apache.log4j.Logger; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import org.sonatype.mavenbook.weather.model.Location; import org.sonatype.mavenbook.weather.model.Weather; public class WeatherFormatter { private static Logger log = Logger.getLogger(WeatherFormatter.class); public String formatWeather( Weather weather ) throws Exception { log.info( "Formatting Weather Data" ); Reader reader = new InputStreamReader( getClass().getClassLoader(). getResourceAsStream("weather.vm")); VelocityContext context = new VelocityContext(); context.put("weather", weather ); StringWriter writer = new StringWriter(); Velocity.evaluate(context, writer, "", reader); return writer.toString(); } public String formatHistory( Location location, List<Weather> weathers ) throws Exception { log.info( "Formatting History Data" ); Reader reader = new InputStreamReader( getClass().getClassLoader(). getResourceAsStream("history.vm")); VelocityContext context = new VelocityContext(); context.put("location", location ); context.put("weathers", weathers ); StringWriter writer = new StringWriter();

160

Multi-module Enterprise Project


Velocity.evaluate(context, writer, "", reader); return writer.toString(); } }

Die Vorlage weather.vm gibt die zugehrige Stadt, den Staat, die Region sowie die aktuelle Temperatur aus. Die Vorlage history.vm gibt die rtlichkeit aus, und iteriert dann ber alle gespeicherten Wetterwerte der lokalen Datenbank. Diese beiden Vorlagen befinden sich unter ${basedir}/src/main/resource. Example 7.22. Die velocity Vorlage weather.vm
**************************************** Current Weather Conditions for: ${weather.location.city}, ${weather.location.region}, ${weather.location.country} **************************************** * * * * * Temperature: ${weather.condition.temp} Condition: ${weather.condition.text} Humidity: ${weather.atmosphere.humidity} Wind Chill: ${weather.wind.chill} Date: ${weather.date}

Example 7.23. Die Velocity Vorlage history.vm


Weather History for: ${location.city}, ${location.region}, ${location.country}

#foreach( $weather in $weathers ) **************************************** * Temperature: $weather.condition.temp * Condition: $weather.condition.text * Humidity: $weather.atmosphere.humidity * Wind Chill: $weather.wind.chill * Date: $weather.date #end

161

Multi-module Enterprise Project

7.9. Aufrufen der Kommandozeilen-Anwendung


Das Projekt Modul simple-command ist konfiguriert, ein einziges JAR Archiv, welches den Bytecode des Projektes sowie aller Bytecode der Abhngigkeiten enthlt, zu erstellen. Um diese Baueinheit (Assembly) zu erzeugen, rufen Sie das Goal assembly des Maven Assembly Plugin von innerhalb des Verzeichnisses des Projektes "Simple Command" auf:

$ mvn assembly:assembly [INFO] -----------------------------------------------------------------------[INFO] Building Chapter 7 Simple Command Line Tool [INFO] task-segment: [assembly:assembly] (aggregator-style) [INFO] -----------------------------------------------------------------------[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] Nothing to compile - all classes are up to date [INFO] [surefire:test] ... [INFO] [jar:jar] [INFO] Building jar: .../simple-parent/simple-command/target/simple-command.jar [INFO] [assembly:assembly] [INFO] Processing DependencySet (output=) [INFO] Expanding: .../.m2/repository/.../simple-weather-1-SNAPSHOT.jar into \ /tmp/archived-file-set.93251505.tmp [INFO] Expanding: .../.m2/repository/.../simple-model-1-SNAPSHOT.jar into \ /tmp/archived-file-set.2012480870.tm [INFO] Expanding: .../.m2/repository/../hibernate-3.2.5.ga.jar into \ /tmp/archived-file-set.1296516202.tm ... skipping 25 lines of dependency unpacking ... [INFO] Expanding: .../.m2/repository/.../velocity-1.5.jar into /tmp/archived-file-set.379482 [INFO] Expanding: .../.m2/repository/.../commons-lang-2.1.jar into \ /tmp/archived-file-set.1329200163.tm [INFO] Expanding: .../.m2/repository/.../oro-2.0.8.jar into /tmp/archived-file-set.199315532 [INFO] Building jar: .../simple-parent/simple-command/target/simple-command-jar-with-depende

Der Build schreitet durch die Lebenszyklusphasen Kompilieren des Bytecodes, Aufrufen der Tests und schliesslich Erstellen des JAR-Archives. Zuletzt erstellt das Goal assembly:assembly ein einziges JAR Archiv inklusive aller Abhngigkeiten, indem es allen abhngigen Bytecode in temporre Verzeichnisse entpackt um 162

Multi-module Enterprise Project diesen schliesslich in einem einzigen JAR Archiv zusammenzufassen und im Zielverzeichnis /target unter dem Namen simple-command-jar-with-dependencies.jar abzulegen. Dieses "ber" JAR Archiv kommt auf stolze 15 MB. Vor Sie nun das kommandozeilenorientierte Programm aufrufen, mssen Sie noch das Goal hbm2ddl des Maven Hibernate3 Plugin aufrufen, um die HSQL Datenbank zu erstellen. Sie tun dies, indem Sie den folgenden Befehl innerhalb des Verzeichnisses von "Simple Command" absetzen:
$ mvn hibernate3:hbm2ddl [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'hibernate3'. [INFO] org.codehaus.mojo: checking for updates from central [INFO] -----------------------------------------------------------------------[INFO] Building Chapter 7 Simple Command Line Tool [INFO] task-segment: [hibernate3:hbm2ddl] [INFO] -----------------------------------------------------------------------[INFO] Preparing hibernate3:hbm2ddl ... 10:24:56,151 INFO org.hibernate.tool.hbm2ddl.SchemaExport - export complete [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------

Nach dem Aufruf sollten Sie innerhalb des "Simple Command" Verzeichnisses ein Verzeichnis /data vorfinden. Dieses Verzeichnis beinhaltet die HSQL Datenbank. Um nun das befehlszeilenorientierte Programm aufzurufen, setzen Sie den folgenden Befehl von innerhalb des "Simple Command" Verzeichnisses ab:
$ java -cp target/simple-command-jar-with-dependencies.jar \ org.sonatype.mavenbook.weather.Main 60202 2321 INFO YahooRetriever - Retrieving Weather Data 2489 INFO YahooParser - Creating XML Reader 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

163

Multi-module Enterprise Project


* Date: Wed Aug 06 09:35:30 CDT 2008

Um eine Abfrage der vergangenen Werte abzusetzen, geben Sie den folgenden Befehl ein:
$ java -cp target/simple-command-jar-with-dependencies.jar \ org.sonatype.mavenbook.weather.Main 60202 history 2470 INFO WeatherFormatter - Formatting History Data Weather History for: Evanston, IL, US **************************************** * 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. Fazit
Nun, wir haben viel Zeit damit verbracht, uns Themen anzunehmen, welche nicht im Zusammenhang mit Maven stehen. Wir haben dies getan, um ein vollstndiges und aussagekrftiges Beispielprojekt mit Bezug zur realen Welt zu implementieren. Wir haben uns keine schnellen Abkrzungen geleistet, um Ihnen ein hochglanzpoliertes fix fertiges Produkt zu liefern. Auch war unser Ziel nicht, Sie mit einer Ruby on Rails artigen Zauberei zur Annahme zu fhren, dass Sie nun in wenigen Minuten eine fix-fertige Java-Enterprise-Anwendung hinstellen knnten. - Hiervon gibt es bereits zu viele Beispiel im Markt, zu viele Menschen welche Ihnen das einfachste, umfassenste Framework zu verkaufen versuchen, welches Ihnen erlaubt mit Null Investition von Zeit und Aufmerksamkeit 164

Multi-module Enterprise Project weiterzukommen. Unser Ziel diese Kapitels war es, Ihnen ein umfassendes Bild zu vermitteln: das gesamte kosystem eines Multi-Modul Projekt Builds. Was wir bieten ist Maven im Rahmen einer Anwendung einer Art hnlich deren, welche Sie in freier Wildbahn antreffen, darzustellen. Es ist nicht unsere Art Ihnen eine Art Fast-Food anzubieten: 10 Minuten Bildschirm Show, etwas Schlamm in die Richtung Apache Ant geworfen und Sie davon berzeugt haben Maven einzusetzen! Sollten Sie sich nach dem Lesen dieses Kapitels fragen, was es mit Maven zu tun hat, so waren wir erfolgreich. Wir haben eine Reihe von komplex vernetzten Projekten, unter Einsatz von populren Frameworks erzeugt, und wir haben diese unter Verwendung von deklarativen Methoden verbunden. Die Tatsache, dass mehr als 60% dieses Kapitel der Erklrung von Spring und Hibernate gewidment wurde, sollte Ihnen aufzeigen, dass Maven grsstenteils zurcksteht. Es funktionierte einfach. Es erlaubt uns, uns auf die Anwendung selbst zu konzentrieren, und nicht so sehr auf der Build-Prozess. Sie werden bemerken, dass haben wir ein Projekt erstellt haben, welches Daten in einer Datenbank speichert, ohne ein einziges SQL-Statement abzusetzen. Daraufhin haben Sie eine Web-Anwendung erstellt, ohne sich mit den Erstellung eines Build Skriptes inklusive 20 plus Abhngigkeiten herumzuschlagen um am Ende ein WAR-Archiv zu erstellen. Anstelle Zeit damit zu verbringen Maven zu diskutieren, verbrachten wir die Zeit damit Spring und Hiberante in den Grundzgen einzufhren. Sie knnen das eingefhrte Skelett Projekt dieses Kapitels als Grundlage fr Ihre eigene Projekte verwenden, und die Chancen stehen gut, dass, sollten Sie das tun, Sie sich in der Lage befinden ber die Zeit hinweg mehr und mehr Module nach Bedarf anzulegen. So umfasst das ursprngliche Projekt, auf welchem dieses Beispiel beruht zwei verschiedene Modell-Projekte, mit zwei Persistenzprojekten welche den Anschuss an vllig unterschiedliche Datenbanksysteme bernehmen, mehrere Web-Applikationen, sowie eine Java-Mobil Anwendung. Insgesamt sttzt sich das reale Welt-System auf mindestens 15 miteinander verknpften Module. Was wir hiermit sagen wollen ist, Sie haben soeben das komplexeste Beispiel welches in diesem Buch dargestellt wird gesehen, aber Sie sollten auch wissen, dass dieses Beispiel nur Kratzer an der Oberflche dessen was mit Maven mglich ist, darstellt. 165

Multi-module Enterprise Project

7.10.1. Programmierung gegen Interface-Projekte


Dieses Kapitel stieg in die Tiefe der Multi-Modul-Projekte hinab und war komplexer als die einfachen Beispiele in Chapter 6, Ein multi-modulares Projekt (Kapitel 6: Ein Multi-Projekt-Modul), und dennoch war es eine starke Vereinfachung eines Reale- Welt-Projektes. In einem greren Projekt finden Sie vielleicht sogar selbst ein System hnlich Figure 7.5, Programmierung gegen Interface-Projekte (Abbildung 7.5) wieder.

Figure 7.5. Programmierung gegen Interface-Projekte Wenn wir den Begriff Interface Projekt benutzen, so beziehen wir uns auf ein Maven Projekt, welches einzig aus Interfaces und Konstanten besteht. In Figure 7.5, Programmierung gegen Interface-Projekte (Abbildung 7.5 Programmierung gegen ein Interface Projekt), stellen die Einheiten persist-api 166

Multi-module Enterprise Project sowie parse-api Interfaceprojekte dar. Sollten big-command sowie big-webapp gegen diese Interface Projekte programmiert werden, ist es ein leichtes zu einem spteren Zeitpunkt die Implementierung der Persistenz gegen eine andere auszutauschen. Auf dieser Abbildung werden zwei Implementierungen dargestellt: eine welche die Persistenz aufbauend auf einen XML-Store implementiert, sowie einer weiteren auf der Basis einer relationalen Datenbank. Bei der Anwendung der in diesem Kapitel vorgestellten Konzepte ist es einfach zu sehen, wie Sie, getrieben durch einen an das Programm bergebenen Wert, eine andere Spring ApplicationContext XML Datei bergeben, um damit die unterliegende Persistenzimplementierung auszutauschen. Wie bereits im OO-Design der Applikation, ist oftmals sinnvoll das Interface einer API von der Implementierung einer API in seperate Maven Projekte aufzutrennen.

167

Chapter 8. Optimierung und berarbeitung der POMs


8.1. Einfhrung
In Chapter 7, Multi-module Enterprise Project (Kapitel 7: "Multi-Modul Enterprise Projekt"), zeigten wir auf, wie die verschiedenen Teile eines Maven Builds zusammenkommen, um eine voll funktionsfhige multi modularre Anwendung zu erstellen. Whrend das Beispiel des Kapitels eine wirklichkeitsnahe Anwendung wiederspiegelt - eine Anwendung mit Datenbankintegration, einem Web-Service, und sogar zwei Benutzer Schnittstellen: eine in Form einer Web-Anwendung, und eine als Dienstprogramm; so bleibt das Beispiel-Projekt des Kapitels letztendlich ein konstruiertes. Um die Komplexitt eines realen Projektes abzubilden bruchte es ein Buch von weit grsserem Umfang als das, das Sie gerade lesen. Anwendungen des tglichen Lebens entwickeln sich im Laufe der Jahre und werden oftmals von groen, unterschiedlichen Gruppen von Entwicklern gewartet, welche jeweils ganz verschiedene Schwerpunkte setzen. In einem solchen Projekt, mssen Sie hufig Entscheidungen und Designs gegeneinander abwgen, welche jemand anderes gettigt hat. In diesem Kapitel treten wir nun einen Schritt zurck von den Beispielen, aus Part I, Maven by Example (Teil I: Maven by Example), und stellen uns die Frage, ob es irgendwelche Optimierungen gibt, welche jetzt, wo wir mehr ber Maven wissen, Sinn machen. Maven ist ein vielfltiges Werkzeug, welches so einfach oder auch komplex sein kann, wie Sie es gerade bentigen. Aus diesem Grund gibt es oft viele verschiedene Mglichkeiten, um die gleiche Aufgabe zu bewerkstelligen, und oft gibt es keinen einzigen "richtigen" Weg bei der Konfiguration Ihres Maven-Projektes. Bitte verstehen Sie den letzten Satz nicht falsch. Versuchen Sie nun nicht mit Maven etwas zu lsen, fr das Maven nicht konzipiert wurde! Auch wenn Maven eine Vielfalt verschiedener Anstze untersttzt, gibt es natrlich den "Maven Way", und Sie werden mit Maven produktiver sein wenn Sie diesen einschlagen. Das Ziel diesen Kapitels ist es, einige der Optimierungen weiterzugeben, welche Sie auch 168

Optimierung und berarbeitung der POMs auf ein bestehendes Maven-Projekt anwenden knnen. Warum haben wir nicht gleich ein optimiertes POM eingefhrt, warum der Umweg? POMs pdagogisch sinnvoll zu gestalten, und POMs in der Praxis effizient zu gestalten, sind zwei sehr unterschiedliche Anforderungen. Zwar ist es sicherlich sehr viel einfacher, eine bestimmte Einstellung in Ihrem Profil in der ~/.m2/settings.xml zu definieren, als deren Einbindung in der pom.xml Datei, aber wenn man ein Buch schreibt damit dieses gelesen wird, geht es auch meist darum das Tempo richtig zu whlen und dafr zu sorgen, dass nicht Konzepte eingefhrt werden, bevor Sie dazu bereit sind. In Part I, Maven by Example (Teil I: Maven by Example), haben wir uns grosse Mhe gegeben, den Leser nicht mit zu viel Information zu berlasten, und haben darum einige grundlegende Konzepte wie das des Elements dependencyManagement bewusst bersprungen. Dieses Element wird nun in diesem Kapitel eingefhrt. Im Part I, Maven by Example (Teil I: "Maven by Example") dieses Buches gibt es Beispiele, in welchen die Autoren eine Abkrzung gewhlt haben, oder ber ein wichtiges Detail grosszgig hinweggeschritten sind, einfach um Sie zgig zu den Kernpunkten des Kapitels weiterzuleiten. Sie konnten lernen wie man ein Maven Projekt aufsetzt, kompiliert und installiert, ohne dass Sie durch hunderte Seiten Detailspezifikation waten mussten, welche jeden letzten Schalter erklrte, der Ihnen zur Verfgung gestanden htte. Wir haben diesen Weg bewusst gewhlt, da es uns wichtig schien, den neuen Maven Benutzer schnell zu einem Ergebnis zu fhren, statt Ihn auf einem langen mandernden Weg zu begleiten, welcher uns durch eine schier endlos erscheinende Weite fhrt. Sobald Sie damit begonnen haben, selbst regelmssig Maven einzusetzen, sollten Sie wissen, wie man eigene Projekte und POMs analysiert. In diesem Kapitel treten wir nun einen Schritt zurck, und werfen einen Blick auf das was wir zum Abschlus von Chapter 7, Multi-module Enterprise Project (Kapitel 7: "Multi-Modul Enterprise Projekt") tatschlich bekommen haben.

8.2. POM Bereinigung


Die Optimierung eines multi-modularen POMs wird am besten in mehreren Phasen durchgefhrt, denn es gilt sich auf unterschiedliche Bereiche zu konzentrieren. Im 169

Optimierung und berarbeitung der POMs Normalfall suchen wir nach Wiederholungen innerhalb eines POM und ber dessen Geschwister-POMs hinweg. Wenn Sie am Anfang stehen, oder wenn sich ein Projekt noch immer sehr schnell entwickelt, es ist akzeptabel, einige Abhngigkeiten und Plugin-Konfigurationen hier und da zu duplizieren, aber so wie das Projekt reift und die Anzahl der Module sich erhht, sollten Sie sich Zeit nehmen um die gemeinsamen Abhngigkeiten sowie Plugin Konfigurationen zu refaktorieren/berarbeiten. Die Erstellung effizienter POMs trgt Sie ein grosses Stck des Weges, die Komplexitt Ihres Projekts zu verwalten whrend dieses noch immer wchst. Wo immer Verdopplungen von Informationen auftauchen knnen Sie davon ausgehen, dass es in der Regel einen besseren Weg gibt.

8.3. Optimirung der Abhngigkeiten


Wenn Sie einen Blick in die verschiedenen POMs in Chapter 7, Multi-module Enterprise Project (Kapitel 7: "Multi-Modul Enterprise Projekt") werfen, beachten Sie mehrere bestehende Muster der Replikation/Wiederholung. Das erste Muster, das wir sehen knnen ist, dass einige Abhngigkeiten wie Spring und Hibernate-Annotations in mehreren Modulen definiert werden. Die Hibernate Abhngigkeit hat in jeder Definition die Ausgrenzung von javax.transaction repliziert. Das zweite Muster von Wiederholung ist, dass manchmal mehrere Abhngigkeiten in einem Zusammenhang stehen und sich die gleiche Version teilen. Dies ist hufig der Fall, wenn ein Projekt Release aus mehreren eng gekoppelten Komponenten besteht. Sehen Sie sich zum Beispiel die Abhngigkeiten der Hibernate-Annotations sowie der Hibernate-Commons-Annotations an: beide tragen als Version 3.3.0.ga, und wir knnen davon ausgehen, dass die Version der beiden Abhngigkeiten sich auch in Zukunft im Gleichschritt bewegen wird. Sowohl die Hibernate-Annotations wie auch Hibernate-Commons-Annotations sind Komponenten des gleichen Projekts, freigegeben von JBoss. Wann immer es einen neuen Projekt Release gibt, werden diese beiden Abhngigkeiten sich ndern. Das letzte Muster der Replikation ist die Wiederholung der Geschwister-Modul Abhngigkeiten und Geschwister-Modul-Versionen. Maven bietet einfache Mechanismen, mit denen Sie alle Flle von Duplikation in das Top Level POM (Parent POM) ziehen 170

Optimierung und berarbeitung der POMs knnen. Ein kleine Diskrepanz der Version einer Abhngigkeit eines Projektes bezglich eines Bytecode-Manipulations Bibliothek mit dem Namen ASM, drei Ebenen tiefer in der Projekt-Hierarchie, fhrt leicht zur vollstndigen Blockade einer Web-Applikation, welche von einer ganz anderen Gruppe von Entwicklern bearbeitet wird, und von diesem speziellen Modul abhngig ist. Unit-Tests bestehen, da diese gegen eine Version der Abhngigkeit testen, und scheitern frchterlich in der Produktion, in welcher - in einem WAR-Archive gebndelt eine ganz andere Version dieser Abhngigkeit vorliegt. Sollten Sie Dutzende von Projekten am Laufen haben, welche alle mit etwas wie Hibernate Annotations arbeiten und deren Deklaration sich stndig wiederholt und dupliziert, mit allen Abhngigkeiten und Ausschlssen, so wird die durchschnittliche Zeit zwischen grossen Build Fehlern eher klein sein. So wie Ihre Maven Projekte immer weiter wachsen und komplexer werden, werden Ihre Listen von Abhngigkeiten wachsen; und Sie werden nicht umhinkommen, Versionen und Deklarationen Ihrer Abhngigkeiten in Ihrem Top Level POM zu konsolidieren. Die Wiederholung von Geschwister-Modul-Versionen bereiten das Feld fr einen besonders fieses Problem, welches zwar nicht direkt durch Maven verschuldet wird, aber dessen man sich erst bewusst wird, nachdem Sie ein paar Mal von diesem Fehler gebissen wurden. So Sie das Maven Release Plugin benutzen, ist die Verwaltung der Geschwister Versionen und deren Abhngigkeiten kein Thema, Versionen werden jeweils automatisch aktualisiert. Wenn Simple Web Version 1.3-Snapshot von Simple Persist Version 1.3-Snapshot abhngig ist, und Sie geben beide Module in der Version 1.3 frei, so ist das Maven Release-Plugin schlau genug, um die Versionen innerhalb Ihrer gesamten multi-modularen Projekt POMs automatisch anzupassen. Wenn Sie die Freigabe mittels dem Release-Plugin vornehmen werden automatisch alle Versionen in Ihrem Build auf 1.4-Snapshot hochgezhlt und das Release-Plugin wird darber hinaus allen Code in das Repository einchecken. Ein groes multi-modulares Projekt freizugeben knnte also nicht einfacher sein, bis ... Probleme treten auf, wenn Entwickler nderungen am POM einfliessen lassen, und sich in eine laufende Freigabe einmischen. Oftmals fgt ein Entwickler im Konfliktfall zwei Abhngigkeiten zusammen, oder agiert falsch im Fall eines 171

Optimierung und berarbeitung der POMs Modul Konflikts, so dass er unwissentlich auf eine frhere Version zurckrollt. Da die aufeinander folgenden Versionen der Abhngigkeit gewhnlich kompatibel sind, zeigt sich dies nicht, wenn der Entwickler seinen Build erstellt, und es zeigt sich ebenso wenig in einem Continuous Integration Build-System. Stellen Sie sich einen sehr komplexen Build vor, der Trunk besteht aus Komponenten des 1.4-Snapshot, und jetzt mssen Sie sich vorstellen, dass Entwickler A eine Komponente tief in der Hierarchie des Projekts aktualisiert, welche von der Version 1.3-Snapshot der Komponente B abhngt. Obwohl die meisten Entwickler bereits auf Version 1.4-Snapshot bauen, wird es beim Build keinen Fehler geben, solange wie 1.3-SNAPSHOT und 1.4-SNAPSHOT der Komponente B kompatibel sind. Maven wird auch weiterhin den Build auf der Basis der 1.3-SNAPSHOT-Version von Komponente B ab dem lokalen Repository des Entwicklers durchfhren. Alles scheint ganz reibungslos zu funktionieren, der Build des Projektes luft durch, der Continuous Integration Build funktioniert ebenfalls, ein paar esoterische Fehler im Zusammenhang mit der Komponente B, aber diese werden auf das Werk hinterlistiger Kobolde abgetan. Mittlerweile pumpt eine Pumpe im Reaktor Raum und baut stetig Druck auf, bis schliesslich etwas bricht ... Jemand, nennen wir ihn Herr Unachtsam, hatte beim Zusammenfhren einen Konflikt in Komponente A, um diesen zu lsen, wurde irrtmlicherweise die Abhngigkeit von Komponente A auf Komponente B Version 1.3-SNAPSHOT gekoppelt, whrend der Rest des Projekts stets weiter marschiert. Ein Gruppe Entwickler haben die ganze Zeit versucht, den Fehler in Komponente B zu beheben, und diese stehen vor einem Rtsel, warum Ihnen dies offenbar in der Produktion nicht gelingt. Schlielich befasst sich jemand mit Komponente A und realisiert, dass die Abhngigkeit auf die falsche Version zeigt. Es bleibt zu hoffen, dass der Fehler nicht gro genug war, um Geld oder Leben zu kosten, aber Herr Unachtsam ist beschmt, und seine Kollegen vertrauen ihm ein bisschen weniger als vor der ganzen Abhngigkeits-Sache. (Ich hoffe zwar, dass Herr Unachtsam realisiert, dass es sich hier um einen Benutzerfehler handelt, und das Maven nicht Schuld war. Leider ist es mehr als wahrscheinlich Herr Unachtsam startet eine furchtbare Blog-Tirade und beschwert sich endlos ber Maven, allein schon um sich besser zu fhlen.) 172

Optimierung und berarbeitung der POMs Glcklicherweise ist die Weiderholung von Abhngigkeiten und die Unstimmigkeit von Geschwisterversionen einfach vermeidbar. Es braucht nur einige kleine Vernderungen. Der erste Schritt ist, alle Abhngigkeiten welche in mehr als einem Projekt vorkommen zu finden und diese in das darber stehende POM im Abschnitt dependencyManagement aufzunehmen. Die Geschwister Abhngigkeiten blenden wir fr den Moment aus. Das Simple Parent POM beinhaltet nun die folgenden Eintrge:
<project> ... <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.0.ga</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>3.3.0.ga</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.2.5.ga</version> <exclusions> <exclusion> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </dependencyManagement> ... </project>

Sobald die Abhngigkeiten im bergeordneten POM eingetragen sind, mssen wir 173

Optimierung und berarbeitung der POMs diese Eintrge aus den 'Kind'-POM entfernen. Andernfalls werden die bestehenden Eintrge die des bergeordneten Abschnitts dependencyManagement bersteuern. Der Einfachheit halber werden wir hier nur das Simple Model Modul POM zeigen:
<project> ... <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> </dependency> </dependencies> ... </project>

Das nchste, das wir angehen sollten, ist die Replikation der Hibernate-Annotations sowie der Hibernate-Commons-Annotations, da diese Versionen immer bereinstimmen sollten. Wir tun dies, indem wir ein Property mit dem Namen hibernate-annotations-version erstellen. Der daraus resultierende Abschnitt des bergeordneten POM sieht wie folgt aus:
<project> ... <properties> <hibernate.annotations.version>3.3.0.ga</hibernate.annotations.version> </properties> <dependencyManagement> ... <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>${hibernate.annotations.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>${hibernate.annotations.version}</version> </dependency> ... </dependencyManagement> ... </project

174

Optimierung und berarbeitung der POMs Zum Schluss nehmen wir uns noch der Geschwister-Abhngigkeit an. Einen Weg welchen wir beschreiten knnten wre, wie zuvor auch, diese Abhngigkeiten nach oben in das bergeordnete POM in den Abschnitt dependencyManagement zu verschieben, genau wie die Abhngigkeiten zuvor, mit einer definierten Versionen der Geschwister-Projekte im Top-Level Projekt POM. Dies ist sicherlich ein gltiges Konzept. Allerdings knnen wir dieses Problem mittles dem Einsatz zweier eingebauter Variablen lsen: ${project.groupId} und ${project.version}. Da es sich um Geschwister Abhngigkeiten handelt, macht es nicht viel Sinn, einen numerischen Wert im bergeordneten POM zu definieren, daher sttzen wir uns auf die eingebaute Eigenschaft ${project.version}. Da alle Geschwister derselben Gruppe angehren, knnen wir weitere Zukunftssicherheit einbauen, indem wir auf das bestehende POM mittels der Eigenschaft ${project.groupId} verweisen. Der Abschnitt der Abhngigkeiten des Simple Command Moduls sieht nun wie folgt aus:
<project> ... <dependencies> ... <dependency> <groupId>${project.groupId}</groupId> <artifactId>simple-weather</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>simple-persist</artifactId> <version>${project.version}</version> </dependency> ... </dependencies> ... </project>

Zusammenfassend hier die beiden Optimierungen welche wir angewandt haben, um Wiederholungen in der Deklaration der Abhngigkeiten zu reduzieren:
Ziehen Sie gemeinsame Abhngigkeiten in das bergeordnete POM in den Abschnitt dependencyManagement

175

Optimierung und berarbeitung der POMs Wenn mehr als ein Projekt von einer Abhngigkeit Gebrauch macht, knnen Sie die Abhngigkeit im Element dependencyManagement des bergeordneten POM erfassen. Im bergeordneten POM werden Version und Ausschlsse gesetzt, in den untergeordneten POM mssen sie lediglich die Koordinaten groupId und artifactId angeben. Untergeordnete Projekte knnen die Version sowie die Ausschlsse weglassen, sollte die Abhngigkeit im Element dependencyManagement deklariert sein. Benutzen Sie auf die eingebauten Variablen 'version' und 'groupId' Um sich auf ein Geschwisterprojekt zu beziehen, verwenden Sie ${project.version} und ${project.groupId}. Geschwister-Projekte umfassen fast immer die gleiche groupId und Release-Version. Mittels ${project.version} entschrfen Sie das oben aufgefhrte Problem der Geschwister-Version Missverhltnisse.

8.4. Optimirung der Plugins


Betrachten wir die verschiedenen Plugin-Konfigurationen, knnen wir sehen, dass die Abhngigkeiten zu HSQL DB an mehreren Orten wiederholt wird. Leider ist das Element dependencyManagement nicht auf Plugin-Abhngigkeiten anwendbar, dennoch knnen wir ein Property benutzen, um die verschiedenen Versionen zu konsolidieren. Tendeziell definieren komplexe multi-modulare Maven-Projekte alle Versionen im Top-Level-POM. Dieses Top-Level-POM wird dann zu einem Dreh-und Angelpunkt bezglich allen Vernderungen, welche Auswirkungen auf das gesamte Projekt haben. Stellen Sie sich die Version als Java String in einer Java Klasse vor; bei einer stndigen Wiederholung werden Sie wahrscheinlich eine Variable einsetzen wollen, damit, wenn es den String zu ndern gilt, Sie dies nur an einem Ort durchfhren mssen. Das 'Hochziehen' der Version von HSQLDB in ein Property des Top-Level-POM liefert uns fogenden Eintrag:
<project> ... <properties> <hibernate.annotations.version>3.3.0.ga</hibernate.annotations.version> <hsqldb.version>1.8.0.7</hsqldb.version> </properties> ...

176

Optimierung und berarbeitung der POMs


</project>

Das nchste, was wir bemerken ist, dass die doppelt, sowohl im Simple Websowie im Simple Command Modul vorkommt. Entsprechend der Abhngigkeiten knnen wir die Plugin-Konfiguration in der Top-Level-POM Datei genau wie Abhngigkeiten im Element dependencyManagement definieren. Hierfr benutzen wir das Element pluginManagement in der Top Level POM Datei.
Hibernate3-Maven-Plugin-Konfiguration
<project> ... <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</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>${hsqldb.version}</version> </dependency> </dependencies> </plugin> </plugins> </pluginManagement> </build> ... </project>

177

Optimierung und berarbeitung der POMs

8.5. Optimierung unter Zuhilfenahmen des Maven Dependency Plugin


Grssere Projekte, haben eine Tendenz, dass mit wachsender Anzahl Abhngigkeiten auch zustzliche Abhngigkeiten in ein POM einfliessen. ber die Zeit hinweg werden sich die Abhngigkeiten verndern, und so werden Sie ber kurz oder lang auch verwaiste Abhngigkeiten beherbergen, genauso wie Sie Bibliotheken anziehen werden, welche nicht deklariert sind. Da Maven 2.x transitive Abhngigkeiten im Geltungsbereich des Compilers einschliesst, kann es passieren, dass Ihr Projekt zwar fehlerfrei kompiliert, jedoch in der Produktion nicht lauffhig ist. Nehmen Sie zum Beispiel ein Projekt welches auf eine weit verbreitete Bibliothek wie Jakarta Commons BeanUtils aufsetzt. Statt diese explizit zu referenzieren, verlassen Sie sich auf die transitive Abhngigkeit, da Sie ebenfalls Hibernate einsetzen, welches diese Library transitiv deklariert. Ihr Projekt kompiliert und luft wie erwartet, bis Sie eines Tages Hibernate updaten und hierbei auf eine Version wechseln, welche nicht mehr auf BeanUtils aufbaut. Pltzlich bekommen Sie viele Fehler, deren Grund nicht gerade offensichtlich ist. Darber hinaus kann Maven auftretende Konflikte nicht lsen, da die Abhngigkeit nicht explizit deklariert wurde. Eine bewhrte Faustregel ist es, alle ausdrcklich im Code deklarierten Abhngigkeiten explizit zu deklarieren. Wenn Sie Jakarta Commons Beanutils importieren, so sollten Sie diese auch explizit in der pom.xml-Datei festhalten. Glcklicherweise kann Ihnen hier Maven helfen, denn durch Bytecode Analyse ist Maven in der Lage, solche direkten Abhngigkeiten aufzudecken. Lassen Sie uns das zuvor optimierte POM auf Fehler durchleuchten:
$ mvn dependency:analyze [INFO] Scanning for projects... [INFO] Reactor build order: [INFO] Chapter 8 Simple Parent Project [INFO] Chapter 8 Simple Object Model [INFO] Chapter 8 Simple Weather API [INFO] Chapter 8 Simple Persistence API [INFO] Chapter 8 Simple Command Line Tool [INFO] Chapter 8 Simple Web Application [INFO] Chapter 8 Parent Project [INFO] Searching repository for plugin with prefix: 'dependency'.

178

Optimierung und berarbeitung der POMs


... [INFO] -----------------------------------------------------------------------[INFO] Building Chapter 8 Simple Object Model [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] Nothing to compile - all classes are up to date [INFO] [dependency:analyze] [WARNING] Used undeclared dependencies found: [WARNING] javax.persistence:persistence-api:jar:1.0:compile [WARNING] Unused declared dependencies found: [WARNING] org.hibernate:hibernate-annotations:jar:3.3.0.ga:compile [WARNING] org.hibernate:hibernate:jar:3.2.5.ga: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] org.sonatype.mavenbook.ch08:simple-model:jar:1.0:compile [WARNING] Unused declared dependencies found: [WARNING] org.apache.velocity:velocity:jar:1.5:compile [WARNING] javax.servlet:jstl:jar:1.1.2:compile [WARNING] taglibs:standard:jar:1.1.2:compile [WARNING] junit:junit:jar:3.8.1:test

Die vorangegangene, gekrzte Darstellung zeigt die Ausgabe des Goals dependency:analyse. Dieses Goal analysisert, ob es irgendwelche indirekten Abhngigkeiten gibt, oder Abhngigkeiten, welche zwar referenziert, aber nicht 179

Optimierung und berarbeitung der POMs deklariert werden. Im Projekt Simple Model zeigt das Plugin beispielhaft auf, wie die Abhngigkeit javax.persistence:persistence-api eine "nicht deklarierte" Abhngigkeit darstellt. Um dies genauer zu untersuchen, welchseln Sie in das Verzeichnis des Simple Model Projekt und rufen dort das Goal dependency:tree auf. Dies wird Ihnen eine Auflistung aller direkten und transitiven Abhngigkeiten ausgeben.
$ mvn dependency:tree [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'dependency'. [INFO] -----------------------------------------------------------------------[INFO] Building Chapter 8 Simple Object Model [INFO] task-segment: [dependency:tree] [INFO] -----------------------------------------------------------------------[INFO] [dependency:tree] [INFO] org.sonatype.mavenbook.ch08:simple-model:jar:1.0 [INFO] +- org.hibernate:hibernate-annotations:jar:3.3.0.ga:compile [INFO] | \- javax.persistence:persistence-api:jar:1.0:compile [INFO] +- org.hibernate:hibernate:jar:3.2.5.ga:compile [INFO] | +- net.sf.ehcache:ehcache:jar:1.2.3:compile [INFO] | +- commons-logging:commons-logging:jar:1.0.4:compile [INFO] | +- asm:asm-attrs:jar:1.5.3:compile [INFO] | +- dom4j:dom4j:jar:1.6.1:compile [INFO] | +- antlr:antlr:jar:2.7.6:compile [INFO] | +- cglib:cglib:jar:2.1_3:compile [INFO] | +- asm:asm:jar:1.5.3:compile [INFO] | \- commons-collections:commons-collections:jar:2.1.1:compile [INFO] \- junit:junit:jar:3.8.1:test [INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------

Aus dieser Ausgabe, knnen wir ablesen, dass das bemngelte persistence-api durch Hibernate eingeflossen ist. Ein flchtiger Scan des Quellcodes aus diesem Modul wird uns zeigen dass hier tatschlich viele direkte Referenzen auf die Abhngigkleit javax.persistence vorliegen. Die einfache Lsung besteht darin einen Verweis auf die Abhngigkeit in das POM aufzunehmen. In diesem Beispiel setzen wir die Abhngigkeit zur Version in den Abschnitt dependencyManagement des POM von Simple Parent, da die Abhngikeit im Zusammenhang mit Hibernate steht, und Hibernate dort deklariert wird. Irgendwann wird der Zeipunkt gekommen sein, und Sie werden die Version von Hibernate upgraden. Die Nhe der Auflistung des persistence-api wird es Ihnen dann klarer aufzeigen, dass hier eine Abhngigkeit besteht. 180

Optimierung und berarbeitung der POMs Beim betrachten der Ausgabe von dependency:analyse des Simple Web Moduls werden Sie feststellen, dass Sie eine Referenz zum Simple Model erstellen sollten. Ihr Quellcode in Simple Web referenziert direkt Objekte aus Simple Model welches jedoch nur transitiv ber Simple Persist eingebunden ist. Da es sich hier um eine Abhngigkeit unter Geschwistern handelt welche beide die gleiche groupId sowie version haben, knnen Sie die Abhngigkeit im POM von Simple Web in der Form ${project.goupId} und ${project.version} vornehmen. Wie konnte Maven diese Abhngigkeiten berhaupt aufdecken? Woher weiss dependency:analyse berhaupt welche Klassen und andere Abhngigkeiten von Ihrem Bytecode referenziert werden? Das Dependency Plugin benutzt den ObjectWeb ASM Toolkit um den Bytecode zu analysieren. Mittels ASM durchluft das Dependency Plugin den gesamten Code und erstellt einen Baum aller Klassen welche im aktuellen Projekt referenziert werden. Anschliessend durchluft das Werkzeug alle deklarierten und transitiven Abhngigkeiten und steicht alle Klassen welche den direkten Abhngigkeiten zugeordnet werden knnen. Klassen welche nicht Teil der direkten Abhngigkeitsliste sind, mssen somit der transitiven Abhngigkeitsliste entspringen. Diese knnen als eingebundene, jedoch nicht deklarierte Abhngigkeit (used, undeclared dependencies) ausgegeben werden. Im Gegensatz dazu ist die Liste der deklarierten, aber nicht eingesetzten Abhngigkeiten ungleich schwieriger zu validieren, und weit weniger ntzlich als die der gebrauchten, nicht deklarierternAbhngigkeiten. Zum einen werden manche der Abhngigkeiten nur whrend der Laufzeit oder in Tests angezogen, diese sind im Bytecode nicht ersichtlich. Beim Betrachten der Liste wird dies offensichtlich: so ist zum Beispiel JUnit Teil der Liste, was zu erwarten ist, da es nur zum Test eingesetzt wird. Sie werden auch feststellen, dass Velocity sowie das Servlet API auf der Liste der Abhngigkeiten des Simpel Web Moduls erscheint. Das ist nicht weiter verwunderlich, da whrend das Projekt keine direkten Verweise auf die Klassen dieser Artefakte hat, diese nach wie vor im laufenden Betrieb unverzichtbar sind. Seien Sie vorsichtig mit dem Entfernen unbenutzer, deklarierter Abhngigkeiten (unused, declared dependencies), denn ausser Sie haben eine sehr gute Testabdeckung fgen Sie hierbei leicht Laufzeitfehler ein. Eine noch bsere 181

Optimierung und berarbeitung der POMs berraschung rhrt von Bytecode Optimierern her: So ist es zum Beispiel legal den Wert einer Konstanten zu ersetzen um damit die bestehende Referenz wegzuoptimieren. Die Entfernung dieser Abhngigkeit fhrt jedoch dazu, dass die Kompilierung scheitert, obschon das Tool zeigt, dass diese ungenutzt ist. Es ist abzusehen, dass zuknftige Versionen des Dependency Maven-Plugin wird verbesserte Techniken zur Erkennung solcherlei Problemstellungen bereitstellen werden. Es ist zu empfehlen, dass Sie ab und zu dependency:analyse ausfhren, um solcherlei Fehler des POM aufzudecken. Das Goal kann derart konfigueriert werden, dass beim Auftreten bestimmter Konditionen der Build abbricht, alternativ wird ein Report bereitgestellt.

8.6. Abschliessende POMs


Abschliessend sollen hier nun die endgltigen, optimierten pom.xml-Dateien als Referenz fr dieses Kapitel widergegeben werden. Hier ist das Top-Level POM fr Simple Parent: Example 8.1. Abschliessendes POM des Moduls Simple-Parent
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook.ch08</groupId> <artifactId>simple-parent</artifactId> <packaging>pom</packaging> <version>1.0</version> <name>Chapter 8 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>

182

Optimierung und berarbeitung der POMs


<pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</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>${hsqldb.version}</version> </dependency> </dependencies> </plugin> </plugins> </pluginManagement> </build> <properties> <hibernate.annotations.version>3.3.0.ga</hibernate.annotations.version> <hsqldb.version>1.8.0.7</hsqldb.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.5</version> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId>

183

Optimierung und berarbeitung der POMs


<version>1.0</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>${hibernate.annotations.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> <version>${hibernate.annotations.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.2.5.ga</version> <exclusions> <exclusion> <groupId>javax.transaction</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>

The POM shown in Example 8.2, Abschliessendes POM des Mouls Simple-Command captures the POM for simple-command, the command-line version of the tool. Die folgenden POM erfasst das Simple Version des Tools (Dienstprogramm).
Command Tool,

die Kommando-Zeilen

Example 8.2. Abschliessendes POM des Mouls Simple-Command


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0

184

Optimierung und berarbeitung der POMs


http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch08</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> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>org.sonatype.mavenbook.weather.Main</mainClass> <addClasspath>true</addClasspath> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</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>${project.groupId}</groupId> <artifactId>simple-weather</artifactId> <version>${project.version}</version> </dependency> <dependency>

185

Optimierung und berarbeitung der POMs


<groupId>${project.groupId}</groupId> <artifactId>simple-persist</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> </dependency> </dependencies> </project>

Darauf folgend das POM des Simple Model Projekt. Simple alle Objekt Modelle der gesamten Anwendung.

Model

beinhaltet

Example 8.3. Abschlissendes POM des Moduls Simple-Model


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch08</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>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> </dependency> </dependencies>

186

Optimierung und berarbeitung der POMs


</project>

Im folgenden das POM des Simple Persist Persistenzlogik durch Hibernate gekapselt.

Moduls.

Hierin wird die gesamte

Example 8.4. Abschliessendes POM fdes Moduls Simple-Persist


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch08</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-persist</artifactId> <packaging>jar</packaging> <name>Chapter 8 Simple Persistence API</name> <dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>simple-model</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commons-annotations</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId>

187

Optimierung und berarbeitung der POMs


</dependency> </dependencies> </project>

Dann das Simple Weather Projekt, das Projekt, welches die gesamte Arbeit mit dem Yahoo! Wetter RSS-Feed und dessen Analyse zu tun hat. Dieses Projekt ist von Simple Model abhngig. Example 8.5. Abschlissendes POM des Moduls Simple-Weather
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch08</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-weather</artifactId> <packaging>jar</packaging> <name>Chapter 8 Simple Weather API</name> <dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>simple-model</artifactId> <version>${project.version}</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>org.apache.commons</groupId> <artifactId>commons-io</artifactId>

188

Optimierung und berarbeitung der POMs


<version>1.3.2</version> <scope>test</scope> </dependency> </dependencies> </project>

Schlielich ist das Simple Web Projekt, eine Web-Applikation welche die abgerufenen Wettervorhersagen in einer HSQLDB Datenbank speichert, sowie mit Simple Weather und den daraus bereitgestellten Bibliotheken kommuniziert. Example 8.6. Abschliessendes POM des Moduls Simple-Webapp
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook.ch08</groupId> <artifactId>simple-parent</artifactId> <version>1.0</version> </parent> <artifactId>simple-webapp</artifactId> <packaging>war</packaging> <name>Chapter 8 Simple Web Application</name> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>simple-model</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>simple-weather</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>simple-persist</artifactId> <version>${project.version}</version> </dependency> <dependency>

189

Optimierung und berarbeitung der POMs


<groupId>org.springframework</groupId> <artifactId>spring</artifactId> </dependency> <dependency> <groupId>javax.servlet</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>org.apache.velocity</groupId> <artifactId>velocity</artifactId> </dependency> </dependencies> <build> <finalName>simple-webapp</finalName> <plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.9</version> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>${hsqldb.version}</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>

8.7. Fazit
Dieses Kapitel hat aufgezeigt, welche Techniken Ihnen zur Verbesserung der Kontrolle Ihrer Abhngigkeiten und Plugins zur Verfgung stehen, um Ihre zuknftigen Builds wartungsfreundlich zu gestalten. Wir empfehlen in regelmigen Abstnden der berprfung Ihres Builds wie aufgezeigt, um sicherzustellen, dass Wiederholungen und damit verbundene potenzielle Krisenherde minimiert werden. Wie Ihr Projekt reift, werden Sie zwangslufig 190

Optimierung und berarbeitung der POMs neue Abhngigkeiten einfhren, oder Sie werden feststellen, dass eine Einzelabhngigkeit nun an 10 oder mehr Orten zum Einsatz kommt und somit besser hher aufgehngt wird. Die Liste der zum Einsatz kommenden bzw. nicht kommenden Abhngigkeiten verndert sich im Laufe der Zeit und lsst sich mit dem Dependency Maven Plugin leicht bearbeiten.

191

Part II. Maven Reference

192

Chapter 9. Das Projekt Objekt Modell (POM)


9.1. Einfhrung
Dieses Kapitel deckt das zentrale Konzept hinter Maven ab: das Projekt Objekt Modell (POM). Es ist im POM, in welchem die Identitt und die Struktur eines Projektes definiert werden, Builds konfiguriert werden, und Projektbeziehungen untereinander bestimmt werden. Das bestehen einer Datei pom.xml definiert ein Maven Projekt.

9.2. Das Projekt Objekt Modell: POM


Maven Projekte, Abhngigkeiten, Builds und Artefakte: das alles sind Objekte, welche modelliert und beschrieben werden mssen. Diese Objekte werden in einer XML-Datei mit dem Namen Projekt Objekt Modell beschrieben. Das POM bestimmt fr Maven was fr eine Art von Projekt vorliegt, und wie das Standardverhalten angepasst werden muss, um aus den Quellen die erwartete Ausgabe zu generieren. Gleich einer Webapplikation welche eine Datei web.xml besitzt, welche diese beschreibt, konfiguriert und definiert, so wird ein Maven Projekt durch die Anwesenheit einer Datei pom.xml definiert. Es ist eine beschreibende Deklaration des Projektes fr Maven. Es ist die bildliche "Karte" welche Maven braucht, um zu verstehen, was vorliegt und wie daraus Ihr Projektbuild erstellt wird. Sie knnten eine pom.xml Datei auch als sinngemsses quivalent eines Makefiles oder einer Ant build.xml Datei sehen. Wenn Sie GNU make benutzen um ein Programm wie z.B. MySQL zu builden, so haben Sie fr gewhnlich eine Datei, das Makefile, welche explizite Instruktionen bereithlt, wie man aus den Quelldateien zu den Binrdateien kommt. Auch wenn Sie Apache Ant benutzen, werden Sie hchstwarscheinlich eine Datei build.xml haben, welche explizite 193

Das Projekt Objekt Modell (POM) Anweisungen enthlt wie vorzugehen ist: bereitstellen, kompilieren, packetieren und deployen der Applikation. make, ant und Maven (mvn) sind sich hnlich, indem sie auf die Prsenz einer gemeinhin bekannten Datei wie dem makefile, build.xml oder pom.xml absttzen. Das ist aber auch der Punkt an welchem die hnlichkeiten aufhren. Wenn Sie eine Maven pom.xml-Datei genauer ansehen, so besteht ein Grossteil des POMs aus Beschreibungen: Wo liegen die Quelldateien? Wo sind die Ressourcen zu finden? Wie wird packetiert? Der Blick auf ein Ant build.xml bringt etwas gnzlich anderes zu Gesicht. Sie werden explizite Instruktionen fr Tasks wie z.B. das Kompilieren von Klassen finden. Das Maven POM hingegen ist deklarativ und auch wenn es mittels dem Maven Ant Plugin mglich ist prozedurale Anpassungen einfliessen zu lassen, mssen Sie sich im allgemeinen nicht um die Details Ihres Projekt Build Prozesses kmmern. Das POM ist auch nicht spezifisch entworfen um Java Projekte zu builden. Auch wenn die allermeisten Beispiele dieses Buchs davon handeln Java Applikationen zu erstellen, so gibt es in der Definition des Projekt Objekt Modells nichts, was tatschlich Java spezifisch ist. Auch wenn die standardmssigen Maven Plugins darauf ausgelegt sind Java JAR Artefakte aus einer Reihe von Quellen, Tests und Resources zu bauen, so hindert Sie nichts daran ein POM fr ein C# Projekt zu definieren, und mittles Werkzeugen von Microsoft proprietre Microsoft Binrdateien zu erstellen. Ebensowenig hindert Sie nichts daran ein POM fr ein technisches Fachbuch zu erstellen. Tatschlich sind die Quellen dieses Buches sowie die Beispiele dieses Buches in einem multi-modularen Maven Projekt definiert, welches eines der vielen Maven DocBook Plugins benutzt um DocBook XSL auf eine Reihe von XML Dateien anwendet. Andere Entwickler haben Maven Plugins geschrieben, um Adobe Flex Quellen in SWCs und SWFs zu berfhren, und weitere haben Maven eingesetzt, um Projekte zu erstellen welche in C geschrieben sind. Wir haben ergrndet, dass das POM beschreibt und deklariert, aber das es im Gegensatz zu Ant oder Make keine exakten Instruktionen beinhaltet. Weiter haben wir festgestellt, dass die Konzepte des POM nicht Java spezifisch sind. Um tiefer in die Details einzusteigen, sehen Sie sich die Figure 9.1, Das Projekt Objekt Modell (Abbildung 9.1: Das Projekt Objekt Modell) bezglich einer Beschreibung der Inhalte eines POM genauer an: 194

Das Projekt Objekt Modell (POM)

Figure 9.1. Das Projekt Objekt Modell Ein POM enthlt vier Arten von Beschreibungen und Konfigurationen: Allgemeine Projekt Informationen Diese umfassen den Projektnamen, die URL eines Projektes, die untersttzende Organisation sowie eine Auflistung der Entwickler und Zutrger, sowie die Lizenzbedingungen eines Projektes. Build Einstellungen In diesem Abschnitt wird das Verhalten des Maven Builds definiert. Wir knnen hier bestimmen wo die Quellen oder Tests zu finden sind, knnen zustzliche oder andere Plugins einbinden. Es knnen Plugin Goals an Lifecyclephasen gebunden werden und spezielle Parameter zur Erstellung des Projektsites eingestellt werden. Build Umgebung Die Build Umgebung besteht aus Profilen, welche fr unterschiedliche Umgebungen aktiviert werden knnen. Zum Beispiel mag es sein, dass Sie 195

Das Projekt Objekt Modell (POM) whrend der Entwicklung auf einen Entwicklungsserver deployen wollen, hingegen in der Produktion wollen Sie auf eine Produktionsmaschiene deployen. Die Build-Umgebung passt die Build Einstellungen ihren spezifischen Umgebungen an, und wird hufig durch eine benutzerspezifische Datei settings.xml unter ~/.m2 ergnzt. Auf die Datei settings.xml wird im weiteren im Chapter 11, Build-Profile (Kapitel 11: Build Profile) sowie im Abschnitt A.1: bersicht des Section A.2, Die Details der settings.xml Datei (Appendix A: Settings Details eingegangen). POM Beziehungen Ein Projekt ist selten freistehend; es hngt von weiteren Projekten ab, erbt Einstellungen von bergeordneten Projekten, definiert seine eigenen Koordinaten und kann auch Untermodule einbinden.

9.2.1. Das Super POM


Vor wir uns mit einigen Beispielen von POMs beschftigen, lassen Sie uns ein zunchst das Super POM genauer ansehen. Alle Maven POM Projekte erweitern das Maven Super POM, welches die Standardeinstellungen definiert, welche von allen Projekten geteilt werden. Das Super POM ist Teil der Maven Installation und kann im Verzeichnis /usr/local/maven/lib in der Datei maven-2.0.9-uber.jar gefunden werden. Wenn Sie in dieses Jar-Archiv hineinsehen, so finden Sie dort eine Datei mit dem Namen pom-4.0.0.xml im Package org.apache.maven.project. Das Super POM von Maven wird in Example 9.1, Das Super POM (Beispiel 9.1: Das Super POM) wiedergegeben. Example 9.1. Das Super POM
<project> <modelVersion>4.0.0</modelVersion> <name>Maven Default Project</name> <repositories> <repository> <id>central</id> # <name>Maven Repository Switchboard</name> <layout>default</layout> <url>http://repo1.maven.org/maven2</url> <snapshots>

196

Das Projekt Objekt Modell (POM)


<enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>central</id> # <name>Maven Plugin Repository</name> <url>http://repo1.maven.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> <releases> <updatePolicy>never</updatePolicy> </releases> </pluginRepository> </pluginRepositories> <build> # <directory>target</directory> <outputDirectory>target/classes</outputDirectory> <finalName>${pom.artifactId}-${pom.version}</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>

197

Das Projekt Objekt Modell (POM)


</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> <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>

198

Das Projekt Objekt Modell (POM)


<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> </project>

Das Super POM definiert einige Standardeinstellungen welche von allen Projekten geerbt werden. Diese Werte werden in den folgenden Abschnitten erlutert: Das standardmssige Super POM definiert ein einziges entferntes Maven Repository, welches die Kennung central trgt. Alle Maven Clients lesen standardmssig von diesem zentralen Repository. Diese Einstellung kann mittels einer benutzerdefinierten settings.xml Datei bersteuert werden. Beachten Sie, dass die standardmssige Super POM Datei snapshot Artefakten des zentralen Repository ausschliesst. Sollten Sie also auf Snapshot Artefakte angewiesen sein, so mssen Sie die Einstellungen des Repositories in Ihrer settings.xml Datei anpassen. Einstellungen sowie Profile werden in Chapter 11, Build-Profile (Kapitel 11: Build Profile) sowie Section A.2, Die Details der settings.xml Datei (Abschnitt A.1: Schnellbersicht des Appendix A: Einstellungen im Detail) ausgefhrt. Ebenfalls im zentralen Maven Repository sind Plugins abgelegt. Das standardmssige Maven Plugin Repository ist ebenfalls das zentrale Maven Repository. Snapshots sind abgeschalten und die Einstellung fr Updates ist auf "never" (nie) eingestellt. Das bedeutet, dass Maven niemals automatisch ein Plugin updaten wird sollte eine neue Version vorliegen. Das Element build setzt die Standardwerte auf die Maven Standard 199

Das Projekt Objekt Modell (POM) Verzeichnisstruktur. Seit der Version 2.0.9 von Maven werden standardmssige Einstellungen fr die Versionen von core-Plugins innerhalb des Super POM gesetzt. Dies wurde eingefhrt, um Benutzern welche keine Plugin Versionen in den POMs setzen eine grssere Stabilitt zu ermglichen.

Figure 9.2. Das Super POM ist immer das hchste bergeordnete POM

9.2.2. Das simpelste POM


Alle Maven POM erben Grundeinstellungen vom Super POM (dieses wurde im vorhergehenden Abschnitt eingefhrt, Section 9.2.1, Das Super POM (Abschnitt 9.2.1: das Super POM)). Sollten Sie also ein einfaches Projekt erstellen wollen, welches ein Projekt aus den Quellen von src/main/java eine Jar-Datei erstellt, Junit Tests unter src/test/java ablaufen lsst, und sodann eine Projektseite mittels mvn site erstellt, so mssen Sie nichts weiter spezifizieren. Alles was Sie in diesem Fall tun mssen ist, das allereinfachste POM zu erstellen, wie dies in Example 9.2, Das einfachste Maven POM (Beispiel 9.2: Das einfachste Maven POM) dargestellt ist. Diese POM definiert lediglich eine groupID, artifactID sowie version, die einzigen drei notwendigen Koordinaten eines jeden Projektes. 200

Das Projekt Objekt Modell (POM) Example 9.2. Das einfachste Maven POM
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook.ch08</groupId> <artifactId>simplest-project</artifactId> <version>1</version> </project>

Ein so einfaches POM ist mehr als ausreichend fr ein einfaches Projekt welches eine Jar Datei erstellt, eine Java Bibliothek zum Beispiel. Das Projekt is unabhngig und steht in keiner Beziehung zu anderen Artefakten. Es fehlen jegliche weitergehenden Informationen wie zum Beispiel Name oder URL. Wrden Sie dieses POM erstellen und dann einige Quelldatein unter dem Unterverzeichnis src/main/java erstellen, wo wrde der Aufruf von mvn package ein einfaches Jar.Archiv erstellen und unter target/simple-project-1.jar ablegen.

9.2.3. Das tatschliche POM


Das einfachste POM fhrt uns geradezu auf das Konzept des tatschlichen POM. Da Projekt Objekt Modelle auch von anderen POM abgeleitet sin knnen, ist es notwendig POM Dateien immer im Kontext des Super POM sowie allen anderen bergeordneten POM und schliesslich des aktuellen POM zu sehen. Maven geht vom Super POM aus und bersteuert die Einstellungen mit den nachfolgenden Einstellungen bergeordneter POMs. Schliesslich berschreibt es die bislang gewonnenen Einstellungen mit denen des (aktuellen) POM. Daraus erhlt Maven das tatschliche POM, das eine - strickten Regeln folgende - Mischung der verschiedenen POM darstellt. Sollten Sie also das tatschliche POM eines Projektes sehen wollen, so mssen Sie das Goal effective-pom des Maven Help Plugin aufrufen, welches bereits zuvor in Section 2.8, Das Maven Hilfe Plugin (Kapitel 2.8: Benutzen des Maven Help Plugin") eingefhrt wurde. Um das Goal effective-pom aufzurufen, geben Sie den folgenden Befehl in einem Verzeichnis welches eine pom.xml Datei enthlt, ein:
$ mvn help:effective-pom

201

Das Projekt Objekt Modell (POM) Die Verarbeitung des Goal effective-pom sollte Ihnen eine XML Struktur des tatschlich vorliegenden POM, der Verbindung des Super POM, aller bergoerdneter POM sowie des POM aus Example 9.2, Das einfachste Maven POM (Beispiel 9.2: Das einfachste Maven POM) wiedergeben.

9.2.4. Echte POMs


Statt Ihnen eine Anzahl vorgefertigter POM vorzustellen, und diese Schritt-fr-Schritt durchzugehen, verweisen wir hier auf die Beispiele des Part I, Maven by Example (Teil I: Maven by Example) dieses Buchs. Maven stellt eine Art Chamleon dar; Sie knnen sich die Eigenschaften herauspicken, welche Sie benutzen mchten. Manche Open Source Projekte schtzen die Mglichkeit, Entwickler und Kontributoren aufzulisten, eine saubere Build-Dokumentation zu erstellen, sowie das Release Management mittels dem Maven Release Plugin zu automatisieren. Andererseits kann es sein, dass jemand, der in sich in der Welt eines Unternehmens bewegt, kein Interesse an den Mglichkeiten des Verteilungsmanagements oder der Aufzhlung der Entwickler hat. Der Rest dieses Kapitels wird daher die Mglichkeiten eines POM im einzelnen beleuchten. Anstatt Sie mit einer 10 seitigen Aufzhlung der verwandten POM zu bewerfen, werden wir versuchen Ihnen eine ntzliche Referenz der einzelnen Abschnitte eines POM zu stellen. In diesem Kapitel werden wir die Verbindungen zwischen den POM diskutieren, aber wir werden diese nicht weiter ausfhren. Suchen Sie nach einem derartigen Beispiel, so bitte ich Sie auf Chapter 7, Multi-module Enterprise Project (Kapitel 7: Ein multi modulares Enterprise Projekt) zurckzugreifen.

9.3. POM Syntax


Das POM wird immer in einer Datei mit dem Namen pom.xml im Basisverzeichnis des Maven Projektes erstellt. Das XML Dokument kann mit der XML Deklaration beginnen, diese kann aber auch weggelassen werden. Alle Werte eines POM sind in Form von Elementen abgelegt.

202

Das Projekt Objekt Modell (POM)

9.3.1. Versionen von Projekten


Eine Maven Projekt Version kodifiziert die Release Nummer welche benutzt wird, um den Release in das Verhltnis zu allen anderen Releases zu setzen; Maven Versionen enthalten die folgenden Komponenten: Hauptversion (Major), Unterversion (Minor), Inkrement (Incremental) sowie Bezeichner/Schlssel. Innerhalb einer version werden diese Bestandteile fogendermassen dargestellt:
<major version>.<minor version>.<incremental version>-<qualifier>

Die version 1.3.5 zum Beispiel besteht aus der Hauptversion 1, der Unterversion 3 sowie dem Inkrement 5. Eine version "5" hat eine Hauptversion 5, keine Unterversion oder Inkrement. Der Schlssel besteht, um Milestone Builds zu erfassen: alpha- sowie beta-Versionen, der Bezeichner wird von der Version mittels einem Bindestrich "-" abgetrennt. So hat zum Beispiel die Version 1.3-beta-01 die Hauptversion 1, die Unterversion 3, kein Inkrement sowie einen Bezeichner von "beta-01". Dass Ihre Versionsnummerierung mit diesem Standard bereinstimmt ist fr Sie von besonderem Interesse, sollten Sie in Ihren POM definierte Versionsbereiche (Ranges) einsetzen. Versionsbereiche, diese werden in Section 9.4.3, Abhngigkeitsspannen (Abschnitt 9.4.3: Abhngigkeits Versionsbereiche) eingefhrt, erlauben Ihnen eine Abhngigkeit zu einem ganzen Gltigkeitsbereich von Versionen zu definieren. Dies ist nur mglich, da es Maven mglich ist, Versionen an Hand des Releases zu sortieren. Dies ist abhngig vom vorgestellten Format. Sollte Ihr System der Releasenummerierung mit dem des Formats <major>.<minor>.<inkrement>-<bezeichner> bereinstimmen, so werden Ihre Versionen korrekt verglichen: 1.2.3 wird als aktuellerer Build gegenber 1.0.2 angesehen. Der Vergleich wird auf der Basis des numerischen Wertes der Version vorgenommen. Sollte Ihre Nomenklatur nicht mit der vorgestellten kongruent sein, so wird die Version im Stringformat verglichen: 1.0.1b wird dann als Zeichenkette mit 1.2.0b verglichen. 9.3.1.1. Version Build Nummern 203

Das Projekt Objekt Modell (POM) Ein Haken ist die Abbildung des Bezeichners. Nehmen wir zum Beispiel die Release Nummern 1.2.3-alpha-2 sowie 1.2.3-alpha-10, wobei alpha-2 der zweite, alpha-10 der zehnte Build darstellt. Auch wenn nun alpha-10 wesentlich aktueller anzusehen ist als alpha-2, so wird Maven wie angedeutet alpha-10 vor alpha-2 darstellen. Maven ist dafr ausgelegt, dem Bezeichner folgende Nummern als Build Nummer zu interpretieren. In anderen Worten, alpha sollte den Bezeichner darstellen, die darauffolgenden Nummer den Build. Obwohl Maven vom Design her den Bezeichner vom Build trennt, so ist der Parsemechanismus derzeit kaputt! Das fhrt dazu, dass der gesamte Bezeichner als Zeichenkette ausgewertet wird, als soches kommt alpha-10 natrlich vor alpha-2. Um dieses Problem zu umgehen, fllen Sie die Nummern zur Linken mit fhrenden Nullen (alpha-010, alpha-002). Das Problem wird in Zukunft sicher behoben werden und Ihr Build wird auch dann noch ohne nderungen korrekt durchlaufen werden. 9.3.1.2. SNAPSHOT Versionen Maven Versionen knnen auch Zeichenketten als Bestandteile haben, um zu signalisieren, dass diese aktiv bearbeitet werden. Enthlt eine Version zum Beispiel das Wort SNAPSHOT, so wird Maven diesen Wert in einen Datums- und Zeitwert vom Typ UTC (Universal Time Convention) umwandeln sobald Sie ein solches Artefact installieren oder freigeben. Ein Beispiel, hat Ihr Projekt eine Version von "1.0-SNAPSHOT" und Sie deployen den Artefakten in das Maven Repository, so wird Maven diese Version - unter der Annahme dass Sie die Freigabe am 7. Februar 2008 um 11:08 Uhr vornehmen - auf "1.0-20080207-230803-1" erweitern. In anderen Worten, wenn Sie einen SNAPSHOT deployen, so geben Sie nicht einen Release einer Softwareversion frei, sondern Sie geben nur eine Momentaufnahme zu einer bestimmten Zeit Ihrer Version der Software frei. Wozu ist das gut? SNAPSHOT-Versionen kommen in Projekten in der aktiven Entwicklung zum Einsatz. sollte ihr Projekt von einer Softwarekomponente abhngig sein, welche noch in der Entwicklung steht, so knnen sie sich zu einem SNAPSHOT Release abhngig machen, Maven wird beim Build periodisch versuchen den neusten Stand der Version herunterzuladen. In gleicher Weise, 204

Das Projekt Objekt Modell (POM) sollte Ihr nchster ofizieller Release Version 1.4 sein, so wrde der Release bis zur endgltigen Freigabe die Version 1.4-SNAPSHOT tragen. Als Standardeinstellung wird Maven nicht gegen ferne Repositorien prfen, wenn eine SNAPSHOT-Version vorliegt. Um dies zu ermglichen, muss das POM eines Projektes ein explizites Element repository oder pluginRepository beinhalten. Bei der endgltigen Freigabe von einer Komponente sollten Sie darauf achten, dass Sie alle Abhngikeiten gegen endgltige Versionen definieren. Sollte eine Abhngigkeit gegen eine SNAPSHOT-Version definiert sein, so ist diese Version nicht stabil, da die Abhngigkeit sich im laufe der Zeit ndern kann. Artefakte welche in ein non-SNAPSHOT Repository wie z.B http://repo1.maven.org/maven2 freigegeben werden, knnen nicht von SNAPSHOT Versionen abhngig sein, das das Maven Super POM SNAPSHOT-Abhngigkeit zum zentralen Repository verbietet. SNAPSHOT Versionen sind nur fr die laufende Entwicklung bestimmt. 9.3.1.3. LATEST sowie RELEASE Versionen Wenn Sie eine Abhngigkeit zu einen Plugin oder Artefakten definiert haben, so knnen sie diese auch gegen die Werte LATEST oder RELEASE definieren. LATEST definiert hierbei die letzte (neuste) Version oder SNAPSHOT Version eines Artefakten, d.h. der neuste Stand eines Artefakten im Repository. RELEASE bezieht sich auf die letzte freigegebenen Version des Artefakts. Im allgemeinen zeugt es von schlechtem Stil, Software zu erstellen, welche nicht von einer bestimmten Version eines Artefakten abhngig ist. Solange Sie eine Version entwickeln mag es sinnvoll sein, gegen LATEST oder RELEASE zu entwickeln, um immer gegen die aktuelle Version eines abhngigen Artefaktes zu arbeiten. Mit der formellen Freigabe sollten Sie allerdings sicherstellen, dass Ihre Software von klar definierten Versionen Abhngig ist, um vorauszusehende rgernisse soweit mglich zu minimieren, insbesondere solche, die davon herrhren, dass Ihre Software von Drittparteien abhngig ist, welche sie nicht beeinflussen knnen. Benutzen Sie LATEST sowie RELEASE mit grosser Vorsicht, wenn berhaupt. Seit Maven 2.0.9 definiert Maven die Versionen der Standard- und Core-Maven Plugins. Dies geschieht innerhalb des Super POM, und hat das Ziel, den Satz der Maven Core Plugins einer bestimmten Version stabil zu halten. Diese nderung 205

Das Projekt Objekt Modell (POM) wurde erstmals mit der Version 2.0.9 eingefhrt um Nachvollziehbarkeit und Stabilitt des Build zu gewhrleisten. Vor Maven Version 2.0.9 war Maven so konfiguriert, dass es automatisch vor jedem Build die Aktualitt der Standard-Plugins auf die Version LATEST berprfte. Dieses Verhalten brachte manche unangenehme berraschung, insbesondere im Falle, dass sich Fehler einschlichen oder das Verhalten eines Plugin in solcher Weise gendert wurde, dass der Build nicht mehr korrekt oder wie zu erwarten zu Ende gefhrt wurde. Auch war nicht sichergestellt, dass ein bestimmter Build reproduzierbar erzeugt werden konnte, da jedes Core Plugin sich potentiell vor dem nchsten Build gendert haben konnte. Insbesondere im Fall, dass eine neuere Version in den zentralen Repositorien freigegeben wurde. Mit Freigabe von Version 2.0.9 kommt Maven nun mit einem definierten Set Core Plugins mit definierten Versionen daher. Non-Core Plugins, und Plugins welchen innerhalb des Super POM keine Version zugeordnet ist, benutzen noch immer LATEST um ein Plugin Artefact aus dem Repository anzuziehen. Aus diesem Grund sollten Sie darauf achten fr alle Non-Core und benutzerdefinierten Plugins immer eine definierte Version festzulegen.

9.3.2. Referenzen auf Properties


Ein POM kann eine Referenz auf einen Wert beinhalten, diese Referenz wird durch das voranstellen eines Dollar Zeichnes und der Einfassung in geschwungenen Klammern MavenProject: org.sonatype.mavenbook:content-de:0.6-SNAPSHOT
@

/usr/local/hudson/hudson-home/jobs/maven-guide-de-to-production/workspace/content

dargestellt. Nehmen Sie zum Beispiel folgendes POM:


<project> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>project-a</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <build> <finalName>${project.groupId}-${project.artifactId}</finalName> </build> </project>

206

Das Projekt Objekt Modell (POM) Sollten Sie den oben aufgefhrte XML Auschnitt in eine pom.xml Datei einfgen und mvn help:effective-pom ausfhren, so werden Sie sehen, dass der Output folgende Zeile beinhaltet (Stand: Ende 08):
... <finalName>org.sonatype.mavenbook-project-a</finalName> ...

Sobald Maven ein POM auswertet, ersetzt Maven Referenzen zu Properties mit den tatschlichen Werten. Im fortgeschrittenen Einsatz von Maven kommen Referenzen hufig zum Einsatz und sind ganz hnlich der Properties von Ant oder Velocity. Es sind einfach nur Variablen welche durch ${ ... } gekennzeichnet sind. Maven stellt drei implizite Variablen bereit, welche zum Einsatz kommen um Umgebungsvariablen, POM Informationen sowie Maven Einstellungen anzuziehen: env Die Variable env legt die Umgebungsvariablen des Betriebssystems oder der Shell frei. So wrde eine Referenz auf innerhalb eines Maven POM mit dem Wert der Umgebungsvariablen ersetzt (oder auch %PATH% unter Windows). project Die Variable project legt das POM offen. Sie knnen mittels der punkt-Notation (.) jeden Wert des POM freilegen. Im vorangegangenen Beispiel benutzen wir groupId sowie artifactId, um den endgltigen Name des Elements finalName zu definieren. Die Syntax dieser Property Referenz ist: org.sonatype.mavenbook-content-de. settings Die Variable settings legt die Werte der settings.xml-Datei offen. Sie knnen mittels der punkt-Notation (.) jeden Wert der settings.xml Datei referenzieren. Ein Wert von ${settings.offline} wrde zum Beispiel den Wert des Elements offline in der Datei unter ~/.m2/settings.xml 207

/usr/local/bin:/usr/local/maven/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/

/usr/local/bin:/usr/local/maven/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/

Das Projekt Objekt Modell (POM) referenzieren. Note Eventuell begegnen Sie in lteren Builds auch dem Ausdruck ${pom.xxx}. Diese Methode wurde abgewertet und es sollte fortan nur noch ${project.xxx} zum Einsatz kommen. ber diese drei impliziten Variablen hinaus ist es ihnen auch mglich Systemvariablen sowie benutzerdefinierte Werte jeglicher Art in einer Maven POM Datei oder einem Build zu referenzieren: Java System Properties Alle Properties welche mittels getProperties() von java.lang.System freigelegt werden sind als POM Property zugnglich. Einige der gebruchlichen Systemproperties sind: hudson, /home/hudson, /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre sowie Linux. Eine komplette Aufzhlung der verfgbaren Properties finden sie in der JavaDoc der Klasse java.lang.System. x Beliebige Properties knnen mittels dem Element properties innerhalb einer pom.xml, settings.xml oder einer anderen externen Datei geladen und gesetzt werden. Sollten Sie z.B. das Property fooBar innerhalb ihrer pom.xml gesetzt haben, so knnen Sie dieses Property mittels ${fooBar} referenzieren. Benutzerdefinierte Properties sind immer dann von Nutzen, wenn sie Ressourcen und Ziele abhngig von der zu bestckenden Plattform filtern mssen. Hier noch die Beschreibung der Einstellung ${foo}=bar innerhalb eines POM:
<properties> <foo>bar</foo> </properties>

For a more comprehensive list of available properties, see Chapter 13, Properties and Ressource Filterung. Eine erweiterte Abhandlung der mglichen Properties verweisen wir auf 208

Das Projekt Objekt Modell (POM) Chapter 13, Properties and Ressource Filterung (Kapitel 13: Properties und Ressource Filterung).

9.4. Projekt Abhngigkeiten (Dependencies)


Maven kann sowohl interne wie auch externe Abhngigkeiten verwalten. Eine externe Abhngigkeit eines Java Projekts knnte eine Bibliothek wie zum Beispiel Plexus, das Spring Framework oder Log4J darstellen. Eine interne Abhngigkeit ist zum Beispiel eine Web Applikation welche von einer anderen Applikation abhngig ist, die Dienste, Modell Objekte oder Persistenzlogik bereitstellt. Example 9.3, Projekt Abhngigkeiten (Beispiel 9.3: Projektabhngigkeiten) stellt einige der mglichen Abhngigkeiten dar. Example 9.3. Projekt Abhngigkeiten
<project> ... <dependencies> <dependency> <groupId>org.codehaus.xfire</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>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> </dependencies> ... </project>

Die erste Abhngigkeit ist eine Abhngigkeit der Kompilierung zur XFire SOAP Bibliothek von Codehaus. Sie wrden diese Art der Abhngigkeit whlen, wenn 209

Das Projekt Objekt Modell (POM) Ihr Projekt von dieser Bibliothek zur Kompilierung, zum Test sowie der Ausfhrung abhngt. Die zweite Abhngigkeit ist eine Abhngigkeit bezglich des Glltigkeitsbereichs test, sollten Sie diese Bibliothek nur whrend des Tests bentigen. Die letzte Abhngigkeit des Example 9.3, Projekt Abhngigkeiten (Beispiels 9.3: Projekt Abhngigkeiten) ist eine Abhngigkeit zum Servlet API 2.4. Die letzte Abhngigkeit hat den Gltigkeitsbereich provided. Sie wrden diesen Gltigkeitsbereich whlen, wenn Sie eine Applikation entwickeln, fr welche Sie eine Bibliothek zur Entwicklung und den Test bentigen, diese aber zur Laufzeit von einem Container bereitgestellt wird.

9.4.1. Abhngigkeiten und Gltigkeitsbereich (Scope)


Example 9.3, Projekt Abhngigkeiten (Beispiel 9.3: Projekt Abhngigkeiten) fhrte drei der fnf Gltigkeitsbereiche ein: compile, test sowie provided. Gltigkeitsbereiche legen fest, welche Abhngigkeiten in einem Klassenpfad zur Verfgung stehen, sowie welche Abhngigkeiten in eine Applikation eingefgt werden. Lassen Sie uns nun jeden dieser Gltigkeitsbereiche im Detail ansehen: compile ist der Standardgltigkeitsbereich; alle Abhngigkeiten sind vom Gltigkeitsbereich compile, sofern kein anderer Gltigkeitsbereich angegeben wurde. compile Abhngigkeiten sind in allen Klassenpfaden vorhanden und Sie werden paketiert.
compile

provided Abhngigkeiten kommen zum Einsatz, wenn Sie erwarten, dass diese vom JDK oder einem Container zur Laufzeit bereitgestellt werden. Zum Beispiel wrden Sie bei der Entwicklung einer Web Applikation das Servlet API whrend der Entwicklung im Klassenpfad haben, jedoch nicht in die erstellte WAR Datei einschliessen; das Servlet API wird vom Applikationsserver oder Servlet Container bereitgestellt. provided Abhngigkeiten werden auf dem Klassenpfad zur Kompilierung (nicht der Laufzeit) bereitgestellt. Abhngigkeiten vom Gltigkeitsbereich provided sind nicht transitiv und werden auch nicht paketiert.
provided

210

Das Projekt Objekt Modell (POM) runtime Abhngigkeiten vom Gltigkeitsbereich runtime sind notwendig fr die Ausfhrung sowie den Test der Applikation, nicht jedoch zur Kompilierung. Zum Beispiel bentigen Sie das JDBC API Jar zur Kompilation, jedoch lediglich einen JDBC Treiber zur Laufzeit. test Abhngigkeiten vom Gltigkeitsbereich test sind nicht notwendig fr die normale Ausfhrung der Anwendung und sind daher nur whrend der Kompilierung und Ausfhrung von Tests zugnglich. Der Gltigkeitsbereich test wurde bereits zuvor in Section 4.10, Hinzufgen von Gebietsbezogenen Unit Tests (Abschnitt 4.10: Zufgen von Abhngigkeiten im Gltigkeitsbereich test) eingefhrt. system Der Gltigkeitsbereich system ist hnlich dem von provided mit dem Unterschied, dass Sie einen expliziten Pfad zu einer JAR-Datei auf dem lokalen Dateisystem angeben mssen. Dieser Gltigkeitsbereich soll Ihnen erlauben gegen Objekte zu kompilieren, welche Teil der Systemdateien sind. Ein solcher Artefakt wird als gegeben angenomen und wird nicht gegen das Repository abgeglichen. Sollten Sie den Gltigkeitsbereich system whlen, so mssen Sie unbedingt auch ein Element systemPath angeben. Beachten Sie bitte, dass vom Einsatz des Gltigkeitsbereiches system abgeraten wird. (Sie sollten immer versuchen Abhngigkeiten zu einem ffentlichen oder benutzerdefinierten Maven Repository zu definieren.)

9.4.2. Optionale Abhngigkeiten


Nehmen wir an, Sie arbeiten an einer Bibliothek, welche Caching anbietet. Anstatt das gesamte Caching von Grund auf neu zu entwickeln, werden Sie auf bereits bestehende Bibliotheken aufsetzen, welche Caching auf Dateisystemebene oder verteiltes Caching bereitstellen. Nehmen Sie weiter an, dass der Endbenutzer die Mglichkeit haben soll, zu whlen, ob ein dateisystemgesttztes Caching oder ein in-memory Caching angewandt werden soll. Um den Cache auf der Basis 211

Das Projekt Objekt Modell (POM) Dateisystem zu realisieren werden Sie eine frei verfgbare Bibliothek namens EHCache (http://ehcache.sourceforge.net/) einsetzen, und bei der Umsetzung einer verteilten in-Memory Lsung greifen Sie auf ein Product namens SwarmCache (http://swarmcache.sourceforge.net/) zurck. Sie bauen ein Interface und erstellen eine Bibliothek, welche konfigurativ eine Caching Lsung setzt, mchten aber vermeiden, einem Projekt welches Ihre Bibliothek einsetzt eine Abhngigkeit zu beiden Caching Bibliotheken aufzuzwingen. In anderen Worten, Sie bentigen beide Bibliotheken, um Ihr Projekt zu kompilieren, aber Sie mchten nicht, dass diese als transitive Laufzeitabhngigkeit aller Projekte welche Ihre Bibliothek einsetzen auftritt. Dies knnen Sie durch den Einsatz von optionalen Abhngigkeiten wie im Example 9.4, Erstellen von optionaler Abhngigkeiten (Beispiel 9.4: Erstellen von optionalen Abhngigkeiten erreichen): Example 9.4. Erstellen von optionaler Abhngigkeiten
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>my-project</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>net.sf.ehcache</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>

212

Das Projekt Objekt Modell (POM) Haben Sie eine Abhngigkeit einmal als optional deklariert, so sind Sie gezwungen diese explizit in jedem Projekt zu deklarieren, welche von 'my-projekt' abhngig ist. Zur Verdeutlichung, sollten Sie eine Applikation entwickeln welche von my-project abhngt, und dieses sollte die EHCache Lsung einsetzen, so mssten Sie die nachfolgenden Abhngigkeitsdeklaration in Ihrem Projekt einschliessen:
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>my-application</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>org.sonatype.mavenbook</groupId> <artifactId>my-project</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>swarmcache</artifactId> <version>1.4.1</version> </dependency> </dependencies> </project>

In einer idealen Welt mssten Sie niemals auf optionale Abhngigkeiten zurckgreifen. Statt eines grossen Projektes mit einer Reihe optionaler Abhngigkeiten wrden Sie die EHCache spezifischen Quellen in ein Submodul my-projekt-EHCache und die SwarmCache spezifischen in ein Submodul my-project-SwarmCache auslagern. Auf diese Weise knnten Projekte, einfach ein entsprechendes Implementierungsprojekt referenzieren und von der transitiven Abhniggkeit gebrauch machen, anstatt vom Projekte my-project die Abhngigvkeit explizit zu deklarieren.

9.4.3. Abhngigkeitsspannen
Sie mssen nicht von einer spezifischen Version eines Artefakten abhngig sein; Sie knnen auch eine Spanne der Versionen angeben, welche eine Abhngigkeit erfllen. So knnen Sie zum Beispiel angeben, dass Ihr Projekt von JUnit Version 3.8 oder grsser abhngig ist, oder auch von jeglicher Version zwischen Version 213

Das Projekt Objekt Modell (POM) 1.2.10 und 1.2.14 von JUnit. Sie erreichen dies, indem Sie eine oder mehr Versionen mit den folgenden Zeichen umschliessen: (, ) (runde Klammer): Ausschliesslich der Grenzwerte [, ] (eckige Klammer): Einschliesslich der Grenzwerte Ein Beispiel: solltes Sie alle Versionen von JUnit grsser gleich 3.8 jedoch unbedingt kleiner 4.0 zulassen wollen, so wrde Ihre Abhngigkeit wie in Example 9.5, Definition einer Abhngigkeitsspanne: JUnit 3.8 - JUnit 4.0 (Beispiel 9.5: Deklaration einer Abhngigkeitsspanne: JUnit 3.8 - JUnit 4.0) aussehen: Example 9.5. Definition einer Abhngigkeitsspanne: JUnit 3.8 - JUnit 4.0
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>[3.8,4.0)</version> <scope>test</scope> </dependency>

Sollten sie von einer Version von JUnit nicht grsser als 3.8.1 abhngig sein wollen, so mssten Sie einen oberen einschliessenden Grenzwert setzen, wie dies im Example 9.6, Angabe einer Abhngigkeitsspanne: JUnit <= 3.8.1 (Beispiel 9.6: Deklaration einer Abhngigkeitsspanne: JUnit <= 3.8.1) ausgefhrt ist: Example 9.6. Angabe einer Abhngigkeitsspanne: JUnit <= 3.8.1
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>[,3.8.1]</version>ex-de <scope>test</scope> </dependency>

214

Das Projekt Objekt Modell (POM) Vor, bzw. nach dem Komma ist keine Version notwendig; eine nicht angegebene Version bedeutet +/- Unendlich. Zum Beispiel bedeutet [4.0,) jede Version grsser oder gleich 4.0; (,2.0) jede Version kleiner Version 2.0 und [1.2] bedeutet genau Version 1.2 und nichts anderes. Note Bei der "normalen" Deklaration einer Version wie z. B. Version 3.8.2 von JUnit, wird dies intern abgebildet auf jede Version erlaubt, aber Version 3.8.2 bevorzugt. Dies erlaubt Maven im Falle eines Versionskonflikts mittels einem Konfliktlsungsalgorhytmus die best geeignete Version zu bestimmen. Definieren Sie [3.8.2] so bedeutet dies dass 3.8.2 zum Zuge kommt und keine andere Version. Sollte darberhinaus eine andere Abhngigkeit zu Version [3.8.1] definiert sein, so wird der Build als fehlerhaft angezeigt, und der Konflikt angegeben. Wir weisen Sie auf dieses Verhalten hin, damit Ihnen die Mglichkeit bewusst ist, raten aber diese nur selten - und wirklich nur wenn dies absolut notwendig ist - einzusetzen. Die Konfliktlsung mittles Abhngigkeitsmanagement ist immer vorzuziehen.

9.4.4. Transitive Abhngigkeiten


Eine transitive Abhngigkeit ist eine Abhngigkeit einer Abhngigkeit. Im Falle das Projekt A von Projekt B abhngig ist, welches wiederum von Projekt C abhngt, so wird Projekt C als transitive Abhngigkeit von Projekt A betrachtet. Sollte Projekt C von Projekt D Abhngig sein, so wird auch Projekt D als transitive Abhngigkeit von Projekt A und B betrachtet. Ein Teil der Anziehungskraft von Maven ist, dass es automatisch die transitiven Abhngigkeiten verwaltet und den Entwickler davor bewahrt sich um alle Abhngigkeiten zu kmmern welche ein Projekt bentigt um zu kompilieren und auszufhren. Sie knnen von einem Spring Framework abhngig sein und mssen sich in keiner Weise um all die Abhngigkeiten davon kmmern. Maven tut dies indem es einen Graphen der Abhngigkeiten baut und sich anschiessend um alle Konflikte und berlappungen kmmert. Im Falle dass Maven feststellt, dass zwei Projekte eine 215

Das Projekt Objekt Modell (POM) Abhngigkeit mit der gleichen groupId und artifactId haben, so wird Maven klren welche der Abhngigkeiten automatisch weiterzuverwenden ist, wobei immer die aktuellere Version vorgezogen wird. Obschon dies sehr ntzlich klingt, gibt es einige Extremflle in welchen transitive Abhngigkeiten Probleme bei der Konfiguration aufwerfen. Um derartige Szenarien zu lsen setzen Sie den Ausschluss einer Abhngigkeit (dependency Exclusion) ein. 9.4.4.1. Transitive Abhngigkeiten und Geltungsbereiche Jeder der vorgngig in Section 9.4.1, Abhngigkeiten und Gltigkeitsbereich (Scope) (Abschnitt 9.4.1: Gltigkeitsbereiche von Abhngigkeiten) eingefhrte Gltigkeitsbereich beeinflusst nicht nur den Gltigkeitsbereich einer Abhngigkeit, sondern auch wie sich diese Abhngigkeit als transitive Abhnbigkeit verhlt. Dies wird am besten mittels einer Tabelle veranschaulicht, wie wir dies in Table 9.1, Wie Geltungsbereiche transitive Abhngigkeiten beeinflussen (Tabelle 9.1: Wie Gltigkeitsbereiche transitive Abhngigkeiten beeinflussen) versucht haben. Die Gltigkeitsbereiche welche in der obersten Reihe angegeben werden bezeichnen den Gltigkeitsbereich der transitiven Abhniggkeit. Gltigkeitsbereiche der usseren linken Spalte representieren Gltigkeitsbereiche der direkten Abhngigkeit. Die berschneidung der Reihe mit der Spalte gibt den Gltigkeitsbereich wieder, welcher der transitiven Abhngigkeit zugeordnet wird. Eine leere Zelle bedeutet hierbei, dass die transitive Abhngigkeit eliminiert wird. Table 9.1. Wie Geltungsbereiche transitive Abhngigkeiten beeinflussen Direct Scope Transitive Scope compile compile provided runtime test compile provided runtime test provided provided runtime runtime provided runtime test test 216

Das Projekt Objekt Modell (POM) Um in einem Beispiel das Verhltnis des transitiven Gltigkeitsbereich zu dem Gltigkeitsbereich der direkten Abhngigkeit zu veranschaulichen, betrachten Sie das folgende Beispiel: Sollte ein Projekt A eine Abhngigkeit mit dem Gltigkeitsbereich test mit Projekt B haben, welches wiederum eine Abhngigkeit mit dem Gltigkeitsbereich compile mit Projekt C hat, so wrde Projekt C fortan eine transitive Abhngigkeit mit dem Gltigkeitsbereich test von Projekt A haben. Stellen Sie sich dies als transitive Grenze vor, welche als Filter des Gltigkeitsbereich der Abhngigkeiten arbeitet. Sowohl transitive Abhngigkeiten vom Gltigkeitsbereich provided wie auch test beeinflussen das Projekt gewhnlich nicht. Die Ausnahme ist, sollte eine transitive Abhngigkeit vom Gltigkeitsbereich provided gleichzeitig eine Abhngigkeit zu einer direkten Abhngigkeit darstellen. In diesem Fall wird diese weiterhin eine Abhngigkeit des Projekts vom Gltigkeitsbereich provided bleiben.Transitive Abhngigkeiten, welche vom Gltigkeitsbereich compile oder runtime sind beeinflussen eine direkte Abhngigkeit zum Projekt im allgemeinen unabhngig vom Gltigkeitsbereich. Transitive Abhngigkeiten vom Gltigkeitsbereich compile haben den gleichen Gltigkeitsbereich unabhngig vom Gltigkeitsbereich der direkten Abhngigkeit. Transitive Abhngigkeiten vom Gltigkeitsbereich runtime haben im Allgemeinen den gleichen Gltigkeitsbereich unabhngig von dem, der direkten Abhngigkeit mit der Ausnahme socher, welche vom Gltigkeitsbereich compile sind; in diesem Fall wird der transitive Abhngigkeit der tatschliche Gltigkeitsbereich runtime zugeordnet.

9.4.5. Konfliktauflsung
Es wird wird immer einen Punkt geben, an welchem Sie eine transitive Abhngigkeit ausschliessen mssen, so zum Beispiel im Fall, dass Ihr Projekt von einem Projekt abhngt welches ebenfalls eine Abhngigkeit hat, Sie aber dies entweder ganz auschliessen wollen, oder aber die transitive Abhngigkeit mit einer anderen ersezten mchten, welche dieselbe Funktionalitt anbietet. Example 9.7, Ausschliessen einer transitiven Abhngigkeit (Beispiel 9.7: Auschliessen einer transitiven Abhngigkeit) illustriert ein Beispiel in welchem ein Element 217

Das Projekt Objekt Modell (POM) eine Abhngigkeit zu Projekt A hinzufgt, aber die transitive Abhngigkeit zu Projekt B ausschliesst.
dependency

Example 9.7. Ausschliessen einer transitiven Abhngigkeit


<dependency> <groupId>org.sonatype.mavenbook</groupId> <artifactId>project-a</artifactId> <version>1.0</version> <exclusions> <exclusion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>project-b</artifactId> </exclusion> </exclusions> </dependency>

Oftmals werden Sie auch in die Situation geraten, dass Sie eine Abhngigkeit mit einer anderen ersetzen mchten, welche die gleiche Funktionalitt anbietet. Sollten Sie zum Beispiel von einer Komponente abhngen, welche von der SUN JTA API Implementierung abhngig ist, so mgen Sie diese transitive Abhngigkeit eventuell ersetzen. Hibernate ist ein Beispiel: Hibernate ist vom SUN JTA API Jar abhngig, welche lange Zeit nicht im zentralen Maven Repository zur Verfgung gestanden hat, da es nicht frei weitergegeben werden durfte. Glcklicherweise erstellte das Apache Geronimo Projekt eine unabhngige Implementierung der Bibliothek; diese kann frei verbreitet werden. Um eine transitive Abhngigkeit mit einer anderen Abhngigkeit zu ersetzen, mssen Sie die ursprngliche Abhngigkeit explizit ausschliessen und mit einer deklarierten Abhngigkeit zu dem von Ihnen gewnschten Projekt ersetzen. Example 9.8, Ausschliessen und Ersetzen einer transitiven Abhngigkeit (Beispiel 9.8: Auschliessen und Ersetzen einer transitiven Abhngigkeit) fhrt ein solches Beispiel eines Austausches aus. Example 9.8. Ausschliessen und Ersetzen einer transitiven Abhngigkeit
<dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId>

218

Das Projekt Objekt Modell (POM)


<version>3.2.5.ga</version> <exclusions> <exclusion> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-jta_1.1_spec</artifactId> <version>1.1</version> </dependency> </dependencies>

IIn Example 9.8, Ausschliessen und Ersetzen einer transitiven Abhngigkeit (Beispiel 9.8: Auschliessen und Ersetzen einer transitiven Abhngigkeit) gibt es nichts das darauf hinweisen wrde, dass die Abhngigkeit zu geronimo-jta_1.1_spec ein Ersatz darstellt. Es ist zuflligerweise eine Bibliothek welche die gleiche API zur Verfgung stellt wie die ursprngliche Abhniggkeit. Hier einige Grnde warum Sie eventuell eine bestehende Abhngigkeit auschliessen oder ersetzen mgen: 1. Die groupId oder artifactId des Artefakt hat sich gendert und das aktuelle Projekt bentigt eine Version mit einem anderen Namen, von der eine andere Abhngigkeit abhngt - das Resultat sind zwei Kopien der gleichen Bibliothek auf dem Klassenpfad. Normalerweise wrde Maven diesen Konflikt aufgreifen, lsen und auf eine einzige Abhngigkeit zurckfhren. Sobald aber die groupId oder artifactId sich gendert haben, stellen diese fr Maven zweierlei Bibliotheken dar. 2. Ein Artefakt wird in Ihrem Projekt nicht benutzt und die transitive Abhngigkeit wurde nicht als optional markiert. In diesem Fall kann es sein, Sie mchten die Abhngigkeit ausschliessen, da Ihr System diese nicht bentigt und Sie die Anzahl der verteilten Bibliotheken reduzieren mchten. 3. Ein Artefakt wird von Ihrer Laufzeitumgebung bereitgestellt, Sie sollten diesen daher nicht in Ihr Projekt einschiessen. Ein Beispiel einer solchen 219

Das Projekt Objekt Modell (POM) Abhngigkeit wre, dass eine transitive Abhngigkeit von einem API wie des Servlet API abhngig ist, Sie aber sicherstellen wollen, dass dieses nicht mit Ihrer Web Applikation unter WEB-INF/lib abgelegt wird. 4. Um eine Abhngigkeit auszuschliessen, welche ein API mit mehreren Implementierungen darstellt. Diese Situation wird im Example 9.8, Ausschliessen und Ersetzen einer transitiven Abhngigkeit (Beispiel 9.8: Auschliessen und Ersetzen einer transitiven Abhngigkeit) dargestellt; eine Bibliothek welche vormals mit einer speziellen Lizenz verbunden und eine manuelle Installation erforderlich machend, welche aber durch eine Implementierung des gleichen API seitens Apache Geronimo ersetzt werden konnte.

9.4.6. Abhngigkeits Verwaltung /Dependency Management


Sobald Sie innerhalb Ihrer hchst komplexen Firmenlandschaft mit Ihren zweihunderzwanzig voneinander abhngigen Projekten Maven eingefhrt haben, werden Sie sich die Frage stellen, ob es nicht einen einfacheren Weg gibt, all diese Abhngigkeiten zu verwalten. Solange jedes einzelne Projekt welches eine Abhngigkeit wie zum Beispiel den MySQL Java Connector benutzt, diese Abhngigkeit in Detail, mit Version angeben muss, werden Sie womglich grbere Probleme haben, sobald Sie zu einer neuen Version wechseln mssen. Da die Versionen ber Ihren gesamten Projektbaum verteilt sind, sind Sie gezwungen jede pom.xml Datei manuell anzupassen und dabei sicherzustellen, dass Sie die Referenz korrekt anpassen. Sogar unter Einsatz von find, xargs und awk fahren Sie ein grsseres Risiko, dass Sie dabei ein einzelnes POM verpassen. Glcklicherweise bietet Maven eine Mglichkeit Abhngigkeitsversionen an einem Ort zu konsolidieren: das Element dependencyManagement. Sie finden das Element dependencyManagement gewhnlich in einem top-level POM Ihres Projektes oder sogar Ihrer Organisation. Der Einsatz des Elements dependencyManagement erlaubt es Ihnen eine Abhngigkeit genau zu definineren, ohne dabei eine explizite Version anzugeben. Maven wird den Baum der bergeordneten Hirarchien soweit 220

Das Projekt Objekt Modell (POM) hochgehen, bis es ein Element dependencyManagement findet, um die dort angegebene Version zu benutzen. Ein Beispiel: Sie haben eine grosse Anzahl Projekte, welche alle den MySQL Java Connector Version 5.1.2 einsetzen, so knnen Sie das fogende Element dependencyManagement in Ihrem obersten POM des multi-modularen Projekt definieren. Example 9.9. Definition von Abhngigkeitsversionen in einem Top-level POM
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>a-parent</artifactId> <version>1.0.0</version> ... <dependencyManagement> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.2</version> </dependency> ... <dependencies> </dependencyManagement>

Daraufhin kann ein abgeleitetes Projekt diese Abhngigkeit zum MySQL Java Connector mittels dem folgenden XML zufgen:
<project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.sonatype.mavenbook</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>

Bitte beachten Sie, dass das untergeordnete Projekt die Version der Abhngigkeit 221

Das Projekt Objekt Modell (POM) zum MySQL Java Connector nicht explizit ausweisen musste. Da die Version in einem bergeordneten Projekt POM innerhalb des Elementes dependencyManagement definiert wurde, propagiert diese Version zu unserem Projekt POM. Es ist ausserdem zu beachten, dass, sollte innerhalb des untergeordneten POM tatschlich eine Version ausgewiesen werden, diese die herabgereichte Version des Elements dependencyManagement des bergeordneten POM bersteuert. Das bedeutet, dass die dependencyManagement Deklaration nur zum Zuge kommt, wenn die untergeordneten POM keine Version deklarieren. Abhngigkeits Verwaltung mittels dem Element dependencyManagement innerhalb eines bergeordneten POM ist grundstzlich verschieden von der Definition einer Abhniggkeit innerhalb einem weitlufig gebrauchten bergeordneten POM. Zum einen werden bei der Vererbung alle Abhngigkeiten geerbt. Wird demnach im bergeordneten POM mysql-java-connector als Abhngigkeit deklariert, so besteht diese Abhngigkeit fr jedes Projekt der gesamten Hirarchie. Anstatt nun untergeordneten Projekten unntige Abhnigkeiten zuzufgen, erlaubt der Einsatz des Elements dependencyManagement an einem Ort zentral und konsolidiert die Versionen der Abhngigkeiten zu verwalten ohne diese Abhngigkeiten allen untergeordneten Projekten hinzuzufgen. In anderen Worten ist das Element dependencyManagement gleichzusetzen mit einer Art Umgebungsvariable welche Ihnen erlaubt Abhngigkeiten von einem bestimmten Punkt an abwrts ohne die weitere Spezifikation einer Version zu deklarieren.

9.5. Projekt Beziehungen


Einer der unwiederstehlichen Grnde Maven einzusetzen ist, dass es die Arbeit eine Abhngigkeit nachzuverfolgen (und Abhniggkeiten von Abhniggkeiten) wesentlich vereinfacht. Sobald ein Projekt von einem Artefakten abhngt, welcher wiederum von einem anderen Projekt erzeugt wird, so sprechen wir von einer Abhngigkeit. Im Falle von Java kann dies eine so einfache Sache sein, wie die Abhngigkeit zu einer externen Bibliothek wie zum Beispiel Log4J oder JUnit. Whrend Abhngigkeiten externe Abhngigkeiten abbilden knnen, so kann man mit Abhngigkeiten auch Abhngigkeiten zwischen einer ganzen Anzahl 222

Das Projekt Objekt Modell (POM) von Projekten verwalten. Ist Projekt A also von Projekt B abhngig, so ist Maven intelligent genug zu wissen, dass der Build von Projekt B vor dem von Projekt A ausgefhrt werden muss. Beziehungen bedeuten aber weit mehr als nur Abhngigkeiten und herauszufinden was ein Projekt bentigt um einen Artefakten zu erstellen. Maven ist in der Lage die Beziehung eines Projektes zu dessen bergeordneten Projekten abzubilden, wie auch die eines Projektes zu den untergeordneten Submodulen. Dieser Abschnitt erlutert nun die verschiedenen Beziehungen welche zwischen den Projekten bestehen knnen und wie Sie diese Beziehungen konfigurieren.

9.5.1. Vertiefung von Koordinaten


Koordinaten definieren eine einzigartige Lage eines Projektes, diese wurden in Chapter 3, Ein einfaches Maven Projekt (Kapitel 3: Ein einfaches Maven Projekt) eingefhrt. Mittels Maven Koordinaten bauen Projekte zueinander eine Beziehung auf. Projekt A ist nicht einfach nur von Projekt B abhngig, ein Projekt definiert ber die Koordinaten groupId, artifactId und version hngt von einem anderen Projekt mittels groupId, artifactId und version ab. Als Rckblende, eine Maven Koordinate besteht aus den Komponenten: groupId Eine groupId gruppiert eine Anzahl verwandter Artefakte. Gruppenbezeichner sind im allgemeinen der Java Package Name. So ist zum Beispiel die groupId von org.apache.maven die Basiskennung aller Artefakte, welche vom Apache Maven Projekt erstellt werden. Gruppenkennungen werden im Maven Repository in Pfadnamen umgesetzt, die Gruppenkennung von org.apache.maven kann so zum Beispiel unter /maven2/org/apache/maven auf repo1.maven.org gefunden werden. artifactId Die artifactId ist die Hauptkennung des Projektes. Wann immer Sie einen Artefakten erzeugen, so wird dieser Artefakt mit der artifactId benannt. Sobald Sie sich auf ein Projekt beziehen, so werden Sie die artifactId benutzen. Die Kombination aus groupId und artifactId muss eindeutig sein. 223

Das Projekt Objekt Modell (POM) Das heisst, Sie knnen keine zwei unterschiedlichen Projekte haben, welche beide die gleiche artifactId und groupId haben; artifactIds sind innerhalb einer bestimmten groupId einzigartig. Note Whrend innerhalb von groupIds der Punkt '.' ein gebruchliches Zeichen ist, sollten Sie diesen in der artifactId soweit als mglich vermeinden, da dies zu Problemen fhrt, sollten Sie versuchen einen ausgeschriebenen Namen aufzulsen.

version Sobald ein Artefakt freigegeben wird, so wird er mit einer Version versehen. Diese Version ist eine numerische Kennzeichnung wie zum Beispiel "1.0", "1.1.1" oder "1.1.2-alpha-01". Sie knnen auch unter einer sogenannten SNAPSHOT Releasenummer freigeben. Eine SNAPSHOT Version ist eine Versionsnummer einer Komponente welche noch in der Entwicklung ist, und als soche endet eine derartige Version immer auf SNAPSHOT; zum Beispiel "1.0-SNAPSHOT", "1.1.1.-SNAPSHOT" oder "1-SNAPSHOT". Section 9.3.1.1, Version Build Nummern (Abschnitt 9.3.1: Versionen von Projekten) fhrt Versionen und Gltigkeitsbereiche von Versionen ein. Es gibt auch noch eine vierte, weniger oft benutzte Kennzeichnung: classifier Einen classifier wrden Sie benutzen, im Fall, dass Sie aus technischen Grnden gezwungen sind zwei unterschiedliche Artefakte aus dem gleichen Code zu erzeugen. Nehmen wir an, Sie mchten zwei getrennte Artefakte eines Jars, eines mit dem Java 1.4 Kompiler, ein anderes mit dem Java 6 Compiler kompiliert, erstellen. Sie knnen dann den classifier benutzen, um zwei Artefakte mit den selben Kennungen groupId, artifactId und version zu unterscheiden. Sollte Ihr Projekt von Plattformerweiterungen gebrauch machen, so kann es Sinn machen die unterschiedlichen Platformen mit classifier zu kennzeichnen. classifier werden gewhnlich benutzt, um Artefaktquellen, JavaDocs oder BinrPakete zu Packetieren. 224

Das Projekt Objekt Modell (POM) Wann immer wir in diesem Buch von Abhngigkeiten sprechen, so benutzen wir oft die folgende Kurznotation um eine Abhngigkeit zu beschreiben: groupId:artifactId:version. Um uns auf Version 2.5 des Spring Framework zu beziehen, wrden wir auf org.springframework:spring:2.5 verweisen. Sollten Sie Maven anweisen, mittels dem Maven Dependency Plugin eine Liste aller Abhngigkeiten auszugeben, so werden Sie sehen, dass auch Maven diese Notation benutzt um Informationen in dieser Kurzschreibweise darzustellen.

9.5.2. Multi-modulare Projekte


Multi-modulare Projekte sind Projekte, welche eine Liste von zu buildenden Modulen beinhalten. Ein multi-modulares Projekt ist immer vom Packetierungstyp POM und produziert nur selten einen Artefakten. Ein multi modulares Projekt besteht in dem Sinne nur, um Artefakte fr einen Build zusammenzustellen. Figure 9.3, Projektbeziehungen in einem multi modularen Projekt (Abbildung 9.3: Projektbeziehungen in einem multi modularen Projekt) stellt eine Projekthierarchie dar, welche aus zwei bergeordneten Projekten vom Packetierungstyp POM und drei Projekten vom Packetierungstyp jar besteht.

Figure 9.3. Projektbeziehungen in einem multi modularen Projekt 225

Das Projekt Objekt Modell (POM) Die Verzeichnisstruktur im Dateisystem reflektiert diese modularen Beziehungen. Die zuvor in Figure 9.3, Projektbeziehungen in einem multi modularen Projekt (Abbildung 9.3: Projektbeziehungen in einem multi modularen Projekt) dargestellten Projekte htten die folgende Dateistruktur:
top-group/pom.xml top-group/sub-group/pom.xml top-group/sub-group/project-a/pom.xml top-group/sub-group/project-b/pom.xml top-group/project-c/pom.xml

Die Projekte stehen zueinander in Beziehung, da das Projekt top-group sowie das Projekt sub-group jeweils Untermodule innerhalb des POM referenzieren. Hier ein Beispiel: das Projekt org.sonatype.mavenbook:top-group ist ein multi modulares Projekt vom Packetierungstyp POM. Die pom.xml Datei des Projektes top-group wrde die folgenden Elemente beinhalten: Example 9.10. Gruppen Element modules des Projekts top-group
<project> <groupId>org.sonatype.mavenbook</groupId> <artifactId>top-group</artifactId> ... <modules> <module>sub-group</module> <module>project-c</module> </modules> ... </project>

Sobald Maven das top-group POM einliest, wird zunchst das Element modules ausgelesen und dabei festgestellt, dass das Projekt top-group die Projekte sub-group und projekt-c referenziert. Maven wird daraufhin in jedem der Unterverzeichnisse nach einer entsprechenden Datei pom.xml suchen. Dieser Prozess wird fr jedes Unterverzeichnis wiederholt: Maven liest die Datei ./sub-group/pom.xml und kann daraus ableiten, dass das Projekt sub-group zwei weitere Projekte mit den nachfolgenden Elementen modules referenziert. Example 9.11. Element modules des Projekts sub-group 226

Das Projekt Objekt Modell (POM)


<project> ... <modules> <module>project-a</module> <module>project-b</module> </modules> ... </project>

Bitte beachten Sie, dass wir die Unterprojekte eines multi modularen Projekts Module und nicht Kinder oder Kind-Projekte nennen. Dies ist hilfreich, um Projekte welche Bestandteil eines multi modularen Projektes sind, nicht mit solchen zu verwechseln, welche voneinander Projektinformationen erben.

9.5.3. Projekt Vererbung


Es wird Momente geben, in denen Sie Werte von einem bergeordneten POM in ein Projekt erben mchte. Sei es, dass Sie ein grosses System erstellen und Sie mchten die selben Abhngigkeiten nicht wieder und wieder wiederholen. Sie knnen sich diese Wiederholungen ersparen indem Sie von Vererbung mittels dem Element parent Gebrauch machen. Sobald ein Projekt ein Element parent ausweist, bernimmt es die Informationen des bergeordneten POM. Es kann daraufhin diese Werte bersteuern oder weiter ausfhren. Alle Maven POMs erben Werte von einem bergeordneten POM. Gibt ein POM kein bergeordnetes Projekt mittels dem Element parent an, so wird das POM die Werte des Super POM annehmen. Example 9.12, Projekt Vererbung (Beispiel 9.12: Projekt Vererbung) gibt ein Element parent des Projektes projekt-A wieder, welches die Werte des Projektes a-parent bernimmt. Example 9.12. Projekt Vererbung
<project> <parent> <groupId>com.training.killerapp</groupId> <artifactId>a-parent</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>project-a</artifactId> ...

227

Das Projekt Objekt Modell (POM)


</project>

Der Aufruf von mvn help:effective-pom innerhalb von Projekt project-a wrde darlegen, dass das resultierende POM ein Ergebnis der Verschmelzung des Super POM und des POM von Projekt a-parent sowie projekt-a ist. Die impliziten und expliziten Vererbungsbeziehungen von projekt-a werden in Figure 9.4, Projekt Vererbung von a-parent sowie project-a (Abbildung 9.4: Projekt Vererbung von a-parent sowie project-a) dargestellt.

Figure 9.4. Projekt Vererbung von a-parent sowie project-a Sobald ein Projekt ein bergeordnetes Projekt angibt wird Maven dieses bergeordnete POM als Ausgangspunkt benutzen, es wird dieses POM auswerten, vor es das derzeitige POM auswertet. Dieses vererbt alle Werte, inklusive der Koordinaten groupId und version. Bitte beachten Sie, das das Projekt projekt-a weder groupId noch version angibt, da beide Werte vom bergeordneten POM geerbt wird. Besteht ein Element parent, so muss das POM lediglich eine artifactId ausweisen. Diese Art der Vererbung ist nicht zwingend: Projekt project-a knnte genauso gut 228

Das Projekt Objekt Modell (POM) eine andere groupId und version tragen, jedoch, da keine Werte angegeben sind, wird Maven jeweils Werte welche im bergeordneten POM angegeben sind, benutzen. Sobald Sie Maven dazu einsetzen, grosse, multi-modulare Projekte zu erstellen, werden Sie des fteren viele Projekte erstellen, welche eine gemeinsame groupId und version tragen. Mit der Entscheidung von einem POM abzuleiten, knnen Sie dennoch feldweise bestimmen ob Sie die Informationen ableiten oder bersteuern mchten. Im folgenden eine Liste der Felder, welche in einem Maven POM abgeleitet werden: Bezeichner (mindestens ein Bezeichner groupId oder artifactId muss bersteuert werden) Abhngigkeiten Entwickler und Mitwirkende Liste der Plugins Liste der Auswertungen Plugin Executions (Ausnahmen mit bereinstimmenden ids werden verschmolzen) Plugin Konfigurationen Sobald Maven Abhngigkeiten ableitet, wird es die Abhngigkeiten der untergeordneten Projekte den Abhngigkeiten der bergeordneten Projekte anfgen. Sie knnen diese Funktionalitt nutzen, um breit eingesetzte Abhngigkeiten in einem bergeordneten POM anzugeben von welchem dann alle Projekte ableiten. Nehmen Sie zum Beispiel an, Sie verwenden im allgemeinen das Log4J-Framework, Sie knen dann dieses im bergeordneten POM einsetzen. Jedes Projekt, welches von einem solchen bergeordneten POM ableitet wird, wird dann das Log4J Framework als Abhngigkeit erben. In gleicher Weise ist es Ihnen mglich in einem bergeordneten POM die gleiche Version eines bestimmten Maven Plugin zu definieren welches zum Einsatz kommt.

229

Das Projekt Objekt Modell (POM) Maven geht davon aus, dass das bergeordnete POM im lokalen Repository, oder aber vom direct bergeordneten lokalen Verzeichnis (../pom.xml) verfgbar ist. Sollten beide Ortsangaben ungltig sein, so kann das Standardverhalten mittels dem Element relativePath bersteuert werden. Hierzu ein Beispiel: manche Organisationen bevorzugen eine flache Projektstruktur in welcher ein bergeordnetes Projekt POM nicht automatisch ein bergeordnetes Verzeichnis darstellt. Es knnte genausogut ein Unterverzeichnis darstellen. Sollte Ihr abgeleitetes Projekt unter dem Verzeichnis ./projekt-a abgelegt sein, und das bergeordnete Projekt liegt unter dem Verzeichnis ./a-parent, so knnten Sie wie unten ausgefhrt eine relative Ortsbestimmung vornehmen:
<project> <parent> <groupId>org.sonatype.mavenbook</groupId> <artifactId>a-parent</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../a-parent/pom.xml</relativePath> </parent> <artifactId>project-a</artifactId> </project>

9.6. POM Best Practices


Maven kann vielseitig eingesetzt werden; es untersttzt gleichsam einfache Einzelprojekte wie auch Systeme welche hunderte von verschachtelten Submodule umfassen. Ein grosser Teil des Lernprozesses mit Maven umzugehen ist nicht der Umgang mit der Maven Syntax, sondern der Aufbau der Erfahrung und des Gesprs fr den "Maven Way" - der besten Art und Weise im Umgang mit der Organisation und dem Aufbau von Projekten welche durch Maven erstellt werden. Im folgenden Abschnitt wollen wir einige dieser Erkenntnisse sammeln und weitergeben, um Ihnen das Mhsal des jahrelangen Durcharbeiten von Diskussionsforen und Mailinglisten zu ersparen.

9.6.1. Zusammenfassen von Abhngigkeiten


Sollten Sie es mit einer Anzahl Abhngigkeiten zu tun haben, welche logisch 230

Das Projekt Objekt Modell (POM) zusammengehren so knnen Sie ein Projekt erstellen, welches diese Abhngigkeiten ebenfalls zusammenfasst. Ein Beispiel: nehmen wir an Sie bauen eine Anwendung und setzen Hibernate ein, ein verbreitetes Werkzeug zur Abbildung von Objekten auf Relationale Darstellungen. Jedes Projekt welches Hibernate einsetzt mag zugleich vom Spring Framework sowie einem MySQL-Treiber abhngig sein. Anstatt nun alle diese Abhngigkeiten in jedem Projekt welches Hibernate einsetzt zu deklarieren, knnten Sie ein spezielles POM erstellen, welches nichts weiter tut, als diese Abhngigkeiten als Gruppe von gemeinsamen Abhngigkeiten zu deklarieren. Sie knnten also ein Projekt mit dem Namen persistence-deps (Kurzform von Persistenz-Dependencies (=Abhngigkeiten)) deklarieren und daraufhin alle Projekte welches in irgendeiner Weise Persistenz bentigt von diesem Projekt abhngig deklarieren: Example 9.13. Zusammenfassen von Abhngigkeiten in einem einzigen POM Projekt
<project> <groupId>org.sonatype.mavenbook</groupId> <artifactId>persistence-deps</artifactId> <version>1.0</version> <packaging>pom</packaging> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>${hibernateVersion}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>${hibernateAnnotationsVersion}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-hibernate3</artifactId> <version>${springVersion}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysqlVersion}</version> </dependency> </dependencies> <properties> <mysqlVersion>(5.1,)</mysqlVersion>

231

Das Projekt Objekt Modell (POM)


<springVersion>(2.0.6,)</springVersion> <hibernateVersion>3.2.5.ga</hibernateVersion> <hibernateAnnotationsVersion>3.3.0.ga</hibernateAnnotationsVersion> </properties> </project>

Sollten Sie dieses Projekt in einem Verzeichnis mit dem Namen persistence-deps erstellen, so mssen sie lediglich diese pom.xml-Datei erstellen und den Aufruf mvn install absetzen. Da der Packetierungstyp POM ist, wird dieses POM sogleich in Ihr lokales Repository eingepflegt. Sie knnen nun dieses Projekt als Abhngigkeit in Ihren anderen Projekten definieren und sogleich werden alle Abhngigkeiten Ihrem Projekten zugefgt. Bei der Definition der Abhngigkeiten des Projektes persistence-deps, achten Sie darauf den Typ der Abhngigkeit auf POM festzulegen. Example 9.14. Deklaration einer Abhngigkeit von einem POM
<project> <description>This is a project requiring JDBC</description> ... <dependencies> ... <dependency> <groupId>org.sonatype.mavenbook</groupId> <artifactId>persistence-deps</artifactId> <version>1.0</version> <type>pom</type> </dependency> </dependencies> </project>

Sollten Sie sich zu einem spteren Zeitpunkt dazu entschliessen einen anderen JDBC Treiber (z.B. JTDS) zu benutzen, so ersetzen Sie einfach die Abhngigkeit innerhalb des Projektes persitence-deps, von mysql:mysql-java-connector auf net.surceforge.jtds:jtds und passen die Versionsnummer version an. Alle vom Projekt persistence-deps abhngigen Projekte werden von nun an gegen JTDS erstellt, sobald Sie auf eine neue Version wechseln. Verwandte Abhngigkeiten zusammenzufassen ist ein guter 232

Das Projekt Objekt Modell (POM) Ansatz um lange POM-Dateien zu krzen nachdem diese zu viele Abhngigkeiten beinhalten. Sollten Sie eine grosse Zahl Abhngigkeiten zwischen verschiedenen Projekten teilen, so knnten Sie natrlich auch Abhngigkeitsverhltnisse zwischen den Projekten definieren und so die Abhngigkeiten in bergeordneten Projekten herausziehen. Der Nachteil eines solchen Ansatzes ist, dass jedes Projekt immer nur ein bergeordnetes Projekt haben kann. oftmals macht es mehr Sinn verwandte Abhngigkeiten zusammenzufassen und mittels einer POM-Abhngigkeit einzubinden. auf diese Art und Weise kann ein Projekt so viele dieser konsolidierten Abhngigkeiten via POM Abhngigkeit einbinden wie ntig. Note Maven orientiert sich bei der Aufsung von Abhngigkeitskonflikten an der Tiefe des Abhngigkeitsbaumes. Maven verfolgt hierbei einen Nchster-Gewinnt Ansatz. Der Einsatz dieser Art der Zusammenfassung schiebt Abhngigkeiten im Kontext weiter (nach hinten) weg. Dies ist wichtig zu beachten, sollten Sie sich zwischen der Zusammenfassung innerhalb eines POM oder Abhngigkeitsmanagement mittels abhngiger POM zu entscheiden haben.

9.6.2. Multi-modular vs. Vererbung


Es besteht ein deutlicher Unterschied zwischen der Vererbung von einem bergeordneten POM sowie der Einbindung in einem multi-modularen POM. Ein bergeordnetes Projekt "vererbt" dessen Werte an untergeordnete Projekte. Ein multi-modulares Projekt verwaltet lediglich eine Anzahl untergeordneter Projekte oder Module. Eine multi-modulare Abhngigkeit ist vom obersten Projekt an nach unten definiert, bei der Erstellung eines multi-modularen Projektes definieren Sie lediglich in einem Projekt, dass dessen Build eine Anzahl angegebener Module einbinden soll. Multi-modulare Builds werden eingesetzt, um Module innerhalb eines einzigen Builds zu gruppieren. Die Vererbungshierarchie wird von den Endknoten nach innen definiert. Die Vererbungshierarchie befasst sich eher mit der Definition/Bestimmung eines speziellen Projektes. Sobald Sie ein untergeordnetes Projekt mit dem darberliegenden in Verbindung bringen (vererben), weisen Sie 233

Das Projekt Objekt Modell (POM) Maven damit an, dass die POM-Definitionen voneinander abgeleitet sind. Um Ihnen den Weg der Entscheidung bezglich der Ansatzes welcher Vererbung gegenber einem Ansatz basierend auf multi-modularer Definition nher zu bringen, hier zwei Beispiele: Das Maven Projekt, welche zum Einsatz kommt um dieses Buch zu generieren sowie eines ausgedachten Projektes, welches eine Anzahl logisch gruppierter Abhngigkeiten beinhaltet. 9.6.2.1. Einfaches Projekt Lassen Sie uns zunchst mit dem Beispiel des Projekt Maven Buch loslegen. Die Vererbung sowie die multi-modularen Abhngigkeiten sind in Figure 9.5, maven-book Multi-module vs. Vererbung dargestellt.

Figure 9.5. maven-book Multi-module vs. Vererbung Zur Erstellung des Buches welches Sie soeben lesen rufen wir mvn package eines multi-modularen Projektes mit dem Namen maven-book auf. Dieses 234

Das Projekt Objekt Modell (POM) multi-modulare Projekt schliesst zwei Untermodule ein: book-examples sowie book-chapters. Keines der beiden Unterprojekte teilt sich gemeinsame Vorfahren, die einzige Verbindung besteht, in dem, dass beides Untermodule des Projektes maven-book sind. Das Projekt book-examples erstellt die ZIP und TGZ Archive welche Sie herunterladen knnen um an die Beispiele des Buches zu gelangen. Wenn wir die Buchbeispiele aus dem Verzeichnis /book-examples mittels mvn package erstellen, weiss das Projekt nicht, dass es Teil eines grsseren Projektes ist. Es interessiert sich auch nicht fr das bergeordnete Projekt maven-book. Das Einzige was bewusst wird ist, dass das bergeordnete Projekt das alleroberste POM von Sonatype ist, und dass es ein Archiv von Beispielen erstellt. In diesem Fall besteht das Projekt maven-book lediglich zur Vereinfachng und als Klammer ber mehrere Module hinweg. Alle Buch Projekte definieren ein bergeordnetes Projekt. Jedes der drei Projekte: maven-book, book-examples und book-chapters weisst ein gemeinsames Projekt sonatype aus. Dies ist ein weit verbreiteter Ansatz in grossen Organisationen; statt jedes Projekt auf das Super POM zurckzufhren, wird ein bergeordnetes "Firmen"-Projekt erstellt, welches als Basisprojekt fr alle anderen Projekte dient sollte ein Projekt von keinem anderen Proekt in logischer Abhngigkeit stehen. In diesem Beispiel gibt es zm Beispiel keinen Grund das Projekt book-examples und book-chapters von einem gemeinsamen bergeordneten POM abhngig zu definieren. Beides sind grundstzlich verschiedene Projekte mit ganz unterschiedlichen Abhngigkeiten, Build-Konfigurationen und vllig unterschiedlichen Plugins welche zum Einsatz kommen um den von Ihnen hier gelesenen Inhalt zu erstellen. Das POM sonatype bietet dennoch der Organisation die Mglichkeit das Standardverhalten von Maven allgemein zu beeinflussen und organisationsspezifische Einstellungen des Build oder Verteilungseinstellungen global vorzunehmen. 9.6.2.2. Multi-modulare Enterprise Projekte Lassen Sie uns ein Beispiel betrachten, welches der Realitt nher kommt, in welchem Vererbung sowie multi-modulare Beziehungen nebeneinander existieren. Eine Anzahl Projekte, wie diese in realen Situationen vorkommen sind in Abbildung Figure 9.6, Enterprise multi-modular gegenber Vererbung 235

Das Projekt Objekt Modell (POM) dargestellt. Zunchst gibt es auf hchster Ebene ein POM der Organisation mit einer artifactId von sonatype. Weiter sehen Sie ein multi-modulares Projekt mit dem Namen big-system welches Untermodule auf der Server- und der Client-Seite referenziert.

Figure 9.6. Enterprise multi-modular gegenber Vererbung Was spielt sich hier nun ab? Lassen Sie uns versuchen das wilde Knuel von Pfeilen zu entwirren. Zunchst betrachten wie big-system. Das Projekt big-system ist das Projekt, auf welchem Sie mvn package aufrufen um es zu erstellen und als Gesamtsystem zu testen. big-system referenziert zwei Untermodule: client-side sowie server-side. Jedes dieser zwei Module enthlt allen Quellcode, welcher entweder auf der Client- oder der Serverseite ablaufen 236

Das Projekt Objekt Modell (POM) wird. Sehen wir uns die Serverseite einmal genauer an: Unter dem Modul server-side gibt es ein Projekt server-lib sowie ein multi-modulares Projekt web-apps. web-apps hat wiederum zwei Untermodule: client-web sowie admin-web. Fangen wir einmal mit der Vererbungsbeziehung von client-web und admin-web von web-apps an. Da anzunehmen ist, dass beide Webanwedungen auf dem selben Framework (sagen wir z.B. Wicket) basierend umgesetzt werden, wrden beide Anwendungen die selben Core-Abhngigkeiten besitzen. Die Abhngigkeiten zum Servlet-API, JSP-API sowie zum Wicket-Framework wrden alle im Projekt web-apps definiert werden. Beide Module, client-web und admin-web haben zustzlich eine Abhngigkeit zum Projekt server-lib, diese Abhngigkeit wird ebenfalls im Projekt web-apps definiert. client-web und admin-web werden beide nur sehr kleine POMs besitzen, diese enthalten wenig mehr als deren Identitten, einer Deklaration des bergeordneten Moduls sowie einem Buildnamen fr den resultierenden Artefakten. Als nchstes sehen wir uns die Vererbungsbeziehung von web-apps und server-libs von server-side an. In diesem Fall treffen wir die Annahme, dass zwei getrennte Entwicklergruppen bestehen, eine fr serverseitige Entwicklung sowie eine andere fr clientseitige Entwicklung. Die Aufzhlung der Entwicker auf der Serverseite wrde im Projekt server-side vorgenomen und an alle darunterliegenden Module vererbt: web-apps, server-lib, client-web sowie admin-web. Wir knnten zudem die Annahme treffen, dass die Server seitigen Projekte einen anderen Build sowie andere Verteileinstellungen bentigen welche spezifisch der Entwicklung dieser Projektgruppe gelten. Das Projekt server-side knnte ein Build-Profil erstellen, welches nur fr die serverseitige Entwicklung Sinn macht. Dieses Profil knnte z.B. die Datenbankanbindungsparameter enthalten, oder die serverseitigen POM knnten eine bestimmte Version des Maven Jetty Plugins bestimmen, welche fr alle Projekte, welche das POM von Projekt server-side erben, gleich sein sollte. In diesem Beispiel wird Vererbung genutzt, um Beziehungen darzustellen, welche auf gemeinsame Abhngigkeiten und Konfigurationen einer Anzahl Projekte die logisch in Zusammenhang stehen, zurckzufhren sind. Alle Projekte unterhalb des Projektes big-system stehen zueinander als Untermodule in Beziehung, aber 237

Das Projekt Objekt Modell (POM) nicht alle Untermodule werden konfiguriert um auf das bergeordnete Modul zu verweisen (Vererbung), welches das Projekt als Untermodul definiert. Dass alle Module als Untermodule definiert sind, ist schlicht zweckmssig: um das Gesamtsystem big-system zu erstellen, gehen Sie einfach in das entsprechende Verzeichnis und fhren mvn package aus. Wenn Sie das Diagramm noch einmal genau studieren, so werden Sie feststellen, dass zwischen den Projekten server-side und big-system keine Vererbungsbeziehung besteht: Warum nicht? POM-Vererbung ist usserst mchtig, kann aber auch bermssig eingesetzt werden. Wenn es Sinn macht, Abhngigkeiten und Buildeinstellungen gemeinsam zu erstellen, dann sollte auch Vererbung zum Zug kommen. Es macht aber keinen Sinn Vererbung einzusetzen, wenn es klare Unterschiede in den Projekten gibt. Nehmen wir beispeilhaft die server- und clientseitigen Projekte. Es ist durchaus mglich das System so zu definieren, dass client- und serverseitig beide von einem gemeinsamen POM, von big-system, erben. Sobald aber klare Differenzen zwischen den Untermodulen bestehen, sind Sie gezwungen eine gemeinsame Buildkonfiguration zu erstellen, welche die entsprechenden Untermodule nicht beeinflusst. Auch wenn beide Projekte, client-side und server-side von Log4J abhngen mgen, so knnen Sie dennoch ganz unterschiedliche Plugin-Konfigurationen bentigen. Ab einem bestimmten Punkt ist es mehr eine Frage des Stils und der Erfahrung wenn es darum geht eine Entscheidung zu fllen, ob eine gewisse Duplikation ein geringer Preis dafr ist, dass zwei unabhngige Projekte wie hier client-side und server-side wirklich unabhngig voneinander bestehen. Der Entwurf eines riesigen Netzes von mehr als 30 Modulen, welche alle ber fnf Ebenen POM Konfiguration voneinander abhngig sind ist nicht immer der Weisheit letzter Schluss. In einem solchen Geflecht kann es gut sein, dass Sie zwar die Abhngigkeit von Log4J nur ein einziges Mal definieren mssen, aber Sie sind eben auch gezwungen sich durch fnf Ebenen POM durchzukmpfen um zu verstehen wie Maven auf ein bestimmtes effektives POM kommt. Die ganze Komplexitt also nur, um sich die Wiederholung von fnf Zeilen Abhngigkeitsdefinition zu sparen! Unter Maven gibt zwar es den "Maven Way", aber oftmals gibt es viele Wege um zum selben Ziel zu gelangen. Es kommt dann ganz auf Vorlieben und Stil an. Im allgemeinen wird es nicht falsch sein, wenn alle Ihre Module auf ein einziges Ursprungsmodul zurckgehen, aber es kann auch gut 238

Das Projekt Objekt Modell (POM) sein, dass sich Ihr Stil im Einsatz von Maven ber die Jahre ndert. 9.6.2.3. Elterliche Prototyp Projekte Schauen Sie sich doch noch den hypothetischen, in Abbildung Figure 9.7, Der Einsatz von bergeordneten Projekten als "Prototypen" von spezialisirten Projekten dargestellten kreativen Einsatz von Vererbung in einem multi-modularen Build an, welcher darauf abzielt gewisse Abhngigkeiten wiederzuverwenden.

Figure 9.7. Der Einsatz von bergeordneten Projekten als "Prototypen" von spezialisirten Projekten Figure 9.7, Der Einsatz von bergeordneten Projekten als "Prototypen" von 239

Das Projekt Objekt Modell (POM) spezialisirten Projekten ist ein weiterer Ansatz wie man Vererbung in multi-modularen Projekten einsetzen kann. In diesem Beispiel bestehen zwei voneinander unabhngige Projekte: sytem-a und system-b definieren zwei vllig unabhngige Anwendungen. system-a definiert zwei Untermodule: a-lib und a-swing. system-a und a-lib definieren beide eine direkte Abhngigkeit zum hchststehend POM sonatype. a-swing hingegen definiert swing-proto als bergeordnetes Modul. In diesem System definiert swing-proto ein grundlegendes POM fr Swing basierte Anwendungen und struts-proto definiert ein grundlegendes POM fr Struts 2 basierte Web-Anwendungen. Whrend das POM sonatype berragende Werte wie z.B. die groupId, Organisationsinformation und Build-Profile definiert, definiert struts-proto alle Abhngigkeiten welche bentigt werden, um eine Struts-Anwendung zu erstellen. Dieser Ansatz ist besonders zu empfehlen, sollten Sie viele unabhngige Applikationen betreiben, welche aber alle auf den gleichen Grundregeln aufsetzen. Sollten Sie z.B. viele Struts-Anwendungen erstellen, welche jedoch voneinander unabhngig sind, wird es Ihnen eine Hilfe sein ein Projekt struts-proto zu definieren. Der Nachteil dieses Ansatzes ist, dass er es Ihnen verunmglicht, Vererbungsbeziehungen innerhalb von system-a und system-b Projekthierarchien zu benutzen, um Informationen wie z.B. Entwickler und andere Build-Informationen zu vererben, ein Projekt hat immer nur ein einziges bergeordnetes Projekt. Eine weitere Schattenseite dieses Ansatzes ist, dass Sie mit dem ersten Auftreten eines Projektes welches ausserhalb dieses Rasters fllt, gezwungen sind entweder den "Prototyp" zu bersteuern, oder aber einen Weg finden mssen, um Anpassungen am gemeinsamen, bergeordneten Modul einzufhren, ohne dabei die bestehenden Module zu beeinflussen. Im allgemeinen ist es nicht ratsam POMs als Prototypen fr spezialisierte Projekte einzusetzen.

240

Chapter 10. Der Build Lebenszyklus


10.1. Einfhrung
Maven modelliert Projekte als Nomen welche von einem Projekt Objekt Modell (POM) beschrieben werden. Das POM fngt die Identitt des Projektes ein: Was beinhaltet das Projekt? Welche Art der Packetierung bentigt das Projekt? Ist das Projekt ein abgeleitetes Projekt? Was sind die Abhngigkeiten? Im vorangegangenen Kapitel haben wir eingefhrt wie ein Projekt beschrieben werden kann, was wir nicht eingefhrt haben sind die Mechanismen mittels welchen Maven auf diesen Objekten agieren kann. Im Maven Universum werden Verben durch Goals, welche in Maven Plugins verpackt und an Lebenszyklusphasen gebunden sind, dargestellt. Ein Maven Lebenszyklus besteht aus einer Reihe namentlich benannter Lebenszyklusphasen: prepare-resources, compile, package und install neben anderen. Es gibt also eine Phase welche die Kompilierung beschreibt und eine Phase welche die Packetierung umfasst. Darber hinaus gibt es vorbereitende und nachbereitende Phasen, welche benutzt werden, um Goals welche vor oder gerade nach einer bestimmten Phase abgearbeitet werden mssen zu registrieren. Sobald Sie Maven aufrufen um einen Build zu erstellen, rufen Sie tatschlich Maven dazu auf eine bestimmte Kette von Phasen zu durchlaufen und alle an eine Phase gebndene Goals abzuarbeiten. Ein Build Lebenszyklus ist eine Abfolge von Phasen welche existiert, um einer Anzahl Goals zu ordnen. Diese Goals sind gewhlt und an Phasen gebunden abhngig vom entsprechenden Packetierungstyp des Projektes in Verarbeitung. In Maven gibt es drei Standard Lebenszyklen: clean, default (auch build genannt) und site. Dieses Kapitel wird erlutern, wie Maven Goals an Lebenszyklusphasen bindet und wie Lebenszyklen angepasst werden knnen. Die Standard Lebenszyklusphasen werden ebenfalls eingefhrt.

10.1.1. Lebenszyklus: clean


Der erste Lebenszyklus fr welchen Sie sich interessieren werden ist zugleich der 241

Der Build Lebenszyklus einfachste Lebenszyklus von Maven. Der Aufruf von mvn clean started den Lebenszyklus clean welcher aus drei Phasen besteht:
pre-clean clean

post-clean Die interessante Phase des Lebenszyklus clean ist die Phase clean. Das Goal clean (clean:clean) des Plugins clean wird an die Phase clean des Lebenszyklus clean gebunden. (Noch ganz sauber oder was!?!) Das Goal clean:clean lscht die Ergebnisse des vorgehenden Builds indem es das Zielverzeichnis lscht. Sollten Sie das Zielverzeichnis nicht weiter angepasst haben, so ist dieses Zielverzeichnis das Verzeichnis ${basedir}/target wie dies im Super POM definiert ist. Die Ausfhrung des Goals clean:clean wird nicht direkt mit dem Aufruf mvn clean:clean gestartet, statt dessen wird die Phase clean des Lebenszyklus zur Ausfhrung gebracht. Die Ausfhrung der Phase clean ermglicht Maven auch Goals welche an die Phase pre-clean gebunden sind auszufhren. Ein Beispiel: nehmen wir an Sie mchten das Goal antrun:run whrend der Phase pre-clean anstossen, um eine Nachricht auszugeben, oder um ein Archiv des Project Build Verzeichnis anzulegen bevor dieses gelscht wird. Der Aufruf von clean:clean wird den Lebenszyklus gar nicht ausfhren, jedoch wird die Angabe der Phase clean auslsen, dass die drei Lebenszyklusphasen bis zur Phase clean ausgefhrt werden. Example 10.1, Auslsen eines Goals in der Phase pre-clean (Beispiel 10.1: Auslsen eines Goals in der Phase pre-clean) zeigt beispielhaft eine Build Konfiguration welche das Goal antrun:run and die Phase pre-clean bindet um eine Warnung auszugeben, welche mitteilt, dass der Projektartefakt gelscht werden soll. In diesem Beispiel wird das Goal antrun:run benutzt, um ein beliebiges Ant Kommando auszufhren um zu prfen ob es den Artefakten gibt. Besteht der Artefakt und soll gelscht werden, so wird dies auf der Konsole ausgegeben. Example 10.1. Auslsen eines Goals in der Phase pre-clean 242

Der Build Lebenszyklus

<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/antcontrib.properties" /> <available file="${project.build.directory}/${project.build.finalName}.${project.packagin property="file.exists" value="true" /> <if> <not> <isset property="file.exists" /> </not> <then> <echo>No ${project.build.finalName}.${project.packaging} to delete</echo> </then> <else> <echo>Deleting ${project.build.finalName}.${project.packaging}</echo> </else> </if> </tasks> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>ant-contrib</groupId> <artifactId>ant-contrib</artifactId> <version>1.0b2</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>

Das Ausfhren von mvn clean auf einem Projekt mit der oben gegebenen Build 243

Der Build Lebenszyklus Konfiguration wird eine Ausgabe hnlich der unten wiedergegebenen erzeugen.
[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 your-project-1.0-SNAPSHOT.jar [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] ------------------------------------------------------------------------

Zustzlich zur Mglichkeit Maven so zu konfigurieren, dass es ein Goal whrend der Phase pre-clean ausfhrt wird, kann man das Clean Plugin so anzupassen, dass es Dateien ber denen des Zielverzeichnisses hinaus lscht. Sie knnen das Plugin so konfigurieren, dass es bestimmte in einer Aufzhlung angegebene Dateien lscht. Das unten aufgefhrte Beispiel konfiguriert clean so, dass es unter Einsatz der standard Ant Wildcards (* und **) alle .class Dateien in einem Verzeichnis mit dem Namen target-other/ lscht Example 10.2. Anpassen des Verhaltens des Clean Plugin
<project> <modelVersion>4.0.0</modelVersion> ... <build> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <configuration> <filesets> <fileset> <directory>target-other</directory> <includes> <include>*.class</include>

244

Der Build Lebenszyklus


</includes> </fileset> </filesets> </configuration> </plugin> </plugins> </build> </project>

10.1.2. Standard Lebenszyklus: default


Die meisten Maven Benutzer sind mit dem Standardlebenszyklus vertraut. Dieser bildet das algemeine Modell des Build Prozesses einer Software Applikation ab. Die erste Phase ist validate und die letzte Phase deploy. Die Phasen des Maven Standard Lebenszyklus sind in Table 10.1, Maven Lebenszyklusphasen (Tabelle 10.1: Maven Lebenszyklusphasen) aufgefhrt. Table 10.1. Maven Lebenszyklusphasen Lebenszyklus Phase validate Beschreibung Validieren, dass ein Projekt komplett ist, und dass alle notwendigen Informationen um einen Build zu erstellen verfgbar sind. Generieren jeglicher Quellen welche bentigt werden um in ein Kompilat eingefgt zu werden. Verarbeiten der Quellen, zum Beispiel um Werte zu Filtern Generieren der Ressourcen welche einem Paket beigefgt werden Kopieren und Verarbeiten der Ressourcen, Ablage in das Zielverzeichnis 245

generate-sources

process-sources generate-resources process-resources

Der Build Lebenszyklus Lebenszyklus Phase Beschreibung bereit um zu packetieren. compile process-classes Kompilieren der Quellen des Projektes. Nachverarbeitung der generierten Dateien der Kompilierung, zum Beispiel um Bytecode Modifikationen einzufgen. Generieren von Test Quellcode welcher in das Kompilat eingefgt werden muss. Verarbeiten des Test Quellcodes, z.B. um Werte zu filtern Erstellen der Test Ressourcen Verarbeiten und Kopieren der Ressourcen in das Test-Zielverzeichnis Kompilieren der Test Quelldateien in das Test Zielverzeichnis Abarbeiten der Tests unter Einsatz eines geeigneten Unit Test Frameworks. Diese Tests sollten nicht voraussetzen, dass der Code Packetiert und Deployed wird. Ausfhren jeglicher notwendiger Schritte, um die Packetierung vorzubereiten, dies fhrt oftmals zu einer unpacketierten verarbeiteten Version des Pakets (Teil von Maven 2.1+) Paketieren des Kompilates in ein verteilbares Format wie z.B. JAR, WAR oder EAR Ausfhren vorbereitender Schritte fr Integrationstests. Dies kann die Erstellung 246

generate-test-sources process-test-sources generate-test-resources process-test-resources test-compile test

prepare-package

package

pre-integration-test

Der Build Lebenszyklus Lebenszyklus Phase Beschreibung des notwendigen Testumfeldes umfassen. integration-test Verarbeiten und deployen des Packages in eine Umgebung in welcher Integrationstests ausgefhrt werden knnen. Ausfhren von abschliessenden Schritten nachdem die Integrationstests ausgefhrt wurden, dies kann auch die Bereinigung der Umgebung beinhalten. Jegliche Prfungen ausfhren um sicherzustellen dass das Package die erforderlichen Kriterien erfllt. Installieren des Packages in das lokale Repository um dort lokal als Abhngigkeit fr andere Projekte bereitzustehen. Kopiert das endgltige Paket in das ferne Repository um dieses anderen Entwicklern und Projekten bereitzustellen. Dieser Schritt ist gewhnlich nur bei offiziellen Versionen von Bedeutung.

post-integration-test

verify

install

deploy

10.1.3. Lebenszyklus: site


Maven kann mehr als nur Software Artefakte von Projekten erstellen. Es kann auch Projektdokumentation und Reports bezglich dem Projekt oder eine Reihe von Projekten, erstellen. Projektdokumentation und Site Generierung haben einen eigenen Lebenszyklus zugeordnet, welcher vier Phasen kennt: 247

Der Build Lebenszyklus 1. pre-site 2. site 3. post-site 4. site-deploy Die an den Lebenszyklus site gebundenen Goals sind: 1. site - site:site 2. site-deploy -site:deploy Die Art der Packetierung ndert im allgemeinen diesen Lebenszyklus nicht, da Packetierungstypen sich primr mit der Artefakt Erzeugung befassen, nicht mit der Art des Sites der Generiert wird. Das Site Plugin started die Ausfhrung der Doxia Dokument Generierung und anderer Report generierender Plugins. Sie knnen einen Site eines Maven Projekts erstellen indem Sie das folgende Kommando absetzen:
$ mvn site

Die Generierung von Sites mittels Maven wird in Chapter 15, Projekt-Site Erstellung (Kapitel 15: Site Generierung) weiter vertieft.

10.2. Package-spezifische Lebenszyklen


Die genauen Goals welche an eine Phase gebunden werden sind bestimmt durch die Menge der Goals welche durch die projektspezifische Packetierung festgelegt wird. Ein Projekt welches vom Packetierungs Typ jar ist hat einen anderen Standardsatz Goals als das ein Projekt vom Typ war hat. Das Element packaging beeinflusst den Satz der Goals welche beim Build abgearbeitet werden mssen. Um Ihnen beispielhaft vorzufhren wie sehr packaging den Build beeinflusst, hier zwei Projekte: Eines mit packaging-Element pom und eines vom Typ jar. Das Projekt vom Typ pom wird das Goal site:attach-descriptor in der Phase 248

Der Build Lebenszyklus


packaging

abarbeiten, das Projekt vom Typ jar wird satt dessen das Goal jar:jar

abarbeiten. The following sections describe the lifecycle for all built-in packaging types in Maven. Use these sections to find out what default goals are mapped to default lifecycle phases. Der folgende Abschnitt beschreibt den Lebenszyklus aller standardmssig verfgbaren Package Typen in Maven. Benutzen Sie diesen Abschnitt als Referenz um herauszufinden welche Goals standardmssig an welche Phase gebunden werden.

10.2.1. jar
JAR ist der Standard Paketierungstyp, es ist der am hufigsten benutzte und die am meisten in Lebenszyklen angetroffene Konfiguration. Die Standard Goals des JAR Lebenszyklus sind in Table 10.2, Standard Goals des JAR Packaging (Tabelle 10.2: Standard Goals des JAR Packaging) aufgefhrt. Table 10.2. Standard Goals des JAR Packaging Lebesnzyklus Phase 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

249

Der Build Lebenszyklus

10.2.2. pom
POM ist der einfachste Paketierungstyp. Der generierte Artefakt ist sich selbst, kein JAR, WAR oder EAR. Es gibt keinen Code zu Testen oder Kompilieren, und es gibt auch keine Ressourcen zu verarbeiten. Die Standard Goals des POM Lebenszyklus sind in Table 10.3, Standard Goals des POM Packaging (Tabelle 10.3: Standard Goals des POM Packaging) aufgefhrt: Table 10.3. Standard Goals des POM Packaging Lebenszyklus Phase package install deploy Goal site:attach-descriptor install:install deploy:deploy

10.2.3. plugin
Dieser Paketierungstyp ist hnlich dem der JAR Packetierung mit drei Unterschieden: plugin:descriptor, plugin:addPluginArtifactMetadata, und plugin:updateRegistry. Diese Goals generieren eine Descriptor Datei und fhren gewisse nderungen an den Repository Daten aus. Die Standard Goals des plugin Lebenszyklus sind in Table 10.4, Standard Goals des plugin Packaging (Tabelle 10.4: Standard Goals des plugin Packaging) aufgefhrt: Table 10.4. Standard Goals des plugin Packaging Lebenszyklus Phase generate-resources process-resources compile process-test-resources Goal plugin:descriptor resources:resources compiler:compile resources:testResources 250

Der Build Lebenszyklus Lebenszyklus Phase test-compile test package install deploy Goal compiler:testCompile surefire:test jar:jar, plugin:addPluginArtifactMetadata install:install, plugin:updateRegistry deploy:deploy

10.2.4. ejb
Enterprise Java Beans (EJBs) sind eine hufing angewandte Technologie fr die Modell getriebene Entwicklung von Enterprise Java Applikationen. Maven untersttzt EJB 2 und EJB 3, obschon man das Plugin speziell konfigurieren muss um EJB 3 zu untersttzen. Standardmssig wird EJB 2.1 umgesetzt, wobei das Plugin nach bestimmten EJB Konfigurationsdateien sucht. Die Standard Goals des ejb Lebenszyklus sind in Table 10.5, Standard Goals des ejb Packaging (Tabelle 10.5: Standard Goals des ejb Packaging) aufgefhrt: Table 10.5. Standard Goals des ejb Packaging Lebenszyklus Phase 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 251

Der Build Lebenszyklus

10.2.5. war
Der Paketeierungstyp war ist hnlich dem des Types jar oder ejb. Die Ausnahme hierbei ist das Goal war:war. Bitte beachten Sie, dass das war Plugin eine web.xml Konfigurationsdatei im Verzeichnis src/main/webapp/WEB-INF voraussetzt. Die Standard Goals des war Lebenszyklus sind in Table 10.6, Standard Goals des war Packaging (Tabelle 10.6: Standard Goals des war Packaging) aufgefhrt: Table 10.6. Standard Goals des war Packaging Lebenszyklus Phase 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
EARs sind wohl das einfachste Java EE Konstrukt, bestehen Sie ja lediglich aus der Deployment Beschreibungsdatei (Descriptor) application.xml, Ressourcen und einigen Modulen. Das ear Plugin hat besitzt ein Goal mit dem Namen generate-application.xml welche die applicaiton.xml Datei auf der Basis des POM generiert. Die Standard Goals des ear Lebenszyklus sind in Table 10.7, Standard Goals des POM Packaging (Tabelle 10.7: Standard Goals des ear Packaging) aufgefhrt:

252

Der Build Lebenszyklus Table 10.7. Standard Goals des POM Packaging Lebenszyklus Phase generate-resources process-resources package install deploy Goal ear:generate-application-xml resources:resources ear:ear install:install deploy:deploy

10.2.7. Andere Packetierungs Typen


Dies ist keine abschliessende Liste aller fr Maven verfgbarer Paketierungstypen. Es bestehen eine ganze Anzahl Paketierungs Formate verfgbar mittels externer Projekte und Plugins: der Typ native archive (NAR), die Typen SWF und SWC fr Projekte welche Adobe Flash und Flex Inhalte erzeugen und viele andere. Sie knnen ebenfalls eigene Benutzer spezifische Paketierungs Typen definieren und den standardmssigen Lebenszyklus Ihren spezifischen Bedrfnissen anpassen. Um einen derart angepassten Paketierungstypen einzusetzen braucht es zwei Dinge: ein Plugin welches den angepassten Lebenszyklus definiert und ein Repository welches dieses Plugin beinhaltet. Manche angepassten Paketierungs Typen sind in Plugins definiert und ber das zentrale Repository verfgbar. Hier ein Beispiel eines Projekts welches sich auf das Israfil Flex Plugin sttzt und einen benutzerdefinierten Paketierungstyp SWF benutzt um die Ausgabe aus Adobe Flex Quellen zu erstellen. Example 10.3. Benutzerdefinierter Packetierungs -Type fr Adobe Flex (SWF)
<project> ... <packaging>swf</packaging> ...

253

Der Build Lebenszyklus


<build> <plugins> <plugin> <groupId>net.israfil.mojo</groupId> <artifactId>maven-flex2-plugin</artifactId> <version>1.4-SNAPSHOT</version> <extensions>true</extensions> <configuration> <debug>true</debug> <flexHome>${flex.home}</flexHome> <useNetwork>true</useNetwork> <main>org/sonatype/mavenbook/Main.mxml</main> </configuration> </plugin> </plugins> </build> ... </project>

In Section 17.6, Plugins and the Maven Lifecycle (Abschnitt 17.6 Plugins und der Maven Lebenszyklus) fhren wir aus, wie Sie Ihren eigenen Paketierungstypen mit angepasstem Lebenszyklus erstellen. Das Beispiel sollte Ihnen aufzeigen was notwendig ist, um einen angepassten Paketierungstypen einzusetzen. Das einzige was Sie tatschlich dazu beitragen mssen ist, das Plugin welches den angepassten Paketierungstyp mitbringt zu referenzieren. Das Israfil FLex Plugin ist ein Drittpartei Maven Plugin welches von Google Code bereitgehalten wird. Fr weitere Informationen bezglich des Plugins, oder den Schritten die notwendig sind um Adobe Flex zu Kompilieren, wenden Sie sich bitte an http://code.google.com/code.google.com/p/israfil-mojo. Das Plugin liefert die folgenden Lebenszyklen des SWF Packetierungs Typ. Table 10.8. Standard Lebenszyklus fr SWF Packetierung Lebenszyklus Phase compile install deploy Goal flex2:compile-swc install deploy

254

Der Build Lebenszyklus

10.3. Gebruchliche Lebenszyklus Goals


Viele der Paketierungs-Lebenszyklen haben hnliche Goals. Wenn Sie die Goals des war und des jar Lebenszyklus vergleichen, so werden Sie feststellen, dass diese sich lediglich in der Phase package unterscheiden. Die Phase package des Lebenszyklus war ruft war:war auf, die des Lebenszyklus jar ruft jar:jar auf. Die meisten der Lebenszyklen mit welchen Sie in Kontakt kommen werden teilen sich einige gemeinsame Lebenszyklus Goals um Ressourcen zu Managen, Tests Abzuarbeiten sowie Quellen zu Kompilieren. In diesem Abschnitt wollen wir nun einige dieser gemeinsamen Lebenszyklus Goals genauer betrachten.

10.3.1. Ressourcen Verarbeiten


Die meisten Lebenszyklen binden das Goal resources:resources an die Phase process-resources. Diese Phase verarbeitet Ressourcen und kopiert diese in das Zielverzeichnis. So Sie dieses nicht angepasst haben, gelten die im Super POM festegelegten Standardverzeichnisse, das heisst, Maven kopiert die Dateien von ${basedir}/src/main/resources nach ${project.build.outputDirectory}. Zustzlich zu der reinen Kopieraktion kann Maven auch die Ressourcen filtern, d.h. Sie knnen gewisse Token in den Dateien ersetzen. Genau wie Variablen innerhalb der POM Datei mittels ${ } markiert sind, so knnen Sie die gleiche Syntax einsetzen um Variablen innerhalb von Ressourcen zu referenzieren. Im Zusammenspiel mit Build-Profilen kann diese Eigenschaft dazu benutzt werden, um Builds fr unterschiedliche Zielplattformen zu erstellen. Dies trifft man hufig in Umgebungen an, welche fr das gleiche Projekt unterschiedliche Builds fr das Development, Test, Integrationstest und Produktion erstellen mssen. Bezglich weiter Informationen zu Build-Profilen verweisen wir auf Chapter 11, Build-Profile (Kapitel 11: Build Profile). Um Ressource Filterung zu veranschaulichen, stellen Sie sich vor, Sie habe ein Projekt mit einer XML-Datei unter /src/main/resources/META-INF/services.xml. Hierbei mchten Sie eine Konfigurationseinstellung in eine Property-Datei auslagern. In anderen Worten, Sie mchten zum Beispiel die Werte der JDBC URL, Benutzername und Passwort 255

Der Build Lebenszyklus der Datenbank nicht direkt in der service.xml Datei ablegen. Statt dessen mchten Sie eine Property Datei mit den variablen Werten Ihres Programms anlegen. Das ermglicht Ihnen, alle Konfigurationsparameter in einer Datei zusammenzufassen, um diese an einem Ort zu ndern sobald Sie von einer Umgebung in eine andere wechseln. Sehen Sie sich also zuallererts den Inhalt der entsprechenden Datei services.xml unter /src/main/resources/META-INF an: Example 10.4. Einsatz von Properties in den Projektressourcen
<service> <!-- This URL was set by project version ${project.version} --> <url>${jdbc.url}</url> <user>${jdbc.username}</user> <password>${jdbc.password}</password> </service>

Die in der XML Datei zum Einsatz kommende Syntax ist die selbe welche bereits in der POM Datei zum Einsatz kommt. Die erste zum Einsatz kommende Variable ist sogar eine Maven-implizite Variable welche vom POM bereitgestellt wird. Die Variable projekt erlaubt den Zugriff auf die Werte des POM. Die folgenden drei Referenzen sind jdbc.url, jdbc.username und jdbc.passwort. Diese benutzerdefinierten Variablen wurden in der Property Datei unter src/main/filters/default.properties definiert. Example 10.5. Datei default.properties unter src/main/filters
jdbc.url=jdbc:hsqldb:mem:mydb jdbc.username=sa jdbc.password=

Um Ressourcenfilterung der Datei default.properties einzustellen, mssen innerhalb des POM zwei Dinge gesetzt werden: eine Liste der properties-Dateien innerhalb des Elements filters der Buildkonfiguration, sowie eine Maven Einstellung dass das Ressourcenverzeichnis der Filterung unterliegt. Standardmssig ist dieses Verhalten abgestellt und Ressourcen werden direkt in das Ausgabeverzeichnis kopiert, oder Maven bergeht diesen Schritt ganz. Diese 256

Der Build Lebenszyklus Einstellung ist standardmssig so gewhlt, damit es nicht vorkommt, dass ohne ersichtlichen Grund alle bestehenden ${...}-Referenzen ersetzt werden, welche Sie gar nicht ersetzen wollten. Example 10.6. Ressourcen Filtern (Ersetzen von Properties)
<build> <filters> <filter>src/main/filters/default.properties</filter> </filters> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build>

Wie mit allen Verzeichnissen unter Maven, ist es nicht Bedingung, das das Ressourcenverzeichnis unbedingt unter src/main/ressources liegt. Das ist lediglich der entsprechende Standardpfad wie er im Super POM festgelegt ist. Ebenfalls ist es gut zu wissen, dass Sie nicht gezwungen sind, alle Ihre Ressourcen in ein einzigen Verzeichniss zu konsolidieren. Sie knnen Ressourcen auch in getrennten Verzeichnissen unter src/main ablegen. Nehmen Sie einmal an, Sie arbeiten an einem Projekt mit hunderten von XML-Dokumenten und hunderten von Bildern. Anstatt nun alle diese Dateien unter dem Verzeichnis src/main/ressources gemischt abzulegen, ist es mglich, zwei Verzeichnisse src/main/xml und src/main/images anzulegen um die Inhalte dort abzulegen. Um weitere Verzeichnisse Ihrer Liste von Ressourceverzeichnissen zuzufgen, mssen Sie folgendes Element resource Ihrer Buildkonfiguration zufgen: Example 10.7. Festlegen zustzlicher Ressource Verzeichnisse
<build> ... <resources> <resource> <directory>src/main/resources</directory> </resource> <resource>

257

Der Build Lebenszyklus


<directory>src/main/xml</directory> </resource> <resource> <directory>src/main/images</directory> </resource> </resources> ... </build>

Sollten Sie ein Projekt erstellen, welches eine Befehlszeilenapplikation erzeugt, so finden Sie sich oftmals in einer Situation wieder, in welcher Sie einfache Shell Skripte erstellen, welche ein Jar-Dateien des Builds referenzieren. Sollten Sie dann das Assembly Plugin benutzen um ein Distributionspaket in Form eines ZIP- oder TAR-Archivs zu erstellen, so macht es Sinn, alle ihre Skripte in einem Verzeichniss wie etwa src/main/command zusammenzufassen. Im folgenden Ausschnitt einer POM Ressourcenkonfiguration knnen Sie sehen, wie wir Ressourcenfilterung und eine Referenz auf eine Projektvariable benutzen knnen, um den endgltigen Ausgabenamen des jar-Archives zu definieren. Weitere Informationen bezglich des Maven Assembly Plugins finden Sie in Chapter 12, Maven Assemblies (Kapitel 12: Maven Assemblies). Example 10.8. Filterung von Skript Ressourcen
<build> <groupId>org.sonatype.mavenbook</groupId> <artifactId>simple-cmd</artifactId> <version>2.3.1</version> ... <resources> <resource> <filtering>true</filtering> <directory>${basedir}/src/main/command</directory> <includes> <include>run.bat</include> <include>run.sh</include> </includes> <targetPath>${basedir}</targetPath> </resource> <resource> <directory>${basedir}/src/main/resources</directory> </resource> </resources> ... </build>

258

Der Build Lebenszyklus Der Aufruf von mvn process-resources dieses Projektes erzeugt zwei Dateien, run.sh sowie run.bat, beide unter ${basedir}. Wir haben innerhalb eines Elements resource diese zwei Dateien herausgepickt, Filterung eingestellt, und den Zielpfad (targetPath) auf ${basedir} gesetzt. In einem zweiten Elememt Resource haben wir definiert, dass die Ressourcen des Standard Ressourcenpfades in das Standardausgabeverzeichnis kopiert werden ohne diese zu filtern. Example 10.8, Filterung von Skript Ressourcen (Beispiel 10.8: Filterung von Skript Ressourcen) zeigt beispielhaft auf, wie Sie zwei Resourceverzeichnisse bestimmen und diese mit unterschiedlichen Filterkriterien sowie Zielverzeichnissen versehen. Das Projekt des Example 10.8, Filterung von Skript Ressourcen (Beispiels 10.8: Filterung von Skript Ressourcen) wrde eine Datei run.bat unter src/main/command mit folgendem Inhalt enthalten:
@echo off java -jar ${project.build.finalName}.jar %*

Nach der Ausfhrung von mvn process-resources, erscheint eine Datei run.bat im Verzeichnis ${basedir} mit folgendem Inahlt:
@echo off java -jar simple-cmd-2.3.1.jar %*

Die Mglichkeit unterschiedliche Filter fr speziefische Untergruppen von Ressourcen zu setzen, ist ein weiterere Grund weshalb Projekte mit vielen verschiedenen Arten von Artefakten es oftmals als hilfreich erachten, diese in verschiedenen Verziechnissen abzulegen. Die Alternative zum Ablegen verschiedener Ressourcetypen in unterschiedlichen Verzichnissen ist der Einsatz von komplexeren Stzen von Ein- und Ausschlusskriterien, um die entsprechenden Ressource Dateien welche einem Muster gengen, zu spezifizieren.

10.3.2. compile
Die allermeisten Lebenszyklen binden das Goal compile des Compiler Plugin an die Phase compile. Diese Phase ruft compile:compile auf, welches konfiguriert ist, alle Quellen zu verarbeiten und den resultierenden Bytecode im Build Ausgabeverzeichniss abzulegen. Sollten Sie die Standardeinstellungen des 259

Der Build Lebenszyklus SuperPOM nicht angepasst haben, so wird compile:compile alle Quellen unter src/main/java verarbeiten und das Ergebnis unter /target/classes ablegen. Das Compile Plugin ruft javac auf, und hat die Standardeinstellungen 1.3 und 1.1, in anderen Worten, das Compiler Plugin geht davon aus, dass Sie Java 1.3 konformen Code erzeugen und diesen an eine Java Virtual Machine 1.1 addressieren. Sollten Sie diese Einstellungen verndern wollen, so mssen sie die Ziel und Quellkonfiguration ihres Projektes dem Compiler Plugin mit auf den Weg geben. Sie tun dies mittels einem Eintrag in der POM Datei wie dies in Example 10.9, Einstellen der Quell- und Zielkonfiguration des Compiler Plugins (Beispiel 10.9: Einstellen der Quell- und Zielkonfiguration des Kompiler Plugins). Example 10.9. Einstellen der Quell- und Zielkonfiguration des Compiler Plugins
<project> ... <build> ... <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> ... </build> ... </project>

Beachten Sie, dass wir das Compiler Plugin konfigurieren, und nicht das spezifische Goal compile:compile. Um nur das spezifische Goal compile:compile zu konfigurieren, mssten wir das Element configuration unterhalb eines Elements execution des Goals compile:compile spezifizieren. Wir haben aber das Quell-und Zielverzeichnis des Compile Plugins konfiguriert, denn wir wollten nicht nur dieses eine Goal konfigurieren. Das Compiler Plugin kommt ebenfalls zum Einsatz, wenn Maven die Testquellen mittels dem Goal 260

Der Build Lebenszyklus verarbeitet. Die Definition des Plugin erlaubt uns die Konfiguration einmal auf der Pluginebene fr alle Goals vorzunehmen.
compile:testCompile

Sollten Sie den Ort Ihrer Quelldateien umdefinieren mssen, so knnen Sie dies durch die Vernderung der Build Konfiguration erreichen. Sollten Sie zum Beispiel ihre Quellen unter src/java statt src/main/java ablegen, und sollten das Ergebnis unter classes anstatt target/classes ablegen wollen, so knnen Sie jederzeit die Standarwerte sourceDirectory (Quellverzeichnis) des SuperPOM bersteuern. Example 10.10. bersteuern des Standard Quellverzeichnisses
<build> ... <sourceDirectory>src/java</sourceDirectory> <outputDirectory>classes</outputDirectory> ... </build>

Warning Obschon es Grnde geben mag die dafr sprechen, Maven ihren Wnschen bezglich Verzeichnisstruktur anzupassen, so knnen wir hier nicht stark genug betonen, dass es besser ist Ihre eingene Struktur zugunsten der Maven Standardverzeichnisstruktur aufzugeben. Dies ist keinesfalls darin begrndet, dass wir Sie von dieser Struktur bekehren wollen, sondern es ist einfacher fr andere Entwickler, ihre Projektstruktur zu verstehen, sollte diese den grundlegenden Konventionen folgen. Vergessen Sie schon den Ansatz! - Tun Sie sich diesen Gefallen.

10.3.3. Verarbeiten von Test Ressourcen


Die Phase process-test-resources lsst sich kaum von der Phase process-ressources unterscheiden. Es gibt einige triviale Unterschiede des POM, alles andere ist gleich. Sie knnen Test Ressourcen filtern wie die anderen 261

Der Build Lebenszyklus Ressourcen auch. Der standardmssige Ort der Testressourcen ist im Super POM mit src/test/resources gesetzt und das standardmssige Ausgabeverzeichnis von Testressourcen auf target/test-classes wie dies unter ${project.build.testOutputDirectory} definiert ist.

10.3.4. Kompilieren der Test Klassen (testCompile)


Die Phase test-compile ist beinahe identisch mit der Phase compile. Der einzige Unterschied ist, dass test-compile das Goal compile:testCompile anzieht, um Testquellen vom Quellverzeichnis anzuziehen und die Ausgabe im Test-Ausgabeverzeichnis abzulegen. Sollten Sie die Standardverzeichnisse des SuperPOM nicht bersteuert haben, so wird compile:Test die Sourcen aus dem Verzeichnis src/test/java in das Verzeichnis target/test-classes kompilieren. Wie mit den Quellverzeichnissen gilt, sollten Sie den Ort der Test Verzeichnisse ndern wollen, so knnen Sie dies tun indem Sie testSourceDirectory und testOutputDirectory anpassen. Sollten Sie Testquellen unter src-test/ anstatt src/test/java ablegen und den Bytecode unter classes-test/ anstatt target/test-classes ablegen wollen, so wden Sie auf die folgende Konfiguration vornehmen. Example 10.11. bersteuern des Ortes der Testquellen und -ausgabe
<build> ... <testSourceDirectory>src-test</testSourceDirectory> <testOutputDirectory>classes-test</testOutputDirectory> ... </build>

10.3.5. test
Die meisten Lebenszyklen binden das Goal test des Surefire Plugin an die Phase test. Das Surefire Plugin ist das UnitTest Plugin von Maven. Das Standardverhalten des Surefire Plugin ist, nach allen Klassen welche im Test 262

Der Build Lebenszyklus Quellenverzeichnis auf *Test enden zu suchen, um diese als JUnit Tests auszufhren. Das Surefire Plugin kann auch konfiguriert werden die Tests als TestNG Unit Test abzuarbeiten. Nach der Ausfhrung von mvn test sollten Sie feststellen knnen, das das Surefire Plugin eine Anzahl Reports unter target/surefire-reports ablegt. Dieses Reportverzeichnis beinhaltet zwei Dateien fr jeden ausgefhrten Test: eine XML Datei welche Informationen bezglich des Tests enthlt und eine Textdatei welche die Ausgabe des UnitTest enthlt. Sollte ein Problem whrend der Phase test auftreten und ein Unit Test nicht bestehen, so knnen Sie die Ausgabe von Maven zusammen mit dieser Datei benutzen, um den Grund des Abbruchs zu finden. Dieses Verzeichnis surefire-reports/ kommt ebenfalls zum Einsatz whrend der Site Generierung wobei eine einfach zu lesende Zusammenfassung der Unit Tests des Projektes erstellt wird. Sollten Sie an einem Projekt arbeiten, bei welchem einige abbrechende Unit Test bestehen, Sie mchten aber dennoch eine Ausgabe erzeugen, so mssen Sie das Surefire Plugin so konfigurieren, dass dieses die Ausfhrung beim Auftreten eines Fehlers nicht abbricht. Das Standardverhalten ist, dass der Build beim ersten auftreten eines Unit Test Fehlers abbricht. Um dieses Verhalten zu ndern, mssen Sie das Property testFailureIgnore des SureFire Plugin auf true setzen. Example 10.12. Konfiguration des Surefire Plugins um Testabbrche zu ignorieren
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> ... </plugins> </build>

Sollten Sie die Tests komplett bergehen wollen, so knnen Sie dies durch den 263

Der Build Lebenszyklus folgenden Aufruf erreichen:


$ mvn install -Dmaven.test.skip=true

Die Variable maven.test.skip beeinflusst beides, den Compiler und das Surefire Plugin. Geben Sie maven.test.skip=true an, so weisen Sie Maven an die Tests insgesamt zu ignorieren.

10.3.6. install
Das Goal install des Install Plugin ist immer an die Lebenszyklusphase install gebunden. Das Goal install:install installiert den Artefakt in das lokale Repository. Sollten Sie ein Projekt mit der groupId von org.sonatype.mavenbook einen Artefakten mit artifactId von simple-test und einer version von 1.0.2 haben, so wird das Goal install:install das JAR von target/simple-test-1.0.2.jar in
~/.m2/repository/org/sonatype/mavenbook/simple-test/1.0.2/simpletest-1.0.2.jar

kopieren. Ist das Projekt ein Projekt vom Typ POM Pakageing, so wird das POM in das lokale Repository eingestellt.

10.3.7. deploy
Das Goal deploy des Plugins Deploy wird gewhnlich an die Lebenszyklusphase deploy gebunden. Diese Phase wird benutzt, um einen Artefakten in ein entferntes Repository einzustellen. Gewhnlich geschiet dies um ein entferntes Repository bei einer Freigabe aktuell zu halten. Der Deployment Vorgang kann eine einfache Kopieraktion einer Datei darstellen, oder aber auch eine bertragung einer Datei mittles SCP und einem publicKey. Deployment Einstellungen beinhalten gewhnlich Zugangsdaten zu einem entfernten Repository, aus welchem Grund Deployment Einstellungen gewhnlich nicht in der pom.xml Datei gehalten werden. Statt dessen gehen diese gewhnlich in die benutzerspezifische Datei ~/m2/settings.xml. Zu diesem Zeitpunkt reicht es zu wissen, das das Goal deploy:deploy an die Phase deploy gebunden ist und sich der bertragung der Artefakten zu einem verffentlichten Repository und dem damit verbundenen Update der Repository Informationen welche von einem solchen Vorgang 264

Der Build Lebenszyklus betroffen sein knnten, annimmt.

265

Chapter 11. Build-Profile


11.1. Wozu sind sie ntzlich?
Profile erlauben einen bestimmten Build auf eine bestimmte Umgebung abzustimmen, Profile schaffen Portabilitt zwischen verschiedenen Build Umgebungen. Was meinen wir mit unterschiedlichen Build-Umgebungen? Zwei Beispiele von unterschiedlichen Build Umgebungen sind die Umgebungen von Test und Produktion. Solange Sie in einer Entwicklungs-Umgebung arbeiten, mag Ihr System so konfiguriert sein, dass es von einer lokalen Entwicklungsdatenbank liest, whrend in der Produktion ihr System so konfiguriert ist, dass dieses von der produktiven Datenbank liest. Maven erlaubt Ihnen beliebig viele Build Environments zu definieren (Build Profiles) welche jegliche Einstellung der pom.xml-Datei bersteuern knnen. Sie knnen somit Ihre Anwendung im "Entwicklungsprofil" so konfigurieren, dass diese von der Entwicklungsdatenbank liest, und mittels einem "Produktionsprofil" in der Produktion auf die Produktionsdatenbank zeigen lassen. Profile knnen darber hinaus von der jeweiligen Umgebung oder der Plattform aktiviert werden, Sie knnen Ihren Build so anpassen, dass dieser abhngig von der Betriebssystemumgebung oder der Version des installierten JDK sich unterschiedlich verhlt. Vor wir aber nher in die Details der Benutzung und Konfiguration von Maven Build Profilen eingehen, sollten wir zunchst das Konzept der Build Portabilitt definieren.

11.1.1. Was genau bedeutet Build Portabilitt


Die "Protabilitt" eines Builds ist ein Mass dessen, wie einfach es ist, ein bestimmtes Projekt in einer anderen Umgebung zu erstellen/builden. Ein Build, welcher ohne spezielle Konfiguration oder Anpassung von Property Dateien auskommt, ist portabler als ein Build, welcher viel Aufwand bentigt um von Grund auf erstellt zu werden. Die portabelsten Builds sind fr gewhnlich verbreitete Open Source Projekte wie zum Beispiel Apache Commons aus Apache 266

Build-Profile Velocity, welches mit Maven Builds versehen ist, welche keine oder nur geringfgige Anpassungen bentigen. Einfach ausgedrckt, portable Builds funktionieren einfach, so wie sie daher kommen, wohingegen weniger portable Builds von Ihnen abverlangen, dass Sie sich strecken - alle Plattform abhngigen Pfade und Build Tools einstellen. Vor den Details, wie ein Build tatschlich portabel konfigurierbar wird, werden wir nun zunchst die verschiedenen Arten der Portabilitt von welcher wir sprechen werden ansehen. 11.1.1.1. Nicht protierbare Builds Die Absesenheit von Portierbarkeit ist genau der Grund weshalb Build Tools eingesetzt werden - um dies zu verhindern. Dennoch, jedes Werkzeug kann dazu missbraucht werden (sogar Maven) einen nicht portierbaren Build zu erstellen. Ein nicht portierbarer Build ist ein Build welcher nur unter ganz besonderen Umstnden und Kriterien funktioniert (z.B. auf Ihrer lokalen Maschine). Ausser in dem Fall dass Sie ganz alleine fr sich arbeiten, und Sie keinerlei Plne haben jemals zu einer anderen Maschine zu deployen, ist es am besten Non-Portabilitt von vornherein auszuschliessen. Ein nicht portabler Build luft nur auf einer Maschine und ist sozusagen ein Einzelstck. Maven ist darauf ausgelegt nicht portablen Builds entgegenzuwirken, es bietet daher die Mglichkeit Builds mittels Build Profilen anzupassen. Immer wenn ein neuer Entwicker die Quellen eines nicht portablen Buildes bekommt, ist dieser gezwungen einen Grossteil der Build-Skripte anzupassen um den Build erstellen zu knnen. 11.1.1.2. Environment Portabilitt Ein Build ist Umgebungsportabel, wenn dieser Mechanismen bereitstellt, um Verhalten und Konfiguration abhngig von Umgebungen zu definieren. Ein Projekt, welches zum Beispiel in der Test-Umgebung eine Referenz auf eine Test-Datenbank, sowie in der Produktion eine Referenz auf eine produktive Datenbank aufweisst, ist Umgebungsportabel. Es ist warscheinlich, dass ein solcher Build eine Anzahl Properties abhngig von der Umgebung setzt. Sobald Sie in eine andere Umgebung wechseln, oder aber in eine Umgebung welche noch nicht definiert ist, oder noch kein Build Profil erstellt wurde, so wird das Projekt 267

Build-Profile nicht funktionieren. Schliesslich besteht Portabilitt nur zwischen definierten Umgebungen. Sobald ein neuer Entwickler die Quellen eines umgebungsportablen Projektes bekommt, muss dieser den Build in einer definierten Umgebung ablaufen lassen, oder aber eine solche Umgebung erstellen/definieren. 11.1.1.3. Organisationsweite (In-House) Portabilitt Diese Art der Portabilitt dreht sich um Projektanforderungen, dass nur wenige Mitarbeiter auf bestimmte interne Ressourcen wie z.B. Source Code Control oder das interne Maven Repository Zugriff haben. ein Projekt einer grossen Unternehmung mag z.B. von einer internen Datenbank abhngig sein, welche nur in-Haus Entwicklern zugnglich ist, oder ein Open Source Projekt mag bestimmte Zugriffsberechtigungen bentigen, um das Ergebnis eines Builds auf einer Webseite oder einem ffentlich zugnglichen Repository zu verffentlichen. Sollten Sie versuchen ein in-Haus Projekt ausserhalb dieser Umgebung von Grund auf zu erstellen (z.B. ausserhalb des Unternehmens), so wird dieser Build nicht erfolgreich zum Ziel kommen. Dies mag darauf zurckzufhren sein, dass bestimmte Plugins nicht zur Verfgung stehen, oder bestimmte Abhngigkeiten knnen nicht erfllt werden, bestimmt Zugrifsberechtigungen mgen allenfalls nicht bestehen, oder der Zugriff auf interne Ressourcen verwehrt sein. Ein solches Projekt ist nur innerhalb der Umgebungen einer Organisation portabel. 11.1.1.4. Universelle Portabilitt Jerdermann mag die Quellen eines universell portables Projektes herunterladen und ausfhren ohne den Build auf eine bestimmte Umgebung anzupassen. Dies ist die hchste Stufe der Portabilitt; alles darunter erfordert zustzlichen Auwand fr denjenigen der das Projekt erstellen mchte. Diese Art der Portabilitt ist insbesondere fr Open Source Projekte wichtig, da diese davon abhngig sind, dass eventuelle Mitwirkende das Projekt einfach herunterladen und ausfhren knnen. Jeder Entwickler knnte die Quellen eines universell portablen Projektes herunterladen und ausfhren.

268

Build-Profile

11.1.2. Auswahl eines geeigneten Mass der Portabilitt


Es ist ganz offensichtlich, Sie werden alles daran setzen, die niederste Stufe zu vermeiden: den nicht portablen Build. Vielleicht hatten Sie auch bereits die zweifelhafte Ehre in einer Organisation zu Lernen oder Arbeiten, welche eine kritische Anwendung betrieben hat, der ein nicht portabler Build zugrunde lag. In solchen Organisationen knnen Sie eine Anwendung nicht ohne die Hilfe einer bestimmten Person oder dem Einsatz eines bestimmten Servers erstellen. Desweiteren ist es in solchen Organisationen schwierig weitergehende Abhngigkeiten einzufhren oder zu verndern, ohne die zustndige Person welche den nicht portablen Build unterhlt zu konsultieren. Nicht portable Builds entstehen hufig in politisierenden Organisationen, immer dann wenn es wichtig erscheint, dass eine Person oder Gruppe die Macht ber die Kontrolle des Wie und Wann eines Projekt Builds hat. "Wie kann diese Anwedung gebuildet werden? Oh, da mssen wir Hans fragen, niemand sonst kann in die Produktion verteilen!". eine hchst gefhrliche Situation, welche zudem hufiger vorkommt, als Sie es sich vorstellen mgen. Sollten Sie fr eine solche Organisation arbeiten,so wird Maven und insbesondere werden Maven Profile Ihnen helfen diese Situation zu berkommen. Das andere Ende der Portabilittsskala ist die universelle Portabilitt. Universell portierbare Builds gehren im Allgemeinen zu den am schwierigsten zu erreichenden Zielen. Solcherlei Builds beschrnken die Auswahl ihrer Abhngigkeiten auf Projekte und Werkzeuge welche frei verfgbar und ffentlich zugnglich sind. Viele kommerzielle Angebote mssen von der Liste der Mglichen ausgeschlossen werden, da sie voraussetzen, dass einer bestimmten Lizenz zugestimmt wurde. Breite Portabilitt schrnkt auch den Raum der Abhngigkeiten ein welche Teil eines Maven Artefakts sein knnen. Ein Beispiel: sollten Sie von Oracle JDBC Treibern abhngig sein, so werden Ihre Kunden diese seperat herunterladen und installieren mssen. Das ist nicht mehr universell portable, denn Sie sind gezwungen eine Beschreibung zu liefern wie die Umgebung aufgebaut und angepasst werden muss um das Projekt zu erstellen. Andererseits ist es mglich, dass Sie auf JDBC Treiber zurckgreifen, welche in den ffentlichen Maven Repositorien vorhanden sind, wie zum Beispiel MySQL oder HSQLDB. 269

Build-Profile Wie zuvor erwhnt hat Open Source Software den grssten Nutzen von universeller Portabilitt. Breit abgesttze Builds reduzieren die Ineffizienzen welche mit der freien Mitarbeit in einem Projekt verbunden sind. Ein Open Source Projekt hat zwei gut abgegrenzte Benutzergruppen: Endbenutzer und Entwickler. Sobald Benutzer ein Projekt wie zum Beispiel Maven benutzen, und sich entscheiden einen Patch beizusteuern, so mssen sie die Wandlung durchmachen vom Nutzer eines Builds zum Ersteller eines Builds. Sie mssen zunchst einmal zu einem Entwickler werden. Abhngig wie schwierig es ist einen Build zu verstehen ist dies eine Hrde welche den benutzer davon abhalten mag, einen Patch beizusteuern. Mit einem universell portierbaren Projekt muss sich ein Benutzer nicht mit obskuren Anweisungen herumschlagen um zum Entwickler zu mutieren, der Benutzer kann die Quellen herunterladen, verndern und die Erweiterung einreichen, ohne sich mit jemanden in Verbindung zu setzen um zunchst in die Lage zu kommen das Environment zu erstellen. Fllt die Barriere um einen Patch zu erstellen, so werden Sie feststellen, dass die Anzahl der Beitrge, insbesondere der sporadischen Beitrge, steigt, diese wiederum sind oftmals das Znglein an der Waage ob ein Projekt ein Erfolg oder Misserfolg wird. Eine der Nebenwirkungen der Anwendung von Maven in einer Grosszahl verschiedener Open Source Projekte ist, dass es fr viele Entwickler wesentlich einfacher wurde beizusteuern und mitzuarbeiten.

11.2. Portabilitt mittels Maven Profilen


Ein Maven Profil ist eine Zusammenfassung alternativer Konfigurationsparameter welche gesetzt oder bersteuert werden. Mittels einem Profil knnen Sie einen Build fr unterschiedliche Umgebungen erstellen. Profile werden innerhalb der pom.xml-Datei erstellt, und bekommen dort auch einen Bezeichner. Danach knnen Sie Maven mit einem Befehlszeilenparameter aufrufen, in welchem Sie definieren mit welchem Profil die zugehrigen Goals abgearbeitet werden sollen. Die nachfolgende pom.xml-Datei definiert ein Profil production um die standard Compiler-Einstellungen zu bersteuern. Example 11.1. Einsatz eines Maven Profils um die produktiven Einstellungen 270

Build-Profile der Compiler Settings zu bersteuern


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>simple</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>simple</name> <url>http://maven.apache.org</url> <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>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <debug>false</debug># <optimize>true</optimize> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>

In diesem Beispiel haben wir ein Profil production erstellt, welches die Standardeinstellungen des Maven Compiler Plugin bersteuert. Lassen Sie uns nun die Syntax eines Profils genauer ansehen: Das Element profiles ist Teil der pom.xml-Datei, es enthlt ein oder mehrere Profile. Da Profile bestehende Einstellungen einer pom.xml-Datei 271

Build-Profile bersteuern, kommt das Element profiles gewhnlich als letztes Element in einer pom.xml-Datei. Jedes Profil bentigt ein Element id. dieses Element enthlt die Kennung welche benutzt wird, um das Profil von der Befehlszeile aufzurufen. Ein Profil wird mittels dem Argument -P<profile-id> an Maven bergeben. Ein Profil kann viele der Elemente welche innerhalb des Elements project einer pom.xml-Datei bestehen beinhalten. In diesem Beispiel bersteuern wir das Standardverhalten des Compiler Plugin, hierzu mssen wir die Plugin Konfiguration bersteuern, welche normalerweise im Element plugins eines Builds gesetzt wird. Wir bersteuern die Konfiguration des Maven Compiler Plugin. Wir stellen sicher, dass der Bytecode welcher im Profil production erstellt wird keine Debug Informationen enthlt, und dass dieser Code durch die Optimierungsalgorithmen des Compilers gegangen ist. Um mvn install unter dem Profil production aufzurufen, mssen Sie das Argument -Pproduction bergeben. Um zu berprfen, dass das Profil production die Standardeinstellungen des Compilers bersteuert, rufen Sie Maven zustzlich mit eingestellter Debug-Ausgabe (-X) auf, wie im folgenden Abschnitt dargestellt:
~/examples/profile $ mvn clean install -Pproduction -X ... (omitting debugging output) ... [DEBUG] Configuring mojo 'o.a.m.plugins: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) ...

Der Auszug aus der Debug-Ausgabe von Maven zeigt die eingesetzte 272

Build-Profile Konfiguration des Compiler Plugin unter dem Profil production. Wie in der Ausgabe dargestellt ist die Einstellung debug auf false und optimize auf true gesetzt.

11.2.1. bersteuern eines Projekt Objekt Modelles


Whrend das vorangehende Beispiel aufzeigte wie Sie die Standardeinstellungen eines einzelnen Maven Plugin bersteuern knnen, so wissen Sie immer noch nicht, was genau Sie tatschlich innerhalb eines Maven Profil setzen knnen! Die kurze Antwort ist, beinahe alles was Sie in einer pom.xml-Datei setzen knnen. Das Maven POM beinhaltet ein Element profiles als Teil des Elements project welches die alternativen Konfigurationen eines Projektes enthlt. Innerhalb von diesem Element eingeschlossen stehen Unterelemente profile welche die einzelnen Profile definieren. Jedes Profil muss eine eindeutige id haben, darberhinaus kann es beinahe alle Elemente beinhalten, welche man in einem Projekt erwarten wrde. Das folgende XML-Dokument zeigt alle erlaubten Elemente auf, welche ein Profil bersteuern darf. Example 11.2. Erlaubte Elemente in einem Profil
<project> <profiles> <profile> <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>

273

Build-Profile In einem Profil kann man alle Elemente welche hier mit Auslassungzeichen gekennzeichnet sind bersteuern. Ein Profil kann den endgltigen Ausgabenamen eines Projektartefakten bersteuern, Abhngigkeiten und das Verhalten des Projekt-Builds mittels der Plugin-Konfiguration beeinflussen. Ein Profil kann auch die Einstellungen der Verteilung profilabhngig definieren, so knnen Sie zum Beispiel in einem Profil staging definieren das der Artifakt auf einen Staging-Server verteilt wird und somit die Einstellungen des Elements distributionManagement bersteuert.

11.3. Profil Aktivierung


Im vorangegangenen Abschnitt haben wir ausgefhrt, wie man ein Profil erstellt, welches das Standardverhalten einer bestimmten Zielumgebung bersteuert. Im Vorangegangenen war der Standardbuild fr die Entwicklung ausgelegt, und das Profil production wurde erstellt um eine Konfiguration fr die produktive Umgebung bereitzustellen. Was passiert, sollte man Anpassungen in Abhnigkeit von bestimmten Variablen wie zum Beispiel der Betriebssystemumgebung, oder der Version des JDK bentigen? Maven stellt eine Mglichkeit bereit Profile zu "aktivieren", in Abhngigkeit zu bestimmten Umgebungsvariablen einzustellen. Diese Funktionalitt nennt sich Profil-Aktivierung. Nehmen wir einmal folgendes Beispiel: angenommen wir benutzen eine Java Bibliothek welche auf eine Funktionalitt aufsetzt, welche erst in JDK Version 6 zur Verfgung steht: die Skripting Engine wie in JSR-223 definiert. Sie haben den Teil der Bibliothek welcher mit der Skripting Lsung zu tun hat in ein eigenes Maven Projekt abgetrennt; nun mchten Sie erreichen, dass diejenigen, welche auf Java 5 aufsetzen das Gesamtprojekt erstellen knnen ohne dabei die Java 6 abhngige Erweiterung zu erstellen. Sie knnen dies erreichen, indem Sie ein Maven Profil erstellen, welches die Skripting Erweiterung lediglich im Fall dass gegen JDK 6 gebuildet wird, hinzufgt. Lassen Sie uns zunchst die Verzeichnisstruktur ansehen und erklren, wie wir uns vorstellen, dass Entwickler das System erstellen sollen. Sobald jemand mvn install auf einer Java 6 JDK Umgebung aufruft, mchten Sie, dass das Projekt simple-script in den Build eingebunden wird. Unter Java 5 JDK 274

Build-Profile Umgebungen soll dieses Projekt bersprungen werden. Wrden Sie das Projekt dennoch aufrufen, so wird der Build abbrechen, da die Skripting Engine nicht auf dem Klassenpfad vorhanden ist. Lassen Sie uns nun die pom.xml-Datei der Bibliothek genauer ansehen: Example 11.3. Dynamisches Einfgen von Untermodulen mittels Profile Aktivierung
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook</groupId> <artifactId>simple</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>simple</name> <url>http://maven.apache.org</url> <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>

Beim Aufruf von mvn install unter Java 1.6 werden Sie sehen, wie Maven in das Unterverzeichnis simple-script wechselt und das Projekt simple-script erstellt. Sollten Sie mvn install unter Java 1.5 aufrufen, so wird der Build das Untermodul simple-script gar nicht erst aufsuchen. Eine tiefere Betrachtung dieser Aktivierungs-Konfiguration 275

Build-Profile Das Element activation benennt die Bedingungen der Profilaktivierung. In diesem Beispiel haben wir angegeben, dass das Profil sich bei einer Java Version welche mit "1.6" beginnt, aktiviert. Dies schliesst "1.6.0_03", 1.6.0_12", oder jede andere Version, welche mit "1.6" anfngt ein. Aktivierungsparameter beschrnken sich keinesfalls auf die Version von Java, eine Liste aller Aktivierungsparamenter finden Sie unter Konfiguration der Aktivierung. In diesem Profil fgen wir das Untermodul simple-script zu. Diese Anweisung wird Maven dazu veranlassen in das Verzeichnis simple-script zu wechseln und dort nach einer Datei pom.xml zu suchen.

11.3.1. Konfiguration der Aktivierung


Aktivierungen knnen einen oder mehrere der Auswahlparameter JDK Version, Betriebssystem Parameter, Dateien oder Properties beinhalten. Ein Profil wird aktiviert, sobald alle Kriterien erfllt sind. Ein Beispiel: ein Profil knnte die Aktivierungsparamenter: Betriebssystem der Windows Familie und JDK von Version 1.4 benenen. Ein derartiges Profil wrde nur aktiviert, wenn der Aufruf auf einer Windows Plattform unter Java 1.4 ausgefhrt wird. Sobald das Profil aktiviert ist, bersteuern alle enthaltenen Elemente deren entsprechenden Elemente auf Projektebene, als wre das Profil mittles dem Argument -p auf Befehlszeilenebene bergeben worden. Das nachfolgende Beispiel gibt ein Profil wieder, welches nur unter einer ganz bestimmten Kombination von Betriebssystem Parametern, Properties und einer JDK Version aktiviert wird. Example 11.4. Aktivierung eines Profiles mittels Parameter: JDK Version, OS Parameters, und Properties
<project> ... <profiles> <profile> <id>dev</id> <activation> <activeByDefault>false</activeByDefault># <jdk>1.5</jdk># <os> <name>Windows XP</name># <family>Windows</family>

276

Build-Profile
<arch>x86</arch> <version>5.1.2600</version> </os> <property> <name>mavenVersion</name># <value>2.0.5</value> </property> <file> <exists>file2.properties</exists># <missing>file1.properties</missing> </file> </activation> ... </profile> </profiles> </project>

Das vorangehende Beispiel definiert eine sehr eng definierte Menge von Aktivierungsparametern. Wir werden nun jede Bedingung im Detail beleuchten: Das Element activeByDefault definiert, ob das Profil standardmssig aktiviert ist. Dieses Profil wird nur aktiviert, sollte eine JDK Version welche mit "1.5" anfngt, vorliegen. Dies schliesst "1.5.0_01" oder "1.5.1" ein. Das Profil zielt auf eine ganz bestimmte Version von WindowsXP ab, Version 5.1.2600 der 32-Bit Plattform. Sollte Ihr Projekt das native-Plugin zur Erstellung eines C-Programms einsetzen, so werden Sie sich ofter in der Situation wiederfinden gegen eine spezifische Plattform zu builden. Das Element property, welches Maven anweist dieses Profil zu aktivieren, sollte das Property mavenVersion auf 2.0.5 gesetzt sein. mavenVersion ist ein implizites Property, welches allen Maven Builds zur Verfgung steht. Das Element file erlaubt es, ein Profil zu aktivieren, abhngig von der Existenz (oder Abwesendheit) einer Datei. Das Profil dev wird aktiviert, sollte eine Datei mit dem Namen file2.properties im Wurzelverzeichnis des Projektes vorhanden sein. Das Profil dev wird nur aktiviert, sollte keine Datei mit dem Namen file1.properties im Projekt Wurzelverzeichnis vorhanden sein.

277

Build-Profile

11.3.2. Aktivierung wenn ein Property nicht vorhanden ist


Sie knnen ein Profil abhngig von einem Wert eines Property wie zum Beispiel environment.type aktivieren. So knnen Sie ein Entwicklungsprofil aktivieren, sollte das Property environment.type gleich dev sein, oder ein Produktionsprofil falls das Property auf prod gesetzt ist. Sie knnen auch ein Profil auf die Abwesendheit eines Property hin aktivieren. Im folgenden ein Beispiel einer Konfiguration, welche ein Profil aktiviert, sollte das Property environment.type whrend der Ausfhrung von Maven nicht vorhanden sein: Example 11.5. Aktivierung eines Profiles wenn ein Property nicht vorhanden ist
<project> ... <profiles> <profile> <id>development</id> <activation> <property> <name>!environment.type</name> </property> </activation> </profile> </profiles> </project>

Beachten Sie das Ausrufezeichen das dem Property-Namen vorangeht. Das Ausrufezeichen wird oft auch als bang bezeichnet und signalisiert eine Negation: nicht. Dieses Profil wird aktiviert, sollte ein Property von ${environment.type} nicht bestehen.

11.4. Auflisten der aktuell aktiven Profile


Maven Profile knnen innerhalb von pom.xml, profiles.xml, ~/.m2/settings.xml oder ${M2_HOME}/conf/setings.xml gesetzt werden. ber 278

Build-Profile diese vier Ebenen hinweg gibt es wohl keinen vernnftigen Weg zusammenzuhalten, welche Profile zu einer gegebenen Zeit zur Verfgung stehen, ohne sich genau zu merken welche Profile innerhalb dieser vier Lokationen definiert wurden. Um es einfacher zu gestalten herauszufinden welche Profile zur Verfgung stehen und wo diese definiert wurden, definiert das Maven Help Plugin ein separates Goal active-profiles, welches alle gerade aktiven Profile ausgibt und angibt, wo diese definiert wurden. Sie knnen das Goal active-profiles im Wurzelverzeichnis eines Projektes wie folgt aufrufen:
$ mvn help:active-profiles Active Profiles for Project 'My Project': The following profiles are active: - my-settings-profile (source: settings.xml) - my-external-profile (source: profiles.xml) - my-internal-profile (source: pom.xml)

11.5. Tips und Tricks


Profile knnen zur Build-Portabilitt beitragen. Sollten Sie geringe Anpassungen des Builds bezglich unterschiedlicher Betriebssystem- Plattformen vornehmen wollen, oder unterschiedliche Resultate abhngig von der Zielplattform bentigen, so werden Build Profile die Portabilitt Ihres Builds erhhen. Profile, definiert durch Einstellungen, verringern im allgemeinen die Portabilitt, da diese zustzliche Projektinformationen darstellen, welche ebenfalls an den Entwickler weitergegeben werden mssen. Die Nachfolgenden Abschnitte geben Hinweise und Anleitung wie Sie Maven Profile in Ihren Projekten sinnvoll einsetzen knnen.

11.5.1. Gemeinsame Umgebungen


Eines der grundstzlichen Motive fr Maven Projekt Profile zu ermglichen, kam aus der Notwendigkeit heraus, umgebungsspezifische Konfigurationen zu ermglichen. In einer Entwicklungsumgebung werden Sie Bytecode mit eingeschlossenen Debug-Informationen wnschen, und Sie werden gegen eine Entwicklungsdatenbank konfiguriereren. In einer produktiven Umgebung hingegen 279

Build-Profile werden Sie eventuell auf ein signiertes Jar sowie dem Zugriff auf eine produktive Datenbank bestehen. In diesem Kapitel haben wir bislang eine Anzahl Profile mit Bezeichnern wie "dev" oder "prod" erstellt. Einfacher ist es sicherlich, derartige Profile von Umgebungsvariablen abhngig zu machen und diese gemeinsamen Umgebungsvariablen ber alle Projekte hinweg anzuwenden. Ein Beispiel: sollten alle Projekte ein Profil development besitzen, welches mittels einem Property environment.type mit dem Wert "dev" aktiviert wird, und sollten alle diese Projetke ein Profil production besitzen, welches mittels einem Property environment.type des Wertes "prod" aktiviert wird, so knnen Sie ein Standardprofil in Ihrer settings.xml-Datei definieren, das das Property environment.type auf Entwicklungsmaschinen immer auf 'dev' setzt. Auf diese Weise definiert jedes Projekt ein Entwicklungsprofil, welches immer mit dem gleichen Property aktiviert wird. Lassen Sie uns kurz ausfhren wie dies aussieht, im Folgenden die Datei settings.xmlgewhnlich zu finden unter ~/.m2/settings.xml, welche das Property environment.type auf 'dev' setzt. Example 11.6. ~/.m2/settings.xml setzt eine Standardprofileinstellung von environment.type
<settings> <profiles> <profile> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <environment.type>dev</environment.type> </properties> </profile> </profiles> </settings>

Das bedeutet, dass jedes Mal wenn Sie Maven auf Ihrer Maschine ausfhren, dieses Profil aktiviert wird und somit das Property environment.type auf den Wert dev gesetzt ist. Sie knnen nachfolgend dieses Property benutzen, um Profile, welche in einer Datei pom.xml definiert sind, zu aktivieren. Schauen wir uns doch einmal an, wie ein in der pom.xml-Datei definiertes Profil mittels dem Property 280

Build-Profile
environment.type

vom Wert dev aktiviert wird:

Example 11.7. Projekt Profil aktiviert mittels environment.type 'dev'


<project> ... <profiles> <profile> <id>development</id> <activation> <property> <name>environment.type</name> <value>dev</value> </property> </activation> <properties> <database.driverClassName>com.mysql.jdbc.Driver</database.driverClassName> <database.url> jdbc:mysql://localhost:3306/app_dev </database.url> <database.user>development_user</database.user> <database.password>development_password</database.password> </properties> </profile> <profile> <id>production</id> <activation> <property> <name>environment.type</name> <value>prod</value> </property> </activation> <properties> <database.driverClassName>com.mysql.jdbc.Driver</database.driverClassName> <database.url>jdbc:mysql://master01:3306,slave01:3306/app_prod</database.url> <database.user>prod_user</database.user> </properties> </profile> </profiles> </project>

Dieses Projekt definert einige Properties wie database.url und database.user welche vielleicht zum Einsatz kommen, um ein weiteres Maven Plugin das in der pom.xml-Datei angegeben ist, zu konfigurieren. Es gibt Plugins, welche eine Datenbank verndern, SQL ausfhren, und auch Plugins wie das Hibernate3 Plugin welches annotierte Modell Objekte, welche in einem Persistenzframework 281

Build-Profile zum Einsatz kommen, generiert. Einige dieser Plugins knnen in der Datei pom.xml mittels dieser Properties konfiguriert werden. Diese Properties knnten auch zum Filtern von Ressourcen benutzt werden. In diesem Beispiel, da wir ein Profil unter ~/.m2/settings.xml definiert haben, welches environment.type auf dev setzt, wird das Profil development immer aktiviert sein, wenn wir Maven auf dieser Maschine unter dem eingenen Benutzer ausfhren. Um diese Einstellung zu bersteuern mssen wir auf der Befehlszeilenebene das Property setzen. Sollten wir das Profil production aktivieren wollen, so knnten wir Maven mit dem fogenden Aufruf starten:
~/examples/profiles $ mvn install -Denvironment.type=prod

Das Property auf der Befehlszeile zu setzen wrde den Standard welcher in ~/.m2/settings.xml gesetzt wurde bersteuern. Wir htten genausogut ein Profil mit einem Bezeichner von 'dev' definieren knnen und dieses mittels dem Argument -p aufrufen knnen, aber der Einsatz des Property environment.type erlaubt uns andere pom.xml-Dateien ebenfalls gegen diesen Standard zu programmieren. Jedes Projekt Ihrer Codebasis knnte sich auf ein Profil absttzen, welches mittels dem selben Property environment.type aktiviert wird. Dieses wird in jeden Benutzers settings.xml-Datei gesetzt. Auf diesem Weg knnen Entwickler eine gemeinsame Konfiguration in der Entwicklung teilen, ohne diese Konfiguration in nicht portablen settings.xml-Dateien festzuschreiben.

11.5.2. Geheimnisse bewahren


Diese Best Practice baut auf den vorhergehenden Abschnitt auf. In Projekt Profil aktiviert mittels environment.type 'dev' enthlt das Profil production das Property database.password nicht. Wir haben das bewusst so gewhlt, um Ihnen zu demonstrieren wie man Geheimnisse in der benutzerspezifischen Datei settings.xml ablegen kann. Sollten Sie Ihre Anwendung in einer grossen sicherheitsbewussten Organisation entwickeln, so ist es warscheinlich, dass die Mehrheit der Entwickler das Password der produktiven Datenbank nicht kennt. In Organisationen welche klar trennen zwischen Entwicklungs- und Operativen Einheiten wird dies der Normalfall sein. Entwickler haben in solche Organisationen Zugriff auf Entwicklungs- und Staging-Umgebungen, aber nicht 282

Build-Profile (und wollen oft auch nicht) auf produktive Umgebungen. Es gibt viele Grnde warum dies sinnvoll ist, insbesondere sollte eine Organisation mit sensitiven Daten finanzieller, persnlicher oder geheimdienstlicher Natur umgehen. In solchen Szenarien ist es oftmals so, dass der produktive Build nur vom Lead-Entwickler oder gar einem Mitglied der operativen Gruppe erstellt werden darf. Beim Ausfhren des Builds unter dem environment.type prod muss diese Variable wie folgt in der settings.xml-Datei definiert werden: Example 11.8. Einfgen von "Geheimnissen" in einem benutzerspeziefischen Settings Profile
<settings> <profiles> <profile> <activeByDefault>true</activeByDefault> <properties> <environment.type>prod</environment.type> <database.password>m1ss10nimp0ss1bl3</database.password> </properties> </profile> </profiles> </settings>

Dieser Benutzer hat ein Standardprofil erstellt, welches die Variable environment.type auf prod setzt und auch ein produktives Password definiert. Sobald das Projekt ausgefhrt wird, wird das Profil production mittels environment.type prod aktiviert und das Property database.password wird gesetzt. Auf diese Art knnen Sie die gesamte produktionsspezifische Konfiguration in eines Projekts pom.xml-Datei angeben und lediglich ein einziges Geheimnis wahren, welches notwendig ist, auf die produktive Datenbank zuzugreifen. Note Geheimnisse treten fr gewhnlich mit der Portabilitt in den Konflikt, aber das macht ja auch Sinn. Sie wollen Geheimnisse ja eben auch nicht ffentlich auflegen!

283

Build-Profile

11.5.3. Plattform Klassifikatoren


Nehmen wir einmal an, Sie haben eine Bibliothek oder ein Projekt welches plattform-spezifische Anpassungen vornimmt. Auch wenn Java plattformneutral ist, so gibt es doch Situationen in welchen Sie gezwungen sind Code zu schreiben welcher plattformspezifischen "nativen" Code aufruft. Eine weitere Mglichkeit ist die, dass Sie Code in C geschrieben haben welcher mittels dem Maven Native Plugin kompiliert wird und Sie mchten einen plattformabhngigen qualifizierten Artifakten erstellen und ablegen. Sie knen dann den Klassifikator mit dem Maven Assembly Plugin oder dem Maven Jar Plugin setzen. Die folgende pom.xml-Datei erzeugt einen qualifizierten Artifakt abhngig von Profilen welche durch Betriebssystemparameter aktiviert werden. Bezglich weiterer informationen zum Maven Assembly Plugin verweisen wir auf das Kapitel Chapter 12, Maven Assemblies. Example 11.9. Bestimmen von Artifacten mittels Plattform Aktivierten Projekt Profilen
<project> ... <profiles> <profile> <id>windows</id> <activation> <os> <family>windows</family> </os> </activation> <build> <plugins> <plugin <artifactId>maven-jar-plugin</artifactId> <configuration> <classifier>win</classifier> </configuration> </plugin> </plugins> </build> </profile> <profile> <id>linux</id> <activation> <os> <family>unix</family>

284

Build-Profile
</os> </activation> <build> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> <classifier>linux</classifier> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>

Sollte das Betriebssystem der Windows-Familie angehren, so wird diese pom.xml-Datei ein JAR Artefakt erzeugen und mit "-win" qualifizieren. sollte das Betriebssystem der UNIX-Familie zugerechnet werden, so wird der Artefakt mit "-linux" qualifiziert. Dieses POM hngt zwar erfolgreich den qualifizierenden Zusatz an den Artefakt an, ist aber ausladender als unbedingt notwendig, insbesondere durch die redundante Konfiguration des Maven Jar Plugin in beiden Profilen. Das Beispiel knnte unter zuhilfenahme diverser Substitutionen in folgender Art umgeschrieben werden um die Redundanzen zu minimieren: Example 11.10. Bestimmen eines Artifacts mittels Plattform aktiviertem Projektprofile und Variablensubstitution
<project> ... <build> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> <classifier>${envClassifier}</classifier> </configuration> </plugin> </plugins> </build> ... <profiles> <profile> <id>windows</id> <activation>

285

Build-Profile
<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>

Diese pom.xml-Datei zwingt uns nicht ein Element build zur Konfiguration des Jar Plugin einzufgen. Statt dessen wird jedes Profil mittels der Betriebssystem-Familie aktiviert und setzt sodann das Property envClassifier auf entweder win oder linux. Dieses Property envclassifier wird dann in der normalen pom.xml im Element build referenziert, um dort den Klassifikator and das Projekt-Jar anzufgen. Der JAR Artefakt wird den Namen ${finalName}-${envClassifier}.jar tragen und als Abhngigkeit in folgender Art und Weise eingeschlossen (Beispiel: linux): Example 11.11. Abhngigkeit zu einem qualifizierten Artifact
<dependency> <groupId>com.mycompany</groupId> <artifactId>my-project</artifactId> <version>1.0</version> <classifier>linux</classifier> </dependency>

286

Build-Profile

11.6. Zusammenfassung
Bei sinnvollem Umgang mit Profilen knnen diese die spezifische Konfiguration eines Builds auf verschiedenen Plattformen einfach machen. Sobald Ihr Build von einer plattformabhngigen Gegebenheit abhngig ist, z.B. dem Pfad zu einem Applikationsserver, so knnen diese Informationen in einem Profil abgelegt werden, welches durch einen Betriebssystemparameter aktiviert wird. Sollten Sie ein Projekt bearbeiten welches bedingt, das fr verschiedene Umgebungen unterschiedliche Artefakte erstellt werden, so knnen Sie diese Anpassungen des Build-Verhaltens auf verschiedene Umgebungen oder Plattformen mittels profilabhngiger Plugin-Konfigurationen beeinflussen. Durch den Einsatz von Profilen knnen Builds portabler werden. Es gibt also keinen Grund Ihre Build-Logik umzuschreiben, um eine neue Umgebung zu untersttzen, bersteuern Sie lediglich die Teile der Konfiguration welche Sie anpassen mssen und verwenden den Rest der Konfiguration wieder.

287

Chapter 12. Maven Assemblies


12.1. Einfhrung
Maven bietet Plugins welche eingesetzt werden knnen um die hufigsten Typen von Archiven zu erzeugen. Die meisten derer knnen wiederum von anderen Projekten als Abhngigkeit eingebunden werden. Einige Beispiele hierfr sind JAR, WAR, EJB und EAR Plugins. Wie bereits im Kapitel Chapter 10, Der Build Lebenszyklus angesprochen, entsprechen sich die verschiedenen Paketierungstypen dieser Plugins den meist geringfgig unteschiedlichen Build Prozessen. Whrend Maven mittels Plugins und angepassten Lebenszyklen die standard Paketierungstypen untersttzt, gibt es dennoch Situationen in welchen Sie ein angepasstes Archive oder Verzeichnis mit einenem spezifischen Layout erstellen mssen. Solche angepasste Layoutstrukturen nennt man Assemblies. Es gibt eine Reihe guter Grnde warum Sie ein zugeschnittenes Archiv fr Ihr Projekt erstellen wrden. Der wichtigste Grund ist die Verteilung. Das Wort "Verteilung" wird fr unterschiedliche Personen (und Projekte) ganz unterschiedliche Bedeutungen haben, abhngig davon, wie ein Projekt zum Einsatz kommen soll. Im wesentlichen erlauben derartige Archive eine praktische Art die Projektergebnisse zu installieren oder anderweitig zugnglich zu machen. In manchen Fllen kann dies bedeuten eine Webanwendung mit einem Applikationsserver wie z.B. Jetty zu Bndeln. In andern mag es bedeuten die Dokumentation eines API zusammen mit den Quellen und den Binaries wie in eine JAR Datei zusammenzupacken. Assemblies sind gewhnlich ntzlich, wenn Sie die endgltige Version eines Produktes erstellen. Zum Beispiel sind Produkte wie Nexus, vorgestellt im Kapitel Chapter 16, Repository Management mit Nexus, das Produkt eines grossen multi-modularen Maven Projektes, und das Archiv, welches Sie letztendlich von Sonatype herunterladen wurde mittels eines Maven Assembly erstellt. In den meisten Fllen ist das Assembly Plugin am besten geeignet eines Projektes Verteilpaket zu erstellen. Jedoch mssen Assemblies nicht unbedingt veteilbare 288

Maven Assemblies Archive darstellen; Assemblies sind gedacht, dem Maven Benutzer eine flexible Mglichkeit zu schaffen, massgeschneiderte Archive jeglicher Art zu erstellen. Im wesentlichen sind Assemblies dazu da, die Lcken zwischen den standard Archivformaten wie sie die Paketierungstypen bieten zu schliessen. Natrlich knnten Sie auch ein komplettes Maven Plugin schreiben um Ihr spezifisches Archivformat zu erstellen; zusammen mit der dazugehrenden Lebenszyklusabbildung und der Konfiguration der Artefaktverarbeitung um Maven zu beschreiben was zu tun ist. Assemblies machen diesen Aufwand in den meisten Fllen unntig indem sie eine generalisierte Untersttzung der Erstellung Ihrer speziellen Archivtypen bieten ohne allzuviel Zeit darauf zu verwenden Maven Code zu erstellen.

12.2. Assembly Grundlagen


Vor wir uns nun in die Details strtzen bietet es sich an, erst noch ber die zwei Haupt Goals des Maven Assembly Plugin zu reden: assembly:assembly sowie single mojo. Ich fhre diese zwei Goals in unterschiedlicher Art und Weise auf, da dies besser aufzeigt, dass diese zwei Goals ganz unterschiedlich eingesetzt werden. Das Goal assembly:assembly ist darauf ausgelegt von der Befehlszeile gestartet zu werden, und sollte niemals an eine Lebeszyklusphase gebunden werden. Das Goal single mojo hingegen ist darauf ausgelegt, Teil des tgliche Build Ablaufes darzustellen, es sollte wie die meisten Goals an eine Phase Ihres Projekt Build Lebenszyklus gebunden werden. Der Hauptgrund dieses Unterschieds ist, dass das Goal assembly:assembly ein sogenanntes aggregierendes Mojo darstellt. Ein Mojo welches darauf ausgelegt ist, innerhalb eines Buildlaufes nur einmal ausgefhrt werden, unabhngig wieviele Projekte Teil des Buildlaufes sind. Ein aggregierendes Mojo bezieht seine Konfiguration vom Ursprungsprojekt, gewhnlich dem hierarchisch hchsten POM oder direkt als Parameter von der Befehlszeile. Sollte ein solches Mojo an eine Lebenszyklusphase gebunden werden, so kann dies unerwartete Nebeneffekte haben. Es kann zum Beispiel dazu fhren, dass das Goal eine andere Phase vorgngig zur Ausfhrung bringt was darin endet, dass die Paketierungsphase zweimal durchlaufen wird. 289

Maven Assemblies Da das Goal assembly:assembly ein aggregierendes Mojo darstellt, bringt dies etliche Probleme mit sich. Es sollte daher nur als einzelstehendes Mojo von der Befehlszeile aufgerufen werden. Binden Sie das Goal assembly:assembly niemals an eine Lebenszyklusphase. Das Goal assembly:assembly war das ursprngliche Goal des Maven Assembly Plugin, es war nie darauf ausgelegt Teil eines normalen Buildlaufes zu sein. Als es sich herausstellte, dass das Erstellen von Assembly Archiven eine regulre Anforderung an einen Buildlauf ist, wurde das Goal single Mojo entwickelt. Das Mojo geht davon aus, dass es an den richtigen Ort innerhalb eines Buildlaufes gebunden wurde, so dass es zum entsprechenden Zugriff auf die entsprechenden Dateien und Artefakte hat welche es zur erfolgreichen Ausfhrung (als Teil des Lebenszyklusses) eines grossen multi-modularen Maven Projektes braucht. In einer multi-modularen Umgebung wird das Goal single Mojo so oft ausgefhrt, wie dieses an unterschiedliche POM gebunden ist. Im Gegensatz zum Goal assembly:assembly wird single Mojo nicht die vorgngige Ausfhrung einer anderen Lebenszyklusphase erzwingen. Das Maven Assembly Plugin stellt ber diese zwei Goals hinaus etliche weitere Goals zur Verfgung. Die Vorstellung dieser anderen Mojos geht jedoch weit ber dieses Kapitel hinaus, da diese Goals exotische sowie inzwischen berholte Anwendungsflle addressieren und darber hinaus fast nie gebraucht werden. Soweit mglich sollten Sie in jedem Fall das Goal assembly:assembly benutzen um ein Assembly ab der Befehlszeile zu erstellen, sowie das Goal single Mojo um dies an eine Lebenszyklusphase gebunden zu tun.

12.2.1. Vordefinierte Assembly Descriptoren (Archiv-Beschreibungen)


Auch wenn sich aus Gewohnheit viele Benutzer dafr entscheiden, Ihre eigene Achiv-Beschreibungen zu erstellen, so ist dies in den meisten Fllen genau genommen nicht notwendig. Das Assembly Plugin bietet fr mehrere verbreitete Archiv-Typen bereits eingebaute Beschreibungen welche Sie benutzen knnen ohne auch nur eine Zeile Konfiguration zu schreiben. Die folgenden Assembly Deskriptoren (Archiv-Beschreibungen) sind bereits im Maven Assembly Plugin vordefiniert: 290

Maven Assemblies
bin

Der Deskriptor bin wird benutzt, um die zum Projekt gehrende LIZENZ, das README/LIESMICH sowie die HINWEIS-Datei mit den Projekt Artefakten zusammenzupacken, wobei davon ausgegangen wird, dass das Projekt ein JAR erstellt. Stellen Sie sich dies als die kleinstmgliche Binrkomposition fr in sich abgeschlossene Projekte vor.
jar-with-dependencies

Der Deskriptor jar-with-dependencies erstellt ein JAR welches neben den Inhalten des Hauptprojekts auch alle entpackten Inhalte der Archive der Laufzeitabhngigkeitenenthlt. Zusammen mit einem entsprechenden Main-Class Eintrag im Manifest (wird unter "Plugin Konfiguration" weiter unten besprochen) kann ein solcher Deskriptor ein in sich abgeschlossenes ausfhrbares JAR Ihres Projektes erstellen, auch wenn dieses Abhngigkeiten zur Laufzeit hat.
project

Der Deskriptor project sichert die Struktur Ihres Projektes wie dieses auf Ihrem Dateisystem und ebenfalls wahrscheinlich, in Ihrem Quellcode Repository besteht. Natrlich ist das Zielverzeichnis hierbei ausgenommen, genau wie auch eventuelle Metadaten der Versions Kontroll Software (z.B. CVS und .svn Verzeichnisse, an welche wir uns alle gewhnt haben). Der Sinn dieses Deskriptors ist lediglich ein Projekt Archiv zu erstellen, welches nach dem entpacken bereitsteht um Maven darauf auszufhren.
src

Der Deskriptor src erzeugt ein Archiv Ihrer Projekt Quellen sowie der pom.xml Dateien, zusammen mit allen notwendigen LIZENZ-, README-/LIESMICH- und HINWEIS-Dateien welche sich im Hauptverzeichnis befinden. Dieser Vorlufer des Deskriptors project erzeugt ein Archiv, welches in den meisten Fllen von Maven verarbeitet werden kann. Jedoch, aufgrund der Annahme das sich alle Quellen und anderweitige Resourcen im Standarverzeichnis /src befinden, besteht die Gefahr, dass alle nicht im Standard liegenden Verzeichnisse - und mit diesen Dateien welche fr den Build entscheidend sein mgen - verlohren 291

Maven Assemblies gehen.

12.2.2. Erstellen eines Assembly


Das Assembly Plugin kann auf zweierlei Weise aufgerufen werden: Sie knnen es direkt von der Befehlszeile aufrufen, oder Sie knnen es als Teil Ihres Buildprozesses anstossen, indem Sie es an eine Phase des Build-Lebenszyklus binden. Der direkte Aufruf hat seine Berechtigung, insbesondere fr Einzelzusammenstellungen welche nicht Teil Ihrer Hauptarbeit sind. In den meisten Fllen werden Sie Ihre Projektartefakten als Teil des normalen Buildprozesses paketieren. Diese Art des Vorgehens hat den Vorteil, dass Ihre angepassten Artefakte als Einheit in den Maven Repositorien abgelegt werden, unabhngig davon wo und wann das Projekt installiert oder verteilt werden soll. Es ist somit zu jeder Zeit fr die Benuzter verfgbar. Als Beispiel einer Anwendung eines direkten Aufrufs des Assembly Plugins, stellen Sie sich vor Sie mchten jemandem eine Kopie Ihres Projektes senden, in einer Form, dass diese Person das Projekt von den Quellen erstellen kann. Anstatt nur das Produkt Ihrer Arbeit zusammenzupacken, wollen Sie auch die Quellen einschliessen. Eine solcherlei Zusammenstellung wird sicher die Ausnahme sein, weshalb es auch nicht sinnvoll ist dieses als Bestandteil des POM zu definieren. Statt dessen knnen Sie den folgenden Aufruf absetzen:
$ mvn -DdescriptorId=project assembly:single ... [INFO] [assembly:single] [INFO] Building tar : /Users/~/mvn-examples-1.0/assemblies/direct-invocation/\ target/direct-invocation-1.0-SNAPSHOT-project.tar.gz [INFO] Building tar : /Users/~/mvn-examples-1.0/assemblies/direct-invocation/\ target/direct-invocation-1.0-SNAPSHOT-project.tar.bz2 [INFO] Building zip: /Users/~/mvn-examples-1.0/assemblies/direct-invocation/\ target/direct-invocation-1.0-SNAPSHOT-project.zip ...

Stellen Sie sich vor, Sie wollen ein ausfhrbares JAR aus Ihrem Projekt erstellen. Sollte Ihr Projekt vollstndig eigenstndig sein, ohne weitere Abhngigkeiten, so kann dies erreicht werden, indem man auf dem Hauptprojektartefakten die Konfiguration archive des JAR Plugin aufruft. Es ist jedoch so, dass die meisten Projekte Abhngigkeiten haben, und diese Abhngigkeiten mssen schliesslich in 292

Maven Assemblies ein ausfhrbares JAR eingeschlossen werden. In einem solchen Fall werden Sie sicherstellen wollen, dass bei jedem Erstellen des Hauptartefaktes - des Projekt JAR - auch dieses ausfhrbare JAR erstellt wird. Unter der Annahme, dass die Hauptklasse des Projektes org.sonatype.mavenbook.App ist, so wird die folgende Konfiguration des POM ein ausfhrbares JAR erstellen: Example 12.1. Assembly Descriptor eines ausfhrbaren JAR
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook.assemblies</groupId> <artifactId>executable-jar</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>Assemblies Executable Jar Example</name> <url>http://sonatype.com/book</url> <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> </descriptorRefs> <archive> <manifest>

293

Maven Assemblies
<mainClass>org.sonatype.mavenbook.App</mainClass> </manifest> </archive> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>

Ich mchte Ihre Aufmerksamkeit auf zwei Besonderheiten des oben wiedergegebenen POM lenken: Erstens, anstelle des zuvor benutzten Elements descriptorId setzen wir den Konfigurationsabschnitt des Elements descriptorRefs ein. Ein solches Vorgehen erlaubt es verschiedene Assemblies whrend eines einzigen Laufes des Assembly Plugin zu erstellen; und das mit geringstmglichem Zusatzaufwand in der Konfiguration. Zweitens setzt das Element archive innerhalb des Elements configuration das Haupt-Klassen Attribut des Manifests des erstellten JAR. Dieser Abschnitt ist gewhnlich verfgbar fr Plugins welche ein JAR erstellen, so wie hier fr das JAR Plugin welches zur Erstellung der standard Projekt Paketierungs Typen zum Einsatz kommt. Sie knnen jetzt das ausfhrbare JAR erstellen, indem Sie mvn package aufrufen. Anschliessend noch die Ausgabe des Verzeichnisses, welche aufzeigt, dass ein zustztliches JAR erzeugt wurde. Schliesslich versuchen wir das JAR auszufhren, als Beweis, dass dies tatschlich ein ausfhrbares JAR ist:
$ mvn package ... (output omitted) ... [INFO] [jar:jar] [INFO] Building jar: ~/mvn-examples-1.0/assemblies/executable-jar/target/\ executable-jar-1.0-SNAPSHOT.jar [INFO] [assembly:single {execution: create-executable-jar}] [INFO] Processing DependencySet (output=) [INFO] Building jar: ~/mvn-examples-1.0/assemblies/executable-jar/target/\ executable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar ... (output omitted) ... $ ls -1 target ... (output omitted) ... executable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar executable-jar-1.0-SNAPSHOT.jar ... (output omitted) ... $ java -jar \

294

Maven Assemblies
target/executable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar Hello, World!

Von der vorausgehenden Ausgabe knnen Sie ablesen, das der normale Buildlauf nun einen zustzlichen Artefakten - das ausfhrbare JAR - zu den bestehenden Artefakten, erstellt. Der neue Artefakt trgt einen klassifizierenden Bezeichner jar-with-dependencies. Da das JAR ausfhrbar sein soll, haben wir dieses versucht, und die erwartete Ausgabe "Hello, World!" bekommen.

12.2.3. Assemblies als Abhngigkeit


Sollten Sie im Laufe des normalen Buildprozesses Assemblies generieren, werden diese Artefakte Ihren normalen Projekt Artefakten zugefgt. Das bedeutet, diese werden in gleicher Weise in das Repository installiert und freigegeben und sind fortan wie diese aufzulsen. Jedes Assembly bekommt die gleichen Basiskoordinaten (groupId, artifactId, und version) wie das Projekt. Diese Artefakte sind jedoch Anhnge zum Hauptartefakt, was im Universum von Maven bedeutet, dass diese auf den selben Artefakten aufbauen aber eine andere Prgung haben. Ein paar Beispiele: Quellcode Assemblies enthalten die rohen Daten welche ein Build bentigt, jar-with-dependencies enthalten das Ergebnis eines Buildlaufes inklusive aller notwendigen Abhngigkeiten. Anhnge zu Artefakten drfen eine Haupeigenschaft von Maven Projekten aushebeln, dass es genau einen Artefakt zu einem Projekt gibt. Das ist genau aus dem Grund mglich, da sie Anhnge zu einem Projekt darstellen. Da Assemblies/Zusammenstellungen (normalerweise) Anhnge zu einem Projekt sind, muss jeder Artefakt zustzlich zu den Koordinaten (Bezeichnern) eine Kennzeichnung tragen, um diese vom Haupartefakten zu unterscheiden. Standardmssig ist diese Kennzeichnung die selbe wie die des Bezeichners des Deskriptors. Beim Einsatz der eingebauten Assembly Deskriptoren, wie im Beispiel oben, wird die Kennzeichnung gewhnlich mit dem Bezeichner welcher im Feld descriptorRef benutzt wurde, gleichgesetzt. Nachdem Sie also ein Asembly neben einem Artefakten verteilt haben, wie knnen Sie dieses nun als Abhngigkeit in ein anderes Projekt einbinden? Die Antwort ist einfach: Erinnern Sie sich an die Abschnitte Section 3.5.3, Maven Koordinaten 295

Maven Assemblies sowie Section 9.5.1, Vertiefung von Koordinaten bezglich der Abhngigkeiten von Projekten in Maven; Projekte definieren Abhngigkeiten zu anderen Projekten durch eine Kombination von vier Koordinaten: groupId, artifactId, version, und packaging. Im Abschnitt Section 11.5.3, Plattform Klassifikatoren, wird gezeigt wie mehrere Ausprgungen eines Artefakts bestehen knnen und wie man die zustzliche Koordinate classifier benutzt, um um mittels einem Wert von entweder win oder linux die richtige plattformspezifische Form auswhlt. Zusamenstellungen knnen also wie normale Abhngigkeiten benutzt werden, wobei die normalen Koordinaten zum Einsatz kommen, zuzglich dem notwendingen Element classifier, unter welchem der Artefakt installiert oder verteilt wurde. Sollte die Zusammenstellung nicht als JAR vorliegen, so muss zustzlich der Typ angegeben werden.

12.2.4. Zusammenstellen von Assemblies mittels Assembly Abhngigkeiten


Ist das nicht ein verwirrender Titel? Lassen Sie uns ein Szenario entwerfen welches den Gedanken von zusammengestellten Assemblies verdeutlicht. Vielleicht mchten Sie ein Archiv erstellen, welches eine Anzahl Assemblies enthlt. Gehen Sie einmal davon aus, dass Sie ber ein multi-modulares Projekt verfgen, und nun ein Assembly verteilen mchten, welche aus einer Anzahl voneinander in Beziehung stehender Projekt Assemblies besteht. In diesem Abschnitt erstellen wir eine Bndelung von "build-baren" Projekt Verzeichnissen fr eine Anzahl Projekte welche gewhnlicherweise zusammen benutzt werden. Der Einfachheit halber werden wir die zwei oben ausgefhrten - eingebaut vorhandenen - Deskriptoren project und jar-with-dependecies zum Einsatz bringen. In diesem speziellen Beispiel gehen wir davon aus, dass jedes Projekt zum normalen JAR Artefakt ebenfalls einen Artefakt eines Assembly project erstellt. Nehmen Sie darber hinaus an, dass jedes Projekt des multi-modularen Buildlaufes das Goal single an die Phase packaging bindet und die descriptorRef project benutzt. Jedes Projekt eines multi-modularen Builds erbt diese Konfiguration von einem bergeordneten POM dessen Element pluginManagement in Example 12.2, Konfiguration des Projekt Asseembly im top-level POM ausgefhrt ist. 296

Maven Assemblies Example 12.2. Konfiguration des Projekt Asseembly im top-level POM
<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>

Jedes untergeordnete Projekt POM referenziert die Plugin Konfiguration aus Example 12.2, Konfiguration des Projekt Asseembly im top-level POM in dem es eine minimale Plugin Deklaration im Build-Abschnitt des POM aufnimmt. Dies ist in Example 12.3, Aktivierung der Assembly Plugin Konfiguration im Untermodul ausgefhrt. Example 12.3. Aktivierung der Assembly Plugin Konfiguration im Untermodul
<build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> </plugin>

297

Maven Assemblies
</plugins> </build>

Um die entsprechenden Projekt Assemblies zu erstellen, rufen Sie mvn install aus dem bergeordneten Verzeichnis auf. Sie sollten beobachten knnen, wie Maven die entsprechenden Artefakte mit entsprechenden Bezeichnern in Ihr lokales Repository installiert.
$ mvn install ... Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\ second-project/target/second-project-1.0-SNAPSHOT-project.tar.gz to ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\ second-project-1.0-SNAPSHOT-project.tar.gz ... Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\ second-project/target/second-project-1.0-SNAPSHOT-project.tar.bz2 to ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\ second-project-1.0-SNAPSHOT-project.tar.bz2 ... Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\ second-project/target/second-project-1.0-SNAPSHOT-project.zip to ~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0-SNAPSHOT/\\ second-project-1.0-SNAPSHOT-project.zip ...

Beim Aufruf von mvn install wird Maven jeweils den Projektartefakten sowie das entsprechende Assembly in Ihr lokales Repository installieren. Alle diese Artefakte sind fortan fr weitere Projekte mittels normaler Koordinaten referenzierbar. Sollte Ihr Ziel nun sein, ein Assembly bestehend aus den Assemblies mehrerer Projekte zu erstellen, so erreichen Sie dies, indem Sie ein weiteres Projekt erstellen, welches die entsprechenden Projekt Assemblies als Abhngigkeiten definiert. Dieses Bndel von Projekten (mit dem treffenden Namen bundle-project; engl. Bndelprojekt) trgt Verantwortung fr die Erstellung der Zusammenstellung. Das entsprechende POM des Projektes ist im XML-Dokument von Example 12.4, POM eines Assembly Bndel-Projektes wiedergegeben. Example 12.4. POM eines Assembly Bndel-Projektes
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0

298

Maven Assemblies
http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook.assemblies</groupId> <artifactId>project-bundle</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <name>Assemblies-as-Dependencies Example Project Bundle</name> <url>http://sonatype.com/book</url> <dependencies> <dependency> <groupId>org.sonatype.mavenbook.assemblies</groupId> <artifactId>first-project</artifactId> <version>1.0-SNAPSHOT</version> <classifier>project</classifier> <type>zip</type> </dependency> <dependency> <groupId>org.sonatype.mavenbook.assemblies</groupId> <artifactId>second-project</artifactId> <version>1.0-SNAPSHOT</version> <classifier>project</classifier> <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>

Dieses "Bndel"-Projekt POM referenziert die zwei Assemblies von den Projekten 299

Maven Assemblies und second-project. Statt der Hauptartefakte jedes Projektes referenziert das POM die Koordinaten mit Bezeichner und einem Typ zip. Dies fordert Maven dazu auf, das ZIP Archiv aufzulsen, welches von der entsprechenden Zusammenstellung erstellt wurde. Beachten Sie, dass das Bndelprojekt eine Zusammenstellung der Art jar-with-dependencies erstellt.
first-project

erzeugt kein besonders elegantes Archiv, es erzeugt lediglich ein einziges JAR mit dem entpackten Inhalt aller Abhngigkeiten. Dieser Typ weist Maven also an, alle Abhngigkeiten zusammenzutragen, alle JARs zu entpacken um diese anschliessend alle in ein einziges JAR, zusammen mit den Projektartefakten zusammenzupacken. In diesem Beispiel erzeugt dies ein einziges JAR mit den Inhalten von den Projekten first-project und second-project Seite an Seite.
jar-with-dependencies

Diese Beispiel zeigt auf, wie man die grundlegenden Mglichkeiten des Maven Assembly Plugin verbinden kann, um Artefakte zu erzeugen ohne einen speziell angepassten Assembly Deskriptor zu bentigen. Wir erreichen unser Ziel durch die Erstellung eines einzigen Archives welches die verschiedenen Projektverzeichnisse Seite an Seite enthlt. In diesem Fall wird jar-with-dependencies nur als Speicherformat benutzt, weshalb wir auch kein Attribut Main-Class bestimmen. Um das Bndel zu erstellen starten wir eine gewhnlichen Build Lauf des Projektes:
$ mvn package ... [INFO] [assembly:single {execution: bundle-project-sources}] [INFO] Processing DependencySet (output=) [INFO] Building jar: ~/downloads/mvn-examples-1.0/assemblies/as-dependencies/\ project-bundle/target/project-bundle-1.0-SNAPSHOT-jar-with-dependencies.jar

Um zu berprfen, dass die Bndelprojekt-Assembly tatschlich die entpackten Inhalte der abhngigen Zusammenstellungen enthlt knnen Sie jar tf aufrufen:
$ jar tf \ target/project-bundle-1.0-SNAPSHOT-jar-with-dependencies.jar ... first-project-1.0-SNAPSHOT/pom.xml first-project-1.0-SNAPSHOT/src/main/java/org/sonatype/mavenbook/App.java first-project-1.0-SNAPSHOT/src/test/java/org/sonatype/mavenbook/AppTest.java ... second-project-1.0-SNAPSHOT/pom.xml second-project-1.0-SNAPSHOT/src/main/java/org/sonatype/mavenbook/App.java

300

Maven Assemblies
second-project-1.0-SNAPSHOT/src/test/java/org/sonatype/mavenbook/AppTest.java

Jetzt da Sie diesen Abschnitt gelesen haben, sollte sich auch der Sinn des Titels besser erschliessen. Sie haben ein Assembly zweier projektspezifischer Zusammenstellung erstellt, indem Sie ein Projekt eingefgt haben welches beide Artefakte als Abhngigkeit definiert.

12.3. bersicht eines Assembly Descriptors


Sobald die standard Assembly Deskriptoren wie diese inSection 12.2, Assembly Grundlagen eingefhrt wurden nicht ausreichen, werden Sie Ihren eingenen Deskriptor erstellen. Ein Assembly Deskriptor ist ein XML Dokument, welches die Struktur und den Inhalt einer Zusammenstellung festlegt.

301

Maven Assemblies Figure 12.1. Schematische Abbildung eines Assembly Descriptor Die Konfiguration eines Assembly Deskriptors ist in fnf Abschnitten gegliedert, mit zwei Optionalen: eines um standard Assembly-Fragmente zu definieren, sogenannte Komponenten Deskriptoren sowie einem weiteren Abschnitt um spezifische Dateiverarbeitungsklassen zu benennen, welche bentigt werden um eine Zusammenstellung zu erstellen. Im folgenden eine Beschreibung der fnf Hauptabschnitte: Base Configuration / Basiskonfiguration Dieser Abschnitt enthlt Informationen welche von allen Assemblies bentigt werden, sowie einige zustzliche Konfigurationselemente welche optional gebraucht werden knnen und sich auf das Format des Gesamtarchivs beziehen. Um einen vollstndigen Assembly Deskriptor zu erstellen ist es notwendig zumindest die Assembly ID, eine Formatangabe sowie einen der nachfolgenden Abschitte anzugeben. File Information / Datei Informationen Die Konfigurationen in diesem Abschnitt beziehen sich auf spezifische Dateien des Dateisystems welche in den Projektverzeichnissen liegen. Dieser Abschnitt hat zwei wichtige Unterabschnitte files (Dateien) und fileSets (Dateigruppierungen). Sie benutzen diese beiden Abschnitte um Datein und Gruppierungen von Dateien Zugriffsberechtigungen zuzuweisen und um diese in einem Assembly ein- oder auszuschliessen. Dependency Information / Informationen zu den Abhngigkeiten Beinahe alle Projekte jeglicher Grsse sind von anderen Projekten abhngig. Bei der Erstellung von Archieven fr die Verteilung werden gewhnlich alle Abhngigkeiten in die Zusammenstellung eingeschlossen. Dieser Abschnitt definiert, in welcher Weise Abhngigkeiten in einem resultierenden Archiv eingeschlossen werden. Dieser Abschnitt erlaubt es zu definieren, ob Abhngigkeiten entpackt werden, diese direkt in das lib-Verzeichnis eingeschlossen werden oder gar auf einen anderen Namen abgebildet werden sollen. Darberhinaus erlaubt Ihnen dieser Abschnitt die Zugriffsrechte auf die 302

Maven Assemblies Abhngigkeiten zu setzen, sowie festzlegen, welche Abhngigkeiten berhaupt eingeschlossen werden. Repository Information / Repository Informationen Manchmal ist es ntzlich, kann man die Gesamtheit aller nowendigen Artefakte eingrenzen, welche bentigt werden ein Projekt zu erstellen. Solche Artefakte knnen Abhngigkeiten, POM-Dateien von abhngigen Artefakten, oder auch bergeordnete POM-Dateien sein. In diesem Abschnitt ist es mglich ein oder mehr Repository Systeme in Ihre Zusammenstellung aufzunehmen, inklusive mehrer mglichen Konfigurationen. Zu diesem Zeitpunkt ist es nicht mglich, Plugin-Artefakte in diesen Repositorien aufzunehmen. Module Information / Informationen zu den Modulen Dieser Abschnitt erlaubt Ihnen vererbliche Strukturen bei der Definition von Assemblies auszunutzen, um entsprechende Quell-Dateien, Artefakte und Abhngigkeiten des bergeordneten Moduls einzuschliessen. Dieser Abschnitt ist der komplexeste des gesamten Assembly Deskriptors, denn dieser Abschnitt ermglicht Ihnenn auf zweierlei Weise mit Modulen und Untermodulen zu arbeiten: zum einen als Anzahl von fileSets (mittels den Abschnitten bezglich Quellen) oder in Bezug auf dependencySets (mittels den Abschnitten bezglich der Binaries).

12.4. Der Assembly Descriptor


Dieser Abschnitt ist eine kurze bersicht ber den Assembly Deskriptor, wir werden versuchen Ihnen ein paar Tips und Leitgaben zur Erstellung von benutzerdefinierten Assembly Deskriptoren zu geben. Das Assembly Plugin ist das grsste Plugin der Maven Familie und auch eines der flexibelsten.

12.4.1. Property Referenzen in Assembly Descriptoren


Jedes im Kapitel Section 13.2, Maven Properties vorgestellte Property kann innerhalb eines Assembly Deskriptors referenziert werden. Vor der Verarbeitung jeglicher Assembly Deskriptoren von Maven, wird dieser mit den Informationen 303

Maven Assemblies des POM und der aktuellen Build-Umgebung abgeglichen. Alle innerhalb von POM-Dateien zulssigen Properties sind auch in Assembly Deskriptoren gltig, einschliesslich POM Properties, Werte von POM Elementen, System Properties, benutzerdefinierte Properties wie auch Betriebssystemvariablen. Es gibt eine einzige Ausnahme bezglich diesem Auswertungsschritt: die Elemente der verschiedenen Unterabschnitte unterhalb von outputDirector, outputDirectoryMapping und outputFileNameMapping. Diese Elemente werden von der Verarbeitung ausgeschlossen, um zu ermglichen, dass Artefakt- oder Modul-spezifische nderungen bei der Auflsung der Elemente eingebracht werden knnen.

12.4.2. Notwendige Basisinformationen fr Assemblies


Es gibt zwei grundlegende Eintrge, welche fr jegliches Assemby bentigt werden: die Kennung (ID) und eine Liste der Archivformate welche erstellt werden sollen. Tatschlich braucht es mindestens noch einen weiteren Eintrag im Deskriptor - die meisten Archiv-Prozessoren bentigen die Angabe mindestens einer Datei - aber ohne Kennung (ID) und Formatangabe gibt es in keinem Fall ein zu erzeugendes Archiv. Die Kennung findet nicht nur im Namen des Archivs Verwendung, sondern auch als Teil des Artefakt Bezeichners innerhalb des Maven Repositories. Der Format-Eintrag bestimmt die Instanz des archivierenden Prozessors welche das schliessendliche Archiv der Zusammenstellung erzeugt. Alle Assembly Deskriptoren mssen daher mindestens eine Kennung (ID) sowie einen Formateintrag enthalten: Example 12.5. Notwendige Elemente eines Assembly Descriptors
<assembly> <id>bundle</id> <formats> <format>zip</format> </formats> ... </assembly>

Der Eintrag der Kennung (id) kann eine beliebige Zeichenkette sein, diese darf 304

Maven Assemblies allerdings keine Leerschlge enthalten. Normalerweise werden als Worttrennzeichen Bindestriche eingesetzt. Sollten Sie zum Beispiel eine Zusammenstellung einer besonderen, einmaligen Paketstruktur erstellen, so knnten Sie auf eine Kennung 'besondere-einmalige-Paketstruktur' zurckgreifen. Verschiedene Archivformate einer Zusammenstellung werden gleichzeitig in einem einzigen Assembly Deskriptor untersttzt, dies erlaubt es Ihnen die bekannten Formate .zip, .tar.gz sowie .tar.bz2 der Archive zur Verteilung einfach zu ertellen. Sollten Sie das von ihnen erwnschte Archivformat nicht finden, so knnen Sie ein eigenes Format definieren. Benutzerdefinierte Formate werden weitergehend im Abschnitt Section 12.5.8, componentDescriptors und containerDescriptorHandlers behandelt. Das Assembly Plugin bietet direkte Unterttzung fr die folgenden Formate:
jar zip tar bzip2 gzip tar.gz tar.bz2 rar war ear sar dir

305

Maven Assemblies Die Elemente id und format sind auch deshalb so wichtig, da diese einen Bestandteil der Koordinaten der Zusammenstellung abgeben. So ergibt sich aus dem Beispiel Example 12.5, Notwendige Elemente eines Assembly Descriptors eine Zusammenstellung vom Typ zip mit der Artefakt Bezeichnung bundle.

12.5. Bestimmen des Inhaltes eines Assemblies


Theoretisch reichen die Elemente id und format fr einen zulssigen Assembly Deskriptor; es ist jedoch so, dass viele Archiv Prozessoren scheitern, ist nicht mindesten eine Datei vorhanden welche dem resultierenden Archiv zugefgt wird. Die Aufgabe zu definieren welche Dateien tatschlich einem Archiv zugefgt werden sollen, fllt den fnf Hauptabschnitten des Assembly Deskriptors zu: files, fileSets, dependencySets, repositories und moduleSets. Um diese Abschnitte rasch einzufhren, fangen wir mit dem elementarsten Element an: files. Fortfahren werden wir mit den zwei am hufigsten benutzten Abschnitten: fileSets und dependencySets. Danach ist es ein Leichtes auch noch repositories und moduleSets einzufhren.

12.5.1. Element

files

Das Element files ist das einfachste Element eines Assembly Deskriptors, es ist daarauf ausgelegt Dateien zu bezeichnen, welche eine relativ zum Projektverzeichnis bestimmte Lage besitzen. Der Einsatz dieses Elements gibt Ihnen die volle Kontrolle ber genau die Dateien welche Sie in Ihre Zusammenstellung einbinden mchten, es lsst Sie genau bestimmen wie diese benannt werden sollen und wo im Archiv diese abgelegt werden. Example 12.6. Einschlissen einer JAR Datei in ein Assembly mittels dem Element files
<assembly> ... <files>

306

Maven Assemblies
<file> <source>target/my-app-1.0.jar</source> <outputDirectory>lib</outputDirectory> <destName>my-app.jar</destName> <fileMode>0644</fileMode> </file> </files> ... </assembly>

Unter der Annahme, dass Sie ein Projekt namens my-app in Version 1.0 erstellen, so wrde in Example 12.6, Einschlissen einer JAR Datei in ein Assembly mittels dem Element files Ihr Projekt JAR im Verzeichnis lib abgelegt, die Version aus dem Dateinamen herausgterennt, so dass die resultierende Datei nur noch my-app.jar heisst. Das JAR wrde global lesbar, aber nur fr Eigner schreibberechtigt werden (das ist die Bedeutung des Elements fileMode 0644 auf Dateien angewandt; in Unix vierstelliger Benutzerrechtsnotation). Weitere Informationen bezglich des Formats der Werte des Elements fileMode finden Sie im Wikipedia-Eintrag bezglich der vierstelligen Benutzerrechtsnotation (four-digit Octal notation). Sie knnen, unter der Voraussetzung dass Ihnen die genauen Dateien bekannt sind, eine sehr komplexe Zusammenstellung mittels Elementen file vornehmen. Sie knnten diese sogar soweit ausbauen, dass Sie mit einem benutzerdefinierten Plugin die Liste der Dateien erstellen, woraus Sie dann den Assembly Deskriptor generieren indem Sie Elemente, wie oben ausgefhrt, einfgen. Obwohl die einzelne Auflistung jeder Datei, deren Namen, Lokation und Berechtigungen innerhalb einer Zusammenstellung Ihnen genaueste Kontrolle gibt, so ist dies ein sehr mhsames Vorgehen. Im Allgemeinen werden Sie auf Gruppierungen von Dateien und Abhngigkeiten arbeiten, Sie tun dies durch die Verwendung von Elementen fileSets. Die weiteren vier Abschnitte zur Auswahl von Dateien sind darauf ausgelegt ganze Dateigruppen welche bestimmten Kriterien entsprechen, zu bearbeiten.

12.5.2. Element

fileSets

hnlich des Abschnitts ber die Datei Auswahl (Element files) befasst sich auch 307

Maven Assemblies das Element fileSet mit Dateien die einen bestimmten relativen Ort zum Projektverzeichnis besitzen. Jedoch, im Gegensatz zu Element files beschreibt das Element fileSets Gruppierungen von Dateien, definiert durch Datei-und Pfadmuster welchen diese entsprechen (oder eben nicht entsprechen!) und der allgemeinen Verzeichnisstruktur in welcher diese sich befinden. Das einfachste fileSet definiert lediglich das Verzeichnis in welchem sich die Dateien befinden.
<assembly> ... <fileSets> <fileSet> <directory>src/main/java</directory> </fileSet> </fileSets> ... </assembly>

Das oben abgebildete Element fileSet schliesst lediglich den Inhalt des Verzeichnisses src/main/java unseres Projektes ein. Es nutzt hierbei viele der bestehenden Standardeinstellungen, welche wir im folgenden genauer ansehen wollen. Zuallererst fllt auf, dass wir im Element fileSet gar nicht angeben, wo innerhalb der Zusammenstellung die entsprechenden Dateien abgelegt werden sollen. Standardmssig ist das Zielverzeichnis (angegeben im Element outputDirectory) dasselbe wie das Quellverzeichnis (in unserem Fall das Verzeichnis src/main/java). Zustzlich haben wir keinerlei Ein- oder Ausschlusskriterien in Form von Dateimustern definiert. Werden diese nicht angegeben, so wird davon ausgegangen, dass Sie alle Dateien des Quellverzeichnisses einschliessen, mit einigen wenigen, wichtigen Ausnahmen. Diese Ausnahmen betreffen zumeist Meta-Daten von Source Control Systemen und deren Verzeichnisse, diese werden durch die Einstellung useDefaultExcludes gesetzt, welche standarmssig auf true gesetzt ist. Solange dies aktiviert ist wird die Einstellung useDefaultExclude Verzeichnisse wie .svn und CVS aus einer Zielzusammenstellung heraushalten. Der Abschnitt Section 12.5.3, Standard Auschlussmuster in fileSets gibt eine detailierte Liste der standard Auschlussmuster. Sollten wie innerhalb eines Elements fileSet mehr Kontrolle ausben wollen, so knnen wir dies. Example 12.7, Einschliessen von Dateien mittles dem Element 308

Maven Assemblies
fileSet

gibt ein Element fileSet wieder, bei welchem alle Standardelemente gesetzt sind: Example 12.7. Einschliessen von Dateien mittles dem Element 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>

Das Unterelement includes besteht aus einer Liste von Elementen include welche Pfadmuster definieren. Diese Muster knnen auch Jokerzeichen im "ant"-Stil beinhalten, wobei '**' bedeutet: passt zu einem oder mehr Verzeichnissen, '*' passt auf Teil eines Dateinamens und '?' welches ein einziges Zeichen ersetzt.Example 12.7, Einschliessen von Dateien mittles dem Element fileSet benutzt hierbei ein Element fileMode welches definiert, dass die resultierenden Eintrge von allen gelesen werden knnen, aber nur Eigner Schreibrechte besitzen. Da das Element fileSet auch Verzeichnisse einschliesst, besteht wiederum die Mglichkeit das Element directoryMode zu setzen, welches dem Element fileMode sehr hnliche Funtionalitten aufweist. Da die Berechtigung ein Verzeichnis "auszufhren" auf das Auflisten des Inhaltes abgebildet wird, stellen wir sicher, dass Verzeichnisse nebst "lesbar" auch "ausfhrbar" (also aufzulisten) sind. Wie auch schon bei Dateien werden nur Eigentmer Schreibrechte besitzen. Das Element fileSet bietet aber auch noch weitere Mglichkeiten. Zunchst einmal erlaubt es den Einschluss eines Elements excludes in gleicher Weise wie bereits das Element includes definiert wurde. Diese Auschlusskriterien erlauben 309

Maven Assemblies es Ihnen bestimmte Dateien aus dem resultierenden fileSet auszuschliessen. Einschlusskriterien bersteuern hierei Auschlusskriterien. Zustzlich knnen Sie die Einstellung filtering auf true setzen, sollten Sie bestimmte Ausdrcke bei den eingeschlossenen Dateien durch Property-Werte ersetzen wollen. Ausdrcke knnen entweder durch ${ und } (normale Maven Ausdrcke wie z.B. ${project.groupId}) oder durch @variable@ (normale Ant Ausdrcke wie z.B. @project.groupId@) eingeleitet werden. Sie knnen das Zeilenabschlusszeichen Ihrer Dateien durch das Element lineEnding bestimmen. Erlaubte Zeilenabschlusselemente sind: keep Erhalten des Zeilenumbruch-Zeichen der Quelldatei (dies ist der Standardwert) unix Unix-artiger Zeilenumbruch lf Ausschliesslich Zeilenvorschub dos MS-DOS-artiger Zeilenumbruch crlf Zeilenumbruch gefolgt von einem Zeilenvorschub Schliesslich, sollten Sie wirklich alle Dateiauswahlkriterien einsetzen wollen, so knnen Sie auch noch das Element useStrictFiltering auf einen Wert von true setzen (Standard ist false). Dies ist immer dann ntzlich, wenn unbenutzte Muster andeuten, dass in Zwischenablage-Verzeichnissen gewisse Dateien fehlen. Sollte das Element useStrictFiltering auf true gesetzt sein, so bricht das Assembly Plugin ab, sollte eines der Muster nicht erfllt werden, d.h. keine passende Datei gefunden werden. In anderen Worten, sollten Sie ein Einschlusskriterium gesetzt haben und die entsprechende Datei aus einem Build Lauf ist nicht vorhanden, so wird Maven einen Fehler annehmen und abbrechen.

310

Maven Assemblies

12.5.3. Standard Auschlussmuster in fileSets


Beim Einsatz der Standard-Ausschlussmuster, wird das Maven Assembly Plugin mehr als nur die SVN- und CVS- Datein und Verzeichnisse ignorieren. Standardmssig sind die Auschlussmuster durch die Klasse DirectoryScanner des Projektes plexus-utils welches von Codehaus gehostet wird festgelegt. Die Menge der Auschlussmuster ist als static final StringArray mit dem Namen DEFAULTEXCLUDES in DirectoryScanner definiert. Der Inhalt des Array wird in Example 12.8, Definition von Standard Ausschlussmustern von Plexus Utils wiedergegeben: Example 12.8. Definition von Standard Ausschlussmustern von Plexus Utils
public static final String[] DEFAULTEXCLUDES = { // Miscellaneous typical temporary files "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*", // CVS "**/CVS", "**/CVS/**", "**/.cvsignore", // SCCS "**/SCCS", "**/SCCS/**", // Visual SourceSafe "**/vssver.scc", // Subversion "**/.svn", "**/.svn/**", // Arch "**/.arch-ids", "**/.arch-ids/**", //Bazaar "**/.bzr", "**/.bzr/**", //SurroundSCM "**/.MySCMServerInfo",

311

Maven Assemblies
// Mac "**/.DS_Store" };

Die Standardmenge der Ausschlussmuster schliesst Temporrdateien des GNU Emacs sowie weitere gebruchlichen temporren Dateien des Mac und gebruchlicher Quellverwaltungssysteme (auch wenn Visual Source Save eher ein Fluch als ein Verwaltungssystem ist) ein. Sollten Ihnen diese Standardmuster nicht ausreichen, knnen Sie diese auch bersteuern, Sie setzen useDefaultExcludes auf false und definieren einen Satz Auschlussmuster innerhalb Ihres eigenen Assembly Deskriptor.

12.5.4. Element

dependencySets

Eine der gelufigsten Anforderungen an Assemblies ist die Einbindung von Projektabhngigkeiten in ein Zielarchiv. Whrend die Elemente file und fileSets sich mit Dateien Ihres Projektes befassen, sind Abhngigkeiten nicht an einen Ort innerhalb Ihres Projektes gebunden. Artefakte von welchen ein Projekt abhngig ist, mssen whrend des Buildlaufes aufgelst werden. Artefakte aus Abhngigkeiten sind abstrakt, sie haben keinen bestimmten Ort und werden mittels einem Satz symbolischer Koordinaten referenziert. Die Elemente file und fileSets bentigen in der Spezifikation einen konkreten Quellpfad, Abhngigkeiten hingegen werden durch eine Kombination von Maven Koordinaten und Abhngigkeits-Gltigkeitsbereichen in ein Assembly eingebunden oder ausgeschlossen. Das einfachste Element dependencySet ist ein leeres Element:
<assembly> ... <dependencySets> <dependencySet/> </dependencySets> ... </assembly>

Das oben ausgefhrte dependencySet wird allen Laufzeitabhngigkeiten Ihres 312

Maven Assemblies Projektes Rechnung tragen (der Gltigkeitsbereich Laufzeit schliesst den von Compile implizit ein.) und wird die entsprechenden Abhngigkeiten Ihrem Wurzelverzeichnis des Zielarchivs zufgen. Darberhinaus wird es den Projekt-Hauptartefakt, so dieser vorhanden ist, in das Wurzelverzeichnis kopieren. Note Einen Moment! Wie Sie bemerkt haben befasst sich das Element dependencySet mit den Projektabhngigkeiten, nicht mit dem entsprechenden Zielarchiv? Dieser eher widersinnige Nebeneffekt war ein hufig ausgenutzter Fehler der Version 2.1 des Assembly Plugin, und da Maven Rckwrtskompatibilitt gross schreibt, musste dieses fehlerhafte und widersinnige Verhalten zwischen Version 2.1 und 2.2 erhalten bleiben. Sie knnen dieses Verhalten ber die Einstellung useProjectArtifact bestimmen. Obschon das Standardset der Abhngigkeiten ohne weitere Konfigurationen sehr ntzlich sein kann, erlaubt dieser Abschnitt des Assembly Deskriptors eine breite Vielfalt mglicher Einstellungen. Dies erlaubt es Ihnen das Verhalten Ihren speziellen Bedrfnissen anzupassen. Zum Beispiel mag das Erste was Sie am Set der Abhngigkeiten anpassen wollen sein, den aktuellen Projektartefakten auszuschliessen. Sie tun dies, indem Sie die Einstellung useProjectArtifact auf false setzen (aus Grnden der Rckwrtskompatibilitt ist der Standardwert true). Diese Einstellung erlaubt es Ihnen die Buildlauf Ausgabe unabhngig von den Abhngigkeiten zu definieren. Andererseits knnte es sein, dass Sie sich dafr entscheiden, die Artefakte der Abhngigkeiten entpackt abzulegen. Sie tun dies indem Sie die "unpack" Einstellung auf true setzen (Standardwert: false). Ist unpack auf true gesetzt, so wird das Assembly Plugin die Inhalte aller Artefakte der Abhngigkeiten dem Wurzelverzeichnis des Zielarchivs hinzufgen. Von diesem Punkt an wird es mehrere Mglichkeiten geben was Sie mit Ihrem Set von Abhngigkeiten anstellen wollen. Die folgenden Abschnitte beschreiben wie Sie die Ausgabelokation der dependencySets definieren, sowie Ein- und Auschluss von Abhngigkeiten nach Gltigkeitsbereich festlegen. Zum Schluss werden wir noch einmal zur Entpackfunktionalitt zurckkehren und einige der 313

Maven Assemblies erweiterten Mglichkeiten beim entpacken von Abhngigkeiten ansehen. 12.5.4.1. Anpassen des Ausgabeortes bei Abhngigkeiten Es bestehen zwei Mglichkeiten welche in Kombination eingesetzt werden, um den Ort einer Abhngigkeit innerhalb eines Assemblies zu definieren: die Elemente outputDirectory und outputFileNameMapping. Es kann sein, dass Sie den Ort der Ablage der Abhngigkeiten innerhalb Ihres Assemblies direkt durch Einstellungen an den Abhngigkeiten selbst bestimmen mchten. Nehmen wir an, Sie mchten alle Abhngigkeiten in einem Verzeichnis welches der groupId des Artefakten entspricht, ablegen. In diesem Fall wrden Sie das Unterelement outputDirectory des Elements dependencySet nutzen, und einen Eintrag wie folgenden vornehmen:
<assembly> ... <dependencySets> <dependencySet> <outputDirectory>${artifact.groupId}</outputDirectory> </dependencySet> </dependencySets> ... </assembly>

Der aufgefhrte Eintrag wrde dazu fhren, dass jede einzelne Abhngigkeit in einem Unterverzeichnis abgelegt wird, welches den Namen der Artefakt groupId trgt. Sollten Sie weitere Anpassungen vornehmen wollen, zum Beispiel der Entfernung der Versionsbezeichnung im Namen aller Abhngigkeiten, knnen Sie fr jede Abhngigkeit den Eintrag fr den Ausgabename mittels dem Element outputFileNameMapping wie folgt bestimmen:
<assembly> ... <dependencySets> <dependencySet> <outputDirectory>${artifact.groupId}</outputDirectory> <outputFileNameMapping> ${artifact.artifactId}.${artifact.extension} </outputFileNameMapping> </dependencySet> </dependencySets>

314

Maven Assemblies
... </assembly>

Im vorausgehenden Beispiel wrde eine Abhngigkeit von commons:commons-codec version 1.3 in der Datei commons/commons-codec.jar abgelegt. 12.5.4.2. Auswertung von Properties bezglich der Ausgabelokation von Abhngigkeiten Wie bereits zuvor erwnt, werden die beiden Elemente outputDirectory und outputFileNameMapping nicht mit dem Rest des Assembly Deskriptors ausgewertet. Deren Rohwerte werden mittels zustzlicher, Artefakt spezifischer Ausdrucks Prozessoren verarbeitet. Die mglichen Artefaktausdrcke der zwei Elemente unterscheiden sich nur wenig. In beiden Fllen, sind alle Ausdrucksformen im Stil von ${project.*}, ${pom.*}, und ${*} welche innerhalb eines POM sowie des brigen Assembly Deskriptors zur Verfgung stehen hier ebenfalls einzusetzen. Fr das Element outputFileNameMapping wird der folgende Prozess zur Auswertung eines Ausdrucks angewandt: 1. Sollte der Ausdruck mit dem Muster ${artifact.*} bereinstimmen: a. Abgleich gegen eine Instanz des Artefakts der Abhniggkeit (lst: groupId, artifactId, version, baseVersion, scope, classifier, und file.* -Ausdrcke auf) b. Abgleich gegen eine Instanz des ArtifactHandler der Abhngigkeit (lst Ausdrcke auf) c. Abgleich gegen eine Instanz des Projektes welche mit der Abhngigkeit assoziiert ist (lst hauptschlich POM Properties auf) 2. Sollte der Ausdruck mit dem Muster ${pom.*} or ${project.*} bereinstimmen: 315

Maven Assemblies

a. Abgleich gegen die Instanz des Projektes (MavenProject) des aktuellen Buildlauf 3. Sollte der Ausdruck dem Muster ${dashClassifier?} entspreche und die Artefakt Instanz enthlt eine classifier-Koordinate welche nicht null ist, lst dies auf eine classifier-Koordinate mit vorangestelltem Bindestrich auf (-classifier), andernfalls zu einem Leerstring. 4. Versuche den Ausdruck gegen eine Projektinstanz des aktuellen Buildlauf abzugleichen. 5. Versuche den Ausdruck gegen die POM Properties des aktuellen Buildlauf abzugleichen. 6. Versuche den Ausdruck gegen die verfgbaren System-Properties abzugleichen 7. Versuche den Ausdruck gegen die verfgbaren Betriebssystem Umgebungsvariablen abzugleichen Das Element outputDirectory wird in gleicher Weise abgearbeitet, der einzige Unterschied ist, dass es keine verfgbaren Informationen der Art ${artifact.*} gibt, lediglich die ${project.*} Instanz des entsprechenden Artefakts. Daher sind auch die Ausdrcke welche oben aufgefhrt wurden und von diesen Klassen abhngig sind nicht verfgbar (1a, 1b und 3 der obigen Auflistung). Wie weiss man wann es sinvoll ist die Elemente outputDirectory und outputFileNameMapping zu benutzen? Sobald Abhngigkeiten entpackt werden, wird nur das outputDirectory zur berechnung der Ausgabelokation herangezogen. Im Fall dass Abhngigkeiten als ganze Datei (nicht entpackt) verwaltet werden, knnen beide Elemente outputDirectory und outputFileNameMapping eingesetzt werden. Werden die Elemente gemeinsam genutzt, so ist das Resulat gleichbedeutend mit:
<archive-root-dir>/<outputDirectory>/<outputFileNameMapping>

316

Maven Assemblies Sollte outputDirectory fehlen, so wird es nicht angezogen, sollte outputFileNameMapping fehlen, so ist der Standardwert:

${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension

12.5.4.3. Ein- und Auschluss von Abhngigkeiten in Relation zum Gltigkeitsbereich Im Abschnitt Section 9.4, Projekt Abhngigkeiten (Dependencies) wurde ausgefhrt wie jede Abhngigkeit dem einen oder anderen Gltigkeitsbereich zugeordnet ist. Der Gltigkeitsbereich bestimmt, wann innerhalb eines Buildprozesses eine Abhngigkeit zum Einsatz kommt. So sind Abhngigkeiten vom Gltigkeitsbereich test nicht Teil des Klassenpfades zum Zeitpunkt der Kompilation der (Haupt-)Klassen, werden aber zur Kompilation der Testklassen dem Klassenpfad angefgt. Dies ist so, da Ihre Projekt Quellen keinen testspezifischen Code enthalten sollen, da das Testen keine Funktion des Projektes ist (es stellt eine Funktion des Projekt Build Prozesses dar). In gleicher Weise wird davon ausgegangen, dass Abhngigkeiten des Gltigkeitsbereich provided in der Zielumgebung vorhanden sind. Es ist jedoch so, dass, sollte ein Projekt eine Abhngigkeit des Gltigkeitsbereich provided besitzen, diese bereits whrend des Buildvorangs bentigt wird um zu kompilieren. Daher sind derartige Abhngigkeiten zwar dem Klassenpfad hinzugefgt, nicht jedoch Teil der Artefakte welche mit dem Projekt oder dem Projektassembly gebndelt werden. Im gleichen Kapitel wird ebenfalls ausgefhrt, dass manche Gltigkeitsbereiche andere stillschweigend voraussetzen. Ein Beispiel ist der Gltigkeitsbereich runtime, der stillschweigend den Gltigkeitsbereich compile voraussetzt, da alle Abhngigkeiten zur Zeit der Kompilierung (mit Ausnahme der des Gltigkeitsbereichs provided) zur Ausfhrng notwendig sind. Es gibt hierbei eine Anzahl komplexer Beziehungen zwischen den verschiedenen Gltigkeitsbereichen welche bestimmen wie der Gltigkeitsbereich einer direkten Abhngigkeit den Gltigkeitsbereich einer transitiven Abhngigkeit beeinflusst. In einem Maven Assembly Deskriptor knnen wir daher entsprechend der verschiedenen Gltigkeitsbereiche den Abhngigkeiten unterschiedliche Einstellungen zuordnen. Ein Beispiel: planen wir eine Webanwendung zusammen mit Jetty zu bndeln um eine abgeschlossene Anwendung zu erstellen, so mssen wir alle Abhngigkeiten 317

Maven Assemblies vom Gltigkeitsbereich provided in der Verzeichnisstruktur von Jetty ablegen, welche eingeschlossen werden sollen. Somit werden diese "bereitgestellten" Abhngigkeiten auch der Runtime-Umgebung zur Verfgung gestellt. Hierbei nicht bereitgestellte Abhngigkeiten vom Gltigkeitsbereich runtime werden weiterhin im Verzeichnis WEB-INF/lib landen, was erzwingt, dass diese beiden Abhngigkeits Stze getrennt verarbeitet werden mssen. Die Defiition dieser zwei Abhngigkeits Stze knnte wie der folgende Ausschnitt eines XML Dokuments aussehen: Example 12.9. Erstellen von Abhngigkeitsgruppen mittels Gltigkeitsbereichen
<assembly> ... <dependencySets> <dependencySet> <scope>provided</scope> <outputDirectory>lib/${project.artifactId}</outputDirectory> </dependencySet> <dependencySet> <scope>runtime</scope> <outputDirectory> webapps/${webContextName}/WEB-INF/lib </outputDirectory> </dependencySet> </dependencySets> ... </assembly>

Abhngigkeiten des Gltigkeitsbereichs provided werden dem Verzeichnis /lib des Ursprungsverzeichnis hinzugefgt, von welchem angenommen wird, dass es in den globalen Klassenpfad der Jetty Laufzeitumgebung aufgenommen wird. Wir verwenden hierbei ein Unterverzeichnis welches die ArtefactId als Namen trgt um es zu vereinfachen, den Ursprung einer bestimmten Bibliothek zu finden. Abhngigkeiten zur Laufzeit werden in das Verzeichnis /WEB-INF/lib der Webanwendung aufgenommen. Dieses befindet sich in einem der Unterverzeichnisse des Verzeichnisses /webapps von Jetty, welches mittels einem Property namens webContextName im POM gesetzt wird. Im vorausgehenden Beispiel haben wir die anwendungsspezifischen Abhngigkeiten von denen 318

Maven Assemblies getrennt, welche Teil der Servletspezifikation sind und daher Teil des globalen Klassenpfades. Allerdings mag es nicht ausreichen die Abhngigkeiten nach Gltigkeitsbereich zu trennen, insbesondere nicht bei Webanwendungen. Es ist durchaus denkbar, dass eine oder mehrere Abhngigkeiten des Gltigkeitsbereich runtime standardisierte Bndel nicht kompilierter Ressoucen einer Webanwendung darstellen. Nehmen Sie zum Beispiel eine Anzahl Webanwendungen welche eine gemeinsame Basis von JavaSkript, CSS, SWF oder Bilddateien teilen. Um die Wiederverwendbarkeit zu untersttzen ist es gebruchlich derartige Ressourcen zu bndeln und separat in das Maven Repository einzustellen. Von dem Punkt an ist es mglich diese Resourcen wie gewhnliche Maven Abhngigkeiten - womglich vom Abhngigkeitstyp zip zu addressieren, normalerweise als Teil des Gltigkeitsbereich runtime. Bitte beachten Sie, dass es sich hierbei um Resourcen handelt, nicht binre Abhngigkeiten Ihrer Quellen. Aus diesem Grund ist es nicht angebracht diese in das Verzeichnis /WEB-INF/lib abzulegen. Tatschlich sollten derartige Archive getrennt von den Laufzeit-Binaries entpackt und im Wurzelverzeichnis der Webanwendung abgelegt werden. Um eine derartige Trennung zu erstellen ist es notwending spezielle Ein- und Ausschlusskriterien auf diese bestimmten Koordinaten anzuwenden. In anderen Worten, sollten Sie also drei oder vier Webanwendungen bearbeiten, welche die selben Resourcen benutzen und Sie mchten hierfr ein Assembly erstellen, welches Abhngigkeiten von Scope provided im Verzeichnis /lib ablegt, Abhngigkeiten vom Gltigkeitsbereich runtime im Verzeichnis /webapps/<contextName>/WEB-INF/lib und darberhinaus gewisse Laufzeitabhngigkeiten in das Anwendungswurzelverzeichnis entpackt, so ist dies mglich. In einem Assembly steht es Ihnen frei, verschiedene ein- und Auschlusskriterien zu einem bestimmten Element dependencySet zu definieren. Der folgende Abschnitt wird dies vertiefen. 12.5.4.4. Fine Tuning: Ein- und Ausschlusskriterien fr Abhngigkeiten Eine Abhnigkeit zu einer Resource mag ein einfaches Bndel Ressourcen sein (CSS, JavaSkript oder Grafiken), innerhalb eines Projektes welches ein Assembly 319

Maven Assemblies besitzt das ein ZIP Archiv erstellt. Ausgehend von den bestimmten Gegebenheiten einer Webanwendung ist es uns mglich eine derartige Abhngigkeit zu einer Resource von einer Binrabhngigkeit der Quellen alleine am Typ zu unterscheiden. Die meisten Webanwendungen haben Abhngigkeiten vom Typ jar und so ist es mglich mit einiger Sicherheit zu definieren, dass Abhngigkeiten vom Typ ZIP Ressourcen darstellen. Es kommt aber auch vor, dass Ressourcen im JAR-Format auftreten und dann eine Klassifizierung der Art resource oder nlich haben. In jedem Fall ist es mglich Kriterien zu erstellen um diese Ressourcen herauszufiltern und getrennt von den binren Abhngigkeiten zu verarbeiten. Wir definieren derartige Filterkriterien in den Unterelementen includes sowie excludes des Elements dependencySet. Beide Unterelemente sind Auflistungsabschnitte, das bedeutet, dass diese die Unterelemente include und exclude erlauben. Jedes Element include (exclude) beinhaltet einen String welcher Jokerzeichen enthalten kann. Jeder Wert kann auf verschiedene Art und Weise zur Anwendung kommen. Im allgemeinen werden dreierlei Musterformate untersttzt: - Versionsloser Schlssel Sie wrden dieses Muster anwenden um eine Abhngigkeit gesttzt auf groupId und artifactId zu definieren
groupId:artifactId

- Konfliktschlssel Dieses Muster erlaubt es Ihnen einen breiteren Satz von Koordinaten zu definieren, sowie spezifischere Ein-/Auschlusskriterien auszudrcken.
groupId:artifactId:type[:classifier] groupId:artifactId:type[:classifier]:version

- Genauer Artifakt

Schlssel Sollten Sie die Detailgenauigkeit bentigen, so knnen Sie auch alle Koordinaten angeben. Alle der oben genannten Musterformate untersttzen das Jokerzeichen "*" welches alle Bestandteile eines Schlssels ersetzen kann, und ist nicht darauf angewiesen auf genau einen Bestandteil zu passen (Teile zwischen den Doppelpunkten ':') Beachten Sie auch, dass die Koordinate classifier optional ist, insofern, dass auf Kriterien passende Abhngigkeiten welche keinen Koordinatenbestandteil 320

Maven Assemblies
classifier

besitzen dieser nicht ausgewertet wird.

Im oben angegebenen Beispiel, wobei das herausragende Merkmal der Artifakttyp ZIP ist und keine der Abhngigkeiten einen Koordinatenbestandteil classifier trgt, wrde das folgende Kriterium auf die Ressource-Abhngigkeiten passen (unter der Annahme, dass diese alle vom Typ ZIP sind):
*:zip

Das aufgefhrte Kriterium benutzt die zweite Abhngigkeitsform: den Konfliktschlssel der Abhngigkeit. Jetzt, da wir ein Kriterium gefunden haben welches uns erlaubt Resourcen von binren Abhngigkeiten zu trennen, knnen wir auch unsere Elemente dependencySets entsprechend anpassen um unsere Resource-Archive entsprechend zu verarbeiten. Example 12.10. Benutzung von Abhngkeits Ein- und Ausschlssen in
dependencySets
<assembly> ... <dependencySets> <dependencySet> <scope>provided</scope> <outputDirectory>lib/${project.artifactId}</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> </dependencySet> </dependencySets> ...

321

Maven Assemblies
</assembly>

Im Beispiel Example 12.10, Benutzung von Abhngkeits Ein- und Ausschlssen in dependencySets wurden die Definition der Abhngigkeiten vom Gltigkeitsbereich runtime derart abgendert, dass diese Ressource-Abhngigkeiten ausschliessen. Lediglich binre Abhngigkeiten (Abhngigkeiten nicht vom Typ zip) sollen dem Verzeichnis /WEB-INF/lib der Webanwendung angefgt werden. Die Resource-Abhngigkeiten sind nun in einem eigenen Element dependencySet definiert, derart um diese Abhngigkeiten dem Resourcenverzeichnis der Webanwendung zuzufgen. Der Abschnitt includes des letzten Element dependencySet ist genau das Gegenteil des Abschnitts excludes des vorangehenden Elements dependencySet derart, dass Ressource-Abhngigkeiten mittels den selben Identittskriterien eingeschlossen werden, z.B. *:zip. Das letzte Element dependencySet bezieht sich auf die gemeinsamen Resource-Abhngigkeiten welche konfiguriert sind um diese im Wurzelverzeichnis der Anwendung zu entpacken. Das Beispiel Example 12.10, Benutzung von Abhngkeits Ein- und Ausschlssen in dependencySets beruht auf der Annahme, dass unsere gemeinsamen Ressource-Abhngigkeit von einem Typ ist, welcher sich von allen anderen Abhngigkeiten unterscheidet. Was wrde passieren sollte dies nicht der Fall sein und die Ressoure-Abhngigkeit vom gleichen Typ sein wie alle anderen Ahngigkeiten? Wie knnte man dann die Abhngigkeit herausdifferenzieren? In diesem Fall, in welchem die Resource-Abhngigkeit ebenfalls als JAR mit einer klasssifizierenden Koordinate ressources besteht knnen Sie auf das Identittsmuster setzen und derart die Abhngigkeiten bestimmen:
*:jar:resources

Anstelle der Suche nach Artefakten vom Typ zip ohne Bercksichtigung der klassifizierenden Koordinate suchen wir nun nach Artefakten mit klassifizierender Koordinate ressources welche vom Typ jar sind. Wie bereits im Abschnitt ber fileSets beschrieben, untersttzen dependencySets ebenfalls die Einstellung useStrictFiltering. Sollte diese zugeschaltet sein, wird jedes ausgewiesene Kriterium welches nicht mindestens 322

Maven Assemblies eine passende Abhngigkeit findet einen Fehler ausweisen und die Erstellung des Assembly und damit die Ausfhrung des Buildes abbrechen. Dies kann insbesondere als ntzliches Sicherheitsventil zum Einsatz kommen: um sicherzustellen, dass Abhngigkeiten von Projekten mit dem entsprechenden Assembly Deskriptor synchronisiert sind und so zusammenspielen wie Sie sich das vorgestellt haben. Standardmssig ist die Eingenschaft auf false gesetzt, schon alleine wegen der Rckwrtskompatibilitt. 12.5.4.5. Transitive Abhngigkeiten, Projekt Anhnge, und Projekt Artefakte Der Abschnitt dependencySet untersttzt zwei weitere generelle Mechanismen zur Bestimmung der Untermenge von Artefakten: Transitive Auswahlgruppen und Optionen, um mit Projektartefakten zu arbeiten. Diese beiden Mechanismen sind aus der Notwendigkeit heraus entstanden frhere Konfigurationen zu untersttzen, welche eine freiere Definition des Wortes "Abhngigkeit" zugrunde legten. Fr ein gutes Beispiel, sehen Sie sich den Hauptartefakten eines Projektes an. Typischerweise wrde dieser nicht als Abhngigkeit gesehen, jedoch schlossen frhere Versionen des Assembly Plugin diesen Artefakt in die Berechnung der Abhngigkeiten ein. Um zu diesem Verhalten Rckwrtskompatibilitt zu bieten untersttzt die Version 2.2 (derzeit 2.2-beta-2) des Assembly Plugin eine Einstellung useProjectArtifact dessen Standardwert auf true gesetzt ist. Standardmssig wird bei der Berechnung der Abhngigkeiten versucht werden, den Hauptartefakt in die Bestimmung der passenden Artefakte, einzuschliessen. Sollten Sie es vorziehen sich mit dem Hauptartefakten direkt zu befassen, so setzen Sie diese Einstellung auf false. Tip Die Authoren dieses Buches empfehlen, dass Sie useProjektArtefacts immer auf false setzen. Eine der natrlichen Erweiterungen zum Einschluss des Projekthauptartefakten ist die Mglichkeit die dem Projekt angeschlossenen Artefakte ebenfalls innerhalb eines Elements dependencySet zu verwalten. Um dies zu tun, setzen Sie die 323

Maven Assemblies Einstellung useProjectAttachments (deren Standardeinstellung false ist) um. Die Freigabe dieser Einstellung erlaubt Muster und Kriterien, welche die klassifizierende Koordinate und den Typ eines Artefaktes untersuchen, auch auf Artefakte anzuwenden, welche dem Hauptprojekt angehngt sind. Das bedeutet, diese teilen sich die Hauptkoordinaten groupId, artifactId und version, unterscheiden sich aber im type und/oder klassifizierender Koordinate vom entsprechenden Hauptartefakten. Dies ist insbesondere ntzlich sollten JavaDoc oder Quellen in einem Assembly verarbeitet werden. ber die Verarbeitung der Projektartefakte hinaus gibt es die Mglichkeit die entsprechenden dependencySets mittels zweier Einstellungen bezglich transitiver Auflsung zu beeinflussen. Die erste Einstellung trgt den Namen useTransitiveDependencies (ist standardmssig auf true gesetzt) und bestimmt, wie zu erwarten, ob transitive Abhngigkeiten bei der Berechnung der Abhngigkeitssets berhaupt bercksichtigt werden sollen. Um aufzuzeigen wie diese Einstellung zu benutzen ist, stellen Sie sich vor, Ihr POM htte eine Abhngigkeit zu einem weiteren Assembly. Das Assembly wird (hchstwarscheinlich) eine klassifizierende Koordinate besitzen, welche sich von der des Haupartefaktes unterscheidet, womit der Artefakt dem Projekt angehngt wird. Eine Eigenart des Maven Abhngigkeiten Auflsungsprozesses ist jedoch, dass transitive Abhngigkeitsinformationen des Hauptartefakten bei der Auflsung des Assembly Artefakten zum Zug kommen. Bndelt das Assembly also Abhngigkeiten des Projektes in sich selbst, fhrt der Einsatz von transitiver Abhngigkeitsauflsung unweigerlich zu einer Verdopplung dieser Abhngigkeiten. Um dies zu verhindern, setzen Sie einfach die Einstellung useTransitivDependencies auf false, fr das Element dependencySet welches diese Assembly Abhngigkeit verarbeitet. Die zweite Einstellung bezglich transitiver Abhngikeiten ist bedeutend subtiler: Diese trgt den Namen useTransitivFiltering und ist standardmssig auf false gesetzt. Um zu verstehen, was diese Einstellung ermglicht, ist es wichtig zu verstehen, welche Informationen berhaupt dem Abhngigkeits-Auflsungs-Prozess zur Verfgung stehen. Sollte ein Artefakt eine Abhngigkeit zu einer Abhngigkeit sein, besitzt es, was in Maven als DependencyTrail (AbhngigkeitsSpur) bezeichnet wird. Diese wird als Liste von 324

Maven Assemblies Strings vorgehalten, welche jeweils die vollstndige Artefakt Identitt (groupId:artifactId:type:[classifier:]version) aller Artefakte zwischen Ihrem POM und dem den DependencyTrail besitzenden Artefakten besteht. Mit Rckblick auf die drei zur Verfgung stehenden Mglichkeiten der Kriterienanwendung auf eine Bndel Abhngigkeiten wird Ihnen auffallen, dass die Eintrge in einem DependencyTrail - die vollstndige Artefakt Identitt - dem dritten Typus entsprechen. Sollte die Einstellung useTransitivefilterung zugeschaltet sein, so knnen die Eintrge der Abhngigkeitsspur des Artefakten in gleicher Weise zu einem Treffer fhren wie die Identitt des Artefakten selbst. Sollten Sie also die transitive Filterung in Betracht ziehen, so raten wir Ihnen, auf der Hut zu sein. Ein Artefakt kann von unterschiedlichen Abhngigkeiten mehrmals in eine Bndel Abhngigkeiten eingeschlossen werden, erst mit Version 2.0.9 wird dies beschrnkt und nur der erste Treffer dieser Art der Suche bercksichtigt. Dies wiederum kann zu feinsinnigen Problemen bei der Erstellung eines Satzes Abhngigkeiten zu Ihrem Projekt fhren. Warning Die allermeisten Assemblies bentigen keine derartig feingranulare Kontrolle des Satzes der Abhngigkeiten; wgen Sie genau ab, ob es wirklich gebraucht wird. Ein Tip: warscheinlich nicht.

12.5.4.6. Fortgeschrittene Entpackoptionen Wie zuvor bereits erwhnt ist es in einigen Fllen notwendig eine Abhngigkeit zu entpacken, um ein funktionsfhiges Assembly zu erstellen. Im vorausgegangenen Beispiel war die Entscheidung hierfr einfach. Das Beispiel hat nicht bercksichtigt was entpackt werden muss, und noch weniger was nicht entpackt werden sollte. Um ber das Entpacken der Abhngigkeiten eine grssere Kontrolle auszuben, knnen Sie das Unterelement unpackOptions des Elements dependencySet setzen. Mittels diesem Abschnitt haben Sie die Mglichkeit ber Ein- und Auschlussmuster Dateien des Assemblies zu bestimmen, sowie festzulegen, ob diese Dateien auf Ausdrcke auf der Basis der aktuellen POM Informationen gefiltert werden sollen. Tatschlich sind die zur Verfgung 325

Maven Assemblies stehenden Optionen, welche zum Entpacken von Abhngigkeitsstzen bereitstehen, ganz hnlich denen welche zur Auswahl von Dateien aus der Projektverzeichnisstruktur mit Hilfe der fileSet Deskriptoren bestehen. Um an unser Webanwendungs-Beispiel anzuknpfen, nehmen Sie einmal an, eine der Ressource-Abhngigkeiten wurden mit einer Datei gebndelt welche deren Verbreitungslizenz darstellt. Im Falle unserer Webanwendung werden wir diese 3rd Party Lizenzen mittels einer Datei NOTICES in unser Projektbndel einschliessen, womit wir verhindern wollen, dass die Lizenz eines Ressource Bndels zustzlich eingeschlossen wird. Um diese Datei auszuschliessen, fgen wir lediglich eine unpack-Option in das DependencySet ein, welches die folgenden Ressource-Artefakten verarbeitet: Example 12.11. Ausschliesen von Dateien von einem Abhngigkeits Unpack Bndel
<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> ... </assembly>

Beachten Sie, dass das Ausschlusskriterium welches wir benutzen, denen in der fileSet-Beschreibung sehr hnlich ist. Hierbei sperren wir jegliche Datei welche mit dem Wort LICENSE anfngt in jedem Verzeichnis des Resorce-Artefaktes. Stellen Sie sich die Unpackoptionen wie eine Art fileSet-light vor, welche auf jede 326

Maven Assemblies Abhngigkeit innerhalb eines Abhngigkeitsbndels angewandt wird. In anderen Worten, es stellt eine Art fileSet einer entpackten Abhngigkeit dar. Genau wie wir ein Auschlussmuster auf Dateien innerhalb einer Resource-Abhngigkeit definieren konnten um bestimmte Dateien auszuschliessen, knnen Sie derart festlegen, welchen Satz von Dateien Sie mittels dem Abschnitt includes einschliessen wollen. Die gleiche Implementierung welche bei der Bearbeitung von Ein- und Ausschlusskriterien auf fileSets zum Zug kommt wurde zur Verarbeitung von unpackOptions wiederverwendet. Zustzlich zu den Ein- und Ausschlssen von Dateien bieten die unpackOptions eines Abhngigkeitsbndels auch noch eine Einstellung filtering, deren Standardwert false ist. Auch diese Option wird Ihnen, gesttzt auf die vorhergehenden Abschnitte, bekannt vorkommen. In beiden Fllen werden Maven-Ausdrcke der Art ${property} oder in Ant-Syntax von @property@ untersttzt.Auf Dependency-Bndel angewandt, ist Filterung eine besonders angenehme Eigenschaft, da dies Ihnen erlaubt, standardisierte, versionierte Resource-Vorlagen zu erzeugen, welche erst mit der Einbindung in ein Assembly angepasst werden. Sobald Sie den Einsatz von entpackten, gefilterten Resource-Bndeln, welche gemeinsam abgelegte Resourcen darstellen, gemeistert haben, sind Sie auch in der Lage, wiederholt zum Einsatz kommende Resourcen herauszuabstrahieren. 12.5.4.7. Zusammenfassung von Abhngigkeitsbndeln Schliesslich soll nicht unerwhnt bleiben, dass dependencySets die gleichen Konfigurationen fileMode und directoryMode wie fileSets, bereitstellen. Bedenken Sie aber, dass directoryMode Einstellungen nur zum Zug kommen, sollte die Abhngigkeit entpackt sein.

12.5.5. Element

moduleSets

Multi modulare Builds werden im allgemeinen durch das bergeordnete POM sowie den Module-Abschnitten der in Wechselbeziehungen stehenden POMs zusammengehalten. Gewhnlich werden die untergeordneten Module in den entsprechenden Module Abschnitten der POM definiert, was diese in den Build 327

Maven Assemblies Prozess des bergeordneten POM einschliesst. Wie genau diese Beziehung definiert ist, ist von Bedeutung wenn es darum geht, wie das Assembly Plugin an diesem Prozess teilhaben kann. Wir werden dies spter genauer beleuchten. Zu diesem Zeitpunkt reicht es, sich das Beziehungsmodell wie es unter moduleSets beschrieben ist, zu betrachten. Projekte werden zu multi-modularen Buildlufen zusammengestrickt, da sie Teil eines grsseren Systems sind. Diese Projekte sind darauf ausgelegt, zusammen zum Einsatz zu kommen, und so macht ein einzelnes Module eines grsseren Build Laufes nicht viel Sinn. Die Struktur des Projekts ist davon bestimmt wie wir erwarten, dass das Projekt (und dessen Module) zum Einsatz kommen. Betrachten wir ein Projekt von der Warte eines Benutzers, so macht es Sinn, dass das Endziel eines Buildlaufes eine einzige zu verteilende Datei ist (Distribution), welche ohne grssere Installationsprobleme konsumiert werden kann. Da multi-modulare Maven Builds gewnlich eine hierarchische Struktur aufweisen, in welcher Informationen bezglich Abhngigkeiten, Plugin Konfigurationen und weitere Informationen von oben nach unten vererbt werden, so erscheint es natrlich, dass die Aufgabe alle Module in ein grosses Ganzes zusammen zu fgen dem allerobersten Projekt zufllt. Dies ist der Ort an welchem moduleSet in Spiel kommen. erlauben den Einschluss von Ressourcen in die endgltige Zusammenstellung (Assembly) welche zu beliebigen Modulen der Projektstruktur gehren. Genau wie Sie eine Anzahl Dateien zum Einschluss in ein Assembly mittels fileSets und dependencySets auswhlen knnen, so knnen Sie die Auswahle von Datein und Ressourcen mittels moduleSets bestimmen, um hierbei auf beliebige Module eines multi-modularen Builds zuzugreifen. Dies wird durch zwei spezifische Mglichkeiten der modulspezifischen Auswahl erreicht: Datei-basierend sowie Artefact-basierend. Vor wir nun die Details und Unterschiede zwischen diesen Mglichkeiten ausfhren, lassen Sie uns aufzeigen wie die zu verarbeitenden Module ausgewhlt werden.
molduleSets

12.5.5.1. Modulauswahl Zu diesem Zeitpunkt sind Sie bereits zu gut eingefhrt in die Ein-und Ausschlusskriterien wie diese innerhalb des gesamten Assembly Deskriptors zur 328

Maven Assemblies Anwendung kommen. Sobald Sie sich innerhalb eines Assembly Deskriptors auf Module beziehen werden Sie diese Ein-/Ausschlussmuster benutzen um diesbezglich Regeln zu erstellen. Der grosse Unterschied bei modulbezogenen Regeln ist, dass diese keine Joker beinhalten knnen. (Seit Version 2.2-beta-2 hat diese Eigenschaft nur wenig Interesse gelockt, und daher die Implementierung nicht weiter verfolgt. Statt dessen besteht jegliches Ein-/Auschlussmuster einfach aus der entsprechenden groupId sowie die durch einen Doppelpunkt getrennte artifactId des Moduls:
groupId:artifactId

Zustzlich zu den Ein- und Ausschlusskriterien untersttzt das modulSet eine weitere Auswahl: die Einstellung includeSubModules (dessen Wert auf true gesetzt ist). Die Hierarchieordnung eines multi-modularen Builds ist nicht auf zwei Ebenen eines Projektes begrenzt. Tatschlich knnen Sie eine beliebige Anzahl Hierarchieebenen in Ihren Build einschliessen. Jedes Projekt, welches ein Modul zu einem Modul Ihres Projektes darstellt wird als Submodul gesehen. Zeitweise werden Sie jedes Modul einzeln abhandeln wollen (einschliesslich der zugehrigen Untermodule). Ein Beispiel: es vereinfacht die Erstellung von Artefakt-basierenden Beitrgen aus den Modulen. Um diese zu erstellen belassen Sie die Einstellung useSubModules auf true. Sollten Sie versuchen Dateien von allen Verzeichnisstrukturen der Module einzuschliessen, so macht es Sinn die Verzeichnisstruktur nur ein einziges Mal zu bearbeiten. Sollte Ihre Projektverzeichnisstruktur also die oberste Struktur der Hierarchie, welche im POM enthalten ist, abbilden, so wrde dies zu Auswahlkriterien der Art **/src/main/java fhren, welche nicht nur auf das beabsichtigete Modul Anwendung findet, sondern auf die gesamte Hierarchie. Tatschlich wollen Sie in diesem Fall nur die erste Stufe der Hierarchie und nicht den ganzen Baum bearbeiten; dieser wird als Unterverzeichnis zu Ihrem Projekt bereits bearbeitet. In einem solchen Fall werden Sie die Untermodule getrennt bearbeiten wollen und daher die Einstellung useSubModules auf false setzen. Sobald Sie nun festgelegt haben wie die Modulauswahl fr das entsprechende moduleSet stattfinden soll, so sind wir bereit zu definieren was aus den entsprechenden Modulen eingeschlossen werden soll. Wie bereits beschrieben 329

Maven Assemblies kann dies Dateien oder Artefakten des Modul Projektes umfassen. 12.5.5.2. Element sources Nehmen Sie einmal an, Sie wollen die Quellen der Module Ihres Projektes in ihr Assembly einschliessen, aber ein bestimmtes Modul davon auschliessen. Vielleicht bearbeiten Sie ein Projekt namens GeheimeSosse welche ein Geheimnis, ein sSck heiklen Code beinhaltet welchen Sie nicht mit Ihrem Projekt weitergeben wollen. Der einfachste Weg dies zu erreichen ist es ein moduleSet einzusetzen, welches alle Projektverzeichnisse in ${module.basedir.name} einschliest aber das Modul GeheimeSosse davon ausschliesst. Bei der anschliessenden Bearbeitung des moduleSet wird das entsprechende Modul vom Assembly ausgeschlossen. Example 12.12. Ein- und Ausschluss von Modulen mittels einem a moduleSet
<assembly> ... <moduleSets> <moduleSet> <includeSubModules>false</includeSubModules> <excludes> <exclude> com.mycompany.application:secret-sauce </exclude> </excludes> <sources> <outputDirectoryMapping> ${module.basedir.name} </outputDirectoryMapping> <excludeSubModuleDirectories> false </excludeSubModuleDirectories> <fileSets> <fileSet> <directory>/</directory> <excludes> <exclude>**/target</exclude> </excludes> </fileSet> </fileSets> </sources> </moduleSet> </moduleSets> ... </assembly>

330

Maven Assemblies Im Beispiel Example 12.12, Ein- und Ausschluss von Modulen mittels einem a moduleSet stellen wir die Einstellung includeSubModules auf false. Das vereinfacht uns die Handhabe indem wir uns auf die direkten Untermodule beschrnken, da wir alle Quellen des Projektes bearbeiten und somit Joker auf das fileSet einsetzen knnen. Die Einstellung bewahrt uns davor, uns damit befassen zu mssen, dass tieferliegende Untermodule ebenfalls in das Assembly Archiv eingebunden werden. Das Element exclude befasst sich mit dem Modul geheimeSauce. Wir werden also dessen Projekt Quellen nicht einbinden, denn diese sind - geheim. Normalerweise werden Projektquellen in Verzeichnissen welche mit den Namen der Modulartefakte benannt sind abgelegt. Da Maven aber Module erlaubt, welche nicht in Verzeichnissen mit den Namen der artefactId abgelegt sind, ist es besser Sie arbeiten mit dem Ausdruck ${module.basedir.name} um den tatschlichen Verzeichnisname zu erhalten (${module.bsedir.name} entspricht dem Aufruf MavenProject.getBasedir().getName() ). Es ist wichtig, sich in Erinnerung zu rufen, dass Module nicht Unterverzeichnisse des Projektes sein mssen, welche diese deklariert. Sollte Ihr Projekt eine besonders obskure Verzeichnisstruktur aufweisen, so kann es passieren, dass Sie auf spezielle modulSet Deklarationen ausweichen mssen, welche bestimmte Projekte umfassen und Ihren Besonderheiten Rechnung tragen. Warning Versuchen Sie Ihre eigenen Projektbesonderheiten zu minimieren, obwohl Maven sehr flexibel ist, sollten Sie sich zu oft beim Konfigurieren wiederfinden so gibt es bestimmt einen einfacheren Weg. Eine weitere Anmerkung zu Example 12.12, Ein- und Ausschluss von Modulen mittels einem a moduleSet: da wir im allgemeinen die Verarbeitung der Untermodule ausgeschlossen haben, ist es wichtig sicherzustellen, dass wir diese nun bei der Verarbeitung der direkten Untermodule (erste Ebene) nicht auschliessen und die Quellen damit verlieren. Mittels der Einstellung excludeSubModuledirectories welche auf false gesetzt ist, knnen wir nun die gleichen Datei Ein- und Ausschlussmuster auf die Verzeichnisstrukturen der 331

Maven Assemblies Untermodule welche wir bearbeiten, anwenden. Schliesslich wird in dem Beispiel ausgefhrt, dass wir an den Ausgaben des Build Prozesses dieses modulSet nicht interessiert sind. Wir schliessen also die Verzeichnisse /target aller Module aus. Wir wollen es nicht unerwhnt lassen, dass der Abschnitt sources auch fileSet-artige Elemente direkt einschliessen kann, zustzlich zur Untersttzung von verschachtelten fileSets. Diese Konfigurationselemente werden aus Grnden der Rckwrtskompatibilitt zu frheren Versionen des Assembly Plugin (bis und mit Version 2.1) beibehalten. Diese Vorgngerversionen boten keine Untersttzung fr mehrfache fileSet Deklarationen innerhalb eines Modules ohne hierfr eine separate moduleSet Deklaration bereitzustellen. Diese Mglichkeiten sind nun veraltet und sollten nicht weiter benutzt werden. 12.5.5.3. Interpolation des outputDirectoryMapping in moduleSets Im Beispiel Example 12.12, Ein- und Ausschluss von Modulen mittels einem a moduleSet haben wir das Element outputDirectoryMapping benutzt, um den Namen der Verzeichnisse in welchen jedes Modul Quellen abgelegt werden anzupassen. Die Ausdrcke welche in diesem Element enthalten sind, werden in der genau gleichen Weise aufgelst, wie die fr outputFileMapping - in Bndeln von Abhngigkeiten - der Fall ist (Vergleichen Sie hierzu die Beschreibung unter Section 12.5.4, Element dependencySets). Im Beispiel Example 12.12, Ein- und Ausschluss von Modulen mittels einem a moduleSet haben wir den Ausdruck ${module.basedir.name} benutzt. Sie werden bemerkt haben, dass die Wurzel dieses Ausdrucks 'module' nicht in der Beschreibung des Algorythmus aufgefhrt ist der die Auflsung der Abhngigkeiten beschreibt. Dieses Wurzelobjekt ist spezifisch fr die Konfiguration von modulSets. Die Verarbeitung entspricht genau der von ${artifact.*}-Referenzen welche innerhalb des Elements outputFilemapping vorkommt, nur dass es nun auf des Moduls MavenProjekt, Artifact sowie ArtifactHandler Instanzen angewandt wird, statt auf die der Abhngigkeits Artefakte. 12.5.5.4. Binaries section 332

Maven Assemblies Genau wie der Abschitt ber Quellen sich vorrangig damit befasst, Module in Quellformat einzubinden, so ist der Abschnitt ber Binrdaten vorranging damit befasst das Erzeugnis eines Moduls einzubinden, oder dessen Artefakt. Obwohl dieser Abschnitt primr dazu dient dependencySets zu definieren welche auf die Module eines Bndels anzuwenden sind, so gibt es darber hinaus eine Anzahl weiterer Funktionen einzigartig zur Anwendung auf Modulartefakte welche sich lohnen anzusehen: attachmentClassifier und includeDependencies. Darberhinaus beinhaltet der Abschnitt ber Binaries Optionen hnlich derer des Abschnittes dependencySet, welche sich auf die Verarbeitung des Modulartefakts selbst beziehen. Diese sind: unpack, outputFileNameMapping, outputDirectory, directoryMode, sowie fileMode. Schliesslich knnen die Modul Binaries einen Abschnitt dependencySet beinhalten, um darzustellen, wie jeden Modul Abhngigkeiten in ein Assembly Archiv eingeschlossen werden sollen. Zunchst, lassen Sie uns betrachten, wie die oben genannten Optionen dazu benutzt werden knnen um die moduleigenen Artefakte zu verwalten. Angenommen wir mchten die JavaDoc Archive aller Module in unser Assembly einschliessen. In diesem Fall sind uns die weitern Abhngigkeiten egal, wir mchten lediglich die javadoc.jar Datei. Da diese Datei immer als Beigabe zum Hauptprojektartefakten besteht, ist es notwendig anzugeben, welcher classifier benutzt werden soll um den Artefakten zu holen. Zur Vereinfachung werden wir nicht weiter darauf eingehen, wie die Modul Archive entpackt werden, da diese Konfiguration genau die selbe ist, wie wir sie bereits fr die Abhngigkeits Stze zuvor in diesem Kapitel benutzt haben. Das resultierende Module Bdel sieht dann ungefair wie in Example 12.13, Einschliessen von JavaDoc von Modulen in einem Assembly dargestellt aus. Example 12.13. Einschliessen von JavaDoc von Modulen in einem Assembly
<assembly> ... <moduleSets> <moduleSet> <binaries> <attachmentClassifier>javadoc</attachmentClassifier> <includeDependencies>false</includeDependencies> <outputDirectory>apidoc-jars</outputDirectory> </binaries> </moduleSet>

333

Maven Assemblies
</moduleSets> ... </assembly>

Im Beispiel Example 12.13, Einschliessen von JavaDoc von Modulen in einem Assembly setzen wir die Einstellung includeSubModules nicht explizit, da diese standardmssig auf true steht. Wir wollen mit Sicherheit alle Module verarbeiten Untermodule eingeschossen - durch die Definition eines Modul Bndels, da wir keinerlei Ein- oder Ausschlusskriterien benutzen, welche auf Verzeichnisstrukturen der Untermodule passen knnten. Das Element attachmentClassifier holt den angebundenen Artefakten mit dem classifier javadoc fr jedes verarbeitete Modul. Das Element includeDependencies zeigt dem Assembly Plugin an, dass wir an den Abhngigkeiten des Modules kein Interesse haben, sondern nur am JavaDoc-Anhang interessiert sind. Am Schluss bestimmt das Element outputDirectory, dass alle javadoc Archive in einem Verzeichnis mit dem Namen apidoc-jars unter dem Wurzelverzeichnis abgelegt werden. Auch wenn wir in diesem Beispiel nichts berkompliziertes vollbringen, so ist es dennoch wichtig ein klares Verstndnis aufzubauen, dass auch hier die gleichen nderungen des Ausdrucks-Auflsungs-Algorythmus gelten, wie diese bereits fr das Element outputDirectoryMapping des Abschittes bezglich der Quellenverarbeitung beschrieben wurden. In anderen Worten, alles was bislang unter ${artifact.*} innerhalb des Element outputFileMapping eines dependencySet zur Verfgung stand, steht hier auch unter ${module.*} bereit. Das selbe gilt auch fr das Element outputFileMapping, wird dieses direkt innerhalb eines Abschnitts Binaries angewandt. Schliesslich, lassen Sie uns ein Beispiel ansehen, welches den Modul Artefakten und dessen Laufzeiabhngigkeiten verarbeitet. in diesem Fall wollen wir den Satz der Artefakte ein jeden Moduls in seperate Verzeichnisstrukturen ablegen, entsprechend des Artefakt Namen und Version. Das resultierende Modul ist erstaunlich einfach, und sieht entsprechend des Beispiels Example 12.14, Einschliessen von Module Artifakten und Abhngigkeiten in einem Assembly aus: 334

Maven Assemblies Example 12.14. Einschliessen von Module Artifakten und Abhngigkeiten in einem Assembly
<assembly> ... <moduleSets> <moduleSet> <binaries> <outputDirectory> ${module.artifactId}-${module.version} </outputDirectory> <dependencySets> <dependencySet/> </dependencySets> </binaries> </moduleSet> </moduleSets> ... </assembly>

In Example 12.14, Einschliessen von Module Artifakten und Abhngigkeiten in einem Assembly kommt ein leeres Element dependencySet zum Einsatz, da dieses standardmsig ohne Konfiguration bereits alle Laufzeitabhngigkeiten enthalten sollte. Mit der Definition von outputDirectory auf dem Level des Abschnittes Binaries, sollten neben den direkten Artefakten des Moduls auch alle Abhngigkeiten im gleichen Verzeichnis zusammengefgt werden. Damit mssen wir dies in unserem dependencySet erst gar nicht angeben. Im allgemeinen sind Module Binaries recht einfach. In beiden Abschnitten, dem Hauptteil, welcher sich mit der Verarbeitung des Modul Artfaktes befasst aber auch dem Abschnitt bezglich der Verarbeitung der Abhngigkeiten - ist die Konfiguration sehr hnlich derer eines Bndels Abhngigkeiten. Natrlich beinhaltet der Abschnitt bezglich Binaries auch Optionen welche steuern ob Abhngigkeiten eingeschlossen werden, oder welcher Hauptartefakt zum Zug kommt. Wie der Abschnitt bezglich Quellen beinhaltet auch dieser Abschnitt einige Konfigurationselemente welche nur wegen der Rckwrtskompatibilitt bereitgestellt werden. Diese sollten Sie als veraltet ansehen. Derartige Elemente umfassen die Unterabschnitte includes und excludes. 335

Maven Assemblies

12.5.5.5. moduleSets, Parent POMs und das Element binaries Die Ausfhrungen bezglich der Verarbeitung von Modulen wollen wir mit einer eindringlichen Warnung abschliessen: Es gibt subtile Abhngigkeiten des Designs von Maven bezglich den Abhngigkeiten von einem ber- zu einem Untergeordneten Modul und der Verarbeitung der Abschnittes Binaries eines Modul Satzes. Sobald ein POM ein bergeordnetes Modul deklariert, so muss dieses Modul in der einen oder anderen Art und Weise aufgelst werden, vor ein soches POM einen Buildlauf erfolgreich durchlaufen kann. Sollte das bergeordnete Modul in einem Maven Repository zugnglich sein, so besteht kein Problem. Mit der Version 2.0.9 kann es jedoch zu grsseren Problemen kommen sollte das bergeordnete Modul und dessen POM Teil des gleichen Build sein, insbesondere sollte dieses (bergeordnete) POM versuchen ein Assembly mit den Module Binaries zu erstellen. Maven Version 2.0.9 ordnet Projekte eines multi-modularen Builds entsprechen deren Abhngigkeiten, wobei die entsprechenden Abhngigkeiten eines Projektes vorgngig erstellt werden. Das Problem besteht darin, dass das bergeordnete Modul als Abhngigkeit angesehen wird, deren Verarbeitung vor der Ausfhrung der untergeordneten Module abgeschlossen sein muss. Sollte dann ein Teil des Erstellungsprozesses eines bergeordneten Moduls darin bestehen ein Assembly zu erstellen, welches auf den Ergebnissen der untergeordneten Module aufbaut, so werden diese noch nicht bestehen und damit der Prozess mit einem Fehler abbrechen. Dies ist ein komplexes und subtiles Problem, welches die Mglichkeiten und den Nutzen des Abschnittes Module Binaries des Assembly Deskriptors stark einschrnkt. Es ist sogar so, dass dies als Bug des Assembly Plugin unter: http://jira.codehaus.org/browse/MASSEMBLY-97 aufgenommen wurde. Es bleibt zu hoffen, dass eine zuknftige Version von Maven es schafft, diese Funktionalitt wiederherzustellen, insbesondere, da die Anforderung 'Vorrangig bergeordnetes Modul' unter Umstnden gar nicht unbedingt notwendig ist.

12.5.6. Element Repositories


336

Maven Assemblies Der Abschnitt repositories stellt eine etwas exotischere Funktionalitt des Assembly Deskriptors dar, da nur wenige Anwendungen nebst Maven die vollen Vorzge der Maven Repository Struktur zu nutzen verstehen. Aus diesem Grund, und da diese Funktionalitten denen des Abschnittes dependencySet sehr hnlich sind, werden wir nicht allzuviel Zeit darauf verwenden den Abschnitt repositories des Assembly Deskriptor detailliert einzufhren. In den meisten Fllen sollte es einem Anwender der dependencySets verstanden hat nicht schwer fallen mittels dem Assembly Plugin Repositorien zu erstellen. Wir werden an dieser Stelle den Abschnitt repositories nicht bewerben, und wir werden uns auch nicht die Mhe machen ein elaboriertes Beispiel einzufhren. Wir werden uns darauf beschrnken einige Warnungen auszusprechen fr diejenigen welche diese Funktionalitt benutzen mchten. Nach dieser Einfhrung mchten wir insbesonder auf zwei Funktionen des Abschnitts repositories hinweisen, welche weiterer Erwhnung gebhren: Die erste ist die Eigenschaft includeMetaData. Wird diese auf true gesetzt, so werden MetaDaten wie z.B. die tatschlichen Versionen im Fall von -SNAPSHOT virtuellen Versionen weitergegeben. Standardmssig steht dieser Parameter auf false. Derzeit sind die einzigen Meta Daten welche eingeschlossen werden, sollte dieser Parameter auf true gesetzt werden, die Informationen des Maven Central Repository. Die zweite interessante Funktionalitt ist der Parameter groupVersionAlignements. Wiederum ist dieser Abschnitt eine Liste der einzelnen groupVersionAlignement Konfigurationen. Jeder Eintrag besteht aus zwei Pflicheintrgen - id und version - zusammen mit dem optionalen Eintrag excludes welches eine Liste von artifactId umfasst welche nicht in diese Umordung eingeschlossen werden sollen. Unglcklicherweise beeinflusst diese Umordnung anscheinend nicht die POMs innerhalb der entsprechenden Repositorien. Weder die der Artefakte welche Teil der Umordnung sind, noch solche, welche eine Abhngigkeit zu einem solchen Artefakten definiert haben. Dies macht es schwer eine praktische Anwendung einer derartigen Umordung zu sehen. Im Allgemeinen ist es am einfachsten auf den Abschnitt repositories die gleichen Prinzipien anzuwenden, welche Sie auf dependencySets anwenden 337

Maven Assemblies wrden. Auch wenn der Abschnitt repositories die beiden genannten Zusatzoptionen bietet, so werden diese hauptschlich zum Zwecke der Rckwrtskompatibilitt gefhrt und es ist abzusehen, dass diese in der Zukunft veralten werden.

12.5.7. Verwalten des Wurzelverzeichnisses des Assembly


Jetzt, da wir den Hauptteil des Assembly Deskriptors vorgestellt haben, knnen wir die kontentbezogene Diskussion mit einem etwas einfacheren Thema abschliessen: Stammverzeichnisnamensgebung und Siteverzeichnisbehandlung. Manche werden es als stylistisches Problem abtun und doch ist es oftmals wichtig die Kontrolle ber die Namensgebung des Wurzelverzeichnis des Assemblies zu behalten, oder auch nur die Kontrolle darber ob es ein einziges solches Verzeichnis berhaupt gibt. Glcklicherweise erlauben zwei Konfigurationsoptionen im Kern des Assemply Deskriptors die einfache Verwaltung des Archivwurzelverzeichnisses: includeBaseDirectory und baseDirectory. In Fllen wie dem eines ausfhrbaren JARs, bentigen Sie fr gewhnlich gar kein Archivwurzelverzeichnis. Sie bergehen dies indem Sie die Eigenschaft includebaseDirectory auf false setzen, diese ist standardmssig auf true gesetzt. Das Ergebnis ist ein Archiv das beim Entpacken mehr als ein Verzeichnis im Zielverzeichnis erstellt. Dies wird bei Verzeichnissen welche zum Entpacken erstellt werden nicht gerne gesehen, ist jedoch im Fall von Archiven welche zum direkten Konsum gedacht sind, wie z.B. ausfhrbare JARs, erlaubt. In anderen Fllen ist es wichtig den Namen des Wurzelverzeichnis eines Archivs zu bestimmen, unabhngig von dessen POM Version oder anderen Informationen. Standardmssig ist der Wert des Elements baseDirectory auf ${project.artifactId}-${project.version} gesetzt. Es kann jedoch auf jeglichen Wert welcher aus einfachen Strings oder Ausdrcken welche im Kontext des aktuellen POM ausgewertet werden knnen gesetzt werden. So zum Beispiel ${project.groupId}-${project.artifactId}. Und das knnte gute Neuigkeiten fr Ihr Dokumentationsteam verheissen - Sie haben doch auch eins, oder? Eine weitere zur Verfgung stehende Mglichkeit ist die Einstellung 338

Maven Assemblies
includeSiteDirectory,

dessen Standardwert false ist. Sollte Ihr Projekt zugleich einen Website erstellen, unter Einsatz des Site Lifecycle oder des Goals Site Plugin, so kann deren Ausgabe eingebunden werden, indem diese Einstellung auf true gesetzt wird. Allerdings ist diese Funktion etwas eingeschrnkt, da es lediglich das outputDirectory des Abschnitts reporting des aktuellen POM einschliesst (Standard ist target/site) und bercksichtigt keinerlei Site Verzeichnisse welche in Unterprojekten vorhanden sein knnten. Benutzen Sie es wenn es Ihnen ntzt, eine gute fileSet- oder moduleSet Spezifikation mit entsprechenden Quellen konfiguriert, wird Ihnen den gleichen oder besseren Dienst tun. Dies ist ein weiteres Beispiel der Unterstzung von Funktionalitt zur Wahrung der Rckwrtskompatibilitt. Ihre Ansprche mgen unterschiedlich sein, sollten Sie jedoch einen Site erstellen, welcher sich aus den Ausgaben verschiedener Module zusammensetzt, sollten Sie den Einsatz von fileSets oder moduleSets erwgen, anstatt die Einstellung includeDirectory auf true zu setzen.

12.5.8. componentDescriptors und


containerDescriptorHandlers Um nun die Vorstellung des Assembly Deskriptors abzuschliessen sollten wir noch zwei weitere Abschnitte erwhnen: containerDeskriptorHandlers und componentDeskriptors. Der Abschnitt containerDescriptorHandlers bezieht sich auf massgeschneiderte Komponenten welche Sie einsetzen um die Funktionalitten des Assembly Plugins zu erweitern. Um genauer zu sein, diese Komponenten erlauben es Ihnen, bestimmte Dateien zu bestimmen und zu bearbeiten, welche unter Umstnden sich aus einer ganzen Anzahl Teilbausteinen der Inhalte des Archivs zusammensetzen. Ein gutes Beispiel ist eine Komponente welche aus den web.xml-Dateien von Teilbausteinen und WAR-Fragmenten des Assemblies eine einzige web.xml-Datei zusammensetzt, die bentigt wird um das resultierende Archiv als WAR einzusetzen. The componentDescriptors section allows you to reference external assembly-descriptor fragments and include them in the current descriptor. Component references can be any of the following: 339

Maven Assemblies Die Einstellung componentDescriptors ermglicht Ihnen externe Assembly Deskriptor Fragmente zu erstellen und diese in den aktuellen Deskriptor einzubinden. Derartige externe Referenzen knnen von folgender Art sein: 1. Relative Dateipfade: src/main/assembly/component.xml 2. Artifact Referenzes: groupId:artifactId:version[:type[:classifier]] 3. Klassenpfad Resourcen: /assemblies/component.xml 4. URLs: http://www.sonatype.com/component.xml Bei der Auflsung eines Komponenten Deskriptors wird - nicht ganz zufllig vom Assembly Plugin dieselbe Abfolge abgearbeitet. Die erste zum Erfolg fhrende Referenz kommt zum Einsatz. Komponenten Deskriptoren knnen viele der inhaltsorientierten Abschnitte des Assembly Deskriptors beinhalten mit der Ausnahme von moduleSets, welche als derart projektspezifisch angesehen werden, dass es diese keinen guten Kandidaten zur Wiederverwendung abgeben knnten. Ebenfalls Teil des Komponenten Deskriptors ist der oben erwhnte Abschnitt containerDescriptorHandler. Komponenten Deskriptoren knnen keine Formate, assembly id's oder andere Konfigurationen welche in Relation zum Wurzelverzeichnis des Assembly Archivs stehen, da alle diese einzigartig in der Beziehung zu einem bestimmten Assembly Deskriptor gesehen werden. Auch wenn es Sinn machen wrde den Abschnitt ber Formate wiederzuverwenden, diese Eigenschaft wurde bis Version 2.2-beta-2 des Assembly Plugin nicht realisiert.

12.6. Best Practices


Das Assembly Plugin bietet gengend Freiheiten um viele Probleme auf unterschiedliche Art und Weise zu lsen. Sollten Sie eine einzigartige Anforderung in Ihrem Projekt vorfinden, so ist die Warscheinlichkeit hoch, dass Sie eine der nachfolgend dokumentierten Strategien zum Einsatz bringen knnen, um beinahe jede mgliche Struktur zu erstellen. Dieser Abschnitt nun soll Ihnen die 340

Maven Assemblies verbreiteten Best Practices aufzeigen, welche, so Sie sich daran halten, den Einsatz des Assembly Plugins produktiver und weniger schmerzhaft gestalten knnen.

12.6.1. Standardisierte, wiederverwendbare Assembly Descriptoren


Bislang haben wir uns hauptschlich damit befasst einmalige Lsungen zu erarbeiten. Lsungen welche einen bestimmten Typ von Assembly erzeugen. Was aber macht man wenn man duzende Projekte hat welche alle einen bestimmten Typ von Assembly bentigen? Kurz gesagt, wie knnen wir den Aufwand welchen wir aufgebracht haben ein Assembly genau so hinzubekommen wie wir es bentigen, sicherstellen und diesen Assembly Deskriptor fr andere Projekte wiederverwenden ohne hierbei auf copy & paste zurckzugreifen? Die einfachste Antwort ist den Assembly Deskriptor in einen standardisierten, versionierten Artefakten zu berfhren und diesen zu verffentlichen. Mit der Verffentlichung ist es Ihnen mglich, festzulegen, dass der Assembly Deskriptor als Plugin Abhngigkeit innerhalb des Assembly Plugin Abschnitt des POM definiert wird. Dies fhrt dazu, dass Maven die Abhngigkeit auflst und den Artefakt in den Klassenpfad einfgt. Damit knnen Sie den Assembly Deskriptor mittels dem Abschnitt descriptorRefs der Konfiguration in der Assembly Plugin Deklaration einbinden. Um dies auszufhren, hier ein beispielhafter Assembly Deskriptor:
<assembly> <id>war-fragment</id> <formats> <format>zip</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <dependencySets> <dependencySet> <outputDirectory>WEB-INF/lib</outputDirectory> </dependencySet> </dependencySets> <fileSets> <fileSet> <directory>src/main/webapp</directory> <outputDirectory>/</outputDirectory> <excludes> <exclude>**/web.xml</exclude>

341

Maven Assemblies
</excludes> </fileSet> </fileSets> </assembly>

In Ihr Projekt eingebunden bietet dieser Deskriptor einen ntzlichen Weg den Projektinhalt in einer Art und Weise zu bndeln, dass dieser direkt in eine bestehende Webanwendung entpackt werden kann, um diese zu erweitern (um zum Beispiel eine Erweiterung einzufgen). Sollten Sie jedoch mehr als eines dieser Anwendungsfragmente erzeugen, so ist es gut mglich, dass Sie diesen Assembly Deskriptor vorzugsweise wiederverwenden und nicht kopieren wollen. Um diesen Deskriptor als eigenstndigen Artefakten zu verffentlichen, packen wir diesen in ein eigenes Projekt im Verzeichnis src/main/resources/assemblies. Die Projektstruktur dieses Assembly Deskriptor sieht wie folgt aus:
|-- pom.xml `-- src `-- main `-- resources `-- assemblies `-- web-fragment.xml

Beachten Sie den Pfad unserer web-fragment.xml Datei, des Deskriptors. Standardmssig wird Maven Dateien aus der Verzeichnisstruktur src/main/resources in das endgltige Archiv (JAR) einfgen. Das bedeutet aber auch, dass unser Deskriptor ohne weitere Konfiguration eingefgt wird. Beachten Sie auch den vorangestellten Pfad /assemblies; das Assembly Plugin erwartet diesen Zusatz vor allen Deskriptoren welche im Klassenpfad enthalten sind. Es ist also wichtig, dass wir unseren Deskriptor an der korrekten, relativen Stelle ablegen, damit dieser vom Assembly Plugin zur Zeit der Verarbeitung gefunden werden kann. Beachten Sie darber hinaus, dass dieses Projekt getrennt von Ihrem WebFragment Projekt besteht. Der Assembly Deskriptor wurde ein eigener Artefakt mit eigener Version und vielleicht sogar eigenem Lebenszyklus. Sobald sie dieses neue Projekt mit Maven installieren werden Sie in der Lage sein es in Ihrem WebFragment Projekt zu referenzieren. Um dies zu veranschaulichen, Ihr Build Prozess sollte nun ungefair so aussehen: 342

Maven Assemblies
$ mvn install (...) [INFO] [install:install] [INFO] Installing (...)/web-fragment-descriptor/target/\ web-fragment-descriptor-1.0-SNAPSHOT.jar to /Users/~/.m2/repository/org/sonatype/mavenbook/assemblies/\ web-fragment-descriptor/1.0-SNAPSHOT/\ web-fragment-descriptor-1.0-SNAPSHOT.jar [INFO] --------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] --------------------------------------------------------------[INFO] Total time: 5 seconds (...)

Da es zum Web-Fragment-Deskriptor Projekt keine Quellen gibt, wird der erzeugte JAR-Artefakt lediglich unseren web-fragment Assembly Deskriptor beinhalten. Lassen Sie uns also nun den Deskriptor Artefakten einbinden:
<project> (...) <artifactId>my-web-fragment</artifactId> (...) <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-2</version> <dependencies> <dependency> <groupId>org.sonatype.mavenbook.assemblies</groupId> <artifactId>web-fragment-descriptor</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <executions> <execution> <id>assemble</id> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <descriptorRefs> <descriptorRef>web-fragment</descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin> (...) </plugins>

343

Maven Assemblies
</build> (...) </project>

Zwei Dinge stechen bei dieser Assembly Plugin Konfiguration heraus: Wir mssen eine Abhngigkeit auf der Stufe des Plugins bezglich unserem neu hinzugefgten web-fragment Artefact einfgen, um auf den Assembly Deskriptor mittels Klassenpfad zugreifen zu knnen. Da wir statt einer Dateistruktur oder Referenz auf ein lokales Reppository eine Referenz auf den Klassenpfad benutzen, ist es notwendig den Abschnitt descriptorRefs statt descriptor zu einzusetzen. Beachten Sie auch, dass obwohl der Assembly Deskriptor tatschlich unter assemblies/web-fragment.xml liegt, wir die Lokation innerhalb des Klassenpfades ohne den vorangestellten Zusatz /assemblies angeben. Dies, da das Assembly Plugin davon ausgeht, dass mitgelieferte Assembly Deskriptoren immer im Klassenpfad unter diesem Zusatz zu finden sind. Mit diesen Schritten bleibt es Ihnen frei die POM Konfiguration so oft Sie wollen in Projekten wiederzuverwenden, und das mit der Sicherheit, dass alle web-fragment-Assemblies genau gleich sind. Sollten Sie am Assembly nderungen vornehmen mssen, zum Beispiel um weitere Resourcen einzuschliessen oder die Abhngigkeiten oder Datei Stze anzupassen - Sie knnen einfach die Version des Assembly Deskriptors anpassen und den Deskriptor erneut verffentlichen. POMs welche den Assembly Deskriptor referenzieren, knnen diesen Artefakten nach deren ermessen einbinden. Noch eine abschliessende Bemerkung bezglich Assembly Deskriptor Wiederverwendung: Es macht durchaus Sinn auch die Plugin Konfiguration wiederzuverwenden, zustzlich zur Verffentlichung des Deskriptors als Artefakt. Das ist einfach zu bewerkstelligen: Sie fgen einfach die zuvor ausgefhrte Konfiguration des Abschnitts pluginManagement in Ihr oberstes POM ein. Anschliessend referenzieren Sie die gefhrte Plugin Konfiguration innerhalb Ihren Moduls wie folgt:
(...) <build>

344

Maven Assemblies
<plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> </plugin> (...)

Sollten Sie die ausstehende Plugin Konfiguration - im vorhergehenden Beispiel dargestellt - zum Abschnitt pluginManagement ihres bergeordneten obersten POM zugefgt haben, so wird jedes Projekt welches von diesem POM erbt durch anfgen eines minimalen Eintrages wie dem oben ausgefhrten, die Vorteile der Konfiguration nutzen, und von einem fortschrittlichen Assembly Format whrend des Build Gebrauch machen knnen.

12.6.2. Verteilung (Aggregierung) von Assemblies


Wie oben ausgefhrt bietet das Assembly Plugin viele unterschiedliche Mglichkeiten um verschiedenerlei Archivformate zu erstellen. Archive fr die Distribution sind gewhnlich sehr gute Beispiele hierfr, da diese oftmals verschiedene Module eines multi-modularen Build mit deren Abhngigkeiten und weiteren Dateien und Artefakten zusammenfassen. Eine Distribution zielt darauf ab, alle verschiedenen Quellen in ein einziges Archiv zusammenzufassen welches der Benutzer bequem herunterladen, entpacken und mit Zuversicht ausfhren kann. Wir haben aber auch die potentiellen Nachteile betrachtet die es beim Einsatz von moduleSets im Assembly Deskriptor geben kann - dem, dass im Fall von hierarchischer Beziehungen zwischen benachbarten POMs ein Build verunmglicht wird, da bestimmte Artefakte in bestimmten Fllen nicht zur Verfgung stehen. Insbesondere im Fall, dass ein Modul POM dessen bergeordnetes POM referenziert, wobei dieses eine Konfiguration eines Assembly Plugins beinhaltet. Hierbei wird im Falle eines multi-modularen Build das bergeordnete POM vor den Modul POM erstellt. Das bergeordnete Assembly erwartet fr dessen Module gewisse Artefakte vorzufinden, wobei diese Module hierbei darauf warten dass der Build des bergeordneten Projektes abschliesst. Somit kann der Build nicht abgeschlossen werden (da dieser die Artefakte der Module unmglich finden kann!). In anderen Worten, die untergeordneten Projekte hngen von den 345

Maven Assemblies bergeordneten, und diese wiederum von den untergeordneten Projekten ab. Beispielhaft wollen wir diese Situation am unten ausgefhrten Assembly Deskriptor ausfhren. Es ist darauf ausgelegt in einem Projekt der obersten Hierarchiestufe einer multi-modularen Hierarchie ausgefhrt zu werden.
<assembly> <id>distribution</id> <formats> <format>zip</format> <format>tar.gz</format> <format>tar.bz2</format> </formats> <moduleSets> <moduleSet> <includes> <include>*-web</include> </includes> <binaries> <outputDirectory>/</outputDirectory> <unpack>true</unpack> <includeDependencies>true</includeDependencies> <dependencySets> <dependencySet> <outputDirectory>/WEB-INF/lib</outputDirectory> </dependencySet> </dependencySets> </binaries> </moduleSet> <moduleSet> <includes> <include>*-addons</include> </includes> <binaries> <outputDirectory>/WEB-INF/lib</outputDirectory> <includeDependencies>true</includeDependencies> <dependencySets> <dependencySet/> </dependencySets> </binaries> </moduleSet> </moduleSets> </assembly>

Im gegebenen Fall eines bergeordneten Projektes - genannt app-parent - welches aus drei Modulen besteht app-core, app-web und app-addons, beachten Sie was passiert beim Versuch das Projekt zu erstellen passiert:
$ mvn package

346

Maven Assemblies
[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/distro.xml [INFO] --------------------------------------------------------------[ERROR] BUILD ERROR [INFO] --------------------------------------------------------------[INFO] Failed to create assembly: Artifact: org.sonatype.mavenbook.assemblies: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. ...

Das in der Hierarchie hchststehende Projekt - app-parent - wird zuerst erstellt. Dies aufgrund der Tatsache, dass alle anderen Projekte dieses POM als deren bergeordnetes Projekt ausweisen, welches dieses an die Spitze der Build-Reihenfolge zwingt. Das Modul app-web, welches das Erste innerhalb des Assembly Deskriptor verarbeitete Modul darstellt, wurde noch nicht erstellt. Somit besteht auch noch kein assoziierter Artefakt, was dazu fhrt, das das Assembly nicht erfolgreich abgearbeitet werden kann. Ein Ausweg aus dieser Situation ist es, den Abschnitt execution der Assembly Plugin Deklaration zu entfernen, diese bindet das Plugin an die Lebenszyklus-Phase package des bergeordneten POM, belsst aber den Abschnitt der Konfiguration intakt. Daraufhin wird Maven in zwei Aufrufen ausgefhrt: zunchst mit dem Goal package, um den den multi-modularen Graphen zu builden, und anschiessend in einem separaten Aufruf mit dem Goal assembly:assembly in einem direkten Aufruf des Assembly Plugin um die erstellten Artefakte des vorhergehenden Aufrufs zu verarbeiten und ein Distributionsarchiv zu erstellen. Der Aufruf eines derartigen Build knnte wie folgt aussehen:
$ mvn package assembly:assembly

Dieser Ansatz hat mehrere Nachteile. Zunchst einmal wird die Erstellung des Distributionsarchivs ein zunehmend manueller Prozess welcher die Komplexitt 347

Maven Assemblies steigert und sich negativ auf die allgemeine Fehleranflligkeit auswirkt. Zustzlich kann dieses Vorgehen dazu fhren, dass angefgte Artefakte - welche wrend eines Buildlaufes in Memory zur Verfgung stehen - nun nicht mehr erreichbar sind und daher ein zweiter Lauf auf Referenzen welche sich auf das Dateisystem richten notwendig machen. Statt Artefakte mittels einem modulSet aus dem multi-modularen Build zusammenzufhren, lohnt es sich oftmals auch eine ganz bodenstndige Lsung anzuwenden: der Einsatz eines dedizierten Projekt Moduls fr die Distribution und dem Einsatz von inter-Projekt Abhngigkeiten. Mit diesem Ansatz erstellen Sie ein Projekt, dessen einzige Aufgabe darin besteht, eine Distribution Ihres Projektes zu erstellen. Dessen POM enthlt Abhngigkeitsreferenzen zu allen anderen Modulen der Projekthierarchie und konfiguriert das Assembly Plugin. Hierbei wird dieses an die Lebenszyklusphase package gebunden. Der Assembly Deskriptor selbst beruht auf dem Abschnitt dependencySets statt wie zuvor moduleSets um die Artefakte zu bndeln und zu definieren was denn schliessendlich Teil des Distributionsarchivs wird. Dieser Ansatz umgeht die oben angesprochene Tcke der hierarchischen Beziehungen und hat den zustzlichen Vorteil, dass der Abschnitt der Konfiguration innerhalb des Assembly Deskriptors wesentlich einfacher ist. Um diesen Ansatz umzusetzen erstellen wir eine Projektstruktur die der des oben ausgefhrten ModulSet-Ansatzes sehr hnlich ist. Einschliesslich des neuen Distributionsprojektes kommen wir so zu einem Satz von insgesamt fnf Projekten: app-parent, app-core, app-web, app-addons sowie app-distribution. Das neue POM des Projektes app-distribution, wird ungefair wie dieses aussehen:
<project> <parent> <artifactId>app-parent</artifactId> <groupId>org.sonatype.mavenbook.assemblies</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>

348

Maven Assemblies
<groupId>org.sonatype.mavenbook.assemblies</groupId> <version>1.0-SNAPSHOT</version> <type>war</type> </dependency> <dependency> <artifactId>app-addons</artifactId> <groupId>org.sonatype.mavenbook.assemblies</groupId> <version>1.0-SNAPSHOT</version> </dependency> <!-- Not necessary since it's brought in via app-web. <dependency> [2] <artifactId>app-core</artifactId> <groupId>org.sonatype.mavenbook.assemblies</groupId> <version>1.0-SNAPSHOT</version> </dependency> --> </dependencies> </project>

Beachten Sie bitte, dass wir die Abhngigkeiten zu den anderen Modulen der Projektstruktur aufnehmen mssen, da wir in diesem POM keinen Abschnitt modules haben, auf welchen wir uns absttzen knnten. Zu bemerken ist darberhinaus, dass wir keine explizite Abhngigkeit zu app-core definieren, da dies ja bereits in einer Abhngigkeit zu app-web steht, mssen wir diese Abhngigkeit nicht doppelt verarbeiten (oder deren Vearbeitung ein zweites mal verhindern). Daraufhin, mit dem, dass wir den distro.xml Assembly Deskriptor in das Projekt app-distribution verlagern, mssen wir diesen noch Anpassen um den Abschnitt dependencySets zu benutzen, wie folgt:
<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>

349

Maven Assemblies
</dependencySet> </dependencySets> ... </assembly>

Wenn wir den Build aus dem obersten Projekt dieses Mal anstossen, bekommen wir ein besseres Resultat:
$ mvn package (...) [INFO] --------------------------------------------------------------[INFO] Reactor Summary: [INFO] --------------------------------------------------------------[INFO] module-set-distro-parent ...............SUCCESS [3.070s] [INFO] app-core .............................. SUCCESS [2.970s] [INFO] app-web ............................... SUCCESS [1.424s] [INFO] app-addons ............................ SUCCESS [0.543s] [INFO] app-distribution ...................... SUCCESS [2.603s] [INFO] --------------------------------------------------------------[INFO] --------------------------------------------------------------[INFO] BUILD SUCCESSFUL [INFO] --------------------------------------------------------------[INFO] Total time: 10 seconds [INFO] Finished at: Thu May 01 18:00:09 EDT 2008 [INFO] Final Memory: 16M/29M [INFO] ---------------------------------------------------------------

Wie Sie leicht sehen knnen, ist der Ansatz ber dependencySets wesentlich robuster und -zumindest bis die Maven eigene Logik zur Projekt-Ordnung mit den Mglichkeiten des Assembly Plugin aufgeholt hat - bietet weniger Mglichkeiten Fehler zu machen.

12.7. Zusammenfassung
Wie wir in diesem Kapitel gesehen haben, das Maven Assembly Plugin bietet viele Mglichkeiten massgeschneiderte Archivformate zu erstellen. Obschon die Detaildefinitionen der Archive sehr komplex werden knnen, dass Sie dies nicht mssen sehen wir zum Beispiel beim Einsatz der mitgelieferten/eingebauten standard Assembly Deskriptoren. Auch wenn es Ihr Ziel ist, ihres Projekts Abhngigkeiten und ausgewhlte Projektdateien in einer einzigartigen Archivstruktur zusammenzufhren, so muss die Erstellung des zugehrigen Assembly Deskriptors keine beschwerliche Aufgabe sein. 350

Maven Assemblies Assemblies sind fr eine breite Palette Anwendungen ntzlich, werden aber gewhnlich dazu eingesetzt Distributionen verschiedener Arten zu erstellen. Whrend es viele verschiedene Mglichkeiteb gibt das Assembly Plugin einzusetzen so ist der Einsatz standardisierter Assembly Deskriptoren und die Vermeidung von modulSets im Fall von Distributionen welche Binrdateien enthalten sind zwei sichere Wege Probleme zu vermeiden.

351

Chapter 13. Properties and Ressource Filterung


13.1. Einleitung
In diesem Buch finden Sie durchgngig Hinweise auf Properties (Eigenschaften) welche Sie in POM-Dateien referenzieren knnen. Auf geerbte Abhngigkeiten eines multi-projekt Builds kann mittels der Properties ${project.groupId} sowie ${project.version} zugegriffen werden und jeder Abschnitt eines POM kann referenziert werden indem man einer Variablen die Vorsilbe project. Anfgt. Umgebungsvariablen und Java System Einstellungen knnen referenziert werden, wie auch alle Einstellungen aus Ihrer ~/.m2/settings.xml Datei. Was Ihnen noch nicht auf den Weg gegeben wurde ist eine Aufstellung der mglichen Property Variablen, und eine Beschreibung wie diese zum Einsatz kommen um einen portablen Build zu erstellen. Dieses Kapitel nun liefert Ihnen diese Aufstellung. Sollten Sie bereits Property Referenzen in Ihrem POM einsetzen, so sollte Ihnen ebenfalls bewusst sein, dass Maven eine Funktionalitt mit dem Namen Ressource Filter anbietet, welche Ihnen erlaubt, jegliche Property Referenz zu ndern, welche in einer Ressource Datei unter src/main/resources abgelegt ist. Standardmssig ist diese Funktion deaktiviert, um unbeabsichtigte Vernderung von Property Referenzen zu verhindern. Diese Funktionalitt kann jedoch Einsatz finden, um einen Build auf eine bestimmte Plattform zu richten, oder um wichtige Property Einstellungen in Ressource Dateien, POMs oder Profilen zu externalisieren. Dieses Kapitel hat zum Ziel, die Funktionalitt des Ressource Filtering darzustellen und gibt eine kurze Einfhrung wie diese zum Einsatz kommt um einen portablen Enterprise Build herzustellen.

13.2. Maven Properties


Sie knnen Maven Properties in einer pom.xml Datei, oder irgendeiner anderen 352

Properties and Ressource Filterung Ressource ablegen, welche vom Maven Ressource Plugin und dessen Filter Funktion verarbeitet wird. Ein Property ist immer umschlossen von ${ und } . Um auf das Property project.version zu referenzieren, wrden Sie folgende Variable benutzen:
${project.version}

Es bestehen einige implizite Maven Properties, diese sind:


project.*

Maven Project Objekt Modell (POM). Benutzen Sie das Prfix project.* um Werte des Maven POM zu referenzieren.
settings.*

Maven Settings; Benutzen Sie das Prfix settings.* um Werte aus der lokalen Maven Settings Datei (gewhnlich unter ~/.m2/settings.xml zu referenzieren.
env.*

Umgebungsvariables wie z.B. PATH sowie M2_HOME knnen mittels dem Prfix env.* benannte werden. System Properties Jeglicher Wert welcher durch die System.getProperty() Methode abgefragt werden kann, kann als Maven Property referenziert werden. Zustzlich zu den impliziten Properties wie oben dargestellt, knnen das Maven POM, die Maven Settings Datei sowie das Maven Profil weitere freidefinierte Werte enthalten. Der folgende Abschnitt wird Ihnen einigen Einblick in die verschiedenen in einem Maven Projekt verfgbaren Werte geben.

13.2.1. Maven Projekt Einstellungen


Immer wenn ein Maven Projekt Property referenziert wird, zeigt der Name des Property auf einen Wert des Projekt Objekt Modell (POM). Genauer gesagt, Sie setzen eine Referenz auf ein Property der Klasse org.apache.maven.model.Model welche als implizite Projektvariable dargestellt wird. Wollen Sie sich auf ein 353

Properties and Ressource Filterung Property dieser impliziten Variablen beziehen, so wenden Sie die einfache Punkt-Notation an, um auf ein Bean-Property des Modell-Objektes zu zeigen. Referenzieren Sie zum Beispiel ${project.version}, so rufen Sie tatschlich die Methode getVersion() der Instanz des Modell Objektes auf, als welches das Projekt offengelegt wird. Das POM wird ebenfalls durch die Datei pom.xml dargestellt, welche in allen Maven Projekten prsent ist. Alle Bestandteile des Maven POM knnen als Property angesprochen werden. Eine komplette Referenz der POM Struktur finden Sie unter http://maven.apache.org/ref/2.0.9/maven-model/maven.html. In der folgenden Liste werden wir einige der hufiger gebrauchten Referenzen auf Maven Projekt Properties ausfhren:
project.groupId, project.version

Projekte die Bestandteil eines grossen multi-modularen Build sind, benutzen hufig die selbe groupId und version Bezeichner. Sollten Sie Abhngigkeiten zwischen verschiedenen Modulen deklarieren welche die gleiche groupId und version tragen, so tun Sie gut daran, fr beide eine Property Referenz zu definieren:
<dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>sibling-project</artifactId> <version>${project.version}</version> </dependency> </dependencies>

project.artifactId

Die artifactId eines Projektes wird oft als Name eines Paketes eingesetzt. So mchten Sie, im Falle eines Projektes das als WAR paketiert wird, ein WAR ohne Versionsbezug im Namen generieren. Um dies zu bewerkstelligen wrden Sie project.artifactId wie folgt referenzieren:
<build> <finalName>${project.artifactId}</finalName> </build>

354

Properties and Ressource Filterung


project.name, project.description

Der Name und die Projektbeschreibung sind ofmals ntzliche Referenzen in einer Dokumentation. Anstatt sich damit abzumchen, dass der gesamte Site die gleiche Kurzbeschreibung benutzt, ist es viel einfacher diese Werte zu referenzieren.
project.build.*

Sollten Sie sich auf Ausgabeverzeichnisse berufen mssen, so vermeiden Sie den Einsatz von direkten Bezgen zu den Verzeichnissen wie z.B. target/classes. Statt dessen sollten Sie Property Referenzen auf die Verzeichnisse setzen.
project.build.sourceDirectory project.build.scriptSourceDirectory project.build.testSourceDirectory project.build.outputDirectory project.build.testOutputDirectory project.build.directory

sourceDirectory, scriptSourceDirectory,

und testSourceDirectory geben Ihnen Zugriff auf die Quellverzeichnisse des Projektes. outputDirectory sowie testOutputDirectory geben Ihnen Zugriff auf die Verzeichnisse, welche Maven nutzt um den Byte Code oder Build Output abzulegen. directory bezieht sich auf das Verzeichnis, das alle derartigen Ausgabeverzeichnisse umfasst. Weitere Projekt Property Referenzes Darber hinaus gibt es hunderte Properties welche man innerhalb eines POM referenzieren kann. Eine vollstndige Referenz des POM finden Sie unter http://maven.apache.org/ref/2.0.9/maven-model/maven.html. Sollten Sie eine vollstndige Dokumentation der Maven Modell Objekt Properties 355

Properties and Ressource Filterung bentigen, so bitte wir Sie auf die JavaDoc des Projektes maven-model zurckzugreifen, diese finden Sie unter: http://maven.apache.org/ref/2.0.9/maven-model/apidocs/index.html. Nach dem Laden der JavaDoc, sehen Sie sich die Klasse Model an. Von dieser Klasse aus sollten Sie alle von Ihnen gesuchten POM Properties ansteuern knnen. Sollten Sie das Ausgabeverzeichnis des Builds referenzieren wollen, so sehen Sie in der Maven Model JavaDoc, dass dieses mittels model.getBuild().getOutputDirectory(); erfolgt. Diesen Methodenaufruf wrden Sie in die Maven Property Referenz: ${project.build.outputDirectory} wiederfinden. Bezglich weiterer Informationen zum Maven Model Module, dem Modul, welches die Struktur des POM definiert, mchten wir auf die Maven Model Seite unter http://maven.apache.org/ref/2.0.9/maven-model verweisen.

13.2.2. Properties der Maven Einstellungen (settings.xml)


Sie knnen auf jedes Property der lokalen Einstellungsdatei zugreifen, welche normalerweise unter ~/.m2/settings.xml abgelegt ist. Diese Datei enthlt benutzerspezifische Einstellungen bezglich der Maven Installation wie z.B. dem Ort des lokalen Repository, der lokalen Server Infrastruktur, Profilen sowie Spiegel-Repositorien wie diese von einem Benutzer definiert wurden. Eine ausfhrliche Referenz der lokalen Einstellungen sowie der entsprechenden Properties finden Sie unter http://maven.apache.org/ref/2.0.9/maven-settings/settings.html.

13.2.3. Properties der Umgebungsvariablen


Umgebungsvariablen werden mit einem vorangestellten env.* eingeleitet. Einige der interessanteren Umgebungsvariablen sind in der folgenden Liste aufgefhrt:
env.PATH

Enthlt den aktuellen Pfad (PATH)in welchem Maven luft. PATH enthlt eine 356

Properties and Ressource Filterung Liste von Verzeichnissen, in welchen ausfhrbare Skripte und Programme gesucht werden sollen.
env.HOME

(Unter *nix Systemen) zeigt diese Variable auf das Heimatverzeichnis des Benutzers. Besser und portabler ist es statt dessen ${user.home} einzusetzen.
env.JAVA_HOME

Enthlt das Java Installationsverzeichnis. Dieses wird entweder auf einen Java Development Kit (JDK) oder auf eine Java Laufzeitumgebung (JRE) zeigen. Es empfiehlt sich statt dessen ${java.home} zu benutzen.
env.M2_HOME

Beinhaltet das Maven 2 Installationsverzeichnis Solange die Java System Einstellungen verfgbar sind, sollten Sie diese einsetzen. Um auf das Heimatverzeichnis eines Benutzers zuzugreifen benutzen Sie ${user.home} statt ${env.HOME}. Sie erzeugen damit einen portablerern Build welcher dem Versprechen von Write-One-Run-Anywhere (WORA) der Java Plattform nherkommt.

13.2.4. Java System Properties


Maven legt alle Properties von java.lang.System offen. Alle Daten, welche Sie mittels System.getProperty() beziehen knnen, sind auch fr Maven angreifbar. Die nachfolgende Tabelle fhrt die verfgbaren Properties auf: Table 13.1. Java System Properties System Property
java.version java.vendor

Beschreibung Java Laufzeitumgebung Version Java Laufzeitumgebung Hersteller Java Hersteller URL Java Installationsverzeichnis 357

java.vendor.url
java.home

Properties and Ressource Filterung System Property


java.vm.specification.version

Beschreibung Java Virtual Machine Spezifikation Version Java Virtual Machine Spezifikation Hersteller Java Virtual Machine Spezifikation Name Java Virtual Machine Implementierung Version Java Virtual Machine Implementierung Hersteller Java Virtual Machine Implementierung Name Java Laufzeitumgebung Spezifikation Version Java Laufzeitumgebung Spezifikation Hersteller Java Laufzeitumgebung Spezifikation Name Java Klassenformat Versionsnummber Java Klassenpfad Pfad zum Verzeichnis der Erweiterungen Betriebssystem Name Betriebssystem System Architekture Betriebssystem System Version Datei Trennzeichen ("/" auf UNIX, "\" auf Windows) 358

java.vm.specification.vendor

java.vm.specification.name java.vm.version

java.vm.vendor

java.vm.name

java.specification.version

java.specification.vendor

java.specification.name

java.class.version java.class.path java.ext.dirs os.name os.arch os.version file.separator

Properties and Ressource Filterung System Property


path.separator

Beschreibung Pfad Trennzeichen (":" auf UNIX, ";" auf Windows) Zeilenumbruch ("\n" auf UNIX und Windows) Benutzerkonto Name Benutzerverzeichnis (home) Aktuelles Arbeitsverzeichnis (des Benutzers)

line.separator

user.name user.home user.dir

13.2.5. Benuzerdefinierte Properties


Zustzlich zu den implizit von POM, den Maven Einstellungen, Umgebungsvariablen und Java System Einstellungen bereitgestellten Properties haben Sie die Mglichkeit Ihre eigenen beliebigen Properties zu setzen. Properties knnen als Teil eines POM oder Profil definiert werden. Die Menge der Properties eines POMs oder Maven Profils kann wie alle anderen Properties in Maven angesprochen werden. Benutzerdefinierte Properties knnen innerhalb einer POM Datei referenziert werden, oder Sie knnen eingesetzt werden um Ressourcen mittels dem Maven Resource Plugin zu filtern. Hier ein Beispiel wie man ein beliebiges Property innnerhalb einer POM Datei definiert: Example 13.1. Definition eines benutzerdefinierten Property im POM
<project> ... <properties> <arbitrary.property.a>This is some text</arbitrary.property.a> <hibernate.version>3.3.0.ga</hibernate.version> </properties> ... <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId>

359

Properties and Ressource Filterung


<version>${hibernate.version}</version> </dependency> </dependencies> ... </project>

Das vorgehende Beispiel definiert zwei Properties: arbitrary.property.a und hibernate.version. hibernate.version wird innerhalb einer Abhngigkeitsdefinition eingesetzt. Der Einsatz des Punkt-Zeichens (.) als Trennzeichen in Propertynamen hat sich als gngige Schreibweise fr Properties durchgesetzt; Fr Maven ist hibernate.version lediglich ein Schlssel um den Wert 3.3.0.ga aufzufinden. Example 13.2. Definition eines benutzerdefinierten Property innerhalb einer Profildefinition im POM
<project> ... <profiles> <profile> <id>some-profile</id> <properties> <arbitrary.property>This is some text</arbitrary.property> </properties> </profile> </profiles> ... </project>

Das vorangegangene Beispiel verdeutlicht wie man ein benutzerdefiniertes Property innerhalb einer Profildefinition eines Maven POM definiert. Weitere Details und Informationen bezglich benutzerdefinierter Properties und Profilen finden sie im Chapter 11, Build-Profile (Kapitel 11: Build Profile).

13.3. Ressource Filterung


Sie knnen Maven auch dazu einsetzen, Variablen innerhalb von Projektressourcen zu ersetzen. Sobald Ressourcen Filterung aktiviert ist, durchsucht Maven 360

Properties and Ressource Filterung Ressourcen nach Property Referenzen eingeschlossen in ${ und}. Sobald es eine derartige Referenz gefunden hat, ersetzt es diese mit dem entsprechenden Wert ganz hnlich wie dies auch mit den Property Referenzen eines POM geschieht und im letzen Abschnitt beschrieben wurde. Diese Mglichkeit ist insbesondere dann hilfreich, wenn es notwendig wird einen Build zu parametrisieren um verschiede Konfigurationen zu bergeben, abhngig von der entsprechenden Zielplattform. Oftmals wird eine Datei .properties oder ein XML Dokument unter /src/main/resources die Definition externer Ressource wie Datenbankverbindungen oder Netzwerkparameter enthalten, welche abhngig von der Zielplatform unterschiedlich konfiguriert werden mssen. So hat z.B. ein System welches von einer Datenbank lesen muss eine Datei welche die JDBC URL zusammen mit den entsprechenden Parametern fr den Datenbankzugriff angibt. Benutzen Sie eine andere Datenbank whrend der Entwicklung als in der Produktion (was zu erwarten ist), so knnen Sie entweder diese Ressourcedefinition mittels einer Technologie wie z.B. JNDI externalisieren, oder aber Sie generieren einen Build welcher es versteht, die Zielplattform abhngigen Werte mit den entsprechenden Werten zu setzen. Unter Einsatz von Maven Ressource Filterung knnen Sie Maven Properties setzen und diese dann mittels Maven Profilen entsprechend der bentigten Zielplattform definieren. Um diese Mglichkeit zu illustrieren, hier ein Beispiel: gehen Sie davon aus, dass Ihr Projekt auf dem Spring Framework beruht, welches eine BasicDataSource aus dem CommonsDBCP Projekt konfiguriert. Ihr Projekt wird also unter src/main/resources eine Datei mit dem Namen applicationContext.xml ablegen, welche die in Example 13.3, Maven Properties aus einer Ressource Datei referenzieren (Beispiel 13.3: Maven Properties aus einer Ressource Datei referenzieren) ausgefhrten Daten enthlt. Example 13.3. Maven Properties aus einer Ressource Datei referenzieren
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="someDao" class="com.example.SomeDao"> <property name="dataSource" ref="dataSource"/>

361

Properties and Ressource Filterung


</bean> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans>

Ihr Programm wrde diese Datei zur Laufzeit lesen, und Ihr Build wird Referenzen auf Properties wie z.B. jdbc.url oder jdbc.username mit den Werten welche Sie in Ihrer pom.xml-Datei setzen ersetzen. Ressource Filterung ist standardmssig ausgeschaltet, um die unbewusste und ungewollte Filterung von Werten zu verhindern. Um den Ressource Filter einzustellen, mssen Sie das abgeleitete Element resource innerhalb ihrer POM Datei setzen. Example 13.4, Definieren von Variablen und Aktivierung von Ressource Filterung (Beispiel 13.4: Definieren von Variablen und Aktivierung von Ressource Filterung) illustriert ein POM welches die Variablen aus Example 13.3, Maven Properties aus einer Ressource Datei referenzieren (Beispiel 13.3: Maven Properties aus einer Ressource Datei referenzieren) definiert und Ressource Filterung fr alle Ressourcen unter src/main/resources aktiviert Example 13.4. Definieren von Variablen und Aktivierung von Ressource Filterung
<project> ... <properties> <jdbc.driverClassName> com.mysql.jdbc.Driver</jdbc.driverClassName> <jdbc.url>jdbc:mysql://localhost:3306/development_db</jdbc.url> <jdbc.username>dev_user</jdbc.username> <jdbc.password>s3cr3tw0rd</jdbc.password> </properties> ... <build> <resources> <resource>src/main/resources</resource> <filtering>true</filtering> </resources> </build>

362

Properties and Ressource Filterung


... <profiles> <profile> <id>production</id> <properties> <jdbc.driverClassName>oracle.jdbc.driver.OracleDriver</jdbc.driverClassName> <jdbc.url>jdbc:oracle:thin:@proddb01:1521:PROD</jdbc.url> <jdbc.username>prod_user</jdbc.username> <jdbc.password>s00p3rs3cr3t</jdbc.password> </properties> </profile> </profiles> </project>

Die vier entsprechenden Variablen werden jeweils innerhalb des Elements properties definiert und Ressource Filterung wird fr Ressourcen unter src/main/ressources gesetzt. Da Ressource Filterung standardmssig deaktiviert ist, ist es notwendig fr Ihr Projekt explizit den Wert des Elements filtering auf true zu setzen. Wenn Sie nun ein Projekt mit der Ressource aus Example 13.3, Maven Properties aus einer Ressource Datei referenzieren (Beispiel 13.3: Maven Properties aus einer Ressource Datei referenzieren) und den POM Eintrgen aus Example 13.4, Definieren von Variablen und Aktivierung von Ressource Filterung (Beispiel 13.4: Definieren von Variablen und Aktivierung von Ressource Filterung) builden und Sie dann den Inhalt der Ressource unter target/classes ansehen, so sollten Sie dort die folgende, gefilterte Ressource wiederfinden:
$ mvn install ... $ cat target/classes/applicationContext.xml ... <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/development_db"/> <property name="username" value="dev_user"/> <property name="password" value="s3cr3tw0rd"/> </bean> ...

Das POM aus Example 13.4, Definieren von Variablen und Aktivierung von Ressource Filterung (Beispiel 13.4: Definieren von Variablen und Aktivierung von Ressource Filterung) definiert ebenfalls unter dem Element profiles/profile 363

Properties and Ressource Filterung ein Profile production, welches das Standardprofil mit Werten welche fr eine Produktionsumgebung sinnvoll sind, bersteuert. In diesem ausgefhrten Beispiel definiert das POM Standardwerte fr die Datenbankverbindung auf eine lokal installierte MySQL Instanz. Sollte der Build mit aktiviertem Profil production erstellt werden, so wird Maven das System derart konfigurieren, dass fortan das System gegen eine Oracle Datenbank mit anderen Treibern, URL, Benutzername und Passwort zum Zuge kommt. Wenn sie also den Build mit den oben ausgefhrten Beispielen und aktivierten Profil production ausgefhrt haben, so sollten Sie unter target/classes eine Ressource mit den unten aufgefhrten produktiven Werten auffinden.
$ mvn -Pproduction install ... $ cat target/classes/applicationContext.xml ... <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@proddb01:1521:PROD"/> <property name="username" value="prod_user"/> <property name="password" value="s00p3rs3cr3t"/> </bean> ...

364

Chapter 14. Maven in Eclipse: m2eclipse


14.1. Einfhrung
Die Eclipse IDE ist heutzutage wohl die Entwicklungsumgebung mit der grssten Verbreitung. Es gibt eine riesige Anzahl verfgbarer Plugins (http://www.eclipseplugincentral.com/) und eine unzhlbar grosse Anzahl Organisationen welche deren Software auf Eclipse entwickeln. Einfach ausgedrckt: Eclipse ist allgegenwrtig. Das m2eclipse Projekt bietet eine Maven Untersttzung von innerhalb der Entwicklungsumgebung. In diesem Kapitel werden wir die Mglichkeiten welche uns dieses Werkzeug bietet erkunden.

14.2. m2eclipse
Das m2eclipse Plugin (http://m2eclipse.codehaus.org/) bietet eine Mavenintegration fr Eclipse. M2eclipse bietet ebenfalls Mglichkeiten die Funktionen von zwei weiteren Plugins, dem Subclipse Plugin (http://subclipse.tigris.org) sowie dem Mylin Plugin (http://www.eclipse.org/mylyn) zu nutzen. Das Subclipse Plugin bietet dem m2eclipse Plugin die Mglichkeit direkt mit einem Subversion Repositorien zu interagieren und das Mylyn Plugin erweitert das m2eclipse Plugin um mit dem weit verbreiteten Mylyn Interface zu zu interagieren. Dieses hilft die bersicht im Entwicklungszusammenhang zu behalten. Hier eine Reihe Funktionalitten welche m2eclipse bietet: Erstellen sowie importieren von Maven Projekten Abhngigkeitsverwaltung und Integration mit dem Eclipse Klassenpfad Automatischer Download von Abhngigkeiten und deren Update Artefakt JavaDoc sowie Quellen Auflsung 365

Maven in Eclipse: m2eclipse Erstellen von Projekten basierend auf Maven Artefakten Durchsuchen und Suchen in entfernten Maven Repositorien POM Verwaltung mit automatischem Update der Abhngigkeitsliste Materialisierung ausgehend von einem Maven POM Auschecken eines Maven Projektes von mehreren verteilten SCM Repositorien Anpassen von verschachtelten multi-modularen Maven Projekten auf die Entwicklungsumgebung Eclipse Integration mit dem Web Tools Projekt (WTP) Integration mit AspectJ Development Tools (AJDT) Integration mit Subclipse Integration mit Mylyn Formularbasierter POM Editor Graphische Darstellung des Abhngigkeitsgraphen GUI Darstellung des Abhngigkeitsbaumes und der aufgelsten Abhngigkeiten Es gibt ber diese Liste hinaus gibt es noch viele weitere Funktionalitten welche m2eclipse bietet. Dieses Kapitel wird Sie in einige der eindrucksvolleren Fhigkeiten einfhren, welche derzeit verfgbar sind. Lassen Sie uns damit beginnen, das m2eclipse Plugin zu installieren.

14.3. Installation des m2eclipse Plugins


366

Maven in Eclipse: m2eclipse Um das m2eclipse Plugin lauffhig zu installieren, mssen etliche Voraussetzungen erfllt sein. Sie mssen mindestens auf Eclipse 3.2 aufsetzen, mindestens JDK 1.4 benutzen und sicherstellen, dass Sie auf einem JDK und nicht nur einer Java Runtime (JRE) basieren. Sobald Sie Eclipse sowie einen entsprechenden JDK am Laufen haben, mssen Sie zunchst noch zwei Plugins installieren: Subclipse und Mylyn.

14.3.1. Installieren der Voraussetzungen


Sie knnen die Voraussetzungen zusammen mit m2eclipse installieren: fgen Sie einfach die den Komponennten entsprechenden Update Sites in Eclipse an. Um diese Komponenten dann zu installieren, whlen Sie Hilfe >Software Updates >Suchen und Installieren... Es wird die Update-/Installationsschaltflche anzeigen. Whlen Sie nach neuen zu installierenden Features suchen und whlen Sei weiter. Die Anzeige wird auf xxx wechseln. Whlen Sie Neuer Remote Site und fgen Sie fr jede Komponente die entsprechende Site hinzu, stellen Sie sicher dass der entsprechende Eintrag ausgewhlt ist. Zum Abschluss wird Eclipse ihnen anbieten die ausgewhlten Komponenten zu installieren. Eclipse wird diese dann herunterladen, installieren und konfigurieren. Sollten Sie die neuere Version Eclipse 3.4 (Ganymede) benutzen, so wird die Plugin-Installation leicht von dieser Beschreibung abweichen: unter Ganymede whlen Sie Hilfe > Software Updates und ffnen hiermit den Dialog: xxx. Innerhalb dieses Fensters whlen Sie die Verfgbare Software und dann Site hinzufgen welches den Dialog Site hinzufgen" ffnen wird. Geben Sie die URL des Sites welchen Sie hinzufgen mchten ein und besttigen mit "OK". Im Dialogfenster Software Updates and Add-Ons" werden die entsprechend verfgbaren Plugins der hinzugefgten Sites erscheinen. Sie knnen nun die entsprechenden Module auswhlen und installieren. Eclipse wird die entsprechenden Abhngigkeiten auflsen und gegebenenfalls darum bitten die Software Lizenzbedingungen zu akzeptieren. Nach der Installation wird Eclipse Sie wahrscheinlich aufrufen Eclipse einem Neustart zu unterziehen. 14.3.1.1. Installation von Subclipse 367

Maven in Eclipse: m2eclipse Um Subclipse zu installieren, benutzen Sie den unten aufgefhrten Eclipse Plugin Update Site: Subclipse 1.2: http://subclipse.tigris.org/update_1.2.x Um andere Versionen von Subclipse zu installieren, oder um weitere Informationen bezglich des Subclipse Plugin zu erlagen, wenden Sie sich and den Subclipse Projekt Website: http://subclipse.tigris.org/. 14.3.1.2. Installation von Mylyn To install JIRA integration with Mylyn, add the Mylyn extras Eclipse update URL, you'll want to do this if your organization uses Atlassian's JIRA for issue tracking. To install Mylyn use the following update sites: Um die JIRA Integration mittels Mylyn zu installieren, fgen Sie die Update Site der Eclipse Mylyn Extras hinzu. Dies werden Sie insbesondere tun wollen, wenn Ihre Organisation Atlassian JIRA Issue Tracking einsetzt. Um Mylyn zu installieren, benutzen Sie einen der folgenden Update Sites: Mylyn (Eclipse 3.3): http://download.eclipse.org/tools/mylyn/update/e3.3 Mylyn (Eclipse 3.4): http://download.eclipse.org/tools/mylyn/update/e3.4 Mylyn Extras (JIRA Support): http://download.eclipse.org/tools/mylyn/update/extras Um weitere Informationen bezglich des Mylyn Plugin zu erlagen, wenden Sie sich and den Mylin Projekt Website: http://www.eclipse.org/mylyn/. 14.3.1.3. Installation der AspectJ Development Tools (AJDT) Sollten Sie die Version 0.9.4 von m2eclipse installieren, so werden Sie eventuell auch die beiden Erweiterungen: Web Tools Platform (WTP) sowie AspectJ Development Tools (AJDT) installieren wollen. Um AJDT zu installieren, benutzen Sie:

368

Maven in Eclipse: m2eclipse AJDT (Eclipse 3.3): http://download.eclipse.org/tools/ajdt/33/update AJDT (Eclipse 3.4): http://download.eclipse.org/tools/ajdt/34/dev/update Um weitere Informationen bezglich des AspectJ Development Tools zu erlagen, wenden Sie sich and den AJDT Projekt Website: http://www.eclipse.org/ajdt/. 14.3.1.4. Installation der Web Tools Platform (WTP) To install the Web Tools Platform (WTP). Use one of the following update URLs in Eclipse, or just look for the Web Tools Project in the Discovery Site which should already be in your Eclipse remote update sites list. Um die Web Tools Platform (WTP) zu installieren, benutzen Sie die unten stehende Update URL in Eclipse oder suchen Sie das Web Tools Project innerhalb des Discovery Site welcher bereits Teil der Eclipse Remote Update Site Liste sein sollte. WTP: http://download.eclipse.org/webtools/updates/ Um weitere Informationen bezglich der Web Tools Platform zu erlagen, wenden Sie sich and den WTP Projekt Website http://www.eclipse.org/webtools/.

14.3.2. Installation von m2eclipse


Sobald Sie diese Voraussetzungen erfllt haben und die oben aufgefhrten Komponenten installiert haben, knnen Sie mit der Installation von m2Eclipse fortfahren. Benutzen Sie hierzu die folgende Update URL: m2eclipse Plugin: http://m2eclipse.sonatype.org/update/ Sollten Sie den neusten Entwickler Snapshot Release des Plugins bevorzugen, whlen Sie stattdessen die Update Development URL: m2eclipse Plugin (Development Snapshot): http://m2eclipse.sonatype.org/update-dev/ 369

Maven in Eclipse: m2eclipse Um das m2eclipse Plugin zu installieren, whlen Sie Hilfe > Software Update > Suchen und Installieren Es wird die Update-/Installationsschaltflche angezeigt. Whlen Sie nach neuen zu installierenden Features suchen und whlen Sei weiter. Die Anzeige wird auf xxx wechseln. Whlen Sie Neuer Remote Site und fgen Sie die oben angegebene Site hinzu. Stellen Sie sicher, dass der entsprechende Eintrag ausgewhlt ist. Zum Abschluss wird Eclipse ihnen anbieten m2eclipse zu installieren. Eclipse wird die Komponente dann herunterladen, installieren und konfigurieren. Mit der erfolgreichen Installation des Plugins sollten Sie unter Windows > Preferences in der Liste der Optionen einen Eintrag "Maven" finden.

14.4. Aufschalten der Maven Konsole


Vor wir nun tatschlich anfangen die Mglichkeiten des m2eclipse Plugins auszuleuchten, lassen Sie uns zunchst die Maven Konsole aufschalten. ffnen Sie die Konsolenansicht (Windows > Ansichten > Konsole). Whlen Sie den kleinen Pfeil rechts vom Symbol Konsole ffnen und dort "Maven Konsole"; wie unten dargestellt:

Figure 14.1. Aufschalten der Maven Konsole in Eclipse Die Maven Konsole gibt alle Ausgaben wieder, welche normalerweise auf dem Konsolenfenster ausgegeben werden, wenn Maven von der Befehlszeile gestartet wird. Dies ist sehr ntzlich um zu sehen was Maven gerade macht, oder um Debugausgaben zu analysieren und Probleme anzusehen.

370

Maven in Eclipse: m2eclipse

14.5. Erstellen eines Maven Projekts


Beim Einsatz von Maven werden Projekte gewhlich durch den Einsatz von Maven Archetypen erstellt. Innerhalb von Eclipse werden neue Projekte durch den Neue Projekte Wizard erstellt. Der Eclipse "Neues Projekt"-Wizard bietet eine Flle verschiedener Vorlagen um neue Projekte zu erstellen! Das m2eclipse Plugin baut auf diesen Wizard auf, und bietet die folgenden zustzlichen Mglichkeiten: Auschecken eines Maven Projekts aus einem SCM Repository Erstellen eines Maven Projekts auf der Basis eines Maven Archetyps Erstellen einer Maven POM Datei Wie in Figure 14.2, Erstellen eines Neuen Projekts mit Hilfe des m2eclipse Wizards (Abbildung 14.2: "Erstellen eines Neuen Projekts mit Hilfe des m2eclipse Wizards") dargestellt, sind alle drei Mglichkeiten fr einen Entwickler von Interesse. Lassen Sie uns diese Mglichkeiten im Einzelnen genauer ansehen.

371

Maven in Eclipse: m2eclipse

Figure 14.2. Erstellen eines Neuen Projekts mit Hilfe des m2eclipse Wizards

14.5.1. Auschecken eines Maven Projektes von einem SCM Repository


m2eclipse bietet die Mglichkeit Projekte direkt aus einem SCM Repository auszuchecken. Geben Sie einfach die SCM Daten des Projektes ein und m2eclipse wird das Projekt an den von Ihnen angegebenen Ort auschecken. Dies ist in Figure 14.3, Auschecken eines Projekts aus Subversion (Abbildung 14.3: 372

Maven in Eclipse: m2eclipse "Auschecken eines Projekts aus Subversion" beispielhaft dargestellt:

Figure 14.3. Auschecken eines Projekts aus Subversion Es bestehen zustzlichen Optionen als Teil dieses Dialogs. Diese Ermglichen Ihnen eine bestimmte Version auszuwhlen, entweder indem Sie im Katalog des Subversion Repository auswhlen, oder einfach durch die manuelle Eingabe 373

Maven in Eclipse: m2eclipse Revisionsnummer. Diese Funktionalitten bauen auf Funktionen des Subclipse Plugins auf, um mit dem Subclipse Repository zu interagieren. Darber hinaus untersttzt das m2eclipse Plugin die folgenden SCM Anbieter: Bazaar Clearcase CVS git hg Perforce Starteam Subversion Synergy Visual SourceSafe

14.5.2. Erstellen eines Maven Projekts auf der Basis eines Maven Archetyps
m2eclipse ermglicht ein Maven Projekt auf der Basis eines Maven Archetyps zu erstellen. Es bestehen sehr viele verschiedene Maven Archetypen, diese werden bereits in der Auswahlliste des m2eclipse aufgefhrt werden, wie aus der Figure 14.4, Erstellen eines Neuen Projektes auf der Basis eines Maven Archetyps (Abbildung 14.4: "Erstellen eines Neuen Projektes auf der Basis eines Maven Archetyps" ersichtlich wird:

374

Maven in Eclipse: m2eclipse

Figure 14.4. Erstellen eines Neuen Projektes auf der Basis eines Maven Archetyps Die Liste der aufgefhrten Muster aus Figure 14.4, Erstellen eines Neuen Projektes auf der Basis eines Maven Archetyps (Abbildung 14.4: "Erstellen eines Neuen Projektes auf der Basis eines Maven Archetyps") ist eine Aufzhlung welche von einem Werkzeug genannt Nexus Indexer erzeugt wurde. Nexus ist ein Repository Manager auf welchen in Chapter 16, Repository Management mit Nexus (Kapitel 16: "Repository Manager") nher eingegangen wird. Der Nexus Indexer ist eine Datei die einen Index ber das gesamte betrachtete Maven 375

Maven in Eclipse: m2eclipse Repository darstellt. m2eclipse benutzt diese um alle bereitstehenden Archetypen des gesamten Maven Repository darzustellen. Als dieses Kapitel das letzte Mal angepasst wurde, wurden bereits ca. 90 verschiedene Muster im Archetypdialog dargestellt. Darunter besonders erwhnenswert sind: Die Standardarchetypen von Maven zur Erstellung von Maven Plugins Einfache Web Anwendungen Einfache Projekte Neue Maven Archetypen Databinder Archetypen (datengetriebene Wicket Anwendungen) unter
net.databinder

Apache Cocoon Archetypen unter org.apache.cocoon Apache Directory Server Archetypen unter org.apache.directory.server Apache Geronimo Archetypen unter org.apache.geronimo.buildsupport Apache MyFaces Archetypen unter org.apache.myfaces.buildtools Apache Tapestry Archetypen unter org.apache.tapestry Apache Wicket Archetypen unter org.apache.wicket AppFuse Archetypen unter org.appfuse.archetypes Codehaus Cargo Archetypen unter org.codehaus.cargo Codehaus Castor Archetypen unter org.codehaus.castor Groovy-based Maven Plugin Archetypen (deprecated)24 unter 376

Maven in Eclipse: m2eclipse


org.codehaus.mojo.groovy

Jini Archetypen Mule Archetypen unter org.mule.tools Objectweb Fractal Archetypen unter org.objectweb.fractal Objectweb Petals Archetypen unter org.objectweb.petals ops4j Archetypen unter org.ops4j Parancoe unter org.parancoe slf4j Archetypen unter org.slf4j Springframework OSGI sowie Web Services Archetypen unter
org.springframework

Trails Framework Archetypen unter org.trailsframework


24

And these were just the archetypes that were listed under the Nexus Indexer Catalog, if you switch Catalogs you'll see other archetypes. While your results may vary, the following additional archetypes were available in the Internal Catalog: Und dies sind nur die Archetypen welche vom Nexus Indexer Katalog afugefhrt werden, sollten Sie einen anderen Katalog auswhlen, so werden Sie weitere Archetypen kennen lernen. Die Resultate werden unterschiedlich von Fall zu Fall unterschiedlich sein, im internen Katalog waren zum Beispiel folgende zustzlichen Muster verfgbar: Atlassian Confluence Plugin Archetype unter
com.atlassian.maven.archetypes

24

[4] Verzichten Sie auf den Einsatz des Groovy Maven Plugin des Codehaus Mojo Projekt. Jason Dillon hat inzwischen die Groovy Maven Integrationsbemhungen in das Groovy Projekt von Codehaus verschoben. Fr weitere Informationen wenden Sie sich an http://groovy.codehaus.org/GMaven.

377

Maven in Eclipse: m2eclipse Apache Struts Archetypen unter org.apache.struts Apache Shale Archetypen unter org.apache.shale Ein Katalog ist einfach eine Referenz auf einen Repository Index. Sie knnen die Menge aller Kataloge welche vom m2eclipse Plugin bercksichtigt werden verwalten, indem Sie neben der Drop Down Box des Kataloges den Knopf Configure auswhlen. Sollten Sie Ihren eigenen Archetyp einem Katalog zufgen wollen, so whlen Sie Add Archetype Sobald Sie einen Archetypen ausgewhlt haben, wird Maven den entsprechenden Artefakten aus dem Maven Repository holen und ein entsprechendes Eclipse Projekt erstellen.

14.5.3. Erstellen eines Maven Moduls


m2eclipse bietet auch die Mglichkeit ein Maven Modul zu erstellen. Dies ist beinahe identisch zur Erstellung eines Maven Projektes, da es ebenfalls ein Maven Projekt auf der Basis eines Archetypen erstellt. Jedoch ist ein Maven Modul ein Unterprojekt zu einem anderen Maven Projekt, das gemeinhin als bergeordnetes oder elterliches Projekt bezeichnet wird.

378

Maven in Eclipse: m2eclipse

Figure 14.5. Erstellen eines neuen Maven Modules Beim Erstellen eines neuen Maven Moduls mssen Sie ein bergeordnetes Projekt auswhlen, welches bereits innerhalb der Entwicklungsumgebung existiert. Die Auswahl des Buttons Browse zeigt eine Liste der bereits bestehenden Projekte wie in Figure 14.6, Auswahl eines bergeordneten Projektes eines neues Maven Modul (Abbildung 14.6: "Auswahl eines bergeordneten Projektes eines neues 379

Maven in Eclipse: m2eclipse Maven Modul") dargestellt.

Figure 14.6. Auswahl eines bergeordneten Projektes eines neues Maven 380

Maven in Eclipse: m2eclipse Modul Nach der Auswahl eines bergeordneten Projektes aus der Liste werden Sie auf das "Neues Maven Modul"-Fenster zurckgeleitet, dort ist nun das Feld bergeordnetes Projekt ausgefllt wie in Figure 14.5, Erstellen eines neuen Maven Modules (Abbildung 14.5: "Erstellen eines neuen Maven Moduls") dargestellt. Mit der Auswahl von Weiter werden Sie zur Liste der Maven Archetypen wie in Section 14.5.2, Erstellen eines Maven Projekts auf der Basis eines Maven Archetyps (14.5.2: "Erstellen eines Maven Projekts auf der Basis eines Maven Archetyp") ausgefhrt. Sie knnen dabei auswhlen auf der Basis welchen Musters das neue Maven Modul erstellt werden soll.

14.6. Erstellen einer Maven POM Datei


Eine weitere wichtige Funktionalitt des m2eclipse-Plugins ist es POM-Dateien zu erstellen. m2eclipse stellt einen Wizard bereit, um fr ein bestehendes Projekt eine POM Datei zu erstellen. Dieser POM Wizard wird in Figure 14.7, Abbildung 14.7: Erstellen eines neuen POMs (Abbildung 14.7: Erstellen eines neuen POMs) dargestellt:

381

Maven in Eclipse: m2eclipse

Figure 14.7. Abbildung 14.7: Erstellen eines neuen POMs Zu einem bestehenden Projekt ein neues Maven POM zu erstellen ist einfach: Auswhlen des Projektes, Eingabe der groupID, artefactID sowie version, Auswahl des Paketierungstyps und Vergabe eines Namens in den dafr vorgesehenen Feldern des m2eclipse Wizards. Whlen Sie weiter um Abhngigkeiten zuzufgen.

382

Maven in Eclipse: m2eclipse

Figure 14.8. Hinzufgen von Abhngigkeiten zu einer neuen POM Datei Wie Sie leicht aus Figure 14.8, Hinzufgen von Abhngigkeiten zu einer neuen POM Datei (Abbildung 14.8: "Hinzufgen von Abhngigkeiten zu einer neuen POM Datei") ersehen, sind zunchst keine Abhngigkeiten enthalten. Whlen Sie zufgen um das zentrale Maven Repository nach Abhngigkeiten zu durchsuchen. Dies ist in der nchsten Abbildung, Figure 14.9, Durchsuchen des Zentralen Repositories nach Abhngigkeiten (Abbildung 14.9: "Durchsuchen des Zentralen 383

Maven in Eclipse: m2eclipse Repositories nach Abhngigkeiten") dargestellt:

Figure 14.9. Durchsuchen des Zentralen Repositories nach Abhngigkeiten Nach Abhngigkeiten zu suchen ist einfach; geben Sie die groupId des bentigten Artefakten ein. Figure 14.9, Durchsuchen des Zentralen Repositories nach 384

Maven in Eclipse: m2eclipse Abhngigkeiten (Abbildung 14.9: "Durchsuchen des Zentralen Repositories nach Abhngigkeiten") stellt die Abfrage nach org.apache.commons dar, wobei commons-vfs geffnet ist, um zu sehen welche Versionen verfgbar sind. Die Auswahl der 1.1-SNAPSHOT Version von commons-vfs und nachfolgende Auswahl von Ok fhrt Sie zurck in den Dialog zur Auswahl der Abhngigkeiten, wo Sie dann weitere Abhngigkeiten hinzufgen knnen, oder via Abschliessen das POM erstellen knnen. Bei der Suche nach Abhngigkeiten macht m2eclipse Gebrauch von dem gleichen Nexus Repository Index, welcher auch von Nexus Index Manager aus Chapter 16, Repository Management mit Nexus (Kapitel 16: "Repository Manager") benutzt wird. Jetzt, da Sie die Funktionalitt welche m2eclipse zur Erstellung eines neuen Projektes bietet gesehen haben, lassen Sie uns die verwandten Funktionen zum Import von Projekten ansehen:

14.7. Importieren von Maven Projekten


m2eclipse bietet dreierlei Mglichkeiten Maven Projekte in Eclipse zu importieren: Importieren eines existierenden Maven Projekts Auschecken eines Maven Projektes aus einem SCM Repository Materialisieren eines Maven Projektes Figure 14.10, Importieren eines Maven Projektes (Abbildung 14.10: "Importieren eines Maven Projektes") stellt den Wizard zum Import von Projekten mit den zugehrigen Optionen, welche Maven durch das m2eclipse Plugin bereitstellt, dar.

385

Maven in Eclipse: m2eclipse

Figure 14.10. Importieren eines Maven Projektes Die Dialogbox aus Figure 14.10, Importieren eines Maven Projektes (Abbildung 14.10: "Importieren eines Maven Projektes") kann ber Datei > Importieren und anschliessendem Filtern mit dem Schlsselbegriff maven, innerhalb von Eclipse aufgerufen werden. Wie oben erwhnt bieten sich drei Mglichkeiten ein Maven Projekt zu in Eclipse zu importieren: Maven Projekte Importieren, Auschecken eines Maven Projektes aus einem Repository und Materialisieren von Maven Projekten. 386

Maven in Eclipse: m2eclipse Importieren eines Maven Projektes aus einem SCM Repository ist identisch zur Funktionalitt "Erstellen eines Maven Projektes aus einem SCM Repository" welche vorgngig Diskutiert wurde; eine weitere Behandlung ist berflssig. Lassen Sie uns weitergehen zu den zwei verbleibenden Mglichkeiten ein Maven Projekt zu importieren.

14.7.1. Importiren eines Maven Projektes


m2eclipse kann ein Projekt mit bestehender pom.xml-Datei importieren. Durch Angabe des Verzeichnisses in welchem das Maven Projekt abgelegt wurde, ist m2eclipse in der Lage alle Maven POMs des Projekts zu finden und eine hierarchische Liste dieser aufzustellen. Diese ist in Figure 14.11, Importieren eines multi-modularen Maven Projektes (Abbildung 14.11: "Importieren eines multi-modularen Maven Projektes") dargestellt:

387

Maven in Eclipse: m2eclipse

Figure 14.11. Importieren eines multi-modularen Maven Projektes Figure 14.11, Importieren eines multi-modularen Maven Projektes (Abbildung 14.11: "Importieren eines multi-modularen Maven Projektes") zeigt die Darstellung des zu importierenden Projektes. Bitte beachten Sie, dass alle POMs des Projektes in hierarchischer Darstellung wiedergegeben werden. Das erlaubt Ihnen auf einfache Art und Weise genau auszuwhlen, welche POMs (und damit Projekte) Sie in Eclipse importieren mchten. Haben Sie erst einmal die Projekte welche Sie importieren mchten ausgewhlt, nimmt Ihnen m2eclipse den Import 388

Maven in Eclipse: m2eclipse und das Builden der Projekte mit der Untersttzung von Maven ab.

14.7.2. Materialisieren eines Maven Projektes


Eine weitere Funktionalitt welche m2eclipse bietet ist die Materialisierung eines Projektes. Materialisierung ist hnlich dem Auschecken eines Projektes aus einem SCM Repository, jedoch, anstatt die URL des Repository manuell einzugeben, wird diese aus der obersten POM Datei des Projektes gelesen. Sie knnen diese Funktionalitt dazu benutzen, Projekte aus nichts weiter als einer pom.xml Datei, welche die entsprechenden Elemente enthlt, zu erstellen. Mit dieser Mglichkeit ist es Ihnen gegeben, das Maven Repository zu durchstreifen und die enthaltenen Projekte in Eclipse zu materialisieren. Dies ist insbesondere ntzlich, sollte Ihr Projekt von einer Open Source Library abhngig ist, und Sie versuchen an dessen Quellen zu gelangen. Statt mhsam den Projekt-Website herauszufinden und festzustellen, wie Sie diese aus dem Repository auschecken knnen, benutzen Sie einfach m2eclipse um das Projekt zu materialisieren. Figure 14.12, Materialisieren eines Maven Projektes (Abbildung 14.12: "Materialisieren eines Maven Projektes") stellt den Wizard nach der Auswahl des zu materialisierenden Projekts dar:

389

Maven in Eclipse: m2eclipse

Figure 14.12. Materialisieren eines Maven Projektes Beachten Sie, dass die Dialogbox der Maven Artefakte in Figure 14.12, Materialisieren eines Maven Projektes (Abbildung 14.12: "Materialisieren eines Maven Projektes") leer ist. Dies ist so, da noch keine Projekte ausgewhlt wurden. Um ein Projekt hinzuzufgen mssen Sie auf der rechten Seite den Button 390

Maven in Eclipse: m2eclipse "Hinzufgen" auswhlen und einen Abhngigkeit aus dem zentralen Maven Repository auswhlen. Dies ist in Figure 14.13, Auswahl eines Artefakten zum Materialisieren (Abbildung 14.13: "Auswahl eines Artefakten zum Materialisieren"), dargestellt.

Figure 14.13. Auswahl eines Artefakten zum Materialisieren

391

Maven in Eclipse: m2eclipse Auf die Eingabe einer Auswahl hin werden die mglichen Abhngigkeiten im Maven Repository gesucht. Nach wenigen Momenten Indexierung des lokalen Repositories wird eine Liste der mglichen Artefakte wiedergegeben. Whlen Sie den entsprechendne Kandidaten eines Projektes aus, so dass dieser zur Liste hinzugefgt werden kann, wie dies in Figure 14.14, Materialisieren von Apache Camel (Abbildung 14.14: "Materialisieren von Apache Camel") gezeigt wird.

392

Maven in Eclipse: m2eclipse Figure 14.14. Materialisieren von Apache Camel Nach dem hinzufgen der Abhngigkeit bietet Ihnen das m2eclipse die Mglichkeit alle Projekte des Artefaktes auszuchecken.

14.8. Starten von Maven Builds


m2eclipse wird auch die Mens Run as sowie Debug as anpassen, um Ihnen zu ermglichen Maven Builds zu starten. Figure 14.15, Starten eines Eclipse Builds durch Run as (Abbildung 14.15: "Starten eines Eclipse Builds durch Run as ") stellt das Run as Men eines m2eclispse Projektes dar. Ausgehend von diesem Men knnen Sie eine Anzahl Maven Lebenszyklusphasen wie z. B. clean, install und package direkt starten. Sie knnen auch den Run-Konfigurationsdialog aufrufen und dort spezifische Maven Buildparameter und/oder weitere Optionen setzen.

393

Maven in Eclipse: m2eclipse

Figure 14.15. Starten eines Eclipse Builds durch Run as Beabsichtigen Sie einen Maven Build mit erweiterter Konfiguration zu erstellen, so knnen Sie Run Configuration auswhlen und einen neuen Maven Build erstellen. Figure 14.16, Konfiguration eines Maven Builds mittels "Run Configurations..." (Abbildung 14.16: "Konfiguration eines Maven Builds mittels "Run Configurations..." ") stellt den Run Dialog vor

394

Maven in Eclipse: m2eclipse

Figure 14.16. Konfiguration eines Maven Builds mittels "Run Configurations..." Der Run Configuration ... Dialog erlaubt es, mehrere Goals sowie Profile darzustellen, es werden Auswahlmglichkeiten wie Test auslassen (skip test) oder Update Snapshots und erlaubt Ihnen Parameter ausgehend vom denen des Projektes bis hin zur unterliegenden Java Runtime Umgebung (JRE) oder den Umgebungsvariablen zu setzen. Sie knnen diese Dialogseite benutzen um jeden beliebigen massgeschneiderten Maven Build mittels m2eclipse zu starten.

395

Maven in Eclipse: m2eclipse

14.9. Mit Maven Projekten arbeiten


Das m2eclipse bietet auch eine Reihe Funktionalitten um mit Maven Projekten zu arbeiten sobald diese in Eclipse geladen sind. Viele dieser Funktionen erleichtern das Arbeiten mit Maven, lassen Sie uns diese nher ansehen: Im vorhergehenden Abschnitt materialisierte ich ein Projekt und whlte ein Unterprojekt von Apache Camel aus; camel-core. Wie werden die verschiedenen Mglichkeiten anhand dieses Projektes verdeutlichen. Whlen Sie mit der rechten Maustaste den Menpunkt Maven auf dem camel-core Projekt, so knnen Sie die verfgbaren Maven Funktionen sehen. Figure 14.17, Verfgbare Maven Funktionalitten (Abbildung 14.17: "Verfgbare Maven Funktionen") stellt dies dar:

396

Maven in Eclipse: m2eclipse

Figure 14.17. Verfgbare Maven Funktionalitten Notice in Figure 14.17, Verfgbare Maven Funktionalitten the available Maven features for the camel-core project, including: Beachten Sie in Figure 14.17, Verfgbare Maven Funktionalitten (Abbildung 14.17: "Verfgbare Maven Funktionalitten") die verfgbaren Mglichkeiten des camel-core Projektes, diese umfassen

397

Maven in Eclipse: m2eclipse Hinzufgen von Abhngigkeiten sowie Plugins Updaten von Abhngigkeiten, Snapshots sowie Quellverzeichnissen Erstellen eines Maven Moduls Herunterladen von Quelldateien ffnen von Projekt URLs wie z. B. der Projekt Web Page, dem Issue Tracker, SCM oder Continuous Integration Werkzeugen. Zuschalten/Abschalten der Workspace Auflsung, verschachteltem Modulund Abhngigkeitsmanagement Diese Funktionalitten knnen uns Zeit sparen, und so lassen Sie uns diese genauer ansehen.

14.9.1. Zufgen und Updaten von Abhngigkeiten und Plugins


Nehmen wir einmal an, wir wollen zum camel-core POM eine Abhngigkeit oder ein Plugin hinzufgen. Der Demonstration halber fgen wir commons-lang als Abhngigkeit hinzu. (Da die Funktionalitt zum Hinzufgen von Abhngigkeiten und Plugins genau dieselbe ist, werden wir beispielhaft lediglich eine Abhngigkeit hinzufgen). m2eclipse bietet zwei Mglichkeiten eine Abhngigkeit dem Projekt zuzufgen. Die erste ist, die pom.xml-Datei direkt durch hinzufgen des entsprechenden XML Elements abzundern. Der Nachteil dieses Ansatzes ist, dass Sie bereits die Informationen bezglich der Artefakte im Detail wissen mssen, oder alternativ die Funktionen welche im nchsten Abschnitt dargestellt werden benutzen mssten um diese in den Repository Indexen zu finden. Der Vorteil ist, dass nach einer manuellen nderung und Speicherung des Projekt POM der Maven Abhngigkeits-Container automatisch die Neuerungen reflektiert. Figure 14.18, Manuelles Zufgen einer Abhngigkeit zum Projekt POM (Abbildung 14.18: 398

Maven in Eclipse: m2eclipse "Manuelles Zufgen einer Abhngigkeit zum Projekt POM") zeigt, wie ich eine Abhngigkeit zu commons-lang zum POM der camel-console zugefgt habe und der Maven Abhngigkeits-Container dies automatisch reflektiert und somit darstellt:

Figure 14.18. Manuelles Zufgen einer Abhngigkeit zum Projekt POM Nach dem manuelen Zufgen des Elements dependency an das POM, zeigt die Statusanzeige in der rechten unteren Ecke die Hintergrundaktion wie in Figure 14.19, Updaten von Maven Abhngigkeiten (Abbildung 14.19: "Updaten von Maven Abhngigkeiten") dargestellt, an:

Figure 14.19. Updaten von Maven Abhngigkeiten Manuelles Zufgen von Abhngigkeiten funktioniert gut, aber bentigt mehr Arbeit als dies die zweite Mglichkeit erfordert. Diese Mglichkeit ist viel einfacher, sie setzt nicht voraus, dass Sie irgendwelche Informationen ber die der groupId der Artefakte hinaus haben. Figure 14.20, Suchen einer Abhngigkeit (Abbildung 14.20: "Suchen einer Abhngigkeit") stellt dies dar: 399

Maven in Eclipse: m2eclipse

Figure 14.20. Suchen einer Abhngigkeit Durch eintragen einer groupId in das Abfragefeld durchsucht m2eclipse die Indexe der Repositorien sowie die Versionen der Artefakte welche sich bereits im lokalen Maven Repository befinden. Dies ist die bevorzugte Mglichkeit, da es enorme Zeitersparnisse birgt. Mit m2eclipse gehrt die langwierige Suche durch die zentralen Maven Repositorien der Vergangenheit an. 400

Maven in Eclipse: m2eclipse

14.9.2. Erstellen eines Maven Modules


m2eclipse bringt eine enorme Erleichterung zur Erstellung eines verschachtelten Unterprojektes innerhalb eines multi-modularen Maven Projektes. Sollten Sie ein bergeordnetes Maven Projekt bearbeiten und Sie wollen ein Unterprojekt erstellen, so machen Sie einen Rechts-Click auf dem Projekt, gehen Sie zum Maven Men und whlen Neues Maven Modul Projekt". m2eclipse wird Sie durch die Schritte zum Erstellen eines Untermoduls fhren, das POM erstellen, das elterliche POM anpassen und in den Bezgen reflektieren. Vor es m2eclipse gab war es sehr schwierig, innerhalb von Eclipse mit hierarchisch geschachtelten Projektbumen zu arbeiten. Mittels m2eclipse wurden die darunterliegenden Beziehungen zwischen ber und Unterprojekten in die Entwicklungsumgebung eingebunden.

14.9.3. Herunterladen der Quelldatei(en)


Sollte das zentrale Maven Repository eine Quelldatei der Artefakten beinhalten, so knnen Sie diese mittels Maven herunterladen und in Eclipse bereitstellen. Beim Versuch eine komplexe Anwendung zu Debuggen, ist es manchmal usserst ntzlich, kann man den zu einem bestehenden externen Quellcode einer Abhngigkeit durch einen einfachen Rechts-Click herunterladen und zu debuggen. Whlen Sie diese Funktion, so wird Maven fr Sie versuchen dies zu tun. Ist es nicht mglich, so sollten Sie den Verantwortlichen des Projektes darauf aufmerksam machen, dass dieser im zentralen Maven Repository die entsprechenden Quelldateien hinterlegen.

14.9.4. ffnen von Projektseiten


Das Maven POM enthlt einige sehr ntzliche URLs welche einen Entwickler interesieren mgen: Diese sind die Projekt Webseite, der Link auf das SCM Repository, eine URL auf eine Continuous Integrations Instanz (Dienst wie z.B. Hudson) sowie eine URL, welche auf das entsprechende Issue Tracking System zeigt. Sind diese Variablen im POM gesetzt, so ffnet m2eclipse die entsprechenden Seiten innerhalb eines Browserfensters. 401

Maven in Eclipse: m2eclipse

14.9.5. Auflsen von Abhngigkeiten


Sie knnen ein Projekt so konfigurieren, dass dieses die Abhngigkeiten innerhalb Ihres Workspace auflst. Das hat den Nebeneffekt, dass es unter Umstnden das Verhalten ndert wie Maven einen Artefakten findet. Sollte ein Projekt so konfiguriert sein, dass es Abhngigkeiten innerhalb eines Workspaces auflst, mssen diese Artefakte nicht in Ihrem lokalen Repository vorhanden sein. Nehmen wir einmal an, Projekt A und Projekt B sind beide im gleichen Eclipse Workspace vorhanden. Ist Workspace Auflsung ausgestellt, so wird die Abhngigkeit nur aufgelst, wenn die entsprechenden Artefakte in Ihrem lokalen Repository aufzufinden sind. Ist Workspace Auflsung hingegen aktiviert, so wird m2eclipse die Abhngigkeiten innerhalb Ihres Workspaces auflsen. In anderen Worten, ist Workspace Auflsung aktiviert, so mssen lokale Projekte nicht in Ihrem lokalen Repository vorhanden sein um sich aufeinander zu beziehen. Sie knnen auch das Abhngigkeitsmanagement ausschalten. Das hat dann den Nebeneffekt, dass es m2eclipse anweist, aufzugeben zu versuchen, den Projektklassenpfad zu verwalten, und wird den Maven Abhngigkeits Container aus Ihrem Projekt entfernen. Sollten Sie diese Option whlen, so sind Sie letztendlich mit der Verwaltung des Projektklassenpfades auf sich gestellt.

14.10. Arbeiten mit den Maven Repositorien


m2eclipse bietet auch einige Werkzeuge um die Arbeit mit Maven Repositorien zu erleichtern. Insbesondere stehen Werkzeuge mit folgender Funktionalitt bereit: Suchen von Artefakten Suchen von Java Klassen Indexierung von Maven Repositorien

14.10.1. Suchen von Maven Artefakten sowie Java


402

Maven in Eclipse: m2eclipse

Klassen
m2eclipse fgt dem Navigationsmen von Eclipse weitere Eintrge hinzu, welche die Suche nach Maven Artefakten sowie Java Klassen erleichtern. Diese Funktionalitt wird durch einen Aufruf innerhalb des Mens ausgelst, und ist in Figure 14.21, Suchen von Artefakten und Klassen (Abbildung 14.21: "Suchen von Artefakten und Klassen") dargestellt:

403

Maven in Eclipse: m2eclipse

Figure 14.21. Suchen von Artefakten und Klassen Beachten Sie in Figure 14.21, Suchen von Artefakten und Klassen (Abbildung 14.21: "Suchen von Artefakten und Klassen") im Navigationsmen von Eclipse die Eintrge mit dem Titel: ffnen eines Maven POM und Maven Typauswahl. Der 404

Maven in Eclipse: m2eclipse Eintrag ffnen eines Maven POM erlaubt Ihnen das Maven Repository nach einem bestimmten POM zu durchsuchen, wie in Abbildung Figure 14.22, Suche eines POM (14.22: "Suche eines POM") ersichtlich ist:

405

Maven in Eclipse: m2eclipse Figure 14.22. Suche eines POM Nach der Auswahl eines Artefakts und der Besttigung mit OK wird innerhalb von Eclipse das POM zur Ansicht und Modifikation geffnet. Dies ist sehr hilfreich, wenn Sie das POM eines Artefakten zur schnellen Einsicht ansehen wollen. Der zweite Eintrag im Navigationsmen von m2eclipse ist Open Type from Maven. Diese Funktion erlaubt es Ihnen in einem entfernten Repository nach Java Klassen zu suchen. Beim ffnen des Dialogfensters geben Sie versuchsweise einmal factory bean ein, und Sie werden sehen wie viele Klassen mit diesem Namen gefunden werden! Dies ist in Figure 14.23, Durchsuchen eines Repository nach einer Java Klasse (Abbildung 14.23: "Durchsuchen eines Repository nach einer Java Klasse") dargestellt.

406

Maven in Eclipse: m2eclipse

Figure 14.23. Durchsuchen eines Repository nach einer Java Klasse Dies ist eine grosse zeitliche Entlastung, denn bislang bedeutete die Suche nach 407

Maven in Eclipse: m2eclipse einer Java Klasse eine zeitraubende Suche innerhalb der einzelnen Artefakte eines Repositories. Wenn Sie heute eine bestimmt Klasse suchen, starten Sie einfach Eclipse, gehen zum Navigationsmen und suchen nach der entsprechenden Klasse. m2eclipse wird Ihnen eine Liste der Artefakte zurckgeben in welchem diese Klasse erscheint.

14.10.2. Indizierung von Maven Repositorien


Die Maven Index Anzeige erlaubt es Ihnen POMs in entfernten Repositorien anzuwhlen und in Eclipse auszuwhlen. Um dies zu demonstrieren, whlen Sie View > Show View > Other. Geben sie den Begriff maven in die Suchmaske ein. Sie sollten wie in Figure 14.24, Anzeigen von Maven Indexen im Eclipse View (Abbildung 14.24: Anzeigen von Maven Indexen im Eclipse View") dargestellt ein View der bestehenden Artefakte zur Auswahl gestellt bekommen:

408

Maven in Eclipse: m2eclipse

Figure 14.24. Anzeigen von Maven Indexen im Eclipse View Whlen Sie das entsprechende View aus und besttigen Sie mit OK. Es wird sich das Maven Index View wie in Figure 14.25, Maven Index View (Abbildung 14.25: "Maven Index View") dargestellt ffnen.

409

Maven in Eclipse: m2eclipse

Figure 14.25. Maven Index View Zustzlich in Figure 14.26, Auswahl eines POM innerhalb des Index Views (Abbildung 14.26: "Auswahl eines POM innerhalb des Index Views") dargestellt nach dem manuellen Suchen eines POM:

410

Maven in Eclipse: m2eclipse

Figure 14.26. Auswahl eines POM innerhalb des Index Views Nach der Auswahl des apache-camel Artefakte wird ein Doppelclick dieses in Eclipse zur Bearbeitung ffnen. Diese Funktion erleichtert die Arbeit mit einem entfernten Repository wesentlich und spart darber hinaus viel Zeit. Nach all der Zeit welche Sie in den vergangenen Jahren mit solcherlei Beschftigungen zugebracht haben Ansehen des Inhaltes eines Repositories in einem Webbrowser, Herunterladen des Artefaktes und anschiessenden Greppens nach Klassen oder POM sie werden von m2eclipse angenehm berrascht sein.

411

Maven in Eclipse: m2eclipse

14.11. Der neue graphische POM Editor


Die neuste Inkarnation des m2eclipse Plugin beinhaltet einen graphischen POM Editor, welcher es erlaubt, alle Aspekte eines Projekt POMs in einer einfachen GUI Schnittstelle zu bearbeiten. Um den POM Editor zu ffnen, Klicken Sie auf eine pom.xml Datei. Sollten Sie eine benutzerdefinierte Einstellung eines Editors gewhlt haben, und der graphische POM Editor nicht als Standardeditor bestimmt haben, so knnen Sie die Alternative Open with /Maven POM Editor whlen um diesen zu starten. Der POM Editor wird Ihnen dann die in Figure 14.27, bersichtsanzeige des POM Editors fr das Projekt idiom-core (Abbildung 14.27: "bersichtsanzeige des POM Editors fr das Projekt idiom-core") dargestellte Gesamtbersicht anzeigen. Eine hufige Klage bezglich Maven ist, dass Maven den Entwickler dazu zwingt sich des fteren mit langen, unbesichtlichen und hoch komplexen XML Dokumenten zu befassen, wie diese in einem multi modularen Build vorkommen. Wrend wir, die Autoren davon berzeugt sind, dass dies ein kleiner Preis fr all die Mglichkeiten und Flexibilitt welche Maven bietet ist, so erlaubt der graphische POM Editor die Arbeit mit Maven ohne die das POM untermauernde XML Struktur berhaupt zu kennen.

412

Maven in Eclipse: m2eclipse

Figure 14.27. bersichtsanzeige des POM Editors fr das Projekt idiom-core Das in Figure 14.27, bersichtsanzeige des POM Editors fr das Projekt idiom-core (Abbildung 14.27: "bersichtsanzeige des POM Editors fr das Projekt idiom-core") dargestellte Projekt besitzt einen Artefakten: idiom-core. Es besteht keine groupId oder version, und Angaben zur SCM Verwaltung sind ebenfalls nicht gesetzt. Dies rhrt daher, dass idiom-core die allermeisten Informationen vom bergeordneten Projekt idom erbt. ffnen wir das pom.xml des elterlichen Projekts im graphischen Editor, so wrden wir die Anzeige wie in Figure 14.28, bersichtsansicht des graphischen Editors des bergeordneten idiom Projekts (Abbildung 14.28: "bersichtsansicht des graphischen Editors des bergeordneten idiom Projekts") sehen. Das Symbol des "geffneten Ordners" an zahlreichen Eintrgen des POM Editors 413

Maven in Eclipse: m2eclipse zeigt an, dass der entsprechende Eintrag ebenfalls Teil des Eclipse-Workspace ist, und das Jar-Symbol deutet auf Artefakte welche sich auf ein Maven Repository beziehen. Sie knnen einen solche Eintrag doppelklicken um sich dessen POM Datei im POM Editor anzuzeigen. Dies funktioniert fr Module, Abhngigkeiten, Plugins sowie weiteren Artefakten, welche entsprechende Maven Artefakte aufweisen. Unterstrichene Titel in den Seiten des POM Editors weisen auf Hyperlinks hin, welche benutzt werden knnen um Maven Artefakte ebenfalls im POM Editor zu ffnen.

Figure 14.28. bersichtsansicht des graphischen Editors des bergeordneten idiom Projekts In diesem bergeordneten POM ersichtlich die groupId und version. Beachten Sie bitte, dass ein Grossteil der Detailinformationen welche im POM von idiom-core fehlten, hier gesetzt werden. Die Anzeige des POM Editors beschrnkt sich auf Angaben welche im jeweiligen POM gemacht wurden und zeigt keine geerbten 414

Maven in Eclipse: m2eclipse Werte. Sollten Sie dennoch das tatschliche POM des Projektes ansehen wollen, so nutzen Sie die Mglichkeit tatschliches POM anzeigen von der Toolbar an der oberen rechten Ecke des POM Editors (linke Klammer und Gleichzeichen ber dem blauen Maven Projekt M). Es wird Ihnen das tatschliche POM wie in Figure 14.29, Tatschliches POM von idiom-core (Abbildung 14.29: "Tatschliches POM von idiom-core") dargestellt, angezeigt.

Figure 14.29. Tatschliches POM von idiom-core In der Ansicht Tatschliches POM von idiom-core wird das ursprngliche POM mit den POM der Vorfahren (bergeordnet (Eltern), darber (Grosseltern), etc.) hnlich zum Aufruf mvn help:effective-pom verschmolzen und dargestellt. Da diese Ansicht nun die Kombination vieler verschiedener abhngiger POM ist, ist diese Darstellung schreibgeschtzt und Sie werden in dieser Ansicht keine nderungen vornehmen knnen. In der Ansicht des POM Editors wie in Figure 14.27, bersichtsanzeige des POM Editors fr das Projekt idiom-core (Abbildung 14.27: "bersichtsanzeige des 415

Maven in Eclipse: m2eclipse POM Editors fr das Projekt idiom-core") dargestellt, knnen Sie ebenfalls die Ansicht des bergeordneten POM aufrufen. Whlen Sie bergeordnetes POM ffnen" von der Toolbar an der oberen rechten Ecke des POM Editors (gelber Pfeil nach oben). Der POM Editor bietet eine Anzahl verschieden Ansichten der Informationen des POM, im letzten Tab des Editors knnen Sie die darunterliegende XML-Datei ansehen. Ebenfalls Vorhanden ist ein Tab bezglich Abhngigkeiten, dargestellt in Figure 14.30, Abhngigkeitsansicht des POM Editors (Abbildung 14.30: "Abhngigkeitsansicht des POM Editors"). Dieses gibt Ihnen eine einfache Mglichkeit Abhngigkeiten zu verwalten, sowie den Abschnitt dependencyManagement des POM zu editieren. Die Abhngigkeitsverwaltung integriert ebenfalls die Artefakt Suchfunktion des m2eclipse Plugins. Beim Arbeiten in den Feldern der Abhngigkeiten knnen Sie auf Aktionen aus den Editorfeldern oder auch Ctrl + Leertaste Hilfestellungen zurckgreifen. Mssen Sie einmal weitere Details ber bestimmte Artefakte in Erfahrung bringen, so knnen Sie die Funktion Webseite ffnen von innerhalb des Abhngigkeiten aufrufen, um eine entsprechenden Webseite aufzurufen.

416

Maven in Eclipse: m2eclipse

Figure 14.30. Abhngigkeitsansicht des POM Editors Der Build Tab, dargestellt in Figure 14.31, Build Tab des POM Editors (Abbildung 14.31: "Build Tab des POM Editors") gibt Ihnen Zugriff auf den Abschnitt der Build Elemente. Aus diesem Tab heraus knnen Sie die benutzten Verzeichnisse, Erweiterungen sowie Standard Goal-Namen sowie Ressource-Verzeichnisse bestimmen.

417

Maven in Eclipse: m2eclipse

Figure 14.31. Build Tab des POM Editors Wir haben hier nur eine Untermenge der Funktionalitt des POM Editors aufgezeigt. Sollten Sie an weiteren Informationen interessiert sein, so laden Sie sich doch bitte das m2eclipse Plugin herunter und installieren Sie es.

14.12. Projektabhngigkeiten mit m2eclipse analysieren


Die neueste Version des m2eclipse Plugin umfasst unter anderem auch eine Editor Version mit zustzlichen Abhngigkeitsanalyse-Werkzeugen. Diese werden die Art, wie Abhngigkeiten verwaltet werden, grundstzlich ndern. Eine der 418

Maven in Eclipse: m2eclipse grundlegenden Eigenschaften warum Maven zum Einsatz kommt ist die Art und Weise wie Abhngigkeiten verwaltet werden. Nehmen Sie an, Sie schreiben an einer Applikation welche auf der Spring Hibernate3 Integration aufbaut, alles was Sie tun mssen ist, sich auf den Artefakten spring-hibernate3 des zentralen Maven Repository abzusttzen. Maven wird dieses Artefakt einlesen und alle weiteren transitiven Abhngigkeiten zufgen. Whrend dies eine Funktionalitt ist, welche viele Anwender zum Einsatz von Maven lockt, so kann es eben auch verwirrend werden, sobald ein Projekt auf dutzenden von Abhngigkeiten aufbaut, und diese jeweils weitere duzende Transitive Abhngigkeiten mit sich bringen. Probleme treten vor allem dann auf, wenn Sie von einem Projekt abhngen, dessen POM uvollstndig ist, insbesondere wenn Abhngigkeiten nicht ausreichend definiert und als optional gekennzeichnet sind, oder sobald es Konflikte zwischen transitiven Abhngigkeiten gibt. Im Falle, dass eine der Voraussetzungen der Ausschluss von commons-logging oder des Servlet API ist, oder im Falle dass Sie herausfinden mssen warum in einem bestimmten Gltigkeitsbereich eine bestimmte Abhngigkeit auftritt, werden Sie regelmssig gezwungen sein, auf die Kommandozeilen Werkzeuge dependency:tree und dependency:resolve zurckzugreifen. Das sind die Momente, in denen Ihnen der neue POM Editor des m2eclipse Plugin zur Hilfe kommt. Wenn Sie ein Projekt mit vielen Abhngigkeiten ffnen, so werden Sie die zweispaltige Darstellung der Abhngigkeiten wie in Figure 14.32, Baum der Abhngigkeiten dargestellt im POM Editor (Abbildung 14.32: "Baum der Abhngigkeiten dargestellt im POM Editor") sehen. Die linke Spalte der Anzeige veranschaulicht den Baum der Abhngigkeiten. Die erste Ebene stellt hierbei die direkten Abhngigkeiten zu Ihrem Projekt dar. Jede weitere Ebene ist dabei die nchste Stufe der Hierarchie. Die linke Spalte hingegen gibt Ihnen ein einfaches Werkzeug zur Hand um herauszufinden wie eine bestimmte Abhngigkeit in Ihr Projekt gefunden hat. Die rechte Anzeige Zeigt Ihnen alle aufgelsten Abhngigkeiten an; das stellt die tatschliche Liste der Abhngigkeiten dar, nach der Auflsung aller Konflikte sowie Anwendung aller Gltigkeitsbereiche und stellt somit die Liste der Abhngigkeiten dar, wie Sie Ihr Projekt zur Kompilierung, Test und Paketierung benutzen wird.

419

Maven in Eclipse: m2eclipse

Figure 14.32. Baum der Abhngigkeiten dargestellt im POM Editor Die Funktionalitt welche den Tab Abhngigkeiten so wertvoll macht ist, dass es bei Nachforschungen nachvollziebar ist, wie eine bestimmte Abhngigkeit in die Liste der Abhngigkeiten gekommen ist. Such- und Filter- Funktionalitten welche dem Editor zur Verfgung stehen machen es ein leichtes die Projektabhngigkeiten zu bearbeiten. Sie knnen das Suche Feld der Eingabefelder sowie die Aktivitten Sortieren und Filtern der Abhngigkeits-Hierarchie und der Aufgelsten Abhngigkeiten einsetzen, um sich durch die Abhngigkeiten zu hangeln. Figure 14.33, Lokalisieren von Abhngigkeiten im Abhngigkeitsbaum (Abbildung 14.33: "Lokalisieren von Abhngigkeiten im Abhngigkeitsbaum") stellt dar, was passiert, wenn man die Abhngigkeit commons-logging in der Liste der Aufgelsten Abhngigkeiten auswhlt. Sollte Filterung auf der Abhngigkeitshierarchie der linken Seite eingestellt sein, so wird die Auswahl einer Abhngigkeit auf der rechten Seite automatisch alle die Knoten des Abhngigkeitsbaumes anzeigen, welche zu deren Inklusion gefhrt haben. Sollte 420

Maven in Eclipse: m2eclipse Sie versuchen eine bestimmte Abhngigkeit loszuwerden, so wird Ihnen dieses Werkzeug helfen herauszufinden, welche Abhngigkeiten (eben auch transitive Abhngigkeiten) dazu beitragen, dass eine bestimmte Abhngigkeit aufgelst wurde. In anderen Worten, sollten Sie einen Artefakten wie z.B. commons-logging von Ihrer Liste der Abhngigkeiten lschen wollen, werden Sie hierzu das Abhngigkeits-Werkzeug benutzen wollen.

Figure 14.33. Lokalisieren von Abhngigkeiten im Abhngigkeitsbaum Das m2eclipse Plugin bietet Ihnen des Weiteren auch die Mglichkeit den Baum der Abhngigkeiten graphisch darzustellen. Figure 14.34, Darstellung eines Projektes als Graphen (Abbildung 14.34: "Darstellung eines Projektes als Graphen"), stellt die Abhngigkeiten des idiom-core Projekts dar. Die aller oberste Box stellt das idiom-core Projekt dar, alle darunterliegenden Abhngigkeiten sind sinngemss darunter dargestellt. Direkte Abhngigkeiten sind durch direkte Verbindungen gekennzeichnet, transitive Abhngigkeiten gehen von 421

Maven in Eclipse: m2eclipse andren Abhngigkeiten aus. Sie knnen jede beliebige Abhngigkeit auswhlen, um die Verbindungen hervorzuheben, oder sie knnen mit dem Suche Werkzeug im oberen Bereich der Seite die entsprechenden Knoten finden. Beachten Sie bitte auch das Symbol des offenen Ordners fr diejenigen Artefakte welche lokal vorliegen, und das Symbol der Jar Datei fr Artefakte welche auf ein Maven-Repository zeigen.

Figure 14.34. Darstellung eines Projektes als Graphen Der dargestellt Graph kann durch Rechtsklicken der Maustaste gendert werden. Sie knnen ebefalls Einstellen, ob Sie die artifactId, groupId, version sowie Gltigkeitsbereich dargestellt haben mchten, und ob der Text in der Zeile umgebrochen werden soll.Figure 14.35, Radiale Darstellung des Abhngigkeitsgraphen (Abbildung 14:35 "Radiale Darstellung des Abhngigkeitsgraphen") stellt den gleichen Graphen aus Figure 14.34, Darstellung eines Projektes als Graphen (Abbildung 14.34) in einem anderen Layout dar.

422

Maven in Eclipse: m2eclipse

Figure 14.35. Radiale Darstellung des Abhngigkeitsgraphen

14.13. Maven Einstellungen


Die Mglichkeit, Maven Grundeinstellungen sowie einige Optionen zu setzen, ist ein wichtiger Aspekt an der Arbeit mit Maven. m2eclipse bietet die Mglichkeit diese Einstellungen in der Maven Einstellungen Seite innerhalb von Eclipse zu setzen. Typischerweise, beim Einsatz von Maven von der Befehlszeile, werden diese Einstellungen als Optionen bergeben oder aus dem Verzeichnis ~/.m2 ausgelesen. m2eclipse bietet Zugriff auf die wichtigsten Einstellungen von innerhalb der IDE. Figure 14.36, Maven Einstellungen in Eclipse (Abbildung 14.36 "Maven Einstellungen in Eclipse") stellt die Einstellungsseite innerhalb von 423

Maven in Eclipse: m2eclipse Eclipse dar:

Figure 14.36. Maven Einstellungen in Eclipse Die Tick-Boxen im oberen Bereich erlauben: Maven im Offline Modus zu betreiben, d.h. ohne Zugriff auf entfernte Repositorien Debug Ausgaben auf die Maven Konsole umleiten Quell-Jar Dateien von Artefakten aus entfernten Repositorien herunterladen JavaDoc von Artefakten aus entfernten Repositorien herunterladen Indexe von entfernten Repositorien beim Start herunterladen und aufzufrischen. Der nchste Abschnitt erlaubt in einem Fenster die Auswahl der auszufhrenden 424

Maven in Eclipse: m2eclipse Goals wann immer ein Projekt importiert wird und auch sobald Quellverzeichnisse eines gegebenen Projektes gendert werden. Das Standard Goal ist process-ressources, welches die Ressourcen eines Projektes in das Zielverzeichnis kopiert und das Projekt zur Paketierung vorbereitet. Diese Auswahl anzupassen ist hilfreich, sollten sie benutzerdefinierte Goals aufrufen um Ressourcen zu verarbeiten oder untersttzende Konfigurationen zu generieren. Sollten Sie Hilfe brauchen, ein bestimmtes Goal auszuwhlen, so drcken sie den Select Auswahlknopf um den Goals Dialog aufzurufen. Das linke Fenster aus Figure 14.37, Maven Goal Dialogfenster (Abbildung 14.37: "Maven Goal Dialogfenster") gibt die Auflistung aller Maven Standardlebenszyklen wieder.

425

Maven in Eclipse: m2eclipse

Figure 14.37. Maven Goal Dialogfenster Es ist gut mglich, dass Sie beim Anblick der vielen verfgbaren Goals berwltigt sind. Es bestehen buchstblich hunderte Maven Plugins fr alles Mgliche, von der Generierung der Datenbank Struktur, ber das Durchfhren von Integrationstests, 426

Maven in Eclipse: m2eclipse das Durchfhren von statischen Analysen bis hin zur Generierung von Web Services mittels XFire. Der Goals-Dialog bietet mehr als 200 Plugins mit auswhlbaren Goals. Das Fenster der rechten Seite der Figure 14.37, Maven Goal Dialogfenster (Abbildung 14.37: "Maven Goal Dialogfenster") stellt z.B. die angebotenen Goals des Tomcat Maven Plugin dar. Mittels der Maske Suchen knnen Sie wie gewohnt die Liste reduzieren. m2eclipse wird whrend Sie die Eingabe vornehmen die Liste gemss Ihrer Auswahl anpassen. Eine weitere Option ist die Anzeige der Maven Installationen Konfiguration wie diese in Figure 14.38, Maven Installationen Auswahl Anzeige (Abbildung 14.38: "Maven Installationen Auswahl Anzeige") dargestellt ist:

Figure 14.38. Maven Installationen Auswahl Anzeige

427

Maven in Eclipse: m2eclipse Auf dieser Seite knnen Sie weitere Maven Installationen Ihrer Eclipse Umgebung zufgen. Sollten Sie eine von der mitgelieferten verschiedene Maven Version benutzen wollen, so knnen Sie auf dieser Seite verschiedene Versionen konfigurieren. Die Funktionalitt ist hnlich der, der Java Virtuellen Maschine (JVM) Konfiguration innerhalb von Eclipse. Eine eingebettete Version von Maven, bekannt unter dem Titel Maven Embedder ist bereits gesetzt. Diese wird benutzt um Maven innerhalb von Eclipse auszufhren. Sollten Sie eine andere Installation neben der von Embedder angebotenen einsetzen wollen, knnen Sie diese mittels des Add Buttons zufgen. Abbildung Figure 14.38, Maven Installationen Auswahl Anzeige (14.38: "Maven Installationen Auswahl Anzeige") zeigt die Konfiguration mit Maven Embedder, Maven 2.0.9 sowie Maven 2.1-SNAPSHOT. Die Maven Installationen Auswahl Anzeige erlaubt Ihnen ebenfalls die Dateien der lokalen sowie globalen Einstellungen, der settings.xml Dateien zu setzen. Sollten Sie den Ort dieser Dateien nicht spezifizieren, so geht Maven davon aus, das es die globalen Einstellungen unter conf/settings.xml der ausgewhlten Maven Installation findet. Sie knnen ebenfalls den Ort der Datei der benutzerdefinierten Einstellungen von ~/.m2/settings.xml umdefinieren, sowie den Ort des lokalen Maven Repository unterschiedlich von ~/.m2/repositroy definieren. Ebenfalls zur Auswahl in den Einstellungen von Eclipse steht die Mglichkeit Maven Version Dekoratoren einzustellen. Diese Einstellung gibt die Mglichkeit die aktuelle Version eines Artefakten im Eclipse Package Explorers dazustellen und wird in Figure 14.39, Einstellen der Maven Versions-Dekoratoren (Abbildung 14.39 "Einstellen der Maven Versions-Dekoratoren") dargestellt.

428

Maven in Eclipse: m2eclipse

Figure 14.39. Einstellen der Maven Versions-Dekoratoren Um diese Einstellung zu aktivieren, whlen Sie einfach den Maven Version Dekorator Tick wie in Figure 14.39, Einstellen der Maven Versions-Dekoratoren (Abbildung 14.39: "Einstellen der Maven Versions-Dekoratoren") dargestellt aus. 429

Maven in Eclipse: m2eclipse Sollte dies nicht ausgewhlt sein, so wird das Projekt lediglich mit dem Namen sowie dem relativen Pfad innerhalb des Package Explorers dargestellt, wie in Figure 14.40, Package Explorer ohne Maven Versions-Dekoratoren (Abbildung 14.40 "Package Explorer ohne Maven Versions-Dekoratoren") zu sehen:

Figure 14.40. Package Explorer ohne Maven Versions-Dekoratoren Sobald die Maven Versions-Dekoratoren zugeschaltet sind, wird dem Projektnamen die aktuelle Projektversion zugefgt wie dies in Figure 14.41, Package Explorer mit zugeschalteten Maven Versions-Dekoratoren (Abbildung 14.41: "Package Explorer mit zugeschalteten Maven Versions-Dekoratoren"):

430

Maven in Eclipse: m2eclipse

Figure 14.41. Package Explorer mit zugeschalteten Maven Versions-Dekoratoren Diese ntzliche Funktion erlaubt doch auf einen Blick die eingebundenen Projekt Versionen zu berblicken, ohne den Umweg ber das POM einzuschlagen.

14.14. Zusammenfassung
m2eclipse ist mehr als nur ein Plugin welches die Untersttzung fr Maven innerhalb von Eclipse bereitstellt. Vielmehr ist es eine umfassende Integration welche den Umgang beginnend mit dem Erstellen eines Projektes bis hin zum Herausfinden von impliziten Abhngigkeiten um Lngen vereinfacht. m2eclipse ist ein erster Schritt in die Richtung einer Entwicklungsumgebung, welche den 431

Maven in Eclipse: m2eclipse reichen semantischen Fundus des zentralen Maven Repositorien nutzt. Mit der Verbreitung des m2eclipse Plugin werden viele weitere Archetypen verffentlicht werden, und weitere Projekte werden Wert darin sehen, deren Artefakte ins zentrale Maven Repository zu publizieren. Sollten Sie bereits zuvor versucht haben Eclipse und Maven - ohne die Hilfe eines Werkzeuges welches versteht mit den hierarchischen Abhngigkeiten umzugehen zu benutzen, so knnen Sie einschtzen wie wichtig und zentral die saubere Integration ist, welche ein Arbeiten mit verschachtelten Projekten ermglicht, welche multi-modulare Projekte mit sich bringen.

432

Chapter 15. Projekt-Site Erstellung


15.1. Einleitung
Erfolgreiche Software Anwendungen werden selten von Ein-Personen-Teams erstellt. Sobald wir uns von Software Projekten unterhalten, welche es Wert sind Zeit zu investieren, so haben wir es zumeist mit Gruppen von zusammenarbeiternden Entwicklern zu tun. Dies reicht von Kleingruppen einiger weniger Entwickler bis hin zu Hunderten oder gar Tausenden von Entwicklern welche ber den Erdball verteilt zusammenarbeiten. Die meisten Open Source Projekte (wie z.B. Maven) stehen und fallen Aufgrund der mehr oder weniger bestehenden (guten) Dokumentation welche eine Vielzahl verteilter Entwickler und Benutzer untersttzt. Alle Umgebungen haben gemein, dass es wichtig ist, dass Projekte einen einfachen Prozess zur Erstellung und Verffentlichung einer Online Dokumentation haben. Software Development ist zunchst einmal eine bung der Zusammenarbeit und Kommunikation und die Verffentlichung eines Maven Projekt Sites ist ein Baustein um sicherzustellen, dass ein Projekt mit den End-Kunden in Kontakt treten kann. Eine Website eines Open Source Projektes ist oftmals die Grundlage fr beide Gruppen, die der Benutzer wie auch die der Entwickler. Benutzer sehen sich auf einem Site nach Einfhrungen, Benutzerhandbchern, API Dokumentationen und Foren/Archiven um; Entwickler halten nach Design Dokumenten, Quellcode, Issue Tracking und Release Plnen Ausschau. Grosse Open Source Projekte werden Wiki's, Issue Tracking Systeme und Kontinuierliche Build Systeme in einen Site einbinden, welche die Projektdokumentation mit aktuellen Entwicklungsstnden anreichern. Sollte ein neues Open Source Projekt einen unzureichenden WebSite bereitstellen, einen Site welcher die grundlegende Informationswnsche potentieller Benutzer nicht befriedigt, so ist das oftmals ein Grund fr die zu spterer Zeit fehlenden Akzeptanz - das Projekt wird nicht angenommen werden. In anderen Worten, fr ein Open Source Projekt ist zum Erfolg die Dokumentation oftmals ebensowichtig wie der Quellcode selbst - Open Source lebt von der Community! 433

Projekt-Site Erstellung Maven kann dazu eingesetzt werden, einen Website zu erstellen welcher Informationen bereitstellt, welche fr beide Benutzergruppen relevant sind, die der Benutzer wie auch die der Entwickler. Ohne weitere Konfiguration ist Maven bereits in der Lage verschiedenerlei Reports zu generieren, von solchen zu Unit Testergebnissen, ber Abhngigkeiten von Packages weiter zu Berichten bezglich Qualittsmetriken der Quellen. Maven gibt Ihnen die Mglichkeit einfache Webseiten zu erstellen und diese in einheitlicher Art und Weise darzustellen. Maven kann den Site Inhalt in verschiedenen Formaten publizieren, unter anderem in XHTML und PDF. Maven kann dazu eingesetzt werden, eine API Dokumentation zu erstellen, sowie zur Erstellung von eingebetteter JavaDoc Dokumentationen und kommentierter Quelldateien in Ihrem binr Release Archiv. Sobald Sie Maven dazu einsetzen die entsprechende Projektdokumentation fr Benutzer und Entwicker zu erstellen, knnen Sie Maven ebenfalls dazu benutzen diese Dokumentation zu verffentlichen.

15.2. Erstellen eines Projekt-Sites mit Maven


Um die Mglichkeit einen Projekt-Site zu generieren werden wir dies nun gemeinsam tun. Erstellen Sie zunchst ein Maven Beispielprojekt mit Hilfe des Archteyp Plugin:
$ mvn archetype:create -DgroupId=org.sonatype.mavenbook -DartifactId=sample-project

Der vorgehende Aufruf erstellt Ihnen das einfachste mgliche Maven Projekt mit einer einzigen Java Klasse abgelegt im Verzeichnis src/main/java und einem einfachen POM. Sie knnen nun zu diesem Projekt einen Maven Projekt Site erstellen, indem Sie mvn site aufrufen. Um den Site zu erstellen und das Ergebnis in einem Browser zu betrachten rufen Sie mvn site:run auf. Der Aufruf wird den Projekt-Site erstellen und eine Instanz eines eingebetteten Jetty Servers aufstarten.
$ 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] ------------------------------------------------------------------------

434

Projekt-Site Erstellung
[INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'. [INFO] Setting property: velocimacro.messages.on => 'false'. [INFO] Setting property: resource.loader => 'classpath'. [INFO] Setting property: resource.manager.logwhenfound => 'false'. [INFO] [site:run] 2008-04-26 11:52:26.981::INFO: Logging to STDERR via org.mortbay.log.StdErrLog [INFO] Starting Jetty on http://localhost:8080/ 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 org.apache.jasper.servlet.JspServlet 2008-04-26 11:52:26.244::INFO: Started SelectChannelConnector@0.0.0.0:8080

Sobald Jetty gestartet ist, fragt dieser den Port 8080 ab, Sie knnen den Projekt Site ansehen, indem Sie die Seite http://localhost:8080/ in einem Webbrowser (z.B. Mozilla, IE) aufrufen. Das Ergebnis sehen Sie in Figure 15.1, Einfacher Generierter Maven Site.

Figure 15.1. Einfacher Generierter Maven Site Beim nheren Betrachten des Sites werden Sie merken, dass er als tatschlicher Projekt Site von sample-project nicht weit reichen wird. Es gibt schlicht nicht 435

Projekt-Site Erstellung viel zu sehen (und das ist auch nicht wirklich schn dargestellt). Da das Beispielprojekt keine Entwickler, Email Listen, Issue Tracking Systeme oder Quell Code Repository Konfigurationen aufweist, werden alle diese Seiten leer angezeigt. Sogar die Index-Seite des Projektes liest sich: "There is currently no description associated with this project" - Es ist derzeit keine Beschreibung mit diesem Projekt assoziiert. Um den Site anzupassen mssen Sie dem Projekt und dem zugehrigen POM Inhalt geben. Wollen Sie das Maven Site Plugin benutzen um Ihren Projekt Site zu erstellen, so werden Sie dessen Konfiguration anpassen mssen. Sie werden einige der wichtigen Felder des POM setzen wollen um Maven von den Personen welche an diesem Projekt teilnehmen in Kenntnis zu setzen und Sie werden den Inhalt des linksseitigen Menu sowie die Verweise in der Kopfzeile anpassen wollen. Um den Inhalt des Sites anzupassen sowie die Verweise des Menus anzupassen werden sie den Site Descriptor anpassen.

15.3. Anpassen des Site Descriptors


Sobald Sie dem Site Inhalte zufgen, werden Sie das linksseitige Menu, welches mit Ihrem Site erstellt wird, anpassen wollen. Der folgende Site Descriptor definiert das Logo der oberen, linken Ecke des Projekt Sites. Zustzlich zur Anpassung der Kopzeile fgt das Beispiel einen weiteren Abschnitt "Beispielprojekt" dem linksseitigen Menu zu. Dieser Abschnitt enthlt einen einzigen Verweis auf eine bersichtsseite. Example 15.1. Ein ursprnglicher Site Descriptor
<project name="Sample Project"> <bannerLeft> <name>Sonatype</name> <src>images/logo.png</src> <href>http://www.sonatype.com</href> </bannerLeft> <body> <menu name="Beispielprojekt"> <item name="Overview" href="index.html"/> </menu> <menu ref="reports"/> </body>

436

Projekt-Site Erstellung
</project>

Der Site Descriptor verweist auf eine Grafik. Diese Graphik logo.png sollte sich im Verzeichnis ${basedir}/src/site/resources/images befinden. Zustzlich zur Anpassung des Site Descriptors macht es Sinn, gleich auch eine einfache Seite index.apt im Verzeichnis ${basedir}/src/site/apt zu erstellen. Fgen Sie den folgenden Inhalt in die Seite index.apt ein, diese wird zur Laufzeit in eine Datei index.html Datei umgewandelt und dient als erste Seite welche ein Benutzer zu sehen bekommt, sollte er zu ihrem Maven generierten Projekt Site kommen.
Willkommen zum unserem Beispielprojekt, wir hoffen Sie geniessen die Zeit auf diesem Projekt Site. Wir haben versucht Ihnen eine ntzliche Benutzer- sowie Entwickler-Dokumentation zu erstellen und sind froh, dass Sie sich die Zeit genommen haben diesen Site anzusehen. Welch ein Beispielprojekt Nun, es ist zunchst einfach genug zu erklren: Dieses BeispielProjekt ist ein Beispiel eines Projektes ausgestatet mit einem Site welcher mittels Maven generiert wird. Ein spezielles Team von Freiwilligen hilft, den Beispiel Projekt Site zu unterhalten, und so weiter, ...

Um die Site nun anzusehen, rufen Sie mvn clean site auf, gefolgt von mvn site:run
$ mvn clean site $ mvn site:run

Sobald Sie das getan haben, laden Sie eine Seite im Webbrowser in dem Sie diesen auf http://localhost:8080 richten. Sie sollten eine Darstellung hnlich der in Figure 15.2, Angepasster Sample Projekt Web Site dargestellten erhalten.

437

Projekt-Site Erstellung

Figure 15.2. Angepasster Sample Projekt Web Site

15.3.1. Anpassen der Kopfzeilengraphiken


Um die Grafiken, welche in der oberen rechten und linken Ecke der Seite erscheinen anzupassen, knnen Sie die Elemente bannerLeft und bannerRight innerhalb des Site Descriptors setzen: Example 15.2. Einfgen eines Banners Links und Rechts in einen Site Descriptor
<project name="Sample Project"> <bannerLeft> <name>Left Banner</name> <src>images/banner-left.png</src> <href>http://www.google.com</href> </bannerLeft>

438

Projekt-Site Erstellung
<bannerRight> <name>Right Banner</name> <src>images/banner-right.png</src> <href>http://www.yahoo.com</href> </bannerRight> ... </project>

Beide Elemente bannerLeft sowie bannerRight enthalten innere Elemente name, src sowie href. Im oben dargestellten Site Descriptor wird das Maven Site Plugin eine Kopfzeile mit der Grafik banner-left.png in der linken sowie banner-right.png in der rechten oberen Ecke. Maven wird unter dem Verzeichnis ${basedir}/src/site/resources/images nach den Grafiken suchen.

15.3.2. Anpassen des bersichtsmenues


Um den Inhalt der linksseitigen Navigationsleiste anzupassen, setzen Sie das Element menu mit Unterelementen item ein. Das Element menu fgt der Navigationsleiste einen Abschnitt an, die darin befindlichen Eintrge, als Verweise dargestellt, sind vom Element-Typ item Example 15.3. Erstellen von Meneintrgen in einem Site Descriptor
<project name="Sample Project"> ... <body> <menu name="Sample Project"> <item name="Einleitung" href="index.html"/> <item name="Neuigkeiten" href="news.html"/> <item name="Features" href="features.html"/> <item name="Installation" href="installation.html"/> <item name="Konfiguration" href="configuration.html"/> <item name="FAQ" href="faq.html"/> </menu> ... </body> </project>

439

Projekt-Site Erstellung Menu-Eintrge knnen auch geschachtelt werden. Verschachteln Sie Menu-Eintrge, so erstellen Sie automatisch Faltmenus. Der folgende Eintrag fgt einen Verweis "Entwicklerseiten" an, welcher auf die Seite /developer/index.html verweist. sobald ein Benutzer auf den Eintrag "Entwicklerseiten" geht, werden die Eintrge unterhalb dieses Eintrages angezeigt. Example 15.4. Einfgen eines Links in ein Site Menu
<project name="Sample Project"> ... <body> ... <menu name="Sample Project"> ... <item name="Entwicklerseiten" href="/developer/index.html" collapse="true"> <item name="System Architektur" href="/developer/architecture.html"/> <item name="Embedder's Guide" href="/developer/embedding.html"/> </item> </menu> ... </body> </project>

Hat ein Eintrag das Attrribut collapse auf true gesetzt, so wird Maven den Eintrag erst anzeigen wenn ein Besucher diesen Eintrag anwhlt. Im vorhergehenden Beispiel wird Maven die Eintrge "System Architektur" und "Embedders Guide" nicht als Verweise anzeigen, statt dessen einen kleinen Pfeil darstellen, welcher auf "Entwicklerseiten" zeigt. Sobald ein Besucher den Verweis "Entwicklerseite" aufruft, wird das erweiterte Menu mit den beiden Eintrgen und vorangehendem Pfeil dargestellt.

15.4. Site-Verzeichnisstruktur
Maven legt alle Bestandteile des Projekt Site unter em Verzeichnis src/site ab. Dokumente von hnlichem Format sind in einem Unterverzeichnis von src/site abgelegt. So sind alle APT Dokumente unter src/site/apt abgelegt, alle FML Dokumente sollten sich unter src/site/fml und schliesslich alle XDoc 440

Projekt-Site Erstellung Dokumente unter src/site/xdoc befinden. Der Site Descriptor sollte sich im Verzeichnis src/site in form einer Datei site.xml befinden und alle zugehrigen Ressourcen unter src/site/ressources abgelegt sein. Sobald das Maven Site Plugin einen Projekt Site erstellen soll, wird Maven alles was unter dem Site-Resource Verzeichnis enthalten ist in das Wurzelverzeichnis Ihres neuen Projekt Sites kopieren. Sollten Sie also eine Bilddatei unter src/site/resources/images/test.png abgelegt haben, so wird diese zuknftig unter dem relativen Pfad images/test.png zu finden sein. Das nachfolgende Beispiel stellt die entsprechenden Verzeichnisse der Dateien vom Typ APT, FML, HTML, XHTML sowie einiger XDoc Dateien dar. Beachten Sie dabei, dass XHTML Dateien dabei direkt im Resource-Verzeichnis liegen. Das Dokument architecture.html wird von Doxia nicht weiter verarbeitet; es wird statt dessen einfach in das zugehrige Ausgabeverzeichnis kopiert. Sie knnen diesen Mechanismus unter anderem dazu benutzen, um unverarbeitete HTML-Inhalte darzustellen, ohne dabei von den erweiternten Funktionalitten welche Doxia sowie das Maven Site Plugin bieten,Gebrauch zu machen.
sample-project +- src/ +- site/ +- apt/ | +- index.apt | +- about.apt | | | +- developer/ | +- embedding.apt | +- fml/ | +- faq.fml | +- resources/ | +- images/ | | +- banner-left.png | | +- banner-right.png | | | +- architecture.html | +- jira-roadmap-export-2007-03-26.html | +- xdoc/ | +- xml-example.xml | +- site.xml

441

Projekt-Site Erstellung Beachten Sie bitte, dass die Entwickler Dokumentation unter src/site/apt/developer/embedding.apt abgelegt ist. Dieses zustzliche Verzeichnis innerhalb des apt-Verzeichnisses wird ebenfalls in der Struktur der erzeugten HTML-Seiten der Site abgebildet. Die Inhalte des Verzeichnisses src/site/apt werden in HTML-Ausgaben umgewandelt, welche relativ zum Wurzelverzeichnis der Site abgelegt werden. Liegt eine Datei im Verzeichnis /apt, so wird diese in das Wurzelverzeichnis des generierten Site abgelegt. Liegt eine Datei tiefer, z.B. unter /apt/developer so lst dies die Erstellung eines gleichnamigen Unterverzeichnisses aus, ein Verzeichnis apt/developer wird hierbei auf /developer abgebildet.

15.5. Erstellen einer Projekt-Dokumentation


Maven baut auf einen Dokumentenverarbeitungs Prozessor namens Doxia auf, welcher verschiedene Quellformate lesen und in ein allgemeines Dokumentenmodell umwandeln kann. Doxia kann anschliessen diese Dokumente verarbeiten und das Ergebnis in einer Reihe verschiedener Formate wie z.B. PDF oder XHTML ausgeben. Um eine Dokumentation fr Ihr Projekt zu erstellen, sollten Sie den Inhalt in einem Format ablegen, welcher von Doxia ausgewertet werden kann. Doxia untersttzt derzeit die Formate Almost Plain Text (APT), XDoc (ein Maven 1.x Dokument-Format) XHTML sowie FML (sinnvol fr FAQ Dokumente). Dieses Kapitel enthlt eine Kurzeinfhrung in das APT Format. Bezglich einer tiefergreifenden Einfhrung des APT-Format, oder auch einer Einfhrung in das XDoc Format oder FML verweisen wir auf folgende Dokumente APT Referenz: http://maven.apache.org/doxia/format.html XDoc Referenz: http://jakarta.apache.org/site/jakarta-site2.html FML Referenz: http://maven.apache.org/doxia/references/fml-format.html

15.5.1. Ein APT Beispiel


442

Projekt-Site Erstellung Das Beispiel Example 15.5, APT Dokument stellt ein einfaches APT Dokument dar. Es enthlt einen einleitenden Paragraphen und eine einfache Liste. Beachten Sie bitte auch, dass die Liste mit einem "[ ]" abgeschlossen wird. Example 15.5. APT Dokument
--Einfhrung in das Beispielprojekt --Brian Fox --26-Mar-2008 --Willkommen zum Beispielprojekt Dies ist ein Beispielprojekt, willkommen! es freut uns, dass Sie sich die Zeit nehmen und die Startseite des Beispielprojektes lesen. Wir hoffen, Sie werden Ihren Spass an unserem Beispielprojekt haben. Hier ein paar ntzliche Verweise: * {{{news.html}Neueigkeiten}} * {{{features.html}Features}} * {{{faq.html}FAQ}} []

Wrde das vorgehende APT Dokument aus Beispiel Example 15.5, APT Dokument in der Datei src/site/apt/index.apt abgelegt, so wrde das Maven Site Plugin das APT Dokument mittels Doxia analysieren und den Inhalt in Form von XHTML in der Datei index.html ablegen.

15.5.2. Ein FML Beispiel


Viele Projekte unterhalten eine Frequently Asked Questions (FAQ) Seite. Hier ein Beispiel um das FML Format vorzustellen (Example 15.6, FAQ Markup Sprach Dokument): Example 15.6. FAQ Markup Sprach Dokument 443

Projekt-Site Erstellung
<?xml version="1.0" encoding="UTF-8"?> <faqs title="Frequently Asked Questions"> <part id="General"> <faq id="sample-project-sucks"> <question>Sample project doesn't work. Why does sample project suck?</question> <answer> <p> We resent that question. Sample wasn't designed to work, it was designed to show you how to use Maven. If you really think this project sucks, then keep it to yourself. We're not interested in your pestering questions. </p> </answer> </faq> <faq id="sample-project-source"> <question>I want to put some code in Sample Project, how do I do this?</question> <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>

15.6. Ausrollen eines Projekt-Sites


Sobald nun Ihre Projekt-Dokumentation erstellt ist und Sie einen ansehnlichen Site erstellt haben, werden Sie diese auf einen Server verteilen wollen. Um dies zu bewerkstelligen knnen Sie wiederum das Maven Site Plugin benutzen, welches Ihnen Arbeit abnehmen kann. Es ist mglich die Verteilung auf einem entfernten Server auf verschiedene Art und Weise zu bewerkstelligen, darunter FTP, SCP sowie DAV. Um den Site mittels DAV zu deployen, mssen Sie das Element site innerhalb des Abschnitts distributionManagement des POM wie folgt 444

Projekt-Site Erstellung konfigurieren: Example 15.7. Konfigurieren eines Site Deployments


<project> ... <distributionManagement> <site> <id>sample-project.website</id> <url>dav:https://dav.sample.com/sites/sample-project</url> </site> </distributionManagement> ... </project>

Die URL innerhalb des Elements distributionManagement wird eingeleitet durch DAV, welches dem Maven Site Plugin signalisiert, das der Site mittels einer URL welche WebDAV versteht, verffentlicht werden soll. sobald Sie den Abschnitt distributionManagement zu Ihrem POM des Projektes sample-project zugefgt haben, knnen Sie versuchen den Site zu verffentlichen:
$ mvn clean site-deploy

Sollten Sie einen Server so konfiguriert haben, dass dieser WebDAV versteht, wird Maven ihren Projekt Site zu einem entfernten Server verteilen. Sollten Sie Ihren Projekt Site auf einem Server verffentlichen, welcher der ffentichkeit zugnglich ist, so werden Sie diesen so konfigurieren, dass Sie fr den (schreibenden) Zugriff eine Zugangsberechtigung bentigen. Sollte Ihr Webserver Sie nach einem Benutzername und Passwort fragen (oder anderen Credentials, so knnen Sie diese in der Settings-Datei unter ~/.m2/settings.xml setzen)

15.6.1. Konfigurieren der Server Authentifizierung


Um eine Benutzername/Passwort Kombination, welche whrend der Site Verffentlichung bentigt wird, einzustellen, werden wir die Settings-Datei unter $HOME/.m2/settings.xml in folgender Weise abndern:

445

Projekt-Site Erstellung Example 15.8. Speichern der Server Authentifizierungsdaten in den benutzerspezifischen Einstellungen
<settings> ... <servers> <server> <id>sample-project.website</id> <username>jdcasey</username> <password>b@dp@ssw0rd</password> </server> ... </servers> ... </settings>

Der Abschnitt der Server Authentifizierung kann eine Anzahl verschiedener Authentifizierungselemente enthalten. Sollten Sie SCP fr die Verteilung benutzen, so bevorzugen Sie vielleicht Public-Key Authentifizierung. Um dies zu konfigurieren, setzen Sie die Elemente publicKey und passPhrase statt des Elements password. Mglicherweise mssen Sie dennoch das Element userName setzen, abhngig von der Konfiguration ihres Servers.

15.6.2. Konfigurieren der Datei und Verzeichnisrechte


Sollten Sie in einer grossen Gruppe von Entwicklern arbeiten, so mchten Sie natrlich sicherstellen, dass die Seiten der WebSite mit den korrekten Benutzer/Gruppenkennungen sowie Berechtigungen auf dem Server verteilt werden. Um bestimmte Datei- und Verzeichnisberechtigungen whrend der Verffentlichung zu setzen, fgen Sie in Ihrer Settings-Datei unter $HOME/.m2/settings.xml folgenden Abschnitt ein: Example 15.9. Konfiguration von Datei und Verzeichnis-Rechte eines Remote Server
<settings> ... <servers> ...

446

Projekt-Site Erstellung
<server> <id>hello-world.website</id> ... <directoryPermissions>0775</directoryPermissions> <filePermissions>0664</filePermissions> </server> </servers> ... </settings>

Mit den oben aufgefhrten Berechtigungen werden der Eigentmer (owner) und die Mitglieder der Hauptgruppe (primary group) auf die Dateien und Verzeichnisse schreibberechtigt sein. Annonyme Benutzer werden nur die Berechtigung zum Lesen der Dateien und Auflisten der Verzeichnisse haben; Alle anderen Benutzer sind auf nur-lesen beschrnkt.

15.7. Anpassen des Site Auftritts


Die Maven Standardvorlage eines Projekt Sites lsst vieles zu wnschen brig. Sollten Sie ihren Projekt Site ber das Hinzufgen von Inhalten, Navigationselementen und speziefische Logos hinaus anpassen wollen, so bietet Ihnen Maven hierfr mehrere mgliche Mechanismen. Jeder einzelne bietet Ihnen sukzessive tieferen - Zugang zu Web-Inhalten und Site Struktur. Fr einfache, projektbezogene Anpassungen ist oftmals die Erstellung eines angepassten Stylesheets site.css genug. Sollten Sie jedoch erwarten, dass Ihre Anpassungen in mehreren Projekten in gleicher Weise zur Anwendung kommen, oder sollten Ihre nderungen das von Maven generierte XHTML betreffen, dann sollten Sie sich berlegen eine Maven Skin zu erarbeiten.

15.7.1. Anpassen des Stylesheets site.css


Der eingfachste Weg das Aussehen ihres Projekt Websites zu beeinflussen ist dies mittels einem projektbezogenen Stylesheet site.css zu bewerkstelligen. Wie alle Grafiken oder XHTML-Inhalte welche Sie fr Ihren Site bereitstellen, wird auch das Stylesheet site.css im Verzeichnis src/site/resources abgelegt. Maven 447

Projekt-Site Erstellung erwartet die Datei im Verzeichnis src/site/resources/css vorzufinden. Mittels Cascading Style Sheets (CSS) ist es mglich, die Textanzeige zu verndern, das Layout anzupassen und sogar Hintergrundbilder, Grafiken und Aufzhlungen zu beeinflussen. Ein Beispiel; sollten wir uns entscheiden, die Menu-berschriften ein wenig strker zu betonen, so knnten wir die folgende Anpassung in der Datei src/site/resources/css/site.css vornehmen:
#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; }

Nach erfogreicher erneuten Generierung des Website, sollten die Menu-berschriften mit grauem Hintergrund hinterlegt sein und durch einen zustzlichen Abstand von den Menu-Unterpunkten getrennt sein. Durch Einsatz dieser Datei kann jede von Maven erzeugte Strukture mittels CSS beeinflusst werden. ndern Sie die Datei site.css eines bestimmten Projektes, so wird diese nderung nur dieses eine Projekt betreffen. Sollten Sie daran interessiert sein die nderung so vorzunehmen, dass diese projektbergreifend wirkt, so mssen Sie eine bestimmte Skin fr das Maven Site Plugin erstellen. Tip Es gibt keine gute Referenz bezglich der Struktur der Standardvorlage des Projekt-Sites von Maven. Sollten Sie sich daran versuchen die Style-Vorlagen ihres Sites anzupassen, so ist es ratsam Firefox und eine Erweiterung wie z.B. Firebug einzusetzen, welche Ihnen ermglicht das DOM einer Seite zu betrachten.

15.7.2. Erstellen einer Sitevorlage


Sollte die Standardvorlage fr Sie nun wirklich nicht ausreichen, so knnen Sie 448

Projekt-Site Erstellung immer darauf zurckgreifen, die Maven Standardvorlage des Site anzupassen. Anpassungen der Maven Standardvorlage geben Ihnen die volle Kontrolle ber die Ausgaben des Maven Plugin wobei es mglich ist die Vorlage derart zu verndern, dass man diese nicht wiedererkennt. Das Site Plugin setzt auf eine Engine genannt Doxia auf, welche wiederum auf ein Velocity Vorlagen aufbaut, um eine entsprechende XHTML Seiten zu erzeugen. Um die Struktur einer Seite welche erzeugt wird zu verndern, ist es mglich, im POM eine angepasste Seitenvorlage anzugeben. Die Site-Vorlage ist sehr komplex und Sie sollten einen guten Grund haben diese zu verndern. Um dies erfolgreich zu bewerkstelligen, holen Sie sich die Standard Velocity Vorlage von Doxia's Subversion Repository default-site.vm ins Verzeichnis src/site/site.vm. Diese Vorlage ist in einer Velocity genannten Sprache geschrieben. Velocity ist eine einfache Vorlagensprache welche es erlaubt einfache Makro-Definitionen zu erstellen und die Properties und Methoden eines Objektes in einfacher Schreibweise zugnglich zu machen. Eine umfngliche Einleitung wrde den Rahmen dieses Buches sprengen, wir verweisen daher auf den Projekt Site von Velocity http://velocity.apache.org. Die Standard Site Vorlage ist sehr umfangreich, jedoch ist die nderung welche es bentigt, das linksseitige Menu zu anzupassen, eher einfach. Sollten Sie also versucht sein das Aussehen eines Menu-Eintrages zu verndern, so suchen Sie das Makro menuItem auf. Dieses finden Sie als Abschnitt wie folgt:
#macro ( menuItem $item ) ... #end

Wenn Sie nun die Makro-Definition mit dem unten angegebenen Makro ersetzen, so wird dies JavaSkript einsetzen, um Ihnen das Aus- und Einklappen von Menus ermglichen, ohne hierbei einen gesamten Seitenladevorgang zu bentigen.
#macro ( menuItem $item $listCount ) #set ( $collapse = "none" ) #set ( $currentItemHref = $PathTool.calculateLink( $item.href, $relativePath ) ) #set ( $currentItemHref = $currentItemHref.replaceAll( "\\", "/" ) ) #if ( $item && $item.items && $item.items.size() > 0 )

449

Projekt-Site Erstellung
#if ( $item.collapse == false ) #set ( $collapse = "collapsed" ) #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 ( $item.img ) #if ( ! ( $item.img.toLowerCase().startsWith("http") || $item.img.toLowerCase().startsWith("https") ) ) #set ( $src = $PathTool.calculateLink( $item.img, $relativePath ) ) #set ( $src = $item.img.replaceAll( "\\", "/" ) ) <img src="$src"/> #else <img src="$item.img" align="absbottom" style="border-width: 0"/> #end #end #if ( $alignedFileName == $currentItemHref ) <strong>$item.name</strong> #else #if ( $item && $item.items && $item.items.size() > 0 ) <a onclick="expand('list$listCount')" style="cursor:pointer">$item.name</a> #else <a href="$currentItemHref">$item.name</a> #end #end #if ( $item && $item.items && $item.items.size() > 0 ) #if ( $collapse == "expanded" ) <ul id="list$listCount" style="display:block"> #else <ul id="list$listCount" style="display:none"> #end #foreach( $subitem in $item.items ) #set ( $listCounter = $listCounter + 1 ) #menuItem( $subitem $listCounter ) #end </ul> #end </li> #end

Diese nderung erweitert das Makro menuItem um einen Parameter. Damit die 450

Projekt-Site Erstellung neue Funktionalitt eingesetzt werden kann, mssen Sie noch alle Referenzen zu diesem Makro anpassen, andernfalls kann es dazu kommen, dass die erweiterte Vorlage unerwnschten oder sogar inkonsistenten XHTML Code erzeugt. Um diesen Referenzwechsel abzuschliessen, erweitern Sie das Makro mainMenu in gleicher Weise. Sie knnen das Makro finden, indem Sie nach einem Eintrag wie dem folgenden suchen:
#macro ( mainMenu $menus ) ... #end

Ersetzen Sie das bestehende Makro mainMenu mit der folgenden Implementierung:
#macro ( mainMenu $menus ) #set ( $counter = 0 ) #set ( $listCounter = 0 ) #foreach( $menu in $menus ) #if ( $menu.name ) <h5 onclick="expand('menu$counter')">$menu.name</h5> #end <ul id="menu$counter" style="display:block"> #foreach( $item in $menu.items ) #menuItem( $item $listCounter ) #set ( $listCounter = $listCounter + 1 ) #end </ul> #set ( $counter = $counter + 1 ) #end #end

Dieses neue Makro mainMenu ist mit dem neuen Makro menuItem von zuvor kompatibel, und zustzlich bietet es Untersttzung eines JavaSkript erweiterbaren obersten Menu. Die Auswahl eines obersten Menu-Eintrages erlaubt es dem Benutzer das ganze Menu zu sehen, ohne diesen hierbei zu einem erneuten Laden der Seite zu zwingen. Die nderung des Makro menuItem fhrte eine JavaSkript-Funktion expand() ein. Diese Methode muss der XHTML-Hauptvorlage gegen Ende angefgt werden. Suchen Sie nach einer Stelle welche der folgenden hnlich sieht:
<head> ...

451

Projekt-Site Erstellung
<meta http-equiv="Content-Type" content="text/html; charset=${outputEncoding}" /> ... </head>

und ersetzen Sie diese mit:


<head> ... <meta http-equiv="Content-Type" content="text/html; charset=${outputEncoding}" /> <script type="text/javascript"> function expand( item ) { var expandIt = document.getElementById( item ); if( expandIt.style.display == "block" ) { expandIt.style.display = "none"; expandIt.parentNode.className = "collapsed"; } else { expandIt.style.display = "block"; expandIt.parentNode.className = "expanded"; } } </script> #if ( $decoration.body.head ) #foreach( $item in $decoration.body.head.getChildren() ) #if ( $item.name == "script" ) $item.toUnescapedString() #else $item.toString() #end #end #end </head>

Nach dieser nderung der Standardvorlage des Sites mssen Sie noch das POM Ihres Projektes so abndern, dass dieses auf die neue Site Vorlage zeigt. Um die Sitevorlage anzupassen, wenden Sie das Element templateDirectory und konfigurieren die Vorlagenproperties des Maven Site Plugin. Example 15.10. Anpassen der Seitenvorlagen in einem Projekt POM
<project> ... <build> <plugins> <plugin> <artifactId>maven-site-plugin</artifactId> <configuration>

452

Projekt-Site Erstellung
<templateDirectory>src/site</templateDirectory> <template>site.vm</template> </configuration> </plugin> </plugins> </build> ... </project>

An dieser Stelle sollte es Ihnen mglich sein den Website erneut zu generieren. Sobald Sie dies tun werden Sie bemerken, das die Resourcen und das Stylesheet der Projekt-Site fehlen. Sobald ein Maven Projekt die Site-Vorlage anpasst, erwartet das Site Plugin, dass das Projekt alle Standardgrafiken sowie Stylesheets liefert. Um nun Ihre Projektresource beizusteuern ist es am einfachsten diese von den Standardverzeichnissen der Doxia Site Vorlage in Ihr eigenes Projektverzeichnis zu kopieren. Sie knnen dies mittels der folgenden Aufrufe bewerkstelligen (*nix):
$ svn co \ http://svn.apache.org/repos/asf/maven/doxia/doxia-sitetools/\ trunk/doxia-site-renderer $ rm \ doxia-site-renderer/src/main/resources/org/apache/maven/\ doxia/siterenderer/resources/css/maven-theme.css $ cp -rf \ doxia-site-renderer/src/main/resources/org/apache/maven/\ doxia/siterenderer/resources/* \ sample-project/src/site/resources

Machen Sie einen Check-Out des Projektes doxia-site-renderer, entfernen Sie die Standardvorlagen maven-theme.css und kopieren Sie die restlichen Resourcen in Ihres Projekts Verzeichnis src/site/resources. Sobald Sie nun den Site wieder erstellen, werden Sie bemerken, dass ein paar Menu-Eintrge wie normaler, unformatierter Text aussehen. Dies geht auf eine trickreiche Interaktion zwischen Ihrer neuen Sitevorlage und dem Site-Styleshet zurck. Der Fehler kann behoben werden, indem man das entsprechende Stylesheet site.css anpasst um die korrekten Verweisanzeigefarben zurckzuholen. Fgen Sie einfach folgenden Eintrag hinzu:
li.collapsed, li.expanded, a:link { color:#36a;

453

Projekt-Site Erstellung
}

Bei erneuter Erstellung des Site sollte die Verweisfarbe in den Menus ebenfalls korrekt angezeigt werden. Sollten Sie die neue Sitevorlage auf das gleiche Beispielprojekt dieses Kapitels anwenden, so werden Sie feststellen, dass nun das Menu in einer Baumstruktur vorliegt. Das Anwhlen von "Developer Resources" fhrt nicht mehr zur "Developer Resources"-Seite, statt dessen ffnet sich ein Untermenu. Da Sie das Menu Developer Resources in ein dynamisch angezeigtes Untermenu verwandelt haben, knnen Sie hierdurch nicht mehr lnger auf die Seite developer/index.apt zugreifen. Um dies wiederherzustellen empfiehlt es sich, einen Menu-Eintrag "bersichtsseite" zu erstellen, welcher auf die entsprechende Seite verweist: Example 15.11. Einfgen eines Menueeintrages in einen Site Descriptor
<project name="Hello World"> ... <menu name="Main Menu"> ... <item name="Developer Resources" collapse="true"> <item name="Overview" href="/developer/index.html"/> <item name="System Architecture" href="/developer/architecture.html"/> <item name="Embedder's Guide" href="/developer/embedding.html"/> </item> </menu> ... </project>

15.7.3. Wiederverwendbare Website Skins


Sollte Ihre Organisation viele Maven Projekt Sites erstellen, so ist es wahrscheinlich, dass Sie die neue Sitevorlage sowie die Stylesheet Anpassungen ber alle Projekte hinweg benutzen mchten. Sollten Sie also viele Projekte auf die selbe Sitevorlage sowie Stylesheets aufbauen wollen, so benutzen Sie am besten Mavens Untersttzung von Skins (engl. "hute"). Maven Skins erlauben es Ihnen die notwendingen Resourcen, Stylesheets und Vorlagen zusammenzupacken so dass diese von anderen Projekten benutzt werden knnen, anstatt diese mhsam fr 454

Projekt-Site Erstellung jedes Projekt zu reproduzieren. Nebst der Mglichkeit Ihre eigene Skin zu definieren, ziehen Sie bitte auch in Betracht eine der alternativen Maven Skins zu benutzen. Sie knnen von einer Anzahl verschiedener Skins whlen. Jede definiert einen eigenen Aufbau, Navigation, Grafiken/Logos und Vorlagen: Maven Classic Skin - org.apache.maven.skins:maven-classic-skin:1.0 Maven Default Skin - org.apache.maven.skins:maven-default-skin:1.0 Maven Stylus Skin - org.apache.maven.skins:maven-stylus-skin:1.0.1 Sie finden die neuste abschliessende Liste der verfgbaren Skins im Maven Repository: http://repo1.maven.org/maven2/org/apache/maven/skins/. Das Erzeugen einer angepassten Skin besteht lediglich im "Verpacken" der angepassten Datei maven-theme.css in ein Maven Projekt, so dass dieses mittels groupId, artifactId und version referenziert werden kann. Dieser Artefakt kann dann auch zustzliche Resources wie z.B. Grafiken, angepasste Sitevorlagen (in Velocity geschrieben und dadurch in der Lage eine vernderte Site Struktur aufzubauen) enthalten. In den meisten Fllen reichen Anpassungen der Stylesheets aus, die von ihnen gewnschten Vernderungen zu implementieren. Um den Ablauf zu zeigen, lassen Sie uns eine eigene Skin fr das Beispielprojekt erstellen. Wir beginnen mit dem angepassten Stylesheet maven-theme.css. Zunchst, vor wir das benutzerdefinierte Stylesheet erstellen, sollten wir ein eigenes Maven Projekt erstellen um zu ermglichen, den Site im Site Descriptor des Beispielprojekt zu referenzieren. Fangen wir damit an, ein Standardprojekt mittels dem Maven Archtetype Plugin zu generieren. Geben Sie von einem Verzeichnis ber dem Wurzelverzeichnis des Beispielprojekts folgenden Befehl ein:
$ mvn archetype:create -DartifactId=sample-site-skin -DgroupId=org.sonatype.mavenbook

Dies wrid ein Projekt generieren (und ein Verzeichnis) mit dem Namen sample-site-skin. Wechseln Sie in das neue Verzeichnis sample-site-skin, entfernen Sie alle bestehenden Quellcode- und Test-Artefakte und erstellen Sie ein 455

Projekt-Site Erstellung Verzeichnis /src/main/resources um Ihre Skin Resourcen abzulegen:


$ cd sample-site-skin $ rm -rf src/main/java src/test $ mkdir src/main/resources

15.7.4. Erstellen einer Angepassten Themenvorlage (CSS)


Als nchstes, schreiben Sie ein Stylesheet fr Ihre massgeschneiderte Skin. Diese Datei maven-theme.css sollte im Verzeichnis src/main/resources/css/ abgelegt werden. Im Unterschied zur Datei site.css, welche in den Site spezifischen Verzeichnissen eines Projektes befindet, wird die Datei maven-theme.css als Teil eines JAR Artefact in Ihrem localen Maven Repository abgelegt. Um Teil dieses Skin-JAR-Artefaktes zu werden, muss die Datei maven-themes.css im Hauptverzeichnis src/main/resources des Projekt Resource Verzeichnisses abgelegt werden. Wie bereits mit der Standard Sitevorlage, sollten Sie einen geeigneten Einstiegspunkt finden, um das Stylesheet anzupassen. Kopieren Sie das Stylesheet welches von der Maven Standardskin (default) benutzt wird in Ihr Projekt und nennen es maven-theme.css. Um von dieser Datei einfach eine Kopie zu erstellen, speichern Sie den Inhalt der Datei maven-theme.css aus dem Projekt maven-default-skin in das Verzeichnis src/main/resources/css/ Ihres neuen Skin Projekts. Da wir nun die Grundlinie festgelegt haben, erweitern wir diese mit den Stylesheet Anweisungen unserer vorgngigen Datei site.css. Ersetzen Sie den Style-Block #navcolumn h5 mit dem folgenden:
#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; }

456

Projekt-Site Erstellung

Sobald Sie mit der Anpassung der Datei maven-theme.css abgeschlossen haben, builden und installieren Sie das JAR des Beispielprojekt Sites in Ihr lokales Repository durch den Aufruf:
$ mvn clean install

Sobald der Aufruf abgeschlossen ist, der Artefakt in Ihrem lokalen Repository installiert, wechseln Sie zurck in Ihr Beispiel Projekt Verzeichnis. Sollten Sie bereits die Datei site.css angepasst haben, so nennen Sie diese um in site.css.bak damit diese nicht weiter die Arbeit des Maven Site Plugin beeinflusst.
$ mv src/site/resources/css/site.css src/site/resources/css/site.css.bak

Um fr das Projekt sample-project nun die Skin sample-site-skin anzuziehen mssen Sie noch eine Referenz auf den Artefakt sample-site-skin in den Site Descriptor des Projekts einfgen. Ein Site referenziert eine Skin im Site Descriptor mittels dem Element skin: Example 15.12. Konfiguration einer Angepassten Site Skin in einem Site Descriptor
<project name="Sample Project"> ... <skin> <groupId>org.sonatype.mavenbook</groupId> <artifactId>sample-site-skin</artifactId> </skin> ... </project>

Sie knnen sich eine Maven Skin als Abhnigkeit veranschaulichen. Site Skins werden als Artefakte mit einer groupId und artefactId angesprochen. Der Einsatz von Site Skins erlaubt Ihnen jegliche Site Anpassungen in ein einziges Projekt zusamen zu ziehen und damit die Verwendung von angepassten Stylesheets und Sitevorlagen genauso einfach zu gestalten wie die Wiederverwendung von Build Logik mittels einem angepassten Maven Plugin. 457

Projekt-Site Erstellung

15.7.5. Anpassen der Sitevorlage in einer Skin


Genauso wie Sie das Stylesheet einer Maven Skin anpassen knnen, so knnen Sie auch die Sitevorlage anpassen. Doxia's Site Prozessor erwartet eine Datei site.vm im Verzeichnis META-INF/maven/ innerhalb des Skin JAR Artefakt. Um eine angepasste Vorlage einzubinden, kopieren Sie die Vorlage an die richtige Stelle innerhalb der Skin sample-site-skin. Am vorherigen Beispiel: kopieren Sie die angepasste Sitevorlage von zuvor in das Verzeichnis src/main/resources/META-INF/maven innerhalb der Skin sample-site-skin:
$ mv sample-project/src/site/site.vm \ sample-site-skin/src/main/resources/META-INF/maven

Sollten Sie zuvor bereits die Sitevorlage des Beispielprojekts angepasst haben, so enfernen Sie die Pluginkonfiguration welche auf diese angepasste Vorlage zeigt. Das Site Plugin wird sodann den Site auf der Basis der in der Site Skin angegebenen Vorlage erstellen.
<plugin> <artifactId>maven-site-plugin</artifactId> <configuration> <templateDirectory>src/site</templateDirectory> <template>site.vm</template> </configuration> </plugin>

Es wird erwartet, dass eine Maven Site Skin alle abhngigen Resourcen einschliesst. Diese Resourcen umfassen alle Stylesheets, Graphiken und Logos. Sollten Sie bereits zuvor die Sitevorlage angepasst haben, so haben Sie bereits die standarmssigen Resourcen des Doxia Site Prozessors in Ihres Beispielprojekt sample-project in das Verzeichnis src/site/resources eingefgt. Sie sollten diese Dateien nun aus dem Projekt sample-project entfernen und in das neue Projekt sample-site-skin einfgen. Dies knnen Sie mit den folgenden Befehlen bewerkstelligen:
$ cd .. $ mkdir -p sample-site-skin/src/main/resources/css $ mv sample-project/src/site/resources/css/maven-base.css \ sample-site-skin/src/main/resources/css $ mkdir -p sample-site-skin/src/main/resources/images $ mv sample-project/src/site/resources/images/logos \

458

Projekt-Site Erstellung
sample-site-skin/src/main/resources/images $ mv sample-project/src/site/resources/images/expanded.gif \ sample-site-skin/src/main/resources/images $ mv sample/src/site/resources/images/collapsed.gif \ sample-site-skin/src/main/resources/images

Sie haben nun die Skin sample-site-skin angepasst, diese mssen Sie nun wieder in Ihr Repository installieren. Sobald dieser Schritt abgeschlossen ist und Sie den Site des Projekt sample-project erneut erstellen, werden Sie festellen, das die angepasste Skin zum Zug kommt. Weiter werden Sie bemerken, dass die Farbe der Menus noch danebenliegt, denn Sie haben die notwendigen Stylesheet Elemente der eingezogenen und erweiterten Menus noch nicht angepasst. Um dies zu tun, ndern Sie die Datei maven-theme.css des Verzeichnisses /src/maven/resources/css. ndern Sie
a:link { ... }

in:
li.collapsed, li.expanded, a:link { ... }

Erstellen Sie erneut die Skin, installieren diese in Ihr Repository, weiter generieren Sie erneut die WebSite. Sie werden feststellen, das die Menu Eintrge nun wieder wie erwartet erscheinen. Alles in allem haben sie nun erfolgreich ein benutzerdefiniertes Maven Motiv erstellt, welches eingesetzt werden kann, um Styles und Vorlagen auf eine ganze Anzahl Projekte anzuwenden.

15.8. Tips und Tricks


Hier in diesem Abschnitt wollen wir noch ein paar Tips und Tricks weitergeben welche Ihnen im Umgang mit Maven Sites und Skins helfen knnten.

15.8.1. Einfgen von XHTML in das Element HEAD


459

Projekt-Site Erstellung Um XHTML in ein Element HEAD einzufgen, erweitern Sie das Element body Ihres Site Descriptors mit einem Element head. Das folgende Beispiel zeigt wie jede Seite eines Websites sample-project mit einem Verweis auf einen Feed erweitert wird: Example 15.13. Einfgen von XHTML in das Element HEAD
<project name="Hello World"> ... <body> <head> <link href="http://sample.com/sites/sample-project/feeds/blog" type="application/atom+xml" id="auto-discovery" rel="alternate" title="Sample Project Blog" /> </head> ... </body> </project>

15.8.2. Hinzufgen von Links zum Site Logo


Sollten Sie an einem Projekt arbeiten, welches als Teil einer grossen Organisation entwickelt wird, so kann es vorkommen, dass Sie die Projekt Logos mit Verweisen unterlegen mchten. Nehmen Sie einmal an, Ihr Projekt ist Teil der Apache Software Foundation, Sie wollen erreichen, dass das Logo direkt auf den WebSite der Apache Software Foundation verweist. Den gleichen Verweis mchten Sie womglich bezglich eines bergeordneten Projektes einfgen. Um dem Loge einen Verweis anzufgen, erweitern Sie das Element body des Site Descriptors mit einem Element links. Jedes Element links wird in einem Band, geanu unter Ihrem Logo, als Verweis dargestellt. Der nachfolgende Ausschnitt wird zwei Verweise, einen zur Apache Softare Foundation (ASF) sowie einen weiteren zu Maven hinzufgen. Example 15.14. Hinzufgen von Links zum Site Logo
<project name="Hello World">

460

Projekt-Site Erstellung
... <body> ... <links> <item name="Apache" href="http://www.apache.org"/> <item name="Maven" href="http://maven.apache.org"/> </links> ... </body> </project>

15.8.3. Hinzufgen von Breadcrumbs zu Ihrem Site


Sollte ihre eigene Hierarchie im Kontext einer grsseren logischen Hierarchie bestehen, so bietet es sich an, dass Sie dem Benutzer zum besseren berblick eine "Breadcumbs-Bar" einfgen, welche dem Benutzer ermglicht den berblick zu behalten und schnell in ein bergeordnetes Verzeichnis zu springen. Um Breadcrumbs zu konfigureiren, fgen sie ein Element breadcrumbes in das Element body Ihres Site Descriptor ein. Die entsprechenden Eintrge sollten vom obersten zum niedersten in der Hierarchie aufgelistet werden. Im folgenden Beispiel ist davon auszugehen, dass der eintrag Mojo hierarchisch vom Eintrag Codehouse eingeschlossen wird. Example 15.15. Konfiguration von Breadcrumbs
<project name="Sample Project"> ... <body> ... <breadcrumbs> <item name="Codehaus" href="http://www.codehaus.org"/> <item name="Mojo" href="http://mojo.codehaus.org"/> </breadcrumbs> ... </body> </project>

461

Projekt-Site Erstellung

15.8.4. Hinzufgen der Projekt Version


Sollten Sie ein Projekt mit mehreren Versionen bearbeiten, so ist es oftmals hilfreich auf jeder Seite die Versionsnummer anzugeben. Um die Projektversionsnummer auf jeder Seite eines Projekt Sites anzugeben fgen Sie ein Element version in das Element body des Site Descriptors ein. Example 15.16. Positionieren der Versionsinformation
<project name="Sample Project"> ... <version position="left"/> ... </project>

Der oben gegebene Eintrag wird die Version (in diesem Fall der des Projektes sample-project; die Anzeige wird lauten: "Version: 1.0-SNAPSHOT") in der oberen, linken Ecke der Site dargestellt, direkt neben dem Verffentlichungsdatum "Last Published". Mgliche Positionierungen des Elements version sind: left Links in der Kopfzeile, direkt unterhalb des Site Logo right Rechts in der Kopfzeile, direkt unterhalb des Site Logo navigation-top Am oberen Ende der Navigationsleiste navigation-bottom Am unteren Ende der Navigationsleiste none Unterdrcken der Version.

462

Projekt-Site Erstellung

15.8.5. Anpassen der Positionierung und des Formats des Verffentlichungsdatums


Es kann vorkommen, dass Sie die Position oder das Format der Anzeige "Letzte Verffentlichung:" Ihres Projekt Website verndern mchten. Wie bereits zuvor in der Beschreibung des Tipps bezglich der Projektversion knnen Sie mit den unten angegebenen Parametern die Positionierung verndern. left Links in der Kopfzeile, direkt unterhalb des Site Logo right Rechts in der Kopfzeile, direkt unterhalb des Site Logo navigation-top Am oberen Ende der Navigationsleiste navigation-bottom Am unteren Ende der Navigationsleiste none Unterdrcken des Publikationsdatums Example 15.17. Positionierung des Verffentlichungsdatums
<project name="Sample Project"> ... <publishDate position="navigation-bottom"/> ... </project>

Standardmssig wird die letzte Site Verffentlichung im Datumsformat MM/dd/yyyy wiedergegeben. Sie knnen dieses Format mit den normalen Standardformaten wie in der JavaDoc von java.text.SimpleDateFormat beschrieben abndern (wir verweisen auf die JavaDoc Dokumentation bezglich weitergehender Informationen des SimpleDateFormat ). Um das Format auf 463

Projekt-Site Erstellung
yyyy-MM-dd

abzundern bedarf es dem folgenden Element publishDate:

Example 15.18. konfiguration des Datumsformates


<project name="Sample Project"> ... <publishDate position="navigation-bottom" format="yyyy-MM-dd"/> ... </project>

15.8.6. Einsatz von Doxia Makros


In addition to its advanced document rendering features, Doxia also provides a macro engine that allows each input format to trigger injection of dynamic content. An excellent example of this is the snippet macro, which allows a document to pull a code snippet out of a source file that's available via HTTP. Using this macro, a small fragment of APT can be rendered into XHTML. The following APT code calls out to the snippet macro. Please note that this code should be on a single continuous line, the black slash character is inserted to denote a line break so that this code will fit on the printed page. Zustzlich zu den fortgeschrittenen Mglichkeiten der Ausgabe verfg Doxia ebenfalls ber einen ausgeklgelten Makro Prozessor welcher erlaubt, dass bestimmte Eingabeformate den Einschluss gewisser dynamischer Inhalte erzeugen. Ein gutes Beispiel diese Mechanismus ist das SnippetMakro (engl. Snippet=Abschnittstck) welches ermglicht, ein Stck Quellcode, welches ber HTTP zugnglich ist, in ein Dokument einzubinden. Beim Einsatz dieses Makros kann ein Bruchstck APT in eine XHTML-Ausgabe umgewandelt werden. Der folgende APT Quellcode ruft das SnippetMakro auf. Bitte beachten Sie, dass der abgebildete Aufruf auf einer einzelnen Zeile eingegeben werden sollte und der Backslash nur eingefgt wurde um dies zu verdeutlichen, da die Gesamtzeile hier nicht abgebildet werden kann.
%{snippet|id=modello-model|url=http://svn.apache.org/repos/asf/maven/\ archetype/trunk/maven-archetype/maven-archetype-model/src/main/\ mdo/archetype.mdo}

464

Projekt-Site Erstellung Example 15.19. Ausgabe eines Auschnitt Makros in XHTML


<div class="source"><pre> <model> <id>archetype</id> <name>Archetype</name> <description><![CDATA[Maven's model for the archetype descriptor. ]]></description> <defaults> <default> <key>package</key> <value>org.apache.maven.archetype.model</value> </default> </defaults> <classes> <class rootElement="true" xml.tagName="archetype"> <name>ArchetypeModel</name> <description>Describes the assembly layout and packaging.</description> <version>1.0.0</version> <fields> <field> <name>id</name> <version>1.0.0</version> <required>true</required> <type>String</type> </field> ... </fields> </class> </classes> </model> </pre></div>

Warning Doxia Makros drfen in APT Quelldateien NICHT EINGERCKT werden. Einrcken wird dazu fhren, dass der APT Parser das Makro im Ganzen berspringt. Bezglich weiterer Informationen wie Sie Snippets innerhalb Ihres Quellcodes definieren, dass diese vom SnippedMakro erfasst werden, mchten wir auf den Guide zum Snipped Generator auf der Maven Website verweisen: 465

Projekt-Site Erstellung http://maven.apache.org/guides/mini/guide-snippet-macro.html.

466

Chapter 16. Repository Management mit Nexus


Dieses Kapitel ist veraltet. Obschon die Originalausgabe von 'Maven: The Definitive Guide' ein eigenes Kapitel dem Nexus Repository Manager widmete, hat Sonatype erwogen, dass dieses Thema sich schnell genug weiterentwickelte und vergrsserte, dass es sich lohnt, dieses in einen eigenen Titel herauszulsen. Wir haben uns also dazu entschlossen den Inhalt des Kapitels Repository Management in ein eigenes Buch Repository Management with Nexus herauszulsen. Der neue Titel deckt beide Repostitory Management Packete Nexus Open Source sowie Nexus Professional ab.Sie werden durch den Prozess des Herunterladens und Installieren eines Repository Managers geleitet. Weiter gibt das Buch einen umfassenden berblick der mglichen Konfigurationen. Folgen Sie diesem Verweis um das Buch 'Repository Management with Nexus' zu lesen Note In der Vergangenheit war ein Buch eine eher statische Angelegenheit. Es wurde geschrieben, editiert, gegengelesen dann gedruckt. Nach dem Druck gab es wenige Mglichkeiten sich ber die Struktur des Buches Gedanken zu machen. Das Internet hingegen erffnet Mglichkeiten ein Real-Time jederzeit abrufbereites Buch zu erstellen, welches sich bestndig weiterentwickelt. Die Verlagsindustrie muss sich erst noch anfreunden mit der Art 'lebender' Bcher - Bcher welche sich bereits am Tag nach dem dieses zum Druck gehen verndern knnen; Bcher welche gespalten werden sobald diese ber ein Mass hinaus wachsen und dann weiterwachsen. Wir haben uns entschlossen diesen Schnitt zu machen, da er uns sinnvoll erscheint. Sobald ein Kapitel sich in ein Hunderte Seiten langes Biest entwickelt lohnt es sich nicht, eine jetzt schon starke Referenz weiter aufzublhen. (Aber ein Buch ist ja auch nicht 'schwer' liest man diese im Webbrowser, das ist eine Sache der Perspective!) 467

Repository Management mit Nexus Was fr die Softare entwicklung gilt, gilt ebenso beim schreiben eines Buches. Sollten Sie mit einem klar abgegrenzten und abgeschlossenen Projekt beginnen, so wird eine Zeit kommen, zu welcher es sinn macht dieses Projekt zu refaktorieren, die Bestandteile neu zu ordnen und module herauszulsen. Das ist genau der Prozess welchen wir hier beschreiten, wir refaktorieren das bestehende Buch in zwei schrfer definierte Bcher. Nehmen Sie diese Randnotiz als Warnung wahr. Es wird eine Zeit kommen zu welcher wir auch dieses Rumpfkapitel aus dem Buch entfernen werden. Das Web wird einen Verweis auf das neue Buch erhalten und im PDF wird eine Referenz erhalten bleiben, welche auf das Nexus Buch zeigt.

468

Chapter 17. Writing Plugins


17.1. Introduction
While this chapter covers an advanced topic, don't let the idea of writing a Maven plugin intimidate. For all of the theory and complexity of this tool, the fundamental concepts are easy to understand and the mechanics of writing a plugin are straightforward. After you read this chapter, you will have a better grasp of what is involved in creating a Maven plugin.

17.2. Programming Maven


Most of this book has dealt with using Maven, and for a book on Maven, you haven't seen too many code examples dealing with Maven customization. In fact, you haven't yet seen any. This is by design, 99 out of 100 Maven users will never need to write a custom plugin to customize Maven; there is an abundance of configurable plugins, and unless your project has particularly unique requirements, you will have to work to find a reason to write a new plugin. An even smaller percentage of people who end up writing custom plugins will ever need to crack open the source code for Maven and customize a core Maven component. If you really need to customize the behavior of Maven, then you would write a plugin. Modifying the core Maven code is as far out of scope for most developers as modifying the TCP/IP stack on an operating system, it is that abstract for most Maven users. On the other hand, if you are going to start writing a custom plugin, you are going to have to learn a bit about the internals of Maven: How does it manage software components? What is a Plugin? How can I customize the lifecycle? This section answers some of those questions, and it introduces a few concepts at the core of Maven's design. Learning how to write a custom Maven plugin is the gateway to customizing Maven itself. If you were wondering how to start understanding the code behind Maven, you've found the proper starting line. 469

Writing Plugins

17.2.1. What is Inversion of Control?


At the heart of Maven is an Inversion of Control (IoC) container named Plexus. What does it do? It is a system for managing and relating components. While there is a canonical essay about IoC written by Martin Fowler, the concept and term have been so heavily overloaded in the past few years it is tough to find a good definition of the concept that isn't a self-reference (or just a lazy reference to the aforementioned essay). Instead of resorting to a Wikipedia quote, we'll summarize Inversion of Control and Dependency Injection with an analogy. Assume that you have a series of components which need to be wired together. When you think about components, think stereo components not software components. Imagine several stereo components hooked up to a Playstation 3 and a Tivo that have to interface with both an Apple TV box and a 50" flat panel LCD TV. You bring everything home from the electronics store and you purchase