Sonatype

Previous: Chapter 2
Next: Chapter 3

I don't know why we are here, but I'm pretty sure that it is not in order to enjoy ourselves. -- Ludwig Wittgenstein

This chapter follows an example project. You may wish to download killerapp and follow along.

Introduction

Programmers are notoriously gawkish when it comes to words - so are we. With this in mind, the first part of this book is focused on using Maven, explaining with code or graphs rather than words when possible. Readers already familiar with Maven would still do well to read through the first few chapters; Maven evolves quickly and you may learn something new.

Maven is a huge project. Although not as large as something akin to the Eclipse project, it is more complex than Ant. It is conceptually simpler, mind you, and easier to manage, but the sheer number of possibilites that Maven affords the build engineer makes it a chore to learn all of its many facates. As hinted at in the introduction, Maven is more than a core project, but is also an umbrella project for the many plugins necessary to complete the usual build tasks. Because of this inherant complexity there are two levels of understanding

The philosophy of this book is simple. This is a book for complete beginners, to give them a solid understanding of what Maven can do, and the best practices that many of us have learned along the way. It is written in the form of a narrative, following each step in the building, documenting, reporting and deployment of a project called the Killer App.

The Killer App is the next big social networking site! It is broken into several sub-projects that take advantage of Maven's code generation, compilation, test execution, packaging and verification and generating documentation - to higher order use-cases such as profile management, artifact classifiers.

Installation

One of Maven's biggest strengths lies in its ability to manage the components required to build an application. This means that if a user attempts to package a Java project into a JAR artifact then Maven will first reach across the internet to Maven's central repository and download the tools necessary in creating a JAR. In Maven, deployable files are called artifacts; thus, a JAR file is an artifact - so is a WAR file.

Before installing you must have a Java version 1.4 or above installed. Ensure that the JAVA_HOME system variable is set and points to your JDK install path. It is also convenient to have the directory containing your "java" binaries in the system PATH.

Installation of Maven 2 is a snap. Visit the Maven site at http://maven.apache.org/ to download the most recent version of Maven 2, in the zip format you wish. Unpack the file to a convenient location that you have access to. This is where Maven is installed, no action is required beyond unpacking it. It is, however, wise to add your Maven install directory to the system PATH.

Ex Nihilo

Open up your favorite command line terminal (cmd.exe or command.com in Windows, or some sort of xterm in Unix flavors) and type the following command:

$ mvn archetype:create -DgroupId=mavenbook -DartifactId=my-app

We have just used Maven to create a project from scratch. The name of the project is "my-app", and the group is "mavenbook" (we will go over "groups" soon, for now note it is required). You will see output similar to the following:

[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:create] (aggregator-style)
[INFO] ----------------------------------------------------------------------------
... <lots of information, lots of downloading artifacts> ...
[INFO] [archetype:create]
[INFO] Defaulting package to group ID: mavenbook
[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: mavenbook
[INFO] Parameter: packageName, Value: mavenbook
[INFO] Parameter: basedir, Value: ~
[INFO] Parameter: package, Value: mavenbook
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: artifactId, Value: my-app
[INFO] ********************* End of debug info from resources from generated POM ***********************
[INFO] Archetype created in dir: ~/my-app
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Tue Apr 24 10:45:00 CDT 2007
[INFO] Final Memory: 4M/8M
[INFO] ------------------------------------------------------------------------

mvn is the Maven 2 command. archetype:create is called a Maven "goal". If you are familiar with Ant, you may concieve of this as similar to a task. Finally, the remaining -Dname=value pairs are arguments that are passed to the goal and take the form of -D properties, similar to the system property options you might pass to the java executable via the command line. The purpose of the archetype:create goal was to quickly "create" a project from an "archetype". The plugin is the prefix "archetype", and the goal is to "create".

$ cd my-app
$ mvn package

When you run the package command, expect the see the following output:

[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO]    task-segment: [test]
[INFO] ----------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
Compiling 1 source file to ~/my-app/target/classes
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
Compiling 1 source file to ~/my-app/target/test-classes
[INFO] [surefire:test]
[INFO] Surefire report directory: ~/my-app/target/surefire-reports

 -------------------------------------------------------
  T E S T S
 -------------------------------------------------------
Running mavenbook.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.047 sec

Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] [jar:jar]
[INFO] Building jar: ~/my-app/target/my-app-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Thu Oct 05 21:16:04 CDT 2006
[INFO] Final Memory: 3M/6M
[INFO] ------------------------------------------------------------------------

It's built! You have now created and run a simple project using Maven. It even works, which you can prove to yourself by running the obligatory hazing program: Hello World.

$ java -cp target/my-app-1.0-SNAPSHOT.jar mavenbook.App
Hello World!

You may notice something slightly different about the above command from the first one. The argument to the latter mvn command was a single word - package - not a colon-seperated pair like the initial archetype:create goal. The first command was a single goal - an objective - of a plugin. Plugins may contain several goals, each a specific objective that may be executed solo or along with other goals to achieve some end; in this case create a project based upon an archetype. A goal is a unit of work in Maven, and indeed beyond a few core background and housekeeping functions, goals do all of the work in Maven.

A Plugin Contains Goals

Note that we did not specify what kind of archetype the goal is to create on our command line, merely what to name the project. This is our first brush with "convention over configuration." The convention, or default, for this goal is to create a simple project (called Quickstart, but you don't need to remember that for now). Thanks to the default behavior of the plugin, we saved ourself a lot of typing for doing something we wanted to do anyway! In this case, generate a quick little project to start with. The archetype plugin is far more powerful than this first example lets on, but it is a great way to get new projects started fast (more details on archetypes in a later chapter).

The second command we ran - mvn package - was not a goal at all, but rather a Maven phase. Phases are a cornerstone of Maven's simplicity in execution, so let us take a little time and go over precisely what Maven folks mean when they speak of phases.

A phase is a step in what Maven calls the "build lifecycle". The build lifecycle is an ordered sequence of phases involved in building a project, beginning with validating the basic integrity of the project to deploying the project to production. These steps are purposefully left vague, as validation, or testing, or deployment may mean different things to different projects. For example, the "package" phase in a jar project means "package this project into a jar", where in an ear project it may mean "package this project into an ear along with its dependencies".

A Lifecycle is a Sequence of Phases

You may be thinking "But you said goals do all of the work!" It's true, they do. A phase is actually a key upon which goals piggyback to give an execution set some structure. Each phase may have zero or more goals bound to it - but usually zero or one. This enforces that, by default, a set of goals are executed in a specific sequence. If you run the mvn package phase again, you will notice that more than one goal was executed. Since our simple quickstart project has (by default) a jar packaging type, then the "jar:jar" goal is bound to the package phase.

A Goal Binds to a Phase

But what of the goals preceding it, like "compiler:compile" and "surefire:test"? These are executed because, unlike executing a specific goal, executing a phase will first execute all proceeding phase, in order, leading up to and including the one specified. Since each phase is actually an abstract correlation to a set of goals, each goal bound to a phase is executed in order. The jar project we are packaging executes the following goals in sequence:

  • [resources:resources] goal is bound to the resources phase.
  • [compiler:compile] goal is bound to the compile phase
  • [resources:testResources] goal is bound to the test-resources phase
  • [compiler:testCompile] goal is bound to the test-compile phase
  • [surefire:test] goal is bound to the test phase
  • [jar:jar] goal is bound to the package phase
Bound Goals are Run when Their Phases Execute

Let us revisit the command we executed above.

mvn package

Since this command executes a phase, it will execute all phases up to that point - well, actually as mentioned before, it is executing all goals bound to each phase up to that point. Since we are working with a jar packaging type project, and by looking at the goal sequence above, we may execute the same thing be typing:

mvn resources:resources \
    compiler:compile \
    resources:testResources \
    compiler:testCompile \
    surefire:test \
    jar:jar

The package phase is nicer, eh? It is also safer, as it does more than compile and package, but also forces testing to take place since it lay in the sequence. Assuming you have written great tests - which we are certain that you always do - you can be assured that the generated jar artifact will work.

Maven Coordinates

There are two basic components to the Maven system: goals and POMs. We have already covered the first. The second is the POM, which is an acronym for Project Object Model - it is a declarative description of a project defined in a single xml file named pom.xml. They relate together rather simply. Goals are actions we wish to take upon a project, and a project is defined by a POM. Another way of looking at it is: if we consider a build system as a series of statements, goals are the verbs; the POM and other project files, nouns.

Let us take a look at the POM file for the project we have created.

A POM requires Coordinates

The groupId, artifactId, version and packaging type make up a project's coordinate (sometimes a fifth element, classifier, exists but more on that in a later chapter). Just like in any other coordinate system, a Maven coordinate is an address for a specific point in space, in increasing detail. Up until now we have ignored how Maven accesses all of the projects it needs - and we will still avoid the details for now. What is currently important is that Maven pinpoints a project via its coordinate when one project relates to another, either as a dependency (this project requires another project for some reason), a transative dependency (a dependency of a dependency), a parent (this project inherits some attributes from another project). In the above pom.xml file for our current project, its coordinate is represented as mavenbook:my-app:jar:1.0-SNAPSHOT.

Moreover, packaging is also an important component, though note that groupId:artifactId:version make a project unique - you cannot have a jar and a war with the same key.

These four elements become the key to finding and using one particular project in the vast space of other Mavenized projects, locally and out in cyberspace. Each project out in a Maven repository is located and used by these elements that create a form of address represented as groupId:artifactId:packaging:version. When this project is installed into the local Maven repository, it immediately becomes locally available to any other project that wish's to use it. All one must do is to add it as a dependency of another project.

Maven Space is a coordinate system of projects

Repositories and the POM

A Maven repository is a collection of installed or deployed project artifacts and other metadata information, managed exclusively by Maven. A local Maven repository is a local system directory structure on the building machine containing all of the artifacts that have been downloaded by Maven, either required by plugins used, dependencies of projects built, or manually installed projects via the install plugin. Maven will not work without a local repository. Even the sample project created above kicked off the creation of a local repository. By default, this local repository is under the current user's directory .m2/repository.

In Windows this is likely C:\Documents and Settings\USERNAME\.m2\repository

In *nix systems this is likely ~/.m2/repository

Wherever the differences in local repository location may be, some things are the same. The layout under the repository is (mostly) always groupId/artifactId/version/artifactId-version.packaging. For example, look in your local repository path under junit/junit/3.8.1/. If you have been following the examples thusfar, there will be a file named junit-3.8.1.jar and a junit-3.8.1.pom file (as well as probably a couple checksum files). The files were automatically downloaded and installed by Maven from the remote Maven central repository - more details on that in later chapters.

Maven connects to this space to download artifacts denoted by the coordinate

If you look under the repository mavenbook/my-app/1.0-SNAPSHOT/ you should find... nothing. We have not installed the project yet! But now we will.

mvn install

Just like the package phase executed above, this phase execution is a shorthand notation to execute every goal bound to every phase up to and including install, making this lifecycle equivalent to running:

mvn resources:resources \
    compiler:compile \
    resources:testResources \
    compiler:testCompile \
    surefire:test \
    jar:jar \
    install:install

Check the mavenbook/my-app/1.0-SNAPSHOT/ location again, and you will find the my-app-1.0-SNAPSHOT.jar and my-app-1.0-SNAPSHOT.pom files. As you can imagine the jar is the artifact generated by the jar:jar goal bound to the package phase. The pom file is an installed and slightly modified version of the project's pom.xml file. This pom file gives other projects information about this project, most importantly what dependencies it has. Maven does more than installs a project's dependencies (in our case, junit:junit:jar:3.8.1), but also installs a project's dependency's dependencies - its transative dependencies.

The necessary basic piece of information we will cover is the POM itself. The POM is a single unit of work, no smaller unit conceptually exists within Maven. This comes in handy especially when dealing with large scale projects with complicated dependency hierarchies.

You define the dependencies and Maven manages transitive dependencies for you

The pom.xml we are investigating contains a single dependency junit:junit:jar:3.8.1 (the packaging type defaults to jar, remember?). The scope of that dependency is test, meaning that it will not be required to run compiler:compile, but it will be required to to successfully execute compiler:testCompile. Maven will use dependencies that match a project's coordinates before the first goal execution takes place.

Under normal circumstances dependencies will not be bundled up with the generated artifact (though there are exceptions, such as the ear packaging type) - they are only used for compilation. But as you will find, between the configurability of existing plugins through the POM and the ability to write custom plugins, any structure is possible through Maven.

Site

Lastly, we will quickly cover a rather important piece of Maven's functionality: the site build lifecycle. Unlike the default build lifecycle that manages generation of code, manipulation of resources, compilation, packaging, et cetera, this lifecycle is concerned solely with processing site files under the src/site directories and generating reports.

mvn site

That's it! Thanks to Maven's convention, this simple command will generate a site with very basic information under the target/site directory. Open (in a web browser) the index.html file under that directory and it will display a basic blank Maven site page with a left-hand side menu containing Project Information. This contains normally useful information like a project summary and dependency information - in our case, however, this information is mostly empty, since the POM contains very little information about itself beyond a coordinate, a name, url and single test dependency.

Dependency Report is one of Several Reports Generated by Default

First Run

You may wish to download the KillerApp project and follow along.

By this point you should have - at least - a simple understanding of what Maven is. Although this grasp may not yet be an intuitive understanding, you should by now have a high-concept view of what Maven does (project stuff), and what it can achieve (nearly anything). If you are still lost, never fear. We will now begin working with a simple project that will follow us through the rest of this book, as we open up each galaxy of the Maven universe, and then navigate down to the finer systems contained therein.

The project we will work with is called the Killer App - the ultimate, grandiloquently named, application that will change the world! Social networking applications are all the current rage, and this is yet another. This application has a command-line interface for both managing accounts, as well as mining lists of emails for nefarious spamming purposes. The public side is a web application where users can create accounts and personal pages, as well as adding their buddies who also have accounts. The data is held either in main memory or stored in an xml stream. More importantly, the construction of this project and related tools will touch on all of the major points of Maven, as well as giving you a feeling for Maven's best practices.

killerapp-api
killerapp-cli
killerapp-core
killerapp-model
killerapp-stores
  killerapp-stores-memory
  killerapp-stores-xstream
  pom.xml
killerapp-war
src/site
pom.xml

Note that the Killer App project is by no means a perfect architecture. In all actuality, it does not even rank as "good" - it's rather overdesigned. What it does do is touch on all of the major points that we will cover in this tutorial concerned with usability. By the end of this book you will have all of the necessary knowledge to tackle any issue you, as a user, may encounter in Maven either through direct examples or by enabling you with the tools necessary to find your own answers.

Under the killerapp directory run the following command (if you have not yet downloaded and unzipped the project, do so now):

mvn install

Maven will build all of the projects ordered by the "reactor".

[INFO] Scanning for projects...
[INFO] Reactor build order: 
[INFO]   Killer App
[INFO]   Killer App Model
[INFO]   Killer App API
[INFO]   Killer App Stores
[INFO]   Killer App Memory Store
[INFO]   Killer App XStream Store
[INFO]   Killer App Core
[INFO]   Killer App Commandline Interface
[INFO]   Killer App Web WAR
[INFO] ----------------------------------------------------------------------------
[INFO] Building Killer App
[INFO]    task-segment: [install]
[INFO] ----------------------------------------------------------------------------
[INFO] [site:attach-descriptor]
[INFO] [install:install]
[INFO] Installing ~/killerapp/pom.xml to ~/.m2/repository/com/training/killerapp/killerapp/1.0-SNAPSHOT/killerapp-1.0-SNAPSHOT.pom
[INFO] ----------------------------------------------------------------------------
[INFO] Building Killer App Model
[INFO]    task-segment: [install]
[INFO] ----------------------------------------------------------------------------
...

It executes the full build lifecycle for each project before proceeding onto the next. This ensures that a project that depended upon by the next is built first. You may note that this kind of build hierarchy will not work for circular dependencies (when project A depends on project B which depends on project A). This is correct. Maven does not allow circular dependencies, and the build will fail (and it will tell you) if this is the case.

...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] ------------------------------------------------------------------------
[INFO] Killer App ............................................ SUCCESS [1.530s]
[INFO] Killer App Model ...................................... SUCCESS [3.018s]
[INFO] Killer App API ........................................ SUCCESS [0.161s]
[INFO] Killer App Stores ..................................... SUCCESS [0.011s]
[INFO] Killer App Memory Store ............................... SUCCESS [0.666s]
[INFO] Killer App XStream Store .............................. SUCCESS [0.908s]
[INFO] Killer App Core ....................................... SUCCESS [1.802s]
[INFO] Killer App Commandline Interface ...................... SUCCESS [1.573s]
[INFO] Killer App Web WAR .................................... SUCCESS [0.644s]
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 24 seconds
[INFO] Finished at: Sun Nov 05 00:58:11 CST 2006
[INFO] Final Memory: 15M/28M
[INFO] ------------------------------------------------------------------------

This is the power of Maven's project relationship mechanism. One single base project can handle a whole hierarchy of projects. This project was chosen because it does a good job at representing a reasonable cross-section of issues encountered by a large variety of projects. A rough overview is as follows:

Finally, you can run the project WAR in memory mode with the help of the Jetty plugin.

cd killerapp-war
mvn jetty:run-war

That should start the WAR in a Jetty container via Jetty's run-war goal. Visit the WAR's URL in a browser (http://localhost:8080/killerapp/) and you will see the Killer App in action!

The Killer App in action

Look into the killerapp-war/pom.xml file and you may notice the following lines:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
        <version>6.0.1</version>
        <configuration>
          <contextPath>/killerapp</contextPath>
          <scanIntervalSeconds>15</scanIntervalSeconds>
          <connectors>
            <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
              <port>${jettyPort}</port>
            </connector>
          </connectors>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <properties>
    <jettyPort>8080</jettyPort>
  </properties>
  ...
</project>

This is all the configuration required to run a Jetty container test with Maven. If you had problems getting the sample to start due to port conflict, just change the value of the jettyPort property. Very much flexibility, very little changes. If we could make some basic assumptions about port numbers, and had no desire to set a specific contextPath or relaunch on code changes every 15 seconds, this configuration would be unnecessary. And thus it is with Maven: stick to the convention and avoid configuration!

Getting Help

As comprehensive as a book tries to be, naturally you will encounter problems that we do-not/can-not/will-not cover. In such cases, we suggest searching for answers at the following locations:

  • Maven website - First place to look. A wealth of knowledge, constantly growing, though admittently, sometimes difficult to navigate or find answers if you are not already well on your way to understanding Maven.
  • User mailing list - (users@maven.apache.org) very active, very friendly. Tell 'em we sent ya!
  • Developer mailing list - (dev@maven.apache.org) only if questions/suggestions are directly related to Maven development, not usability questions.

Tips and Tricks

Most chapters will contain a "tips and tricks" section at the end. We will kick this tradition off with one you will use countless times: the maven-help-plugin.

Helping Yourself

The first three goals are simple. You run them in the base of a project directory, and they show you related information about the project. Remember, when you execute a goal you must first prefix it with the plugin name. For example, if you want to execute the help plugin's active-profiles goal, you would type mvn help:active-profiles.

  • help:active-profiles lists the profiles which are currently active for the build.
  • help:effective-pom displays the effective POM for the current build, with the active profiles factored in.
  • help:effective-settings prints out the calculated settings for the project, given any profile enhancement and the inheritance of the global settings into the user-level settings.

The last goal is slightly more complex, showing you information about a given plugin (or one if it's goals). You must at least give the groupId and artifactId of the plugin you wish to describe.

  • help:describe describes the attirbutes of a plugin. This need not run under an existing project directory.

With the plugin parameter you can specify a plugin you wish to investigate, passing in either the plugin prefix (e.g. maven-help-plugin as help) or the groupId:artifact[:version], where version is optional.

mvn help:describe -Dplugin=help

Gives you

[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'help'.
[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [help:describe] (aggregator-style)
[INFO] ----------------------------------------------------------------------------
[INFO] [help:describe]
[INFO] Plugin: 'org.apache.maven.plugins:maven-help-plugin:2.0.1'
-----------------------------------------------
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.

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Wed Mar 14 12:03:04 CDT 2007
[INFO] Final Memory: 2M/5M
[INFO] ------------------------------------------------------------------------

This is rarely useful for anything other than finding a plugin's version, however. The parameter full is worth its (metaphorical) weight in (imaginary) gold.

> mvn help:describe -Dplugin=help -Dfull

[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'help'.
[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [help:describe] (aggregator-style)
[INFO] ----------------------------------------------------------------------------
[INFO] [help:describe]
[INFO] Plugin: 'org.apache.maven.plugins:maven-help-plugin:2.0.1'
-----------------------------------------------
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.

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.
===============================================

... <remove the other goals> ...

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Wed Mar 14 12:08:28 CDT 2007
[INFO] Final Memory: 2M/5M
[INFO] ------------------------------------------------------------------------

This option is great for discovering all of a plugin's goals as well as their parameters. But sometimes this is far more information than necessary. To get information about a single goal, set the mojo parameter instead.

One last tip: All of the help plugins can output to a file via a output parameter. Used like this

mvn help:effective-pom -Doutput=my-output-file.log

Configuring Unit Tests from Maven

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <systemProperties>
            <property>
              <name>my-property</name>
              <value>someValue</value>
            </property>
          </systemProperties>
        </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>
public class PropertyTest extends junit.framework.TestCase
{
  public void testProperty()
  {
    String propertyValue = System.getProperty( "my-property" );
    assertEquals( "someValue", propertyValue );
  }
}

Summary

We have created a simple project, packaged the project into a jar, installed that jar into the Maven repository for use by other projects, and generated a site with documentation... all without writing a single line of code or touching a single configuration file. With a little configuration in the POM the Jetty plugin was able to help us test the WAR of the KillerApp.


Previous: Chapter 2
Next: Chapter 3