Advanced Customization > Info*Engine User’s Guide > Custom Tag Libraries > Java-Based Tag Library Implementation
  
Java-Based Tag Library Implementation
In some cases, writing a Java-based tag library is more appropriate. For example, if you need to integrate with other Java-based APIs that are currently unavailable through Info*Engine, and as a result would require scriptlet code to be embedded within your tasks (or task-based tags). When writing a Java-based tag library implementation, there is a set of interfaces and support base classes that you can implement, and which can then be reused as tags within Info*Engine tasks. Refer to the com.infoengine.task.tagext package within the Javadoc released with your installation (/codebase/infoengine/docs/apidocs) to understand the classes and interfaces.
In this case, tags are simple event-driven Java classes, that you can group together into libraries of tags. You can do this using a simple XML document referred to as a Tag Library Descriptor (TLD) that defines the library and what tags it supports, what attributes each tag supports, and information about the tags and their attributes. A TLD consists of a root taglib node, an optional description node, and an arbitrary number of child tag nodes. Each tag node defines a tag within your tag library and associates that tag with its implementation class. The tag node must contain the name and tagclass child nodes (specifying the tag name and tag implementation class, respectively), and can optionally contain a description node and several attribute nodes.
If added, any attribute nodes specify the attributes a tag supports, whether or not an attribute is required, and if its values can be an expression. For these purposes an attribute node must have name, required, and rtexprvalue child nodes to supply this information. A fragment of a TLD file might look like the following:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
<description>My taglibrary.</description>
<tag>
<name>myTag</name>
<description>what this taglibrary does</description>
<tagclass>org.myorg.tags.MyTag</tagclass>
<attribute>
<name>myAttribute<name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
...
</taglib>
In this case, the tag library contains a tag named “myTag,” which is implemented by the “org.myorg.tags.MyTag” class. The tag requires a single attribute, named “myAttribute,” which can be an expression. To include your tags within an Info*Engine task requires that you specify an @taglib directive in your task that defines a prefix for use with your tags within the task, and also specifies the location of your TLD file (located in the Info*Engine task root). For example, this tag could be used within an Info*Engine task as follows:
<%@taglib uri=”/org/myorg/myTags.tld” uri=”pfx”%>
...
<pfx:myTag myAttribute=”${@FORM[]myAttributeValue[]}” />
Tag attributes are supplied to your tag using standard Java bean-like set accessor methods. When loading a tag library, Info*Engine verifies all of these implementation details. An error is produced if your tag cannot be properly loaded because of an implementation detail, such as a missing setter for a supported attribute. In the example above, the tag might have a setter method as follows:
public void setMyAttribute ( String value )
{
// perhaps set an instance variable or other work
// related to the attribute value specified in the value
// parameter.
}
Tag attributes can have arbitrary data types, and at runtime values are validated or coerced, if necessary. The supported data types of parameter values are:
String
int
boolean
float
com.infoengine.object.factory.Group
Object
Coercion is only supported to the primitive types String, int, boolean, and float. Because Object is included, you can use attributes of any possible type, however in this case your setter method must supply any required type validation or coercion of the attribute value.
Individual tags (implementations of “com.infoengine.task.tagext.Tag”) can be simple, or they can contain child elements (implementations of “com.infoengine.task.tagext.BodyTag”). Instances of BodyTag can also support iteration. A Tag or BodyTag also have the option to implement TryCatchFinally as a means to handle exceptions.
Typically a tag extends either the TagSupport or BodyTagSupport base classes and completes the implementation to add attribute setters and functionality in the necessary do*Tag methods.
In addition, tags can be designed to implicitly set variables within tasks for reuse from scriplet code or from expression language. A tag can support this by implementing the following method defined on “com.infoengine.task.tagext.Tag”:
Tag.VariableInfo[] getVariableInfo ( Map<String,String>atts );
This method is only called at task compilation time to decide whether or not implicit variables need to be defined in the compiled task source. See the Javadoc for a complete description of the getVariableInfo method and how to use this functionality.
At runtime, tags are pooled to avoid performance issues related to constructing large numbers of short-lived objects, which may require excess garbage collection. Therefore, you must be careful that your tag uses optional attributes and stores attribute values in instance variables. You should then implement the doEndTag method and reinitialize instance variables within a finally block. If this is not done, subsequent usages of your tag may not perform as predicted if it carries instance variable values from previous uses.