Java Development with Ant: XDoclet

XDoclet is the real workhorse of this project.  It is used to generate the following artifacts:

XDoclet and EJB

XDoclet was originally made for EJB development, in fact its original name was EJBDoclet.  Its no surprise that XDoclet works wonders for EJB projects.  This project has minimal EJB usage (which is actually not even required), but still exploits a very common usage scenario.  A stateless session bean is written to be the interface to the searching code.   SearchSessionBean is tagged with the appropriate XDoclet @tags and each of the XDoclet subtasks used in <ejbdoclet> use this information to affect the output.  The ejbdoclet target in the main build file consists of this:
<ejbdoclet destdir="${build.dir}/ejb/gen"
addedtags="@xdoclet-generated at ${TODAY}"
ejbspec="1.1"
force="${xdoclet.force}"
 mergedir="metadata/ejb">
<fileset dir="src/ejb"/>

<remoteinterface/>
<homeinterface/>
<utilobject/>
<jboss validatexml="true" destdir="${build.dir}/${site}"/>
 <deploymentdescriptor validatexml="true"/>
</ejbdoclet>

Because the JNDI lookups are site-specific, the jboss.xml deployment descriptor is generated to a site-specific output directory, where the rest of the artifacts go to a common location for all sites. On a related note, the JNDI lookups are generated in a site-specific manner, using a jndi-name attribute on the @ejb.bean tag on SearchSessionBean in this manner:
/**
* @ejb.bean type="Stateless"
* jndi-name="${site}/org.example.antbook.session.SearchSession"
* @ejb.util generate="physical"
*/
public class SearchSessionBean implements SessionBean {
// ...
}
The interesting note here is that XDoclet expands Ant properties when the tags are processed, allowing for some interesting configuration possibilities.

Merge points

Not all information can or should be placed in XDoclet @tags.  Enter merge points.  The templates used by XDoclet often refer to external user-provided files to merge in extra information, such as defining third-party servlets (e.g. Struts ActionServlet).  The merge point files are typically documented in the output.  For example, look in a generated web.xml file to see XML comments stating how to inject your own pieces into the results.  This project has several merge files, all in the metadata/web directory.

Web tier generation

The webdoclet target contains the following usage of the <webdoclet> task:
<webdoclet destdir="${build.dir}/web/WEB-INF"
force="${xdoclet.force}"
mergedir="metadata/web">
<fileset dir="src/web"/>
<configParam name="cactusOn" value="${enable.cactus}"/>
<deploymentdescriptor validatexml="true"
destdir="${build.dir}/${site}"
distributable="false"
/>
<jsptaglib validatexml="true"
shortName="antbook"
filename="antbook.tld"
/>
<strutsconfigxml validatexml="true" version="1.1"/>
<strutsvalidationxml omitdtd="true"/>
</webdoclet>
Of note here:

The configuration parameter cactusOn is passed into the templates, and is used by two custom merge points in <deploymentdescriptor>.  The merge files are processed just as any other XDoclet template, allowing template tags to be used. Both servlets.xml and servlet-mappings.xml (found in metadata/web) have tags surrounding the definition and mapping of the Cactus redirector servlet:
<XDtConfig:ifConfigParamEquals paramName="cactusOn" value="true">
.
.
.
</XDtConfig:ifConfigParamEquals>
Using configuration parameters allows for flexible control in the generation results.  For example, this feature can be used to control a web application's authentication mechanism such that it can be easily switched from BASIC to FORM authentication.

Tag Library Descriptor (TLD) generation

XDoclet makes it easier to develop custom tag libraries by automating the generation of the TLD file.  The <jsptaglib> subtask is used.  The source code consists of a couple of custom tags.  LabelTag is marked like this:
/**
* @jsp.tag name="label" bodycontent="empty"
*/
public class LabelTag extends TagSupport {
.
.
.
/**
* @jsp.attribute required="true"
*/
public void setKey(String key) {
this.key = key;
}

}

web.xml generation

Likewise, XDoclet processes servlet and filter source code in this project to generate the associated definitions and mappings in web.xml.  An example is the TimingFilter code:
/**
* Logs duration of each request.
*
* @web:filter name="TimingFilter"
* @web:filter-mapping url-pattern="/*" servlet-name="TimingFilter"
*/
public class TimingFilter implements Filter {
.
.
.
}

Starter Struts generation

Other details of the strutsgen tool are found on the Struts page.  Using two custom XDoclet templates, a custom written tag handler, and the <template> template subtask, the strutsgen tool saves a great deal of time by generating a JSP and the corresponding ApplicationResource.properties pieces for a form bean.  Field labels are generated automatically in an elegant manner.  For example, a form bean property called lastName (corresponding to setLastName method) will have the label "Last Name" generated (capitalization and word separation is done by the custom tag handler FormTagsHandler).  The strutsgen project build file contains a "gen" target which uses the <template> subtasks:
<xdoclet destdir="${build.dir}"
excludedtags="@version,@author"
force="${xdoclet.force}">
<fileset dir="${struts.src.dir}"
includes="**/${form.name}.java"
/>
<template templateFile="src/FormKeys.xdt"
ofType="org.apache.struts.validator.ValidatorForm"
acceptAbstractClasses="false"
prefixWithPackageStructure="false"
destinationFile="{0}.properties"
/>
<template templateFile="src/StrutsForm_jsp.xdt"
ofType="org.apache.struts.validator.ValidatorForm"
acceptAbstractClasses="false"
prefixWithPackageStructure="false"
destinationFile="{0}.jsp"
/>
</xdoclet>
Its simpler than it looks.  Only non-abstract subclasses of the the Struts ValidatorForm are processed (change this to ActionForm if you are not using Validator).  The output is generated at the top level of the ${build.dir} (prefixWithPackageStructure="false" indicates to ignore the package hierarchy of the classes processes, otherwise the output would be in package structure layout).

To-Do List

Its common-place for developers to tag code with comments like "//FIXME" or "/* TODO */" and then use a text search tool to find places that need to be revisited.  XDoclet provides a standard way to to this and have Javadoc-like HTML reports generated.  Simply mark classes, methods, or member variables with a Javadoc comment like:
/**
* @todo Revisit this code
*/
In order to generate the to-do list from this project, run the "todo" Ant target from the main build file.  The results will be placed in ${build.dir}/todo (typically that is build/todo).