JaVa
   

Understanding Jelly

Jelly is an XML scripting language written by James Strachan and Bob McWhirter (who are also members of another scripting language project, Groovy, http://groovy.codehaus.org/), and Geir Magnusson (project lead on an excellent templating language project, Velocity, http://jakarta.apache.org/velocity). Jelly consists of a series of tag libraries similar to JSP tag libraries. The core tag libraries offer support for coding logic, including files, object creation, and script threading for spawning other Jelly scripts in a new thread.

Java Start Sidebar
Where to Get Jelly

If you want to try Jelly out for other projects, then you can download it as a stand-alone app here:

http://jakarta.apache.org/commons/jelly/

Java End Sidebar

The real joy of Jelly is when you get to the non-core tag libraries. Jelly provides a number of tag libraries that perform additional tasks. Some of these tag libraries are

There are many, many tag libraries, and to realize the full power of Jelly you should take a look at the core tags (http://jakarta.apache.org/commons/jelly/tags.html) and the optional tags (http://jakarta .apache.org/commons/jelly/libs/index.html). An additional tag library specifically written for Maven can be found here: http://maven.apache.org/tags.html. One of the primary reasons why Maven switched to Jelly was the ability to code logic into plug-ins (which Ant currently lacks) and the ability to reuse Ant tasks inside Jelly. This allows users to easily migrate their custom Ant files over to use Maven with a minimal amount of rewriting. So, how can we use Jelly in Maven? Well, the good news is, you already are. The POM file is actually a Jelly script; it's just hidden from your view. But if we want to add some custom Ant tasks into our Maven project, we need to create a maven.xml file and place it at the top level of our project, at the same level as our project.xml. Let's take a look at how to add an existing Ant task into our maven.xml file:

<project default="java:compile"
xmlns:j="jelly:core"
 xmlns:maven="jelly:maven"
 xmlns:deploy="deploy">
 <preGoal name="java:compile">
 <attainGoal name="plugin:goal"/>
 </preGoal>
 <taskdef 
 classname="com.company.AntTask">
 <classpath>
 <path refid="maven.dependency.classpath"/>
 <pathelement path="${maven.build.dest}"/>
 </classpath>
 </taskdef>
 <goal >
 <attainGoal name="plugin:goal"/>
 <attainGoal name="java:compile"/>
 <anttask
 var1="myvariable"
 var2="secondvar to pass to ant task">
 <fileset dir="${maven.build.dir}/classes">
 <include name="**/*.xml"/>
 </fileset>
 </anttask>
 </goal>
</project>


Let's walk through this a bit so you can get the feel for things. First we have the project element. This element allows us to define the default goal for this project. The goal attribute can be any valid goal you can execute on the command line. We have chosen java:compile as the default goal, which will build our class files. You will also see a number of XML namespace declarations here; these are required if you wish to use some of the optional Jelly tag libraries. The Ant tag library and Werkz tag library (which is specific to Maven) are the only two libraries that are registered with an empty namespace element. This allows us to more easily copy over custom Ant scripts and use them in Maven, without having to edit all the elements by hand and add in a namespace declaration. The second element you will notice is the preGoal element. This is part of the Werkz tag library and tells Maven to execute the body inside this element prior to the named goal. So, in our case we want a plugin:goal to execute prior to java:compile being executed. This gives us some incredible control over our build process—if we wanted to copy some files into a specific directory, or perform some file filtering on those files before execution, this is how we would do it. Next we find an Ant task declaration, and as you will notice, this is almost unchanged from a normal Ant task declaration. The only two differences are the variables that you want to pass into the classpath statement. In our case we are passing in two arguments: a reference to maven.dependency.classpath and the classes directory property. Now we get to the fun part! This is where we can define our own goals to execute. All we need here is a goal name. The only caveat is that this name must not conflict with any existing names, which shouldn't be a problem as long as you don't prefix your goals with an existing plug-in name, such as jar:, java:, or test:. We have named our goal myAntGoal, which allows us to type maven myAntGoal on the command line and have this custom goal be executed. Inside this goal we have two elements that define what goals we want to attain prior to executing anything else in our goal. The first one calls a fictitious plugin:goal, and the second calls the java:compile goal. Once these two goals have executed successfully, we want to run our custom Ant task we defined earlier. This is, again, almost identical to the way a custom Ant task would be called in Ant. Here we are calling our Ant task and passing in custom variables needed to run it, along with where we want our XML files to be placed once we have generated them.

That's about it when it comes to Jelly. You can, of course, use any number of additional tag libraries that come with Jelly to perform other tasks. To use it effectively, though, it is helpful to know what some of the Maven properties and references are.


JaVa
Comments