Skip to main content

Easy Custom Tags with Tag Files, Part 1

November 14, 2003

{cs.r.title}






Two new features in JSP 2.0 deal with custom tag libraries. The first is the new
javax.servlet.jsp.tagext.SimpleTag interface, which simplifies the life-cycle of a tag handler. The second feature simplifies the whole process of writing tag extensions entirely. The
latter is a radical change, I would say. For the first time, you don't need a tag library
descriptor for your custom tags. Nor do you have to compile your tag handlers. Now, even
those who don't understand Java can write custom tags. This article discusses tag
files in detail. The first part of this article introduces tag files and presents a few
examples. Part two will deal with the more advanced aspects of tag files and will
discuss the packaging of tag handlers based on tag files. The sample application that is
covered in this article can be downloaded here. To run the application,
you need a JSP-2.0-compliant JSP container, such as Tomcat 5. You need to be familiar with JSP and tag extensions to understand this article well.

Tag extensions are great. They allow you to write completely script-free JSP pages, thus
promoting the separation of labor: page authors and Java programmers can work
simultaneously, on the tasks that best suit them. However, writing custom tags is a tedious chore,
involving writing and compiling a tag handler and defining a tag in the tag library
descriptor. JSP 2.0 adds the javax.servlet.jsp.tagext.SimpleTag interface, which you can
use to write simple tag handlers. However, SimpleTag does not make the whole process
simpler.

Introduction to Tag Files

Writing a traditional custom tag requires two steps:

  1. Writing and compiling a tag handler.
  2. Defining the tag that is associated with the tag handler.

Tag files simplify the process. First, tag files don't need to be compiled. They are
compiled as they are invoked. Also, tag files allow tag extensions to be written using only
JSP syntax. This means someone who does not know Java can also write tag
extensions!

Secondly, a tag element in a tag library descriptor describes the name to be used in a
JSP page to reference the custom action. Using tag files, the name of a custom action is
the same as the tag file representing the action. Therefore, you don't need a tag library
descriptor at all.

Note: JSP containers may choose to compile tag files into Java tag handlers, or interpret
the tag files. For example, Tomcat 5 translates tag files into simple tag handlers whose
classes implement the javax.servlet.jsp.tagext.SimpleTag interface.

A tag file looks like a JSP page. It can have directives, scripts, EL expressions, and
standard and custom tags. A tag file has the .tag or .tagx
extension and can also include
other files that contain a common resource. An include file for a tag file has a
.tagf extension.

To work, tag files must be placed in the WEB-INF/tags directory under your application directory or a subdirectory under it. Just like tag handlers, tag files can also be packaged.

A number of implicit objects are available from inside of a tag file. You can access these
objects from a script or an EL expression. Table 1 lists all of the implicit objects available in
a tag file.

Table 1. The implicit objects

Object Type
request javax.servlet.http.HttpServletRequest
response javax.servlet.http.HttpServletResponse
out javax.servlet.jsp.JspWriter
session javax.servlet.http.HttpSession
application javax.servlet.ServletContext
config javax.servlet.ServletConfig
jspContext javax.servlet.jsp.JspContext

Note that these implicit objects are similar to those available in a JSP page.

Your First Tag File

This section shows how easy it is to write a tag file and use it. The example consists of
one tag file and one JSP page that uses the tag file. The directory structure of the
application is depicted in Figure 1.

Figure 1

Figure 1. The directory structure

The tag file is called firstTag.tag and looks like this:

<%@ tag import="java.util.Date" 
  import="java.text.DateFormat"%>
<%
  DateFormat dateFormat =
    DateFormat.getDateInstance(DateFormat.LONG);
  Date now = new Date(System.currentTimeMillis());
  out.println(dateFormat.format(now));
%>

As you can see in the above listing, a tag file looks similar to a JSP page. The firstTag.tag file
has a tag directive with two import attributes and some script. The output of this tag file
is the current date in long format. To use this tag file as a tag extension, all you need to
do is save it in the WEB-INF/tags directory of your application. The tag file name is
important because it indicates the tag name. Therefore, for the tag file with the name
firstTag.tag, the tag name will be firstTag.

Here's the firstTagTest.jsp page that uses the firstTag.tag file.

<%@ taglib prefix="easy" 
  tagdir="/WEB-INF/tags" %>
Today is <easy:firstTag/>

You can invoke the firstTagTest.jsp page using this URL (assuming you use Tomcat 5 on port 8080):

http://localhost:8080/tagfiles/firstTagTest.jsp

The result is shown in Figure 2.

Figure 2

Figure 2. Tag file in action

Tag File Directives

Just like JSP pages, tag files can use directives to control how the JSP container will
compile or interpret the tag files. Tag file directives have the same syntax as the directives you can use in JSP pages:

<%@ directive (attribute="value")* %>

The asterisk (*) means that what is enclosed in the brackets can be repeated zero or more times. The syntax can be rewritten in a more informal way, as follows:

<%@ directive attribute1="value1"
  attribute2="value2" ... %>

Attributes must be enclosed by single quotes or double quotes. White space after the opening <%@ and before the closing %> is not required, but can improve readability.

Some of the directives you can use in a tag file are the same as those for JSP pages,
except that you don't have a page directive. Instead of the page directive, you have the
tag directive. Also, in tag files, there are two more directives: attribute and variable.
Table 2 lists all of the directives that can appear in a tag file.

Table 2. Tag file directives

Directive Description
tag This directive is similar to the page directive for JSP pages.
include Use this directive to include other resources from the tag file.
taglib Use this directive to use a custom tag library from inside of the tag file.
attribute Use this directive to declare an attribute in a tag file.
variable Use this directive to define a variable that you can expose to the calling JSP page.

Each of the directives is given below.

The tag Directive

The tag directive is similar to the page directive you can use in a JSP page. Here is the
syntax of the tag directive:

<%@ tag (attribute="value")* %>

The syntax can be expressed in the following more informal form:

<%@ tag attribute1="value1" attribute2="value2" ... %>

The list of attributes for the tag directive is given in Table 3. Note that all tag directive attributes are optional.

Table 3. The tag directive's attributes

Attribute Description
display-name A short name to be displayed by an XML tool. The default value is the tag filename, without the .tag extension.
body-content The information about the body content of this tag. The value can be empty,
tagdependent, or scriptless (default).
dynamic-attributes Indicates support for dynamic attributes. The value identifies a scoped
attribute in which to place a Map containing the names and values of the
dynamic attributes passed during this invocation.
small-icon A context-relative path (or a path relative to the tag source file) of a small
image file to be used by XML tools. You don't normally use this attribute.
large-icon A context-relative path, or a path relative to the tag source file, of an image
containing a large icon to be used by XML tools. You don't normally use this
attribute, either.
description A string describing this tag.
example An informal description of an example of a use of this action.
language The scripting language used in the tag file. The value for this attribute for
the current version of JSP must be "java".
import Used to import a class or an interface or all members of a
package. The same as the import attribute in the page directive.
pageEncoding Describes the character encoding for this tag file. The value is of the form
CHARSET, which must be the IANA name for a character encoding. This
attribute is the same as the pageEncoding attribute of the page directive.
isELIgnored Indicates whether EL expressions are ignored or evaluated. The default
value for this attribute is false, which means EL expressions are
evaluated. This attribute is the same as the isELIgnored attribute of the
page directive.

Except for the import attribute, all other attributes can only appear once within a tag
directive or in multiple tag directives of the same tag file. For example, the following tag
file is invalid because the body-content attributes appear more than once in multiple tag
directives:

<%@ tag display-name="Your first tag file"
body-content="scriptless" %>
<%@ tag body-content="empty" %>

The following is a valid tag directive because the import attribute can appear as many
times as desired.

<%@ tag import="java.util.Enumeration"
import="java.util.Iterator" %>

The following is also valid:

<%@ tag body-content="empty"
import="java.util.Enumeration" %>
<%@ tag import="java.sql.*" %>







The include Directive

The include directive for a tag file is the same as the include directive for a JSP page.
You use this directive to include the contents of other files in the current tag file. It is
useful when you have a common source that will be used by more than one tag file.
The included source can be static (such as an HTML file) or dynamic (another tag file).
As an example, the includeDemoTag.tag page below shows a tag file that includes
one static resource (included.html) and one dynamic resource (included.tagf).

This tag file shows the use of the include directive. 
The first include directive demonstrates how you can include
a static resource called included.html.
<br/>
Here is the content of included.html:
<%@ include file="included.html" %>
<br/>
<br/>
The second include directive includes another
dynamic resource: included.tagf.
<br/>
<%@ include file="included.tagf" %>

The included.html file looks like this:

<table>
<tr>
  <td><b>Menu</b></td>
</tr>
<tr>
  <td>CDs</td>
</tr>
<tr>
  <td>DVDs</td>
</tr>
<tr>
  <td>Others</td>
</tr>
</table>

The included.tagf file looks like this (note that the recommended extension for a tag file is .tagf):

<%
  out.print("Hello from included.tagf");
%>

To test the includeDemoTag.tag file, use the includeDemoTagTest.jsp page:

<%@ taglib prefix="easy" 
tagdir="/WEB-INF/tags" %>
<easy:includeDemoTag/>

You can invoke the includeDemoTagTest.jsp page with the following URL:

http://localhost:8080/tagfiles/includeDemoTagTest.jsp

The result is shown in Figure 3.

Figure 3

Figure 3. Including other resources from a tag file

The taglib Directive

You can use other custom actions from your tag file using the taglib directive. The taglib directive has the following syntax:

<%@ taglib uri="tagLibraryURI" 
prefix="tagPrefix" %>

The uri attribute specifies an absolute or relative URI that uniquely identifies the tag
library descriptor associated with this prefix.

The prefix attribute defines a string that will become the prefix to distinguish a custom
action.

With a taglib directive, you then can use a custom tag of the following format for a
custom tag that does not have a content body:

<prefix:tagName/>

Or, you can use the following format for a custom tag that has a content body:

<prefix:tagName>body</prefix:tagName>

As an example, consider the taglibDemo.tag file:

<%@ taglib prefix="simple"
tagdir="/WEB-INF/tags" %>
The server's date: <simple:firstTag/>

It uses the firstTag.tag file from the first example to display the server's date. The
taglibDemo.tag file is used in the taglibDemoTest.jsp page:

<%@ taglib prefix="easy"
tagdir="/WEB-INF/tags" %>
<easy:taglibDemo/>

You can invoke this JSP page using the following URL:

http://localhost:8080/tagfiles/taglibDemoTest.jsp

The result is shown in Figure 4.

Figure 4

Figure 4. Using the taglib directive in a tag file

The taglib directive in a tag file is the same as the taglib directive in a JSP page.

The attribute Directive

The attribute directive supports the use of attributes in a tag file. It is equivalent to the
attribute element in a tag library descriptor. Here is the syntax of the attribute directive:

<%@ attribute (attribute="value")* %>

The syntax can be expressed in the following more informal form:

<%@ attribute attribute1="value1"
attribute2="value2" ... %>

The list of attributes for the attribute directive is given in Table 4. Note:
The only required attribute for the attribute directive is the name attribute.

Table 4. The attributes for the attribute directive

Attribute Description
name The name for the attribute that this tag file accepts. The value for the name attribute must be unique throughout the current tag file.
required Indicates whether this attribute is required. The value can be true or false (default).
fragment Indicates whether this attribute is a fragment to be evaluated by the tag handler, or a normal attribute to be
evaluated by the container prior to being passed to the tag handler. The value is either true or false (default). The value is true if this attribute is to be evaluated by the tag handler.
rtexprvalue Specifies whether the attribute's value may be dynamically calculated at runtime by a scriplet expression. The value is either true (default) or false.
type The type of the attribute value. The default is java.lang.String.
description The description of this attribute.

As an example, consider the encode.tag file below, which can be used to HTML
encode a String. This encode tag defines one attribute, input, which is of type
java.lang.String.

<%@ attribute name="input"
required="true" %>
<%!
  private String encodeHtmlTag(String tag) {
    if (tag==null)
      return null;
    int length = tag.length();
    StringBuffer encodedTag =
      new StringBuffer(2 * length);
    for (int i=0; i<length; i++) {
      char c = tag.charAt(i);
      if (c=='>')
        encodedTag.append("<");
      else if (c=='>')
        encodedTag.append(">");
      else if (c=='&')
        encodedTag.append("&");
      else if (c=='"')
        encodedTag.append("""); 
      else if (c==' ')
        encodedTag.append(" ");
      else
        encodedTag.append(c);

    }
    return encodedTag.toString();
  }
%>
<%=encodeHtmlTag(input)%>

To test the encode.tag file, use the encodeTagTest.jsp page:

<%@ taglib prefix="easy"
tagdir="/WEB-INF/tags" %>
<easy:encode input="<br/> means changing line"/>

You can invoke the encodeTagTest.jsp page using the following URL:

http://localhost:8080/tagfiles/encodeTagTest.jsp

The result is shown in Figure 5.

Figure 5

Figure 5. Using attributes in a tag file

Summary

In this first part of the series, you have seen how tag files alleviate the problem of
writing tag extensions. In fact, writing tag files is easy, because you don't need a tag
library descriptor or compile the tag handler. Deployment is also simple: you just need to
copy the tag files under the WEB-INF/tags directory of your application. Part two of this
article will discuss the more advanced aspects of tag files, including the <jsp:doBody> and
<jsp:invoke> standard actions that are new to JSP 2.0.

Budi Kurniawan is a senior J2EE architect.
Related Topics >> JSP   |