Friday, August 28, 2015

Maven, Groovy, Appassember...

Today I wanted to show you how to structure a Maven project so that the end result looks like Maven or Ant distribution. Let's start with the basics.

The problem

When you download Maven or Ant you'll notice that the structure has some very well defined folders. There is a bin folder holding a script that you execute, then there is a lib folder where you store all the jars and then there is some kind of configuration folder (conf, etc) that contains the configuration.

Achieving this kind of final project structure with Maven isn't all that hard but it is a combination of at least 2 plugins.

The solution

First of all you need to make sure you are able to package the application properly. I use for that both the appassembler plugin and the assembly plugin. The first one just brings together the necessary project artifacts, introduces platform-specific startup scripts and finishes the final project structure by copying the production configuration files to their proper location. In our case the final structure will look like this:


bin   <-- platform-dependent scripts that start your application are stored
conf  <-- production configuration files are stored
lib   <-- all the jars live here

Next we use the assembly plugin to package everything nicely into a zip file for distribution. It makes sure the unix/linux scripts have the executable bit set too :)

The second part is enabling Groovy language in the project. There are many ways to use Groovy with Maven but my favorite is the eclipse-groovy-compiler. What it does is it does an automatic joint compilation of both .groovy and .java files so you can interchangeably use Groovy from Java and Java from Groovy. I mean it! You see absolutely no difference there (besides the obviously cleaner Groovy code). You put all files into the obvious /src/main/java folder and that's it!

Since we already have Groovy on the classpath and the Groovy compiler processes all the sources wouldn't it be nice to use it in some tests? How about Spock? There is a catch: there are 2 types of tests you would normally write: unit tests/specs and integration tests/specs. To address both needs we'll use 2 Maven plugins: the standard maven-surefire-plugin for everything unit-related and the maven-failsafe-plugin for all them integration tests. Easy!

And last but not least: I like being able to execute the tool right from Maven's command line. To do that I use the exec-maven-plugin. It's very straightforward. You just define the main class, give it some id, done.

Summary

It may seem like a lot of work to set it all up and I certainly didn't do it all at once. But now that I have this in one place I am finding myself using it more and more often. And it just works! And it makes it dead easy to strip parts out to use it for other projects, for example web applications, integration-tests-only module - you name it!

You can explore a sample project that has all that configured on my GitHub page: https://github.com/padcom/groovy-example. It's all nicely documented to make it easier to follow and customize. All the Java and Groovy source code is obviously trash but is only there to illustrate the idea. You can make use of all the configuration like so:


mvn clean install exec:java

You'll see the unit tests/specs executed as part of the build, then appassembler will kick in and build the final structure, then assembler will package it all nicely into a zip file. Next the integration tests will be executed using the failsafe plugins and both artifacts (the jar and the zip) will be installed in your local maven cache (~/.m2/repository by default). Of course you can also find it all in the target folder where it is all initially built.

Enjoy!

No comments: