7.3 Custom Tag Libraries
7.3.1 Simple Tag Files
The first step in creating a custom tag is to the generation of the business logic for the tag. It is accomplished by creating a .tag file which contains all of the coding associated with the tag. A .tag file is nothing more than a JSP fragment. Since it is JSP based, it has all of the properties available to a JSP page. This includes the implicit objects. The only thing that differentiates it from a JSP page is that it must be marked with a JSP tag directive at the top of the page.
Once the tag is coded, the tag stub must be made available to the web application. This is done by sticking the stub into the war files’s WEB-INF/tag directory. At deployment time, the application server will sift through the war file and find all of the custom tags. All that remains to do is to invoke the custom tag from within other JSP pages.
Directives
There are two directives that are specifically assigned to the creation of tags. The tag directive informs the container that the fragment is a custom tag. The body-content attribute of the directive is used to tell the container which type of tag it is. A value of “empty” tells the container that the tag is body-less. If the tag is a complex tag with a body then the value of “scriptless” is used.
<%@ tag body-content="empty" %>
<%@ tag body-content="scriptless" %>
It is important to note that the tag directive must be the first line within the tag fragment.
The second directive reserved for tags is the attribute directive. It defines the attributes that can be associated with a tag. In the example previously, the multiply tag had two attributes associated with it. They were the values of x and y. For these attributes to be available to the tag they must be defined within the tag fragment using the attribute directive.
Attributes must define three properties. First and foremost they must have a name to associate to the tag. This is the name of the tag’s attribute. The attribute must also have a data type associated with it. This value can be either a String or any of the primitive wrapper classes. Lastly, a required value is used to determine if the tag’s attribute is a required attribute or not. This value can be either
“true” or “false”. Below are some example of defining tag attributes.
<%@ attribute name="firstName" required="true" type="java.lang.String" %>
<%@ attribute name="age" required="true" type="java.lang.Integer" %>
<%@ attribute name="weight" required="false" type="java.lang.Double" %>
The initial attribute, firstName, is a required attribute whose value will be a String. The second attribute, age, is also required and the value must be an integer. The final attribute, weight, is not required but if it is it must be a double value.
The fragment below brings the two directives together into a cohesive example.
<%@ tag body-content="empty" %>
<%@ attribute name="firstName" required="true" type="java.lang.String" %>
<%@ attribute name="age" required="true" type="java.lang.Integer" %>
<%@ attribute name="weight" required="false" type="java.lang.Double" %>
If this fragment is placed within a person.tag file, then the following examples would be valid invocations of the tag file. Notice how the attributes defined above translate into the invocation of the tag.
<tag:person firstName="Beth" age="23"/>
<tag:person firstName="John" age="24" weight="172.4"/>
The next set of tag invocations will fail. Why?
<tag:person firstName="Beth" weight="101.4"/>
<tag:person age="24" weight="172.4"/>
<tag:person firstName="Beth"/>
The first and third examples would fail because the required field age was not supplied. The second would fail because the required field firstName was not defined as an attribute of the tag.
One final note before moving on to tag creation is the additional attribute rtexprvalue. rtexprvalue determines whether or not a attribute can include a run time expression. By default attributes allow rtexprvalue. That means that a JSP expression scriptlet can be used for the assignment of an attribute.
Below is an example of using a JSP expression scriptlet when defining an attribute for a custom tag.
<tag:person firstName="<%= session.getAttribute("name") %>"/>
Creating The Tag’s Business Logic
Once the tag is defined, it is time to embed the tag logic. A tag can contain almost any element which can be found in a normal JSP page. It can use the taglib directive, page directive, and any of the implicit variables defined by JSP.
Below is a solution of the multiply tag used in previous examples.
<%@ tag body-content="empty" %>
<%@ attribute name="x" required="true" type="java.lang.Integer" %>
<%@ attribute name="y" required="true" type="java.lang.Integer" %>
${x * y}
In this case the tag is being defined along with two attributes, x and y. The values from the attributes are multiplied in the EL statement on the last line to show the results of the operation.
While the simple example is effective, it is not very illustrative of what can be done within a tag.
Let’s embellish the example a bit and add a third variable which is optional. In addition, the example will get the user information from the session object and display it along with the results.
<%@ tag body-content="empty" %>
<%@ attribute name="x" required="true" type="java.lang.Integer" %>
<%@ attribute name="y" required="true" type="java.lang.Integer" %>
<%@ attribute name="z" required="false" type="java.lang.Integer" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="results" value="${x * y}"/>
<c:if test="${!empty z}">
<c:set var="results" value="${results * z}"/>
</c:if>
<%
String name = (String)session.getAttribute("userName");
out.print(name + ", the answer to the problem ");
%>
${x} * ${y}
<c:if test="${!empty z}">
to display the user’s name. This was done to provide an example of using scriptlets and implicit variables within the tag. In the real world the JSP scriptlet would have been replaced with an EL expression shown below.
${userName}, the answer to the problem
Once the userName is outputted, a test is done to see if the z attribute was supplied. If z is defined then the display of the formula and results will include the value of z.
Adding Tag Files To WAR With Ant
Now that the simple tag fragment has been coded, how does a developer add the tag into the WAR file generated at compile time? The task can be accomplished through a simple modification to the ANT build.xml file.
The .tag file needs to be added to the WEB-INF/tags directory within the war file. The zipfileset tag that was used to put all of the JSP, HTML, and other resources into the root of the war file can be used to accomplish the task of putting the tag fragments within a tag directory within the WEB-INF.
Below is a modified version the ANT file to include tags.
<war destfile="${dist}/course.war" webxml="${conf.web}/web.xml">
<classes dir="${build}"/>
<lib dir="${web.lib}"/>
<zipfileset dir="${web.jsp}"/>
<zipfileset dir="${web.tags}" prefix="WEB-INF/tags/"/>
</war>
The line below is what was added to the build.xml file for the inclusion of tags.
<zipfileset dir="${web.tags}" prefix="WEB-INF/tags/"/>
The zipfileset task takes all of the tags that reside within the web.tags directory and zip them into a single directory. The prefix attribute is defines what directory within the WAR file in which they will be placed. In this case they are included in the WEB-INF/tags directory.
Invoking Tag Files
The next step after adding the tag files to the WAR file is to import them into JSP pages. The steps for using custom tag libraries are the same for using JSTL. All a developer needs is the proper taglib directive and the custom tag will be available. Below is an example of importing a tag library.
<%@ taglib prefix="bs" tagdir="/WEB/INF/tags" %>
The directive does two things. It points to the WEB-INF/tags directory to look for the appropriate tag information. Secondly, It uses the XML prefix “bs” to provide a unique namespace for tag calls.
It associates the namespace with the set of custom libraries. The name of the tag to invoke must match the name defined in the JSP tag fragment. Below is an example of invoking the multiply tag defined earlier.
<%@ taglib prefix="bs" tagdir="/WEB/INF/tags" %>
<html>
<body>
<h2>Multiply Numbers</h2>
<p>
5 * 4 = <bs:multiply x="5" y="4"/><br/>
8 * 7 = <bs:multiply x="8" y="7"/>
</p>