Monday, February 26, 2007

From maven to mvn : Part 1 -- Building a war

I've been a huge fan of maven since the 0.4 days when it was a pile of reusable ant scripts. I encourage any and all Java developers I come across to convert their projects and use it. However, I'm not going to try to convince you here that you need to use maven. If you do then you're already on the path. If you don't then, well, there are other sites that will attempt to convince you. What I intend to do here is describe my journey from maven 1.0.4 to maven 2.0.4.

For a long time now (and I say "long time" because I really have no sense of time) I've been using a modified version of maven 1.0.4. Modified in the sense that I've tweaked a few of the built-in plug-ins, added my own plug-ins and also written a fair amount of value-add in maven.xml. I also want to point out that we use this as the core build framework where I work. Prior to 1.0.4 we used, of course, 1.0.3 and prior to that was some other 1.x. In other words, we've been using some version of maven for a Very Long Time.

I've been following the maven 2 (henceforth simply "m2") effort since its inception. They fine folks there have made some huge improvements. IMO m2 is so very different from m1 (maven 1.x that is) that it is very nearly should have been called something other than "maven". That may be a bit extreme but I simply want to point out that migrating from maven 1.x to 2.x is not a drop-in scenario.

For quite some time now (where "quite some time" is something less than "long time") I've been pondering conversion to m2. I've had a few false starts where a plug-in I needed wasn't there. I've also had a pretty busy schedule such that I just couldn't dedicate the time to learn m2 well enough to give it a fair shot. Fortunately, some other folks I work with have had a bit of time and have begun their own effort to move to m2.

So, with that being said, this series will track my efforts to convert a very simple web application ("Contacts") from m1 to m2. While simple, the project does have some requirements that do not fit m2's out of the box behavior. My theory is that if I can build this application I can probably then convert our core m1-based build framework to m2.

In this episode my goals are:
- compile the classes and aspects
- build a war (not necessarily deployable)
- test cases should execute and pass
- @foo@ replacement is not necessary

Step 1

Build, test and deploy Contacts using the current m1-based build system. I want to be sure that what I think is working is actually working.

Step 2

The application has several components (sub-projects in maven-speak). For this bit I will focus only on the war. Therefore, copy Contacts/view to Contacts-m2/view. Subsequently clean up Contacts-m2/view to get rid of m1 artifacts (maven.xml, etc.)

mkdir -p Contacts-m2/view/
cp --recursive Contacts/view/* Contacts-m2/view/
cd Contacts-m2 ; rm -f maven.* project.*

Step 3

The project layout has changed. Therefore we have to do some simple relocation:

mkdir src/main
mv src/java src/main/java
mv src/aj src/main/aspect
mv src/webapp src/main/webapp
mv src/test src/test-tmp
mkdir src/test
mv src/test-tmp/src/test/java

Step 4

Now we need to have some m2 artifacts so that m2 knows what to do with all of these things. Specifically, we need a pom.xml that describes our project and how to build it.

The easiest way to bootstrap this is to use m2's archetype system:

mvn archetype:create -DartifactId=my-app

Step 5

Well, Step 4 didn't go so well because we're behind a corporate firewall. To deal with this we need to tell m2 how to deal with the proxy. So now we have a ~/.m2/settings.xml file. We may have to come back to this later but we're good for now.

Try the archetype again... all good. It will take a while since m2 needs to pull dependencies for its plug-ins.

Step 6

Now that we have the archetype we will take its pom.xml and throw everything else away.

mv my-app/pom.xml .
rm-rf my-app

The changes to pom.xml will eventually be significant. For now, we just need to change the groupId, artifactId, name and packaging tags. The first three are whatever you need for your application. packaging will be war since we're building one of those.

Note that we could have used the webapp archetype. I really wanted to start with the basics, though, so I went with jar.

Step 6

Now lets build it and see what happens! It's magic, right? Everything should Just Work?

Start with mvn clean just to make sure we didn't flub the pom.xml. There's nothing to clean, of course, but it gives us a good feeling because it cannot possibly fail!

Next try mvn install to build, test and package the application. Ah well... success was short-lived. My application uses Java 5 stuff, AspectJ and a pile of dependencies. With the default pom.xml this build isn't going to complete.


Thus concludes Part 1. I didn't complete all of my goals but i did make some significant progress.

Actual execution took place over a four-hour period during which I was also dealing with my inbox and the inevitable hourly "emergencies" of software development. During the that window of time I probably spent between 90 and 120 minutes doing the things documented above. (The actual documentation -- four days later -- took about 45 minutes.)

I'm off to lunch now. When I get back I'll proof-read this post and document Part 2 where I sort out the build failures in Step 6.

No comments: