JaVa
   

Creating XDoclet Custom Tags and Templates

As we’ve discussed throughout the tutorial, XDoclet is a code generated engine that extends the concept of a Javadoc tag to other technologies. We can use XDoclet to produce code, text, HTML or just about any other type of output. There are a few different ways this works. First we have the tags which will be added to the source code to be parsed. It you visit xdoclet.sf.net, you will find all of the tags available. The differences in the tags are usually found in the @ part. For example, we have @jsp, @servlet, @struts as well as others. Of course, the tags won’t really do anything until the Ant task is put into play. The various tasks and subtasks added in a build script will trigger a parsing of the source code and the individual tags pulled out. When a tag is found, a resulting template is pulled into the source code and the provided attributes replaced. In this chapter, we want to explore this process a little more and determine how to make our own tags and templates.

XDoclet Architecture

Before we start looking at a template, let’s discuss the XDoclet architecture for a moment. XDoclet can be broken down into three primary components:

In the very beginning of the XDoclet project, a high level of reuse was acheived by relying on the Javadoc to parse the Java source file and generate a tree of classes, language constructs and other metadate. As XDoclet began to become more popular, a need to have a much faster engine developed and the XJavaDoc engine is the result. The new engine does the same work as the Javadoc engine just faster and with a clean API. Once the files have been parsed and "treed," the XDoclet engine reads tags from the metadata and the tree structure itself. The tags are matched with templates to generate code and other output as required by the template and context of the tags. All of the templating is accomplished in the XDoclet engine. Associated with XDoclet is the module which is dynamically loaded by the system. Modules are comprised of tasks, subtasks, tag handlers and template. A module is basically defined by its task. For example, we have the task webdoclet. Of course not much happens with just the task. We need to specify a sub-task like deploymentdescriptor. The sub-tasks job is to define the templates to be used when tags are encountered relating to the sub-task. The templates are really the key to XDoclet. With the sub-tasks and tags, a template will be pulled within play and facilitate the output of specific text whether code or HTML. Fundamentally, all tags in XDoclet are custom tags in the same vein as JSP custom tags. The XDoclet engine has the responsibility to trigger specific tag handlers depending on the tag encountered in the source code. Reflection is used to invoke the handler. So our template tag XDtProperty:forAllClasses will require a method called forAllClasses. A full mapping of tags is accomplished in the xdoclet.xml file found with the XDoclet distribution. The following listing shows an example of the core Ant Tasks.

<xdoclet-module>
 <taghandler namespace="Class" class="xdoclet.tagshandler.ClassTagsHandler"/>
 <taghandler namespace="Comment" class="xdoclet.tagshandler.CommentTagsHandler"/>
 <taghandler namespace="Config" class="xdoclet.tagshandler.ConfigTagsHandler"/>
 <taghandler namespace="Constructor" class="xdoclet.tagshandler.ConstructorTagsHandler"/>
 <taghandler namespace="Field" class="xdoclet.tagshandler.FieldTagsHandler"/>
 <taghandler namespace="Id" class="xdoclet.tagshandler.IdTagsHandler"/>
 <taghandler namespace="Merge" class="xdoclet.tagshandler.MergeTagsHandler"/>
 <taghandler namespace="Method" class="xdoclet.tagshandler.MethodTagsHandler"/>
 <taghandler namespace="Package" class="xdoclet.tagshandler.PackageTagsHandler"/>
 <taghandler namespace="Parameter" class="xdoclet.tagshandler.ParameterTagsHandler"/>
 <taghandler namespace="Property" class="xdoclet.tagshandler.PropertyTagsHandler"/>
 <taghandler namespace="TagDef" class="xdoclet.tagshandler.TagDefTagsHandler"/>
 <taghandler namespace="I18n" class="xdoclet.tagshandler.TranslatorTagsHandler"/>
 <taghandler namespace="Type" class="xdoclet.tagshandler.TypeTagsHandler"/>
 <taghandler namespace="Xml" class="xdoclet.tagshandler.XmlTagsHandler"/>
</xdoclet-module>


In order to determine which of the handlers to use, the XDoclet engine will strip off the XDt string from the tag to obtain the namespace of the handler—in our tags so far, the result would be Property. As a result the class for the XDoclet engine to use is xdoclet.tagshandler.PropertyTagsHandler. The next listing shows a part of the PropertyTagsHandler handler.

public class PropertyTagsHandler extends AbstractProgramElementTagsHandler {
...
public void forAllPropertiesWithTag(String template, Properties attributes)
throws XDocletException
{
...
String requiredTag = attributes.getProperty("tagName");
if (requiredTag == null) {
throw new XDocletException("missing required tag parameter in forAllPropertiesHavingTag");
}
XClass oldClass = getCurrentClass();
XClass superclass = null;
Collection already = new ArrayList();
// loop over superclasses do {
XMethod oldCurrentMethod = getCurrentMethod();
Collection methods = getCurrentClass().getMethods();
for (Iterator j = methods.iterator(); j.hasNext(); ) {
XMethod currentMethod = (XMethod) j.next();
log.debug("looking at method " + currentMethod.getName());
if (currentMethod.getDoc().hasTag(requiredTag)) {
setCurrentMethod(currentMethod);
String propertyName = currentMethod.getPropertyName();
log.debug("property identified " + propertyName);
if (!already.contains(propertyName)) {
generate(template);
already.add(propertyName);
 }
 }
setCurrentMethod(oldCurrentMethod);
}
// Add super class info superclass = getCurrentClass().getSuperclass();
if (superclass != null) {
 pushCurrentClass(superclass);
}
} while (superclass != null);
setCurrentClass(oldClass);
}
...


Just look at the snippet of code, you can see where the handler obtains the name of the current tag and starts looping over the classes.


JaVa
   
Comments