ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Extending Maven Through Plugins
Pages: 1, 2

Step 3. Extending the Plugin Through Java Classes

Now we have a helloworld plug-in that gives us a nice message, but what about adding the date and time to the message? Well, it would be nice if we could specify a property describing the date/time format to use, and get back the date formatted. Unfortunately there isn't a Jelly tag to do this, and maybe we don't want to use the Ant <tstamp/> task.

Fortunately it is very easy to write your own Java classes and integrate them in. First we need to update our POM to specify where our unit tests and Java code live:


We also add to the <dependencies> section of the POM a dependency on commons-logging from Jakarta:


By adding this dependency to our POM, Maven will download from www.ibiblio.org/maven the commons-logging-1.0.3.jar file. Thus, when you distribute the plugin to new users, all of the .jar dependencies defined for the plugin will be downloaded. This means that your plugin distributable can be very small!

Take a look at step3/src/main/example/helloworld/DateFormatter.java. Notice how we don't have to extend any classes or implement any interfaces? This makes it much easier to write portable code. And, of course, because we have Java code and a plugin is like any other Maven project, we can add to our <reports/> section of POM the reports for Javadocs, JUnit tests, JCoverage, etc.

Go ahead and test the code by entering:

c:\helloworld\step3\maven test

Assuming it all passes, you can also generate all of the site documentation into step3/target/docs by entering:

c:\helloworld\step3\maven site

Now that we have our DateFormatter properly working, let's start using it in our plugin.jelly script.

First, we have to import two more namespaces into our project tag:


The jelly:define imports the tag needed to define and interact with our DateFormatter class. The dateformatter specifies under which namespace our DateFormatter will load up.

<define:taglib uri="dateformatter">

As you can see, because we pass the method that will be the equivalent of the main method, we don't have to implement any interfaces. We could call the method to be executed doSomething if we wanted to. This provides a lot of flexibility in reusing existing code.

Now let's go ahead and actually format the date. There is a new variable helloworld.dateFormatPattern that has been defined in plugin.properties. This can be overridden in your project.properties just like the helloworld.message property. The dateformatter object will be bound to a variable called $df when we invoke it so we can later retrieve the formatted date:

<goal name="helloworld" description="Emit Hello World">

  <ant:echo message="${helloworld.message}
  on ${df.formattedDate}"/>

Go ahead and install the plugin and run it by entering:

  c:\helloworld\step3\maven plugin:install
  c:\helloworld\step3\maven helloworld

You should see some output similar to:

    [echo] Hello out there! on 03/07/04 10:07:35

Step 4. Integrating a "Hello World" Maven Report

One of the differentiators between Maven and other tools like Ant and Make is the integrated reports. Maven makes it easy to have reports generated by plugins that share a look and feel and are tied into the site navigation. Typical reports include the results of automated unit tests or generated Javadocs.

To register a new report, you need to define three new goals in your plug-in: helloworld-plugin:register, helloworld-plugin:deregister, and helloworld-plugin:report. These goals are called by Maven to register, unregister, and generate the report, respectively. Then, in the <reports/> section of the POM, you list the new report to be run:


Take a look at step4/plugin.jelly. We have added two more namespaces to support generating reports: xmlns:j="jelly:core" and xmlns:doc="doc".

Then we added the goal helloworld-plugin:report, which takes the "Hello World" message and saves it to a text file:

<goal name="helloworld-plugin:report"
    description="Emit Hello World to File">

  ${helloworld.message} on ${df.formattedDate}

<j:set var="genDocs"
  value="${maven.gen.docs}" />
    title="Hello World Report"
    section="Hello World Report"


Remember the prereqs tag? This specifies that we need to run these goals prior to running the helloworld-plugin:report goal. Also recall that the helloworld goal bound a DateFormatter object to the variable ${df}, which we can then use in all subsequent goals.

The rest consists of writing out a text file in step4/target/helloworld.txt with the text string and then reformatting it using the doc:text-xdoc tag to an XML file.

Go ahead and install the plug-in and then generate the site by entering:

  c:\helloworld\step4\maven plugin:install
  c:\helloworld\step4\maven site

This will generate, in step4/target/docs/, the site documentation that includes your "Hello World" report, which is shown in Figure 1:

Figure 1. Hello World Report
Figure 1. "Hello World" Report

Lastly, there are two basic documents in the /step4/xdocs directory: goals.xml and properties.xml. These are pretty standard documents used in plug-ins to describe what the available goals and properties are for your users, and are available under the Overview menu option in the generated docs.

Distributing Plug-ins

To distribute your plug-in, enter:

  c:\helloworld\step4\maven plugin

This will create a .jar file that has everything you need and will install it into your local Maven repository:

    [jar] Building jar: C:\clients\jn\html\

    [copy] Copying 1 file to C:\java\maven\
Total time: 3 seconds

If you distribute the plugin on a networked repository, then users can download the plugin via the plugin:download goal.

First, you define in your project.properties file where Maven should look for resources to download:


Then, from the command line, you can run plugin:download and Maven will attempt to download the plugin and install it from your local repository.

c:\helloworld\step4\maven plugin:download

In the above example, Maven will look for the plugin.jar file at:



As you can see, Maven's plugin architecture makes it very easy to write your own reusable functionality. The ability to directly use Ant tasks allows you to leverage all the existing Ant tasks in your Maven plugins. And because you can define any Java class as a tag, you can very easily integrate functionality that doesn't already have an Ant task.

Eric Pugh is a freelance consultant who specializes in mentoring groups using open source Java software successfully.

Return to ONJava.com.