Tuesday, July 04, 2006

Maven2, Step by Step

I wrote about my initial experiences with Maven2 in an earlier post. Maven2 is something of a paradigm shift even for seasoned Ant users, since an understanding of the Maven design philosophy is essential for an appreciation of why things work the way they do. Since that post, I have used Maven to set up a web application and a standalone library application, and this article contains more specific details about commands to do various things with Maven2.

Setting up the application skeleton

The Maven2 documentation is silent about how to set up web application skeletons. The standard archetypes allow you to create a simple standalone, a simple web application (no Java code), and a multi-module project. Presumably, the recommended approach to creating a standard web application (JSP and HTML code for the view, and Java code for the Model and Controller layers) is to create a multi-module project containing a single simple web application and one or more standalone applications for the Model and Controller. However, it is possible to make Maven2 work with a standard web application structure by adding some directories to the skeleton created by the standalone Maven archetype.

The Maven2 Getting started Guide has some commands for creating skeletons from standard Maven archetypes. To create the skeleton for an application my-app in the com.mycompany.app namespace using a standalone archetype, run this command:

1
$ mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=my-app

To make a standard web application skeleton from this, add the following directories. The webapps directories is the root of the web applications context, and contains the WEB-INF directory. The resources subdirectory corresponds to the WEB-INF/classes directory for a web application or the conf/ or etc/ directory for a standalone, where all the properties files go. The test/resources/ directory is useful for storing test specific properties files.

1
2
3
4
my-app/src/main/webapps/
my-app/src/main/webapps/WEB-INF/
my-app/src/main/resources/
my-app/src/test/resources/

Finally, to make a web application out of the standard standalone application, change the value of project.packaging from jar to war in the pom.xml file.

Standard Maven2 Goals

Maven2 provides some standard goals which are similar to Ant targets found in most project's build.xml files. This helps people familiar with Ant to make a quick transition to using Maven2. They are as follows:

1
2
3
4
5
6
mvn clean - cleans out all Maven2 generated files.
mvn compile - compiles the Java sources
mvn test-compile - compiles the Java JUnit test classes.
mvn test - runs all JUnit tests in the project.
mvn package - builds the JAR or WAR file for the project.
mvn install - installs the JAR or WAR file in the local Maven repository.

Most of these goals are configured in the super-POM, but if you want to build your application using Java 1.5 (who doesn't these days), you will need some additional configuration in your pom.xml, in the project.build.plugins element in your pom.xml.

1
2
3
4
5
6
7
8
9
      <!-- Java 1.5 compiler plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>

Generating IDE configuration files

Most people work with some kind of IDE, and the IDE must be told where to look for JAR files, Java code, test code, etc. Since this information is already specified in the pom.xml files, Maven2 can generate the IDE artefacts for a large number of popular IDEs in use, such as Eclipse, IDEA and Emacs JDEE. To generate the Eclipse artefacts for your project, run the following command:

1
$ mvn eclipse:eclipse

You also need to tell Eclipse where to find the your local Maven2 repository (under ~/.m2/repository by default). You can do this by setting a global environment variable M2_REPO in the IDE.

Running Jetty in place (webapps)

A nice touch is the Maven2 Jetty Plugin. This starts up a Jetty installation in place in your web application. This is a huge time-saver, since web application development is often an iterative cycle of changing code, deploying to application server, checking a web page and back. Having Jetty running on your web application source enables you to see your changes instantly (or after compiling with changes in Java code). To set it up, you will need to add the following configuration in project.build.plugins in your pom.xml file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty6-plugin</artifactId>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-j2ee_1.4_spec</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
          </dependency>
        </dependencies>
      </plugin>

Then start up Jetty with the following command. You should be able to see your web application on your browser at http://localhost:8080/my-app.

1
$ mvn jetty6:run

Documentation: The project website

I think of documentation as a place to tell the world all about the cool things my project does. However, too many projects skimp on documentation, because of the effort in setting up the infrastructure in place to generate documentation. Maven2 has built in support for generating a project website with all the documentation for your project. Data entered into the pom.xml drives a lot of the reports, such as Mailing List, Issue Management, Source Repository, etc. Maven2 needs to be told which reports to generate in the project.reporting.plugins section of the pom.xml. Details about which pom.xml entries drive which report elements can be found in Resources[2].

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-project-info-reports-plugin</artifactId>
        <reportSets>
          <reportSet>
            <reports>
              <report>dependencies</report>
              <report>project-team</report>
              <report>mailing-list</report>
              <report>cim</report>
              <report>issue-tracking</report>
              <!-- <report>license</report> -->
              <report>scm</report>
            </reports>
          </reportSet>
        </reportSets>
      </plugin>

You can also create project documentation content, such as User Guides, etc, in a variety of formats, such as DocBook and APT (Almost Plain Text). APT is a wiki-like plain text format which I find very convenient. For FAQ entries, Maven2 supports the FML format.

To set up the project site, create the following directories.

1
2
3
4
5
my-app/src/site/apt/
my-app/src/site/fml/
my-app/src/site/resources/
my-app/src/site/resources/images/
my-app/src/site/site.xml

The apt subdirectory should contain the documentation in APT format. The fml subdirectory contains various FAQ source files. The resources subdirectory should contain files and documents that do not need any pre-processing. The files in the apt and fml subdirectory will be pre-processed by the APT and FML processor and be copied to the project site root directory as .html files. The files in the resources subdirectory (including the images/ subdirectory) will be copied to the project site docroot as is. The site.xml specifies the template for your site, ie what the left and right banners should contain, etc. The site.xml file will reference these HTML files.

To generate the project web site, run the following command. The website will be generated under my-app/target/site where you can view it with a browser using the file:// protocol.

1
$ mvn site

Javadocs

The Javadocs plugin needs to be configured explicitly in the project pom.xml in the project.reporting.plugins section.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <configuration>
          <links>
            <link>http://java.sun.com/j2se/1.5.0/docs/api/</link>
            <link>http://plexus.codehaus.org/ref/1.0-alpha-9/apidocs</link>
            <link>http://jakarta.apache.org/commons/dbcp/apidocs/</link>
            ... other third party libs used by your project ...
          </links>
        </configuration>
      </plugin>

If the Javadocs plugin has been configured, then mvn site will automatically generate the Javadocs. Otherwise, they can be generated separately using the command:

1
$ mvn javadoc:javadoc

Java Cross Reference (JXR)

Another cool plugin is the Code Cross Reference that is created using the JXR plugin. The project code is made displayable with line numbers and syntax highlighting, with links to related code. Almost like having an IDE running on the browser in read-only mode. Though not required for all projects, this is very useful to allow people to review your code without having to download it. To configure it, configure the plugin in the project.reporting.plugins section.

1
2
3
4
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jxr-plugin</artifactId>
      </plugin>

Like the Javadocs goal, this will be run as part of mvn site as well, but can be run separately using the command:

1
mvn jxr:jxr

Code Style (Checkstyle)

I chose Checkstyle because I am familiar with it, but I think Maven2 supports other code style checkers too. I use the default Maven code style, since this is likely to become the most popular code style as more and more people embrace Maven2, but this setting can be overriden to use Sun's code style or some other style preferred by your corporation. To configure it (with default Maven code style), we need the following configuration in project.reporting.plugins in the pom.xml file.

1
2
3
4
5
6
7
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-checkstyle-plugin</artifactId>
        <configuration>
          <configLocation>config/maven_checks.xml</configLocation>
        </configuration>
      </plugin>

As before, once configured, the report is run as part of the mvn site command, but can be run separately using the command:

1
$ mvn checkstyle:checkstyle

Unit Test Coverage (Cobertura)

Clover is the most popular tool for checking on Unit test coverage, and Maven2 provides a plugin for that. However, Clover is commercial software and costs money. A free, open-source alternative is Cobertura. Maven2 provides a Cobertura plugin as well. To configure this plugin, add the following XML to project.reporting.plugins section in the pom.xml.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>cobertura-maven-plugin</artifactId>
        <!--
        <executions>
          <execution>
            <id>clean</id>
            <phase>clean</phase>
            <goals>
              <goal>clean</goal>
            </goals>
          </execution>
        </executions>
        -->
      </plugin>

The plugin can be run manually using the command:

1
$ mvn cobertura:cobertura

The plugin leaves a cobertura.ser file in the project root directory, which can be removed using mvn clean. There was a suggestion to automate this by creating an executions subelement under the plugin declaration, but I could not get it to work - the parser complained about invalid tags, so I commented it out (in the above XML snippet). If anyone knows what I did wrong, please let me know.

Deploying files to other locations

I dont know much about this, except that it involves using the Maven2 Wagon Plugin. The plugin supports a wide variety of transport formats. I will post more information about this as I find it. If anyone has some information about using Wagon, would appreciate your posting it here or pointing to links with the information.

So thats basically all I have for now. Hopefully, this article will help kickstart Maven2 adoption in your new projects. Personally, I have used Ant for over 6 years now, and I was justifiably sceptical about switching new development to Maven2. However, I have had good success with Maven2 so far, and I am quite impressed with its range of capabilities in terms of integration with other tools and the services it provides to the developer.

Resources

  • The Maven 2 POM demystified - I have reorganized my template pom.xml according to this article, and it helps a lot in understanding the POM.
  • Get the most out of Maven2 site generation - lots of useful information about what elements to populate to produce good looking Maven2 project reports.
  • The Maven2 Schema - Its hard to figure out what element goes where without examples. The XSD is very detailed and provides good information.
  • Better Builds with Maven - if you haven't already downloaded this free e-book, you should. This is the only book I know of which talks about Maven2, so if you are working with Maven2, you should definitely download and read it.
  • Maven : A Developer's Notebook - covers details of the FML format used for generating FAQ entries.

3 comments (moderated to prevent spam):

Anonymous said...

A complete copy of the project object model file would be helpful. Also, I cannot seem to get any positive coverage results. Maven runs my unit tests (using TestNG) but Cobertura still reports zero coverage. Any suggestions?

Sujit Pal said...

I've got Cobertura reporting coverage results with JUnit, so I suspected that perhaps Cobertura could not grok the results that TestNG generated. Here is a blog post from Brett Porter (one of the main developers of Maven2) describing how to hook up Cobertura and TestNG:
http://blogs.codehaus.org/people/brett/archives/001334_test_ng_and_cobertura_in_maven_2.html

The article actually provides snippets of the POM that are relevant, so posting the full POM would not provide much more information. It may be helpful to check out the Maven2 Schema link at the end of the post for information about where to locate the snippets.

-sujit

Sujit Pal said...

Update: to create an Ant build.xml from your maven2 pom file, use: mvn ant:ant, creates a nice build.xml with some standard targets.