Executing Ant tasks from Maven 2

One of the great things about Maven is that it does so much for you. Unfortunately, this also means that it must make a lot of assumptions (and a few restrictions) in order to do this well. One example is that of creating redistributables. Commons::Net is used mainly for FTP (probably about 90%+ of its users just use this functionality). Thus, I wanted to create a smaller FTP-client only jar alongside the main package. Unfortunately, I couldnt find a way to get Maven to do this. I guess I could have written a Mojo-based plugin that would allow me to specify and generate separate redistributables, but this seemed like a lot of work just for this task. The basic limitation comes from the module-centric way that Maven looks at projects and redistributable package, and in this case, I wasn’t satisfied that I could split the project up in a way that would suit both me and Maven’s requirements. Thankfully, there is an easier way: just use the Maven AntRun plugin:


<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<configuration>
<tasks>
<jar destfile="target/commons-net-ftp-${version}.jar">
<fileset dir="target/classes"
includes="org/apache/commons/net/ftp/**,
org/apache/commons/net/*,
org/apache/commons/net/io/*,org/apache/commons/net/util/*"/>
<fileset dir="${basedir}" includes="LICENSE.txt"/>
<manifest>
<attribute name="Implementation-Vendor" value="Apache Software Foundation"/>
</manifest>
</jar>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

As you can see from the section marked in bold, you have access to the properties exposed by the POM. You just need to hook the task into a specific phase in the lifecycle (I have hooked it into the “package” phase). Of course, if your task is not going to be trivial, you can always encapsulate it in a separate build file and invoke it using Ant’s ant taskdef.

Commons::Net Update

I have just started working on a new branch of Commons::Net which will be a Tiger (Java 5.0) based implementation. This will not require huge changes, but will clear the decks for some of the following features:

  • Removal of all extra dependencies (currently Jakarta ORO is the regular expression implementation used in Commons::Net. It has done and still does a fine job, and the JDK has only matched its functionality in release 5.0. However, the less extra dependencies, the better).
  • JCE-based secure cipher and channel implementations without having to include the extra JSSE jar.
  • A cleanup of some of the more gnarly threading and I/O code. Some of the concurrency classes may come in useful here. I was originally thinking that NIO may be a good option to look at here, however now, I am less convinced. I think the extra complexity may be too much for the potential gains, which would be small, if any. I believe that NIO is a great candidate for a certain class of server applications that may from time to time require a large amount of resources and the ability to handle severe load gracefully. A good case in point would be an application like Azureus (and they do indeed use NIO heavily). For a small synchronous-I/O client-side library like Commons::Net, it would probably just complicate the code with no real performance gains.
  • Some nice syntactic sugar like generics/compile-time type checking and enhanced for/iterator loops.
  • Miscellaneous items, such as this code which FindBugs located for me:


    public DatagramPacket getDatagramPacket()
    {
    if (dp == null)
    synchronized(this) {
    if (dp == null) {
    dp = new DatagramPacket(buf, buf.length);
    dp.setPort(NTP_PORT);
    }
    }
    return dp;
    }

    Previous to JDK 5, this double-checked lock idiom would not be guaranteed to work. However, by marking the dp variable as volatile, the new Java memory model will enforce the correctness of this block of code.

I have also migrated the existing Maven 1 build setup to a Maven 2-based project. Apart from some minor annoyances (like the alpha-state Plexus plugins not being available where they should be), it was quick and easy to get going. I have always liked Maven, and Maven 2 looks like good improvement. It’s under quite heavy development at the moment (as the Apache SVN logs show), but at least the documentation for version 2 is a big improvement over version 1. In particular, the JIRA changelog report is very neat. I haven’t scratched the surface yet of what Maven 2 is capable of, but I’m hoping to have a good look at it over the next month or so.