Anpassung von Maven an eigene Wünsche

Die Seite wird erstellt Simon Scheffler
 
WEITER LESEN
Kapitel 2                                                     KAPITEL 2

                      Anpassung von Maven
                        an eigene Wünsche

In Kapitel 1 haben Sie die Datei project.xml kennen gelernt, die die Be-     In diesem Kapitel:
schreibung des Projekts, Ihrer Organisation, des Teams, die Platzierung      • Installation ei-
der Quelltextdateien und alle anderen für Mavens Buildprozess erforder-        nes Plugins aus
lichen Informationen enthält. Sie haben gesehen, wie man die verfügba-         einem Inter-
ren Ziele ausgibt und wie einfach der Umgang mit Maven ist. Oft ist es         net-Repository
aber erforderlich, den Standardbuildprozess von Maven an eigene Vor-         • Benutzerspezifi-
stellungen anzupassen. Vielleicht benötigen Sie zum Beispiel eine JAR-
                                                                               sche Anpassung
                                                                               eines Plugins
Datei in einem anderen Verzeichnis, oder Sie wollen sogar ein eigenes
                                                                             • Erstellung eige-
Ziel erstellen. In diesem Kapitel werden wir solche Dinge mit Hilfe von        ner Ziele
Jelly und der Datei maven.xml ermöglichen.                                   • Definition eines
Die benutzerspezifische Anpassung von Maven geschieht in einer XML-            preGoal
basierenden Skriptsprache namens Jelly. Jelly verarbeitet eine Folge von     • Definition eige-
XML-Tags, die sequenziell ausgeführt werden. Jelly kennt so genannte           ner Properties
Tag-Bibliotheken, die jeweils eine Gruppe von Tags definieren und zur        • Start des Pro-
Verfügung stellen. Darüber hinaus gibt es verschiedene Tags, die den           gramms aus ei-
                                                                               nem eigenen Ziel
Kern von Jelly bilden und Kontrollstrukturen, z.B. Schleifen, zur Verfü-
                                                                             • Einrichtung ei-
gung stellen. Wenn Sie sich mit den Buildskripten von Ant auskennen,           nes Standard-
dann werden Sie Jelly auf Anhieb verstehen. Im Kontext von Maven wird          ziels
Jelly als Skriptsprache benutzt. Die Plugins von Maven 1 sind zu großen      • Properties über-
Teilen in Jelly geschrieben. Dieses Kapitel behandelt Jelly als Mittel der     schreiben
Wahl zur Erweiterung und Anpassung von Maven.                                • Iteration über
Das Beispielprojekt namens Weather, mit dem wir in dieser Übung arbei-
                                                                               Abhängigkeiten
ten werden, finden Sie auf der Website des Buchs unter http://www.
                                                                             • Anpassung von
                                                                               Look and Feel
mavenbook.org. Sie können das Projekt auch aus dem Subversion-Repo-            der Website
sitory ziehen, das Sie unter http://www.mavenbook.org/svn/mdn/code/          • Benutzung des
finden.                                                                        FAQ-Plugins

                                                                                            43
TIPP
             Bei Maven 1 sind Plugins normalerweise in Jelly geschrieben. In Ma-
             ven 2 wird diese XML-basierende Skriptsprache durch Plugins ersetzt,
             die in ganz normalem Java geschrieben sind. Seien Sie also einiger-
             maßen zurückhaltend mit Jelly. Für die Abkehr von Jelly in Maven 2
             gibt es verschiedene Gründe, unter anderem Geschwindigkeit. Dem-
             zufolge tun Sie gut daran, in Ihr maven.xml so wenig wie möglich zu
             packen und vorzugsweise vorhandene Plugins zu verwenden. Sie er-
             leichtern sich damit den zukünftigen Umstieg auf Maven 2. Natürlich
             wirft das gerade eben Gesagte die Frage nach dem Sinn dieses Kapi-
             tels auf. Aber bei der Arbeit mit Maven 1 ist Jelly eben doch unver-
             zichtbar, und letzten Endes wird auch Maven 2 in irgendeiner Form
             Unterstützung für Jelly enthalten, auch wenn Plugin-Autoren aufge-
             fordert sind, Java zur Implementation ihrer Plugins zu bevorzugen.
             Tatsächlich werden in Maven 2 sogar mehrere Skriptsprachen wie
             Groovy oder Marmalade unterstützt. In diesem Kapitel werden wir
             aber nur Jelly vorstellen und uns darauf verlassen, dass die vorge-
             stellten Konzepte und Ideen weiterhin möglich und relevant bleiben.

     Installation eines Plugins aus
     einem Internet-Repository
     Alle Ihre Bekannten aus der Java-Szene benutzen die neueste und beste
     Version dieses ganz bestimmten Maven-Plugins, so dass Sie sich allmäh-
     lich altbacken vorkommen. Wo bekommt man dieses Plugin? Und wenn
     man es hat, wie wird es installiert? Wir demonstrieren das mit Hilfe des
     Plugins für Apache Axis, das wir in unsere Maven-Installation mit auf-
     nehmen wollen.

     Wie mache ich das?
     Zunächst benötigt man natürlich die Adresse des Internet-Repositorys, in
     dem man das Plugin findet. Im Falle des Plugins für Apache Axis handelt
     es sich dabei um das Repository von http://maven-plugins.sourceforge.
     net/maven/. Allerdings wird dieses Repository alle paar Stunden mit
     http://www.ibiblio.org/maven/ synchronisiert. Das Repository von Ibiblio
     ist das Standardrepository von Maven. Maven benutzt es eigentlich im-
     mer, sofern Sie nicht ausdrücklich ein anderes Repository konfigurieren.
     Wenn Sie trotzdem das SourceForge-Repository direkt verwenden wol-
     len, dann können Sie dies in Ihrer Datei build.properties tun. (Soll die
     Einstellung auch für andere Teammitglieder gelten, dann verwenden Sie
     dagegen project.properties.) Dazu setzen Sie die folgende Property:

44   Kapitel 2: Anpassung von Maven an eigene Wünsche
maven.repo.remote=http://www.ibiblio.org,http://maven-plugins.sf.net/maven
Wie schon gesagt, ist das aber nicht nötig, da der Inhalt des SourceForge-
Repositorys zu Ibiblio synchronisiert wird. Während wir dies schreiben,
trägt die aktuelle Version des Axis-Plugins die Nummer 0.7. (Sie können
unter http://www.ibiblio.org/maven/maven-plugins/plugins/ prüfen, ob
das immer noch der Fall ist.) Die Installation des Axis-Plugins erledigt das
Ziel plugin:download eines anderen Plugins namens Plugin für Sie. Wie
Sie gleich noch sehen werden, müssen darüber hinaus lediglich einige
Properties gesetzt werden.
Ganz analog zur Definition der groupId, der artifactId und der version
bei der Spezifikation einer Abhängigkeit in project.xml benötigen Sie
auch dieselben Properties bei der Installation eines Plugins. Das Plugin
namens Plugin leitet daraus die exakte URL ab, die zum Download des
neuen Plugins erforderlich ist. Das folgende Kommando installiert daher
Version 0.7 des Axis-Plugins:
    C:\>maven plugin:download -DgroupId=maven-plugins ^
    More? -DartifactId=maven-axis-plugin -Dversion=0.7
     __ __
    | \/ |__ _Apache__ ___
    | |\/| / _` \ V / -_) ' \ ~ intelligent projects ~
    |_| |_\__,_|\_/\___|_||_| v. 1.0.2

    build:start:

    plugin:download-artifact:
        [echo] repo is 'http://www.ibiblio.org/maven'
        [echo] trying to download http://www.ibiblio.org/maven/maven-plugins/
    plugins/maven-axis-plugin-0.7.jar
    11K downloaded

    plugin:download:
        [copy] Copying 1 file to C:\apps\maven-1.0.2\plugins
    BUILD SUCCESSFUL
    Total time: 2 seconds
Sie fragen sich möglicherweise nach dem Zusammenhang zwischen
groupId, artifactId und version einerseits und der URL des Plugins an-
dererseits. In Abbildung 2-1 sehen Sie, wie diese Abbildung im Falle des
Axis-Plugins funktioniert.

Abbildung 2-1: Konvention für die URL eines Plugins in einem Internet-Repository

                           Installation eines Plugins aus einem Internet-Repository   45
TIPP
                            Die vollständige zum Download erforderliche URL eines Plugins lautet:
                                 [repository URL]/[groupId]/plugins/[artifactId]-[version].jar
                            Dies ist die allgemeine »Formel«, die das Plugin namens Plugin be-
                            nutzt.

                    Übrigens kennt das Ziel plugin:download auch einen interaktiven Modus.
                    Dieser wird verwendet, wenn Sie das Ziel ohne die nötigen Optionen
                    aufrufen:
                        C:\>maven plugin:download
                         __ __
                        | \/ |__ _Apache__ ___
                        | |\/| / _` \ V / -_) ' \ ~ intelligent projects ~
                        |_| |_\__,_|\_/\___|_||_| v. 1.0.2

                        What is the artifactId of the plugin to download (e.g. maven-axis-plugin)?
                        maven-axis-plugin
                        What is the groupId of the plugin to download? [maven]
                        maven-plugins
                        What is the version of the plugin to download?
                        0.7
In Maven 2 wer-         build:start:
den Plugins bei         plugin:download-artifact:
Bedarf automa-              [echo] repo is 'http://www.ibiblio.org/maven'
tisch geladen und           [echo] trying to download http://www.ibiblio.org/maven/maven-plugins/
                        plugins/maven-axis-plugin-0.7.jar
installiert, so-
                        11K downloaded
bald ein Plugin
zum ersten Mal          plugin:download:
benutzt wird.               [copy] Copying 1 file to C:\apps\maven-1.0.2\plugins
                        BUILD SUCCESSFUL
                        Total time: 33 seconds
                    Um die erfolgreiche Installation des Plugins zu kontrollieren, lassen Sie es
                    am besten seine eigenen Ziele ausgeben. Dies geschieht durch den Auf-
                    ruf von maven -P axis. Sie sollten eine Liste aller Ziele des Axis-Plugins
                    sehen.
                    Wenn Sie wissen wollen, welche Version des Plugins installiert ist (wir
                    verwenden in dieser Übung die Version 0.7.), dann geben Sie maven -i
                    ein:
                        C:\>maven -i

                        [...]
                        maven-aspectj-plugin-3.2
                        maven-aspectwerkz-plugin-1.2

46                  Kapitel 2: Anpassung von Maven an eigene Wünsche
maven-axis-plugin-0.7
    maven-caller-plugin-1.1
    maven-castor-plugin-1.2 [...]
Das war’s auch schon! Das Axis-Plugin ist installiert und steht zur An-
wendung bereit. Und dazu mussten Sie nur das Ziel plugin:download
aufrufen.

Und was ist mit …
… anderen Internet-Repositories von Maven?
Während wir dies schreiben, gibt es schon eine ganze Reihe bekannter
und öffentlich zugänglicher Maven-Repositories, die allerdings alle mit
dem Haupt-Repository auf Ibiblio synchronisiert werden:
  • Das Apache-Repository
  • Das Maven-Plugins-Repository auf SourceForge
  • Das Codehaus-Repository
  • Und verschiedene andere, zum Beispiel OSJava, OpenSymphony oder
    MortBay)
Wenn Sie das Standard-Repository von Ibiblio benutzen, gibt es also kei-
nen Grund, diese Repositories in Ihre eigene Liste mit aufzunehmen, da
sie alle durch Ibiblio abgedeckt werden.

Benutzerspezifische Anpassung
eines Plugins
In dieser Übung arbeiten wir mit einem Webservice, der von der NOAA
(National Oceanic and Atmospheric Administration), einer Behörde der US-
Regierung, bereitgestellt wird. Die US-Regierung hat kürzlich beschlos-
sen, kostenlose Wettervorhersagen bereitzustellen. Diese Aufgabe erle-
digt nun der unter http://weather.gov/xml/ zugängliche Server. Wir wol-
len das Axis-Plugin von Maven benutzen, um Klassen zu generieren, mit
denen wir anschließend eine Vorhersage von diesem Webservice abru-
fen. Dazu werden wir das Axis-Plugin in einem gewissen Rahmen konfi-
gurieren müssen.

Wie mache ich das?
Wenn Sie das Axis-Plugin erfolgreich installiert haben, dann erhalten Sie
mit maven -P axis eine Liste aller Ziele, die dieses Plugin anbietet. Unter
anderem sollte darin axis:wsdl2java enthalten sein. Wir wollen dieses

                                    Benutzerspezifische Anpassung eines Plugins   47
Ziel benutzen, um eine Client-Bibliothek anhand der Web Service De-
     scription Language (WSDL) des Wettervorhersagedienstes zu generieren.
     Die WSDL des Vorhersagedienstes der NOAA finden Sie unter http://
     weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl. Ein WSDL-
     Dokument ist eine XML-Datei, die eine Beschreibung aller per SOAP
     angebotenen Methoden enthält. Das Axis-Plugin soll dieses XML-Doku-
     ment benutzen, um eine passende Client-Bibliothek zu generieren. Für
     diese Übung wollen wir festlegen, dass die WSDL in weather/src/wsdl/
     weather.wsdl gespeichert wird. Das Axis-Plugin soll Java-Quelltexte für
     alle in diesem Verzeichnis liegenden WSDL-Dateien generieren.
     Um die vom Axis-Plugin generierten Quelltexte nutzen zu können, müs-
     sen wir die folgenden Abhängigkeiten in unseren Projektdeskriptor auf-
     nehmen:
         
           commons-discovery
           commons-discovery
           20030211.213356
         
           commons-logging
           commons-logging
           1.0.4
         
           axis
           axis
           1.2-RC3
         
           axis
           axis-jaxrpc
           1.2-RC3
         
           axis
           axis-saaj
           1.2-RC3
         
           axis
           axis-wsdl4j
           1.2-RC3
         
     Um die Client-Bibliothek zu generieren, müssen wir das Axis-Plugin leicht
     umkonfigurieren, da es standardmäßig Java-Quelltexte für die Serverseite
     generiert. Die Konfiguration geschieht durch das Überschreiben von Plug-
     in-Properties in der Datei project.properties. Um eine Liste solcher Proper-
     ties und ihrer Standardwerte zu suchen, haben wir zwei Möglichkeiten:

48   Kapitel 2: Anpassung von Maven an eigene Wünsche
Zunächst einmal können wir einen Blick auf die Website des Projekts
werfen. Zum anderen bietet sich ein Blick in unseren lokalen Plugin-
Cache an. In unserem Fall heißt das, dass wir die Datei ~/.maven/cache/
maven-axis-plugin-0.7/plugin.properties öffnen. Sie sollte in etwa die fol-
genden Werte enthalten:
    maven.axis.dir=${maven.build.dir}/axis
    maven.axis.generated.dir=${maven.axis.dir}/src
    maven.axis.test.dir=${maven.axis.dir}/test
    maven.axis.url=${maven.src.dir}/wsdl
    maven.axis.all=true
    maven.axis.deployscope=session
    maven.axis.factory=org.apache.axis.wsdl.toJava.JavaGeneratorFactory
    maven.axis.helpergen=false
    maven.axis.serverside=true
    maven.axis.skeletondeploy=true
    maven.axis.noimports=no
    maven.axis.verbose=yes
    maven.axis.debug=false
    maven.axis.typemappingversion=1.1
    maven.axis.timeout=45000
Das sind also die Standardwerte der Properties des Axis-Plugins. Wir
bemerken vor allem, dass die Property maven.axis.serverside den Wert
true enthält. Da wir Client-Bibliotheken generieren wollen, müssen wir
diese Property für unser Projekt auf false setzen. Darüber hinaus wer-
den Sie bemerken, dass der Wert von maven.axis.timeout auf 45.000
Millisekunden steht. In unserem Projekt wollen wir das auf 20 Sekunden
reduzieren. Eine besser dokumentierte Liste der Properties des Axis-Plug-
ins finden Sie übrigens auf der zugehörigen Website unter http://maven-
plugins.sourceforge.net/maven-axis-plugin/properties.html. Zusammen-
fassend nehmen wir also zur Konfiguration des Plugins die beiden fol-
genden Properties in weather/project.properties auf:
    # Anpassung des Maven XDoc-Plugins
    maven.xdoc.date = left
    maven.xdoc.date.format = MM/dd/yyyy

    # Anpassung des Maven Axis-Plugins
    maven.axis.serverside = false
    maven.axis.timeout = 20000
    # Anpassung des Maven Test-Plugins
    maven.test.skip = false
    maven.test.fork = yes
Ein Aufruf des Ziels axis:wsdl2java generiert also eine Client-Bibliothek
mit einem Timeout von 20 Sekunden. Vielleicht ist Ihnen aufgefallen,
dass in project.properties auch zwei andere Plugins konfiguriert werden,
nämlich Test und XDoc. Mit der Konfiguration des XDoc-Plugins werden
wir uns noch weiter unten in diesem Kapitel beschäftigen.

                                    Benutzerspezifische Anpassung eines Plugins   49
Mit maven axis:wsdl2java können wir nun die Client-Bibliothek für den
                     SOAP-Service der Wettervorhersage generieren. Die generierten Quell-
                     texte werden in maven.axis.generate.dir gespeichert. Wenn Sie die
                     Unit-Tests des Beispielprojekts aufrufen, dann sollten Sie feststellen, dass
                     das Projekt auch einen Unit-Test enthält, der die Wettervorhersage der
                     NOAA tatsächlich abruft und damit die Funktion der Client-Bibliotheken
                     überprüft.

                     Erstellung eigener Ziele
                     Um eine Client-Bibliothek für den SOAP-Service zu generieren, benötigt
                     man zunächst die WSDL-Datei, die man an wsdl2java übergeben will.
                     Wir wollen nun ein eigenes Ziel namens weather:get-wsdl definieren,
                     das den Download dieser Datei vom Server der NOAA automatisiert.

                     Wie mache ich das?
                     Die Definition unseres eigenen Ziels geschieht als Jelly-Skript in der Da-
                     tei weather/maven.xml. Das ist nicht weiter schwer, wir benutzen intern
                     den get-Task von Ant, der die WSDL-Datei für uns abholen soll. Das neue
                     Ziel sieht damit so aus:
Für Ihr eigenes          
Projekt empfiehlt
                         
der WSDL-Datei
in project.proper-         
                             
ren. Das erleich-            Retrieving WSDL from ${wsdl}
tert die                     
                           
                     Der Wert der Variablen ${wsdl} wird mit j:set gesetzt, eine Mitteilung
                     wird auf der Konsole ausgegeben, und das WSDL-Dokument wird gela-
                     den und in weather/src/wsdl abgelegt. Die Ausgabe der Mitteilung wird
                     mit Hilfe von Ants echo-Task implementiert. Geben Sie einmal maven
                     weather:get-wsdl auf der Kommandozeile ein, dann sollten Sie die fol-
                     gende Ausgabe sehen:
                         C:\dev\mavenbook\code\weather>maven weather:get-wsdl
                          __ __
                         | \/ |__ _Apache__ ___
                         | |\/| / _` \ V / -_) ' \ ~ intelligent projects ~
                         |_| |_\__,_|\_/\___|_||_| v. 1.0.2

50                   Kapitel 2: Anpassung von Maven an eigene Wünsche
build:start:

   weather:get-wsdl:
       [echo] Retrieving WSDL from http://weather.gov/forecasts/xml/DWMLgen/
   wsdl/ndfdXML.wsdl
        [get] Getting: http://weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.
   wsdl
   BUILD SUCCESSFUL
   Total time: 2 seconds

Was ist da gerade geschehen?
Das Tag j:set setzt eine Property namens wsdl. Der Wert der Property ist
die URL der aus dem Internet zu ladenden WSDL-Datei. Sobald die Vari-
able gesetzt ist, steht sie dem Jelly-Skript zur Verfügung und kann mit
${wsdl} referenziert werden. Das Tag set ist ein Bestandteil der Stan-
dardtagbibliothek von Jelly. Diese Standardbibliothek enthält zum Bei-
spiel auch Tags zur Ausführung bedingten Codes oder zur Iteration über
eine Folge. In diesem Kapitel werden Sie noch einige dieser Tags ken-
nen lernen, zum Beispiel j:if oder j:forEach. Ausführlichere Informa-
tionen über die Standardtags von Jelly finden Sie unter http://jakarta.
apache.org/commons/jelly/tags.html.
In maven.xml werden XML-Namensräume benutzt, um die vom jewei-
ligen Jelly-Skript verwendeten Tagbibliotheken zu erkennen. Im obigen
Beispiel wird das Präfix ant auf den Namensraum jelly:ant abgebildet.
Der Namensraum jelly:ant ist wiederum mit Jellys Tag-Library zum
Zugriff auf Ant verbunden. Mit dieser Tag-Library kann man aus Jelly
heraus Ant-Tasks benutzen. In diesem Fall haben wir zum Beispiel den
echo-Task von Ant genauso verwendet, wie wir das auch in einem build.
xml von Ant gemacht hätten:
   Print out some important message!
Der wesentliche Punkt an dieser Stelle ist, dass das Element, das den
Ant-Task anspricht, im Namensraum jelly:ant liegt. Mit Namensräumen
umzugehen ist etwas gewöhnungsbedürftig, aber der wesentliche Punkt
ist eben, dass Ihnen in einem eigenen Ziel von Maven alle Möglichkei-
ten zur Verfügung stehen, die Sie auch in einem Ant-Buildskript haben.
Insbesondere können Sie natürlich alle anderen Ant-Tasks einsetzen, mit
denen Sie sich auskennen. Betrachten Sie dazu das folgende Beispiel aus
einer anderen maven.xml-Datei:
   
                                                         Erstellung eigener Ziele   51
Wenn man in einem Jelly-Skript beliebige Ant-Tasks einsetzen kann,
     dann stellt sich natürlich die Frage nach einer Liste aller Tasks, die in
     Ants build.xml erlaubt sind. Eine vollständige Liste entnehmen Sie am
     besten dem Ant-Manual, das Sie online unter http://ant.apache.org/
     manual/index.html finden. Übrigens verwendet Jelly den Namensraum
     jelly:ant sogar als Standardnamensraum. Statt ant:copy oder ant:
     include können Sie also einfach copy oder include schreiben, wenn Sie
     das angenehmer finden. Wir raten Ihnen davon aber eher ab: Langfristig
     ist es besser, das Präfix ant zu verwenden, auch wenn man dadurch ein
     paar Tastendrucke spart. Die Benutzung von Ant ist nichts Besonderes
     und nur eine der Möglichkeiten von Jelly. Die Verwendung des Ant-
     Namensraums als Vorgabe ist daher reichlich willkürlich und wird mög-
     licherweise in zukünftigen Maven-Versionen entfallen. Benutzen Sie also
     lieber das Präfix ant in Jelly-Skripten.

     Und was ist mit …
     … der Behauptung, Maven sei ein Ersatz für Ant?
     Das ist so nicht ganz richtig. Maven ist kein »Ersatz« für Ant, auch wenn
     Maven auf dem Erfolg von Systemen wie Ant aufbaut. Ant ermöglicht ein
     XML-basierendes Build-Skript, aber Maven ist ein komplettes Buildsys-
     tem. Aber viele Plugins von Maven arbeiten intern mit Ant-Tasks. In die-
     sem Sinne sollte man also eher davon sprechen, dass Maven 1 Ant
     integriert.

     Definition eines preGoal
     Wir möchten als Nächstes den generierten SOAP-Client in unser Projekt
     einbinden. Das geht am besten mit Mavens Axis-Plugin. Wenn das Axis-
     Plugin Quelltexte generiert, dann muss sichergestellt werden, dass die
     generierten Quelltexte mit kompiliert werden. Das wird mit Hilfe eines
     preGoal und eines postGoal des Ziels java:compile realisiert.

     Wie mache ich das?
     Das Axis-Plugin generiert Quelltexte in das Verzeichnis maven.axis.
     generated.dir, das auf target/axis/src voreingestellt ist. Im Normalfall ist
     es nicht erwünscht, die generierten Quelltexte in das Verzeichnis src/

52   Kapitel 2: Anpassung von Maven an eigene Wünsche
main/java mit den manuell erstellten Quelltexten zu kopieren. Anderer-              In Maven 2 gibt
seits müssen die kompilierten Klassen natürlich in das Artefakt des                 es preGoal und
Projekts übernommen werden. Aus diesem Grund muss das Ziel axis:                    postGoal nicht
compile vor dem Ziel java:compile aufgerufen werden: Die Aufgabe von                mehr. Stattdes-
axis:compile ist es, dafür zu sorgen, dass die von axis:wsdl2java                   sen wird der
erzeugten Dateien mit kompiliert werden. Die folgende Datei maven.xml               Buildprozess als
benutzt ein preGoal, das ein anderes Ziel vor java:compile aufruft:                 eine Serie von
                                              Phasen wie build,
                                                                                    compile und test
[axis-wsdl2java] WSDL2Java C:\dev\mavenbook\code\weather\src\wsdl\
                        weather.wsdl
                        Parsing XML file: C:\dev\mavenbook\code\weather\src\wsdl\weather.wsdl
                        Generating C:\...\gov\weather\forecasts\xml\DWMLgen\schema\ndfdXML_xsd\
                        FormatType.java
                        Generating C:\...\gov\weather\forecasts\xml\DWMLgen\schema\ndfdXML_xsd\
                        ProductType.java
                        Generating C:\...\gov\weather\forecasts\xml\DWMLgen\schema\ndfdXML_xsd\
                        WeatherParametersType.java
                        Generating C:\...\gov\weather\forecasts\xml\DWMLgen\wsdl\ndfdXML_wsdl\
                        NdfdXMLPortType.java
                        Generating C:\...\gov\weather\forecasts\xml\DWMLgen\wsdl\ndfdXML_wsdl\
                        NdfdXMLBindingStub.java
                        Generating C:\...\gov\weather\forecasts\xml\DWMLgen\wsdl\ndfdXML_wsdl\
                        NdfdXML.java
                        Generating C:\...\gov\weather\forecasts\xml\DWMLgen\wsdl\ndfdXML_wsdl\
                        NdfdXMLLocator.java
                        Generating C:\...\gov\weather\forecasts\xml\DWMLgen\wsdl\ndfdXML_wsdl\
                        NdfdXMLTestCase.java
                        move the generated testcases to folder c:\dev\mavenbook\code\weather/target/
                        axis/test
                            [move] Moving 1 files to C:\dev\mavenbook\code\weather\target\axis\test

                        axis:copy:
Der Name axis:              [copy] Copying 7 files to C:\dev\mavenbook\code\weather\target\axis\
compile ist irre-       build
                        adding c:\dev\mavenbook\code\weather/target/axis/src to the maven.compile.
führend, wie man        src.set
an der Ausgabe
erkennt. Das Ziel       axis:compile:
                            [echo] Compiling to c:\dev\mavenbook\code\weather/target/classes
ruft keineswegs
den Java-Compi-         java:compile:
ler auf, sondern            [javac] Compiling 8 source files to C:\dev\mavenbook\code\weather\
                        target\classes
erweitert ledig-        Note: Some input files use unchecked or unsafe operations.
lich den Such-          Note: Recompile with -Xlint:unchecked for details.
pfad für Quell-         BUILD SUCCESSFUL
textdateien um          Total time: 7 seconds

das Verzeichnis     Wird java:compile aufgerufen, dann ruft Maven automatisch zunächst
target/axis/src.    axis:compile auf. Dieses Ziel hängt seinerseits von denjenigen Zielen des
                    Axis-Plugins ab, die die WSDL-Dokumente in src/wsdl übersetzen. Die ge-
                    nerierten Quelltexte werden automatisch in den Suchpfad für Quelltexte
                    eingebunden. Prinzipiell könnten wir auch die generierten Quelltexte ins
                    Versionskontrollsystem übernehmen. Das wäre aber redundant, denn die
                    WSDL, das heißt die Vorlage dieser Dateien, ist ja bereits im Versionskont-
                    rollsystem. Indem wir axis:compile als preGoal von java:compile ins
                    Spiel bringen, lassen wir auch diese Klassen kompilieren, ohne sie zu-
                    nächst nach src/main/java kopieren zu müssen.

54                  Kapitel 2: Anpassung von Maven an eigene Wünsche
Was ist gerade geschehen?                                                           Die Syntax eines
                                                                                    postGoal ist die
Mit Axis WSDL2Java werden Klassen generiert und im Verzeichnis
                                                                                    selbe wie die ei-
target/axis/src gespeichert. Da wir diese Klassen keinesfalls modifizieren
                                                                                    nes preGoal. In
wollen, haben wir ein preGoal von java:compile definiert, das axis:
                                                                                    diesem Fall wird
compile aufruft. axis:compile fügt maven.axis.generated.dir in die Pro-
                                                                                    ein Jelly-Skript
perty maven.compile.src.set ein. Dadurch werden die generierten Klas-
                                                                                    definiert, das
sen mit kompiliert, wenn java:compile aufgerufen wird. Mit anderen
                                                                                    ausgeführt wird,
Worten: axis:compile informiert Maven, dass das Verzeichnis target/
                                                                                    nachdem das im
axis/src Java-Quelltexte enthält, die kompiliert und in das Artefakt einge-
                                                                                    name-Attribut
bunden werden müssen.
                                                                                    angegebene Ziel
Schauen wir uns nochmals an, was das Ziel axis:compile genau tut. Dazu              ausgeführt wurde.
werfen wir einen Blick in die zum Axis-Plugin gehörende Datei plugin.
jelly, die wir in ~/.maven/cache/maven-axis-plugin-0.7/plugin.jelly fin-
den:
      
          Verzeichnis ${maven.axis.generated.dir}
                    wird in maven.compile.src.set eingefügt
          
Die wesentliche Zeile haben wir hervorgehoben: Ein Pfad axis.src.set
wird erzeugt und zu maven.compile.src.set hinzugefügt. Das hat zur
Folge, dass die generierten Axis-Klassen von java:compile mit kompi-
liert werden.

Definition eigener Properties
Das Axis-Plugin generiert unter anderem einen Unit-Test für den Web-
service, den die WSDL beschreibt. Allerdings muss dieser Unit-Test ein
wenig an die lokalen Gegebenheiten angepasst werden. Zum Beispiel
erwartet der SOAP-Service für die Wettervorhersage als Parameter einen
Längen- und Breitengrad. Die vom generierten Unit-Test verwendeten
Werte (0,0) sind aber für unsere Zwecke ungeeignet, weil der Wettervor-
hersagedienst weder den Äquator noch die Länge von Greenwitch ak-

                                                    Definition eigener Properties                  55
zeptiert. Wir benötigen ein preGoal und ein postGoal für das Ziel axis:
     wsdl2java, das den Unit-Test in unser Verzeichnis src/test/java kopiert
     und von axis:compile ausschließt. Dieser Unit-Test soll nicht bei jedem
     Aufruf von axis:wsdl2java überschrieben werden. Dazu benötigen wir
     eine eigene Property namens generate.tests.

     Wie mache ich das?
     Zunächst definieren Sie bitte die Property generate.tests in Ihrem pro-
     ject.properties. Die Property soll in Ihrem preGoal und in Ihrem postGoal
     ausgelesen werden. Fügen Sie bitte die folgenden Zeilen in project.pro-
     perties ein:
         # Eigene Properties
         generate.tests = false
     Als Nächstes modifizieren Sie das preGoal und postGoal in maven.xml.
     Beide sollen die neue Property benutzen, um den Unit-Test nur dann zu
     überschreiben, wenn generate.tests den Wert true enthält:
         
     Wenn Sie maven axis:wsdl2java aufrufen, dann liest Maven die Proper-
     ties aus project.properties. Der Standardwert der Property generate.
     tests ist dort als false definiert. Dementsprechend soll axis:wsdl2java
     im Normalfall die Unit-Tests in ${pom.build.unitTestSource} nicht über-
     schreiben. Soll das ausnahmsweise aber doch geschehen, dann rufen wir
     maven axis:wsdl2java -Dgenerate.tests=true auf. In diesem Fall sollten
     wir die folgende Ausgabe sehen:
         axis:wsdl2java:
             [copy] Copying 1 file to C:\dev\mavenbook\code\weather\src\test
             [delete] Deleting directory C:\dev\mavenbook\code\weather\target\axis\
         test\gov

56   Kapitel 2: Anpassung von Maven an eigene Wünsche
Was ist gerade geschehen?                                                            In Maven 2 gibt
                                                                                     es sowohl maven.
Man bezeichnet diese Vorgehensweise als passive oder einmalige Code-
                                                                                     xml als auch
generierung. Zwar müssen die aus der WSDL generierten Quelltexte im
                                                                                     project.properties
Allgemeinen nicht modifiziert werden, im Unit-Test müssen aber die
                                                                                     nicht mehr. Die
Parameter für Längen- und Breitengrad angepasst werden. Wenn der
                                                                                     Konfiguration des
Unit-Test generiert werden soll, dann wird die Property generate.tests
                                                                                     Projekts erfolgt
auf true gesetzt. Ein preGoal von axis:wsdl2java überschreibt Ihren
                                                                                     komplett durch
Unit-Test in src/test genau dann, wenn generate.tests auf true steht.
                                                                                     das Project Ob-
Darüber hinaus gibt es ein postGoal von axis:wsdl2java, das den gene-
                                                                                     ject Model (POM)
rierten Unit-Test in jedem Fall löscht.
                                                                                     in der Datei pom.
In dieser Übung haben wir eine Variable in project.properties definiert. Die         xml.
Variable namens generate.tests dient der Spezifikation eines Standard-
verhaltens, das durch Überschreiben der Variablen auf der Kommando-
zeile angepasst werden kann. Als Sie maven axis:wsdl2java -Dgenerate.
tests=true aufgerufen haben, haben Sie damit einen Wert für generate.
tests definiert, der den aus project.properties überschreibt. Mit Hilfe von
j:if wird der Wert dieser Variablen in maven.xml geprüft:
    
      Tests werden generiert.
    
In diesem Beispiel wird durch einen Aufruf von context.getVariable( )
auf den Wert von generate.tests zugegriffen. Die Variable context hat
den Typ JellyContext und bietet Zugriff auf die von Maven definierten
Variablen des Projekts. Die Variable generate.tests wird mit der String-
konstanten true verglichen. Wenn generate.tests den Wert true ent-
hält, dann wird das Tag ant:echo ausgeführt.

                                 HINWEIS
        Wenn generate.tests den Wert true enthält, dann würden Sie
        vielleicht versuchen, mit dem folgenden Codefragment die Referenz
        auf ${generate.tests} auszuwerten, um gegebenenfalls die Aus-
        führung von ant:echo auszulösen:
             
               Die Property generate.tests enthält
                 den Wert true.
               
        Tatsächlich würde dieses Jelly-Skript das Tag ant:echo ausführen.
        Der Grund ist aber ein ganz anderer, als man zunächst vermuten
        würde. Die Kurzform ${generate.tests} wird zu true evaluiert,
        wenn eine Property generate.tests im Jelly-Kontext definiert und
        nicht null ist. Der Punkt im obigen Jelly-Ausdruck kann zweierlei

                                                     Definition eigener Properties                   57
Bedeutungen haben. Falls es eine Variable im Jelly-Kontext gibt, die
             den Namen generate.tests trägt, dann wird diese Variable zurück-
             gegeben. Falls es keine solche Variable gibt, dann wird Jelly den
             Punkt als Methodenaufruf einer Property interpretieren. Mit anderen
             Worten: ${generate.tests} wird als ${generate.getTests( )}
             interpretiert, was dem Wert null entspricht, da das Objekt gene-
             rate nicht existiert. Im Endeffekt würde ant:echo auch dann
             ausgeführt, wenn generate.tests den String false enthielte, da
             ${generate.tests} als true interpretiert wird, wenn der Inhalt der
             Variablen nicht null ist. Aus diesem Grund sollten Sie eine Variable
             stets mit Hilfe der Methode context.getVariable( ) auswerten.

     Die generierten Unit-Tests verwenden als Längen- und Breitengrad je-
     weils den Wert 0, weshalb sie mit einer Fehlermeldung scheitern. Wenn
     Sie axis:wsdl2java aufrufen und dabei versehentlich Ihr korrigiertes
     Exemplar von NdfdXMLTestCase.java überschrieben haben, dann müs-
     sen Sie anschließend Ihr Original aus dem Versionskontrollsystem wie-
     derherstellen oder das Beispiel erneut korrigieren.
     In dieser Übung wird die Variable ${pom} referenziert. ${pom} bietet unter
     anderem den Zugriff auf alle in project.xml definierten Informationen.
     Wenn Jelly einen Ausdruck wie diesen findet, dann überprüft es zu-
     nächst, ob es einen zum Ausdruck passenden Property-Namen gibt. Wenn
     es keine solche Property im Jelly-Kontext gibt, dann wertet Jelly den Aus-
     druck als eine Folge von Property-Accessormethoden aus. Zum Beispiel
     wird ${pom.build.sourceDirectory} als ${pom.getBuild( ).getSource
     Directory( )} interpretiert. Hier sehen Sie ein anderes Ziel, das den Zu-
     griff auf einige andere Informationen über ${pom} demonstriert:
         
           Projektname: ${pom.name}
           Beschreibung: ${pom.description}
           Quelltextverzeichnis: ${pom.build.sourceDirectory}
           
               Verzeichnis mit Unit-Tests: ${pom.build.unitTestSourceDirectory}
           
     Dieses Ziel gibt einfach den Namen und die Beschreibung des Projekts
     sowie die Verzeichnisse mit den Quelltexten und den Unit-Tests aus. Die
     Verzeichnisnamen erhält man durch Abfragen des org.apache.maven.
     project.Build-Objekts, das als getBuild( ) über org.apache.maven.pro-
     ject.Project zugänglich ist. So sieht die zugehörige Ausgabe aus:
         build:start:

         pom-example:
             [echo] Projektname: Test Application
             [echo] Beschreibung: An example project

58   Kapitel 2: Anpassung von Maven an eigene Wünsche
[echo] Quelltextverzeichnis: C:\dev\mavenbook\code\genapp\test-
    application\src\java
        [echo] Verzeichnis mit Unit-Tests: C:\dev\mavenbook\code\genapp\test-
    application\src\test
    BUILD SUCCESSFUL
    Total time: 1 seconds
Eine vollständige Liste aller über ${pom} zugänglichen Variablen ent-
nimmt man am besten den JavaDocs der Project-Klasse, die man unter
http://maven.apache.org/apidocs/org/apache/maven/project/Project.html
findet. Ganz analog findet man eine Liste der Properties der Dependency-
und Build-Objekte unter http://maven.apache.org/apidocs/org/apache/
maven/project/Dependency.html bzw. http://maven.apache.org/apidocs/
org/apache/maven/project/Build.html.
Ganz nebenbei haben Sie übrigens mit dem Tag maven:get eine Pro-
perty des Axis-Plugins abgerufen. Der Zugriff auf Plugin-Properties sollte
stets über maven:get geschehen und nicht zum Beispiel über ${maven.
axis.test.dir}. Wenn ein Plugin noch nicht initialisiert ist, dann führt
die Referenz auf maven.axis.generated.dir zu einem Fehler. Wenn man
die Property dagegen mit maven:get referenziert, dann initialisiert Maven
bei Bedarf das Plugin, bevor der Zugriff erfolgt. Ganz analog kann man
auch eine Plugin-Property mit maven:set definieren. Zwei Beispiele mit
maven:get bzw. maven:set sollen dies illustrieren: Das erste Beispiel liest
mit maven:get die Property maven.axis.generated.dir aus dem Axis-
Plugin. Das zweite Beispiel modifiziert diesen Wert:
    
Bevor man die Maven-Tags benutzt, muss allerdings erst das Namens-
raumpräfix maven an den Namensraum jelly:maven gebunden werden.
Details zu Jellys Tag-Library Maven finden Sie unter http://maven.apache.
org/reference/maven-jelly-tags/tags.html. Kapitel 6 enthält noch weitere
Details über Plugins.

Und was ist mit …
... den eingebauten Variablen wie ${basedir} und ${pom}? Gibt es dazu
eine Liste?
Ja, die gibt es. Einige besonders häufige Maven-Properties finden Sie in
Tabelle 2-1. Alle diese Properties stehen für die Definition eigener Ziele
in maven.xml zur Verfügung. Die obigen Beispiele eines postGoal und
eines preGoal referenzieren zum Beispiel die Variable ${pom.build.

                                                    Definition eigener Properties   59
sourceDirectory}, um das Verzeichnis mit den Java-Quelltexten zu le-
     sen. Die Variable ${pom} liefert darüber hinaus bei Bedarf alle anderen
     Informationen aus dem POM. Ein anderes wichtiges Beispiel einer einge-
     bauten Property ist ${basedir}, das Wurzelverzeichnis des Projekts.

     Tabelle 2-1: Eine Auswahl von Maven zur Verfügung gestellter Properties

     Eingebaute Property        Beschreibung
     ${basedir}                 Wurzelverzeichnis des Projekts; das Verzeichnis, in dem
                                project.xml und maven.xml liegen.
     ${maven.build.dir}         Das Verzeichnis für temporäre Dateien und generierte
                                Artefakte; normalerweise ${basedir}/target.
     ${maven.build.dest}        Das Verzeichnis für kompilierte Klassen; normalerweise
                                ${basedir}/classes.
     ${user.home}               Das Home-Directory des Benutzers. Unter Unix ist dies
                                üblicherweise /home/tobrien oder dergleichen, unter
                                Windows dagegen C:\Documents and Settings\tobrien.
     ${maven.home.local}        Das Verzeichnis ${user.home}/.maven.
     ${maven.repo.remote}       Das Internet-Repository, aus dem Maven bei Bedarf Arte-
                                fakte nachlädt. Standardmäßig ist dies http://www.ibiblio.
                                org/maven/. Die Property darf eine durch Kommata
                                getrennte Liste von Repositories enthalten. Wenn ein
                                Artefakt im ersten angegebenen Repository nicht gefun-
                                den wird, dann werden der Reihe nach die anderen ver-
                                sucht, bis das Artefakt entweder gefunden wird oder die
                                Liste zu Ende ist.
     ${maven.repo.local}        Das lokale Repository, meist ${maven.home.local}/
                                repository.
     ${context}                 Diese Variable ist in allen Jelly-Skripten automatisch defi-
                                niert und enthält ein Objekt vom Typ JellyContext. Die-
                                ses Objekt bietet Zugriff auf alle Variablen, die dem Jelly-
                                Skript zur Verfügung stehen. Nähere Informationen zu
                                diesem Objekt finden Sie unter http://jakarta.apache.org/
                                commons/jelly/apidocs.
     ${pom}                     Enthält ein Objekt des Typs org.apache.maven.project.
                                Project mit Informationen über das aktuelle Projekt.
                                Diese Variable bietet Ihnen den Zugriff auf die Pfade des
                                Projekts oder der verwendeten Abhängigkeiten.
     Alle System-Properties     Die Klasse System stellt eine Reihe von Properties zur Ver-
                                fügung, die automatisch übernommen werden. Dazu
                                gehören Properties wie java.home, os.arch oder file.
                                separator sowie alle anderen von System definierten Pro-
                                perties.

     Eine vollständige Liste der von Maven bereitgestellten Properties finden
     Sie unter http://maven.apache.org/reference/properties.html. In Kapitel 6
     gehen wir detailliert darauf ein, wie ein Maven-Plugin auf diese Proper-
     ties zugreifen bzw. eigene Properties definieren kann.

60   Kapitel 2: Anpassung von Maven an eigene Wünsche
Start des Programms aus einem
eigenen Ziel
Die Client-Bibliothek ist erzeugt, und damit wird es Zeit, mit Maven die
Klasse mdn.weather.Weather aufzurufen, um die Wettervorhersage für Chi-
cago, Illinois, zu bekommen.

Wie mache ich das?
Definieren Sie ein neues Ziel in maven.xml, das den java-Task von Ant
benutzt, um die Klasse mdn.weather.Weather zu starten:

Die Klasse Weather akzeptiert drei Argumente: Breitengrad, Längengrad
und die Anzahl der Tage, für die eine Vorhersage zu erstellen ist. In die-
sem Ziel haben wir die Koordinaten von Chicago angegeben und die
Vorhersage auf einen einzigen Tag beschränkt. Wenn wir nun mit maven
weather:run unser neues Ziel aufrufen, dann erhalten wir die Antwort in
Form eines XML-Dokuments mit der gewünschten Wettervorhersage:
    
      // 
      
                                       Start des Programms aus einem eigenen Ziel       61
point1
                  
                  Daily Maximum Temperature
                  53
                
                    Daily Minimum Temperature
                    34
                
                  12 Hourly Probability of Precipitation
                  30
                  8
                
     Wir können also mit 53° rechnen1 und müssen mit einer Wahrscheinlich-
     keit von 30% Regen befürchten. Nun ja, letzte Woche war’s schlechter!

     Was ist gerade geschehen?
     Sie haben Ants java-Task benutzt, um die Klasse Weather zu starten.
     Dabei wurden drei Argumente mit Hilfe von ant:arg übergeben. Der Klas-
     senpfad wurde durch einen Aufruf der Methode getDependencyPath( ) des
     Objekts ${pom} gebildet. ${pom.getDependencyPath('axis:axis-saaj')}
     liefert zum Beispiel den absoluten Pfad der Abhängigkeit mit groupId axis
     und artifactId axis-saaj. Natürlich muss eine Abhängigkeit in project.
     xml definiert sein, um in dieser Art und Weise referenziert werden zu kön-
     nen.
     Das Ziel weather:run ruft zunächst ein anderes Ziel (jar) auf, da das
     prereqs-Attribut des Elements goal den Wert jar enthält. Wenn weather:
     run von mehr als einem Ziel abhängen würde, dann könnten diese Ziele
     durch Kommata getrennt in demselben Attribut angegeben werden. Weil
     weather:run vom Ziel jar abhängt, wird dieses Ziel vor jedem Aufruf von
     weather:run ausgeführt. Insbesondere werden auch die Unit-Tests aus-

     1 Gemeint sind 53° Fahrenheit, also ca. 12° Celsius. (Anm.d.Übers.)

62   Kapitel 2: Anpassung von Maven an eigene Wünsche
geführt. Sie können die Unit-Tests auslassen, indem Sie -Dmaven.test.
skip=true als zusätzliches Argument auf der Kommandozeile angeben.
Die folgende Kommandozeile ruft also die Weather-Klasse auf, ohne zuvor
die Unit-Tests auszuführen:
    maven weather:run -Dmaven.test.skip=true
Die Verwendung von ant:java zum Start einer Java-Anwendung ist nicht
die einzige Möglichkeit. Es gibt bessere Vorgehensweisen, als ein eige-
nes Ziel in einem Maven-Projekt zu formulieren. In Kapitel 6 werden Sie
unter anderem ein einfaches Plugin schreiben, das eine JAR-Datei star-
tet.

Einrichtung eines Standardziels
Wenn Sie das Ziel weather:run häufiger von der Kommandozeile aufru-
fen, dann kommt vielleicht irgendwann der Wunsch auf, dieses Ziel als
Standardziel Ihres Maven-Projekts zu verwenden. Das Standardziel ist
dasjenige, das aufgerufen wird, wenn Sie maven von der Kommandozeile
ohne weitere Argumente starten. In diesem Fall würde also das Ziel
weather:run ausgeführt.

Wie mache ich das?
Das Standardziel wird einfach im default-Attribut des project-Elements
angegeben:
    
        // …snip…

Wenn Sie Maven aufrufen, ohne ein bestimmtes Ziel anzugeben, dann
würde Maven also weather:run als Standardziel aufrufen. Niemand hat
gesagt, das würde kompliziert werden!

Properties überschreiben
Sie haben bereits festgestellt, dass die Definition einer Property auf der
Kommandozeile eine andere Definition in den project.properties über-
schreibt. Darüber hinaus werden Properties von Plugins durch Definitio-
nen in den project.properties überschrieben. Nachdem Sie nun den

                                                           Properties überschreiben   63
prinzipiellen Mechanismus des Überschreibens von Properties kennen,
     stellt sich die Frage, wo und wie genau man eine projekt- oder benutzer-
     spezifische Konfiguration vornehmen kann.

     Wie mache ich das?
     In der Übung zur »Benutzerspezifischen Anpassung eines Plugins« zu
     Beginn dieses Kapitels haben wir die Property maven.axis.serverside in
     der Datei project.properties gesetzt. Rufen Sie nun zum Test das Ziel
     axis:wsdl2java auf, und setzen Sie dabei die Property maven.axis.ser-
     verside auf true:
          maven axis:wsdl2java -Dmaven.axis.serverside=true
     Sie sollten an dieser Stelle sehen, dass Maven eine Reihe verschiedener
     Klassen und Deploymentdeskriptoren für einen SOAP-Service von Apa-
     che Axis generiert. Indem Sie die Property maven.axis.serverside auf
     der Kommandozeile gesetzt haben, haben Sie damit den Wert aus pro-
     ject.properties überschrieben. Auf der Kommandozeile gesetzte Proper-
     ties haben Vorrang vor Properties, die an anderer Stelle in Maven gesetzt
     werden.
     Tatsächlich kennt Maven eine ganze Hierarchie von Property-Dateien,
     die man allesamt zur Anpassung an projekt- oder benutzerspezifische
     Wünsche benutzen kann. Maven liest Properties der Reihe nach von den
     folgenden Stellen:
     ${basedir}/project.properties
         Diese Datei liegt im selben Verzeichnis wie maven.xml und project.
         xml. Sie legt das Standardverhalten eines Projekts fest und erlaubt
         die projektspezifische Anpassung der Standards von Maven.
     ${basedir}/build.properties
         Diese Datei liegt ebenfalls im selben Verzeichnis wie maven.xml und
         project.xml. Ihre Aufgabe ist die Anpassung des Projekts an die Wün-
         sche eines bestimmten Benutzers. Wenn Sie den Wert einer Property
         an Ihre persönliche Umgebung anpassen wollen, ohne zugleich die
         Properties anderer Benutzer zu verändern, dann erzeugen Sie eine
         Datei build.properties in ${basedir}. Die in dieser Datei festgelegten
         Werte überschreiben ggf. die in project.properties definierten. Achten
         Sie allerdings darauf, dass build.properties nicht ins Versionskontroll-
         system2 übernommen wird: Diese Datei ist ausschließlich zur Anpas-
         sung des Projekts an die Bedürfnisse eigener Benutzer gedacht.

     2 Am einfachsten geht das, wenn Sie den Namen build.xml in Ihr .cvsignore bzw. als Property
       svn:ignore übernehmen. (Anm.d.Übers.)

64   Kapitel 2: Anpassung von Maven an eigene Wünsche
${user.home}/build.properties
    Falls Ihr Homedirectory eine Datei build.properties enthält, dann wird
    diese zur benutzerspezifischen Anpassung aller Projekte benutzt. In
    diese Datei gehören zum Beispiel die Konfiguration eines Proxyser-
    vers oder eines speziellen Online-Repositorys. Die in dieser Datei
    definierten Properties gelten für alle Projekte, und sie überschreiben
    Werte aus den beiden vorherigen Dateien.
System-Properties (mit der Option -D definiert)
    Sie haben in diesem Kapitel bereits häufig von dieser Möglichkeit
    Gebrauch gemacht. Die Angabe einer Property auf der Kommando-
    zeile überschreibt alle Konfigurationsdateien. Solchermaßen definierte
    Properties sind endgültig.
Abbildung 3-3 illustriert die Definition von Properties in mehreren Schich-
ten, die Sie in dieser Übung kennen lernen. In Kapitel 3 werden Sie se-
hen, dass ein Projekt Properties von einem übergeordneten Projekt erben
kann. Sie werden in Kapitel 3 außerdem sehen, dass Unterprojekte auto-
matisch alle Properties aus den Dateien project.properties und build.
properties des übergeordneten Projekts erben.

Was ist gerade geschehen?
Die verschiedenen Konfigurationsstufen sind je nach Aufgabe unter-
schiedlich gut geeignet. Die Konfiguration eines Proxyservers ist norma-
lerweise für alle Ihre Maven-Projekte dieselbe. Aus diesem Grund setzt
man die entsprechenden Properties am besten in build.properties im
eigenen Homedirectory. Falls Sie dagegen eine Property setzen müssen,
die nur für Sie und nur für ein bestimmtes Projekt gelten soll, dann ist
${basedir}/build.properties dafür der richtige Ort. Falls Sie zum Beispiel
der Release-Manager eines bestimmten Projekts sind, dann benötigen
Sie eine Property maven.username. Diese Property ist benutzer- und pro-
jektspezifisch und gehört deshalb in ${basedir}/build.properties. Diese
Datei gibt es nur auf Ihrer lokalen Maschine, denn sie wird nicht ins Ver-
sionskontrollsystem übernommen. Damit eignet sie sich zur Anpassung
eines bestimmten Projekts an Ihre persönlichen Bedürfnisse. Da die Vor-
gaben eines Open Source-Projekts wie Maven oft für den Einsatz in einer
Firma oder einer ähnlichen Organisation ungeeignet sind, werden Sie
feststellen, dass Sie in ${basedir}/build.properties oder ${user.home}/
build.properties häufig dieselben Einstellungen vornehmen.
Wenn Sie die Properties eines Projekts so konfigurieren wollen, dass diese
auch für die anderen Entwickler gelten, dann gehören diese Einstellun-
gen in ${basedir}/project.properties. Diese Datei gehört ins Versionskon-

                                                    Properties überschreiben   65
trollsystem und eignet sich damit für allgemein sichtbare projektspezifi-
     sche Konfigurationen.

     Iteration über Abhängigkeiten
     Es kommt recht häufig vor, dass man in Jelly-Skripten auf Informationen
     aus dem POM zugreifen muss. Wie wäre es zum Beispiel mit einem Auf-
     ruf des Wetterprogramms ohne die explizite Angabe jeder einzelnen Ab-
     hängigkeit als pathelement?

     Wie mache ich das?
     Der Zugriff auf das POM erfolgt in einem Jelly-Skript über die Variable
     ${pom}. Das folgende Ziel benutzt das Jelly-Tag forEach und ein path-
     element-Tag von Apache Ant, um den korrekten Klassenpfad zum Aufruf
     der Klasse mdn.weather.Weather zu setzen:
         
     Dieses geänderte Ziel funktioniert genauso wie das ursprüngliche Ziel
     weather:run aus dem vorigen Abschnitt. Offensichtlich ist diese Methode
     besser als die erste, weil man die Abhängigkeiten nur an einer Stelle
     pflegen muss: Wenn man eine neue Abhängigkeit zu project.xml hinzu-
     fügt, dann wird sie auch von weather:run automatisch in den Klassen-
     pfad übernommen.

     Was ist gerade geschehen?
     Ihr neues Jelly-Ziel iteriert über die Abhängigkeiten mit Hilfe des Tags j:
     forEach. Die Referenz ${pom.artifacts} bezieht sich auf die Methode
     getArtifacts( ) im POM, also auf eine Instanz der Klasse org.apache.
     maven.project.Project. Das Ergebnis von getArtifacts( ) ist eine Liste
     von org.apache.maven.project.Artifact-Objekten mit Informationen

66   Kapitel 2: Anpassung von Maven an eigene Wünsche
über je ein Artefakt aus project.xml. Die Schleife weist der Reihe nach          Dieses Beispiel
der Variablen lib je eines dieser Artefakte zu. Die Variable erlaubt damit       benutzt j:for-
den Zugriff auf den absoluten Pfad je eines Artefakts über ${lib.path}.          Each, eine von
Viele Informationen wie zum Beispiel der Pfad eines Artefakts aus ${pom}         zwei Kontroll-
sind wie in diesem Fall erst zur Laufzeit verfügbar. Wenn Sie mehr über          strukturen in Jelly
das Artifact-Objekt erfahren wollen, dann werfen Sie am besten einen             zum Bilden von
Blick in die JavaDocs dieser Klasse, die Sie unter http://maven.apache.          Schleifen. Sowohl
org/apidocs/org/apache/maven/repository/Artifact.html finden.                    j:forEach als auch
                                                                                 j:while können
                                                                                 über beliebige Col-
Anpassung von Look and Feel                                                      lections, Maps,
der Website                                                                      Listen oder
                                                                                 Arrays iterieren.
Das Wettervorhersageprogramm funktioniert wie gewünscht. Allerdings
entspricht die mit Maven generierte Website immer noch den Voreinstel-
lungen von Maven. Sie können das Aussehen aber weitgehend an Ihre
eigenen Vorstellungen anpassen.

Wie mache ich das?
Konfigurieren Sie das XDoc-Plugin. Werfen Sie dazu einen Blick auf die
folgenden Properties aus project.properties:
    maven.xdoc.date = right
    maven.xdoc.date.format = MM/dd/yyyy
    maven.xdoc.crumb.separator = >
    maven.xdoc.developmentProcessUrl = http://www.slashdot.org
    maven.xdoc.poweredBy.title = Powered by the Mighty Maven
    maven.xdoc.theme.url=./style/custom.css
Diese Properties setzen die Position und das Format des angezeigten
Datums, den Pfadseparator in der Navigationsleiste, die URL zur Beschrei-
bung des Entwicklungsprozesses sowie den Titel des »Powered by«-
Icons. Wenn Sie maven site aufrufen, dann werden Sie sehen, dass diese
Properties eine Reihe von subtilen Änderungen an der Website vorneh-
men. Die Änderung der URL des Entwicklungsprozesses empfiehlt sich
vor allem dann, wenn Ihre Firma eine eigene Seite zu diesem Thema
unterhält. Wenn Sie diese Property unverändert lassen, dann verweist
sie auf maven.apache.org.

Was ist gerade geschehen?
Die wichtigste Änderung des Look and Feel ist die Wahl des CSS, das
von Maven benutzen soll. Um sich einen Überblick über die verfügbaren
Stylesheets zu verschaffen, werfen Sie am besten einen Blick in das

                                       Anpassung von Look and Feel der Website                    67
Verzeichnis target/docs/style Ihrer generierten Website. Sie sollten dort
     verschiedene Dateien mit Namen wie maven-base.css, maven-classic.
     css oder maven-theme.css finden. Die Anpassung des Look and Feel von
     Maven geschieht durch die Änderung dieser Dateien. Die ursprüngliche
     Datei liegt in xdocs/style/custom.css und wird durch die Property maven.
     xdoc.theme.url referenziert und in die generierte Website eingebunden.
     Eine vollständige Liste aller Properties des XDoc-Plugins finden Sie in der
     Online-Dokumentation unter http://maven.apache.org/reference/plugins/
     xdoc/. Wenn Sie sich einen Überblick über die Anpassung der von Maven
     generierten Website verschaffen wollen, dann schauen Sie sich am bes-
     ten die Website eines anderen Projekts an, die mit Maven erstellt wurde.
     Ein Projekt, dessen Website von Maven generiert wurde, ist übrigens
     Maven selbst. (So eine Überraschung!) Abbildung 2-2 zeigt einen Screen-
     shot der Website des Maven-Projekts.

     Abbildung 2-2: Screenshot einer benutzerspezifisch konfigurierten und mit Maven
     generierten Website

     Die Maven-Website hat eine eigene Navigation, externe Links, ein eige-
     nes Datumsformat und bietet ein generiertes PDF mit dem Inhalt der kom-

68   Kapitel 2: Anpassung von Maven an eigene Wünsche
pletten Site an. Wenn Sie Ihre eigene Site konfigurieren wollen, dann
empfiehlt sich ein Blick in das xdocs-Verzeichnis im Subversion-Reposi-
tory von Apache (http://cvs.apache.org/viewcvs.cgi/maven/maven-1/core/
trunk/xdocs/?root=Apache-SVN). Das Apache-Repository kann über View-
CVS eingesehen werden und erlaubt damit einen Einblick in die Website
des Maven 1-Projekts. Man kann sich damit sehr schön anschauen, wie
man die eigene Website konfigurieren kann. Werfen Sie zum Beispiel
einen Blick in die Datei navigation.xml im Verzeichnis /maven/maven-1/
core/trunk/xdocs. Sie werden dann feststellen, dass das folgende XML-
Fragment das aufklappbare Menü definiert, das wir im Abschnitt User’s
Guide in Abbildung 2-2 sehen:
   
In demselben Verzeichnis finden wir auch die FAQ von Maven in faq.fml
sowie andere XDoc-Dateien mit der ausführlichen Dokumentation des
Maven-Projekts, die bei der Generierung der Website benutzt werden.
Nehmen Sie die Maven-Website ruhig als Vorlage für Ihr eigenes kom-
merzielles oder Open Source-Projekt.

                                         Anpassung von Look and Feel der Website      69
Benutzung des FAQ-Plugins
                      Viele Projekte enthalten ganze Seiten voller häufig gestellter Fragen und
Das Element re-       Antworten. Themen wie »Warum wurde das Projekt gestartet?« findet
ports ist nicht als   man ebenso wie Anweisungen zum Umgang mit speziellen technischen
Ergänzung zu ver-     Problemen. Das FAQ-Plugin von Maven ist ein praktisches Werkzeug zur
stehen. Wenn es       Entwicklung einer solchen Seite.
nur ein report-
Element ent-          Wie mache ich das?
hält, dann wird
                      Um das FAQ-Plugin zu benutzen, müssen Sie es wie folgt im reports-Ele-
auch nur dieser
                      ment der Datei project.xml referenzieren:
Bericht generiert.
Sie müssen wirk-          
                            maven-faq-plugin
lich alle zu gene-        
rierenden Be-
                      Damit ist der Report aktiviert. Als Nächstes erzeugen Sie bitte eine Datei
richte explizit
                      xdocs/faq.fml mit dem folgenden Inhalt:
angeben.
Installation

            Wie installiere ich das Weather-Projekt?
          
            Ganz einfach: Kopieren Sie das Projekt aus dem
              Subversion-Repository, und rufen Sie maven wsdl2java
              auf.
          
Als Nächstes generieren Sie die Site erneut, indem Sie maven site aus-
führen. Dann laden Sie target/docs/index.html in Ihren Browser. Klicken
Sie auf PROJECT REPORTS und FAQS, dann sollten Sie die in Abbildung 2-3
abgebildete Seite sehen.

Abbildung 2-3: Beispiel einer mit Maven generierten FAQ

                                                          Benutzung des FAQ-Plugins   71
Was ist gerade geschehen?
     Sie haben das FAQ-Plugin aktiviert, indem Sie es im reports-Element
     Ihres project.xml referenziert haben. Als Nächstes haben Sie in einem
     XML-Dokument verschiedene Fragen und Antworten formuliert. Bei der
     Generierung der Site wurde diese FAQ automatisch in eine HTML-Seite
     übersetzt und als Link in das Untermenü mit Berichten über das Projekt
     integriert.

72   Kapitel 2: Anpassung von Maven an eigene Wünsche
Sie können auch lesen