Wednesday, November 30, 2005

Using Maven 2, Part 1

****************************************************************
Maven 2 Notes, Part 1
****************************************************************

----------------------------------------------------------------
Section 1: Getting Started
----------------------------------------------------------------

* Just download the binary and unpack. Put Maven 2's bin/ in your PATH.

* This following section is a quick review of the slightly longer intro here:

http://maven.apache.org/guides/getting-started/index.html

The Maven folks have done a good job with their introduction, so my guide below cherry-picks
the parts most relevant to me. I've also tried to supplement the official docs with some pithy observations.

* To create a new project, use the following example command. Both groupId and artifactId are required.

mvn archetype:create -DgroupId=xportlets.jobsubmit -DartifactId=jobsubmit-portlet

This will create the proper directory structure for your project:
1. The "archetype:create" goal will create a directory named after artifactId.
2. It will create a src directory like this: job-submit/src/main/xportlets/jobsubmit/
3. The tests will similarly go in src/test.

Maven 1 had issues with some directory structures matching source code packaging. It's not clear yet
if this is still true, but for now I will take the groupId to be the same as the package name, even
though this is not necessarily the case.

The "create" step unfortunately also populates your src/main and src/test directories with App.java and
AppTest.java, so you probably want to remove these.

* The pom.xml file is the maven2 equivalent of maven 1's project.xml. Fortunately, it looks very similar to the
old project.xml file format, except for a few changes:
1. Projects specify <packaging/>, which controls what happens when you use the "package" goal.
2. <dependencies/> can specify their scope: a jar needed only for testing has a scope <test/>.

* To compile your project, just use this:

mvn compile

This will put files in the usual target/ directory, as in Maven 1. Note this creates classes but does no packaging. To
create a packaged project, use

mvn package

This will first compile, then run any tests, then create a jar, war, etc, in target/. BUT what if you want to
the tests? We need this for OGCE builds, which use HttpUnit and so depend on deployment. Luckily the maven.test.skip
property is still around. Use this:

mvn package -Dmaven.test.skip=true


* To run tests by themselves, use "mvn test". If the classes have not yet been compiled, Maven will do this.

* Run "mvn clean" to clean up.

* One last note here: the various goals (compile, package, clean, etc) are all "lifecycle phases" in Maven 2. More
later.

----------------------------------------------------------------
Section 2: Making Web Applications
----------------------------------------------------------------
* Web application projects obviously have slightly different requirements for their directory structure, so to create
this, use the following convenience method.

mvn archetype:create -DgroupId=xportlets.jobsubmit -DartifactId=jobsubmit-portlet -DarchetypeArtifactId=maven-archetype-webapp

This will make the directories src/main/webapp/ and src/main/resources.

* The problem here is that it is not clear where the actual java code and java tests go. Presumably they can go under
src/main/java and src/tests as before. To test this simply, I created a dummy project (see first section) and copied
over the src/main/java and src/test directories.

This looks like it worked correctly: the resulting war file had all the classes in the right places.

* Next problems: I must specify that Jar A should be included in the WAR's WEB-INF/lib, while Jar B is needed for
compilation but not to be included in the WAR. Simple enough. See the disucssion on "scope" at

http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html.

I first used the "compile" scope--this means a) use the jar to compile, and b) include it in WEB-INF/lib. Beautiful. Your
POM dependency looks like this:

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<!-- Magic happens here -->
<scope>compile</scope>
</dependency>
</dependencies>


* Now if I use the jar to compile but do NOT want to include it in the WAR file, I do this:

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<!-- More magic -->
<scope>provided</scope>
</dependency>
</dependencies>

That is, the "provided" scope compiles with the jar but doens't include it. A quick look in the target/ directory confirms
this.

* But we need to write an archetype that will do all of this automatically.

----------------------------------------------------------------
Section 3: Integrating with Apache Ant
----------------------------------------------------------------
* Maven 2 no longer has that great, cheap maven.xml stuff that let you stick in all of your last-mile deployment stuff
with some ant. However, you can now embed Ant directly within your pom.xml file. The general overview is here:

http://maven.apache.org/guides/mini/guide-using-ant.html.

And the antrun plugin is here:

http://maven.apache.org/plugins/maven-antrun-plugin/

* Basically, the markup in your pom.xml looks something like the following. See the links above for full
exmaples.

<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>process-resources</phase>
<configuration>
<tasks>
<!-- Insert arbitrary Ant -->
<echo message="hollow world"/>
</tasks>
</configuration>
<!-- Run the ant target -->
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

There are two important parts: the configuration phase and the execution phase. Your ant scriplet goes in
in the config phase, in between the targets. You must also run your scriptlet using the "run" goal.

* The mysterious <goal>run</goal> just means that we call the "run" target of the associated maven-antrun-plugin.
See (again) http://maven.apache.org/plugins/maven-antrun-plugin/.


* This is typical of Maven 2 plugin behavior, BTW.

No comments: