Vous êtes sur la page 1sur 10

developerWorks: Java technology : Take control of your JSP pages with custom tags

.................
Advanced search
IBM home | Products & services | Support & downloads | My account

IBM developerWorks : Java technology : Java technology articles

Take control of your JSP pages with custom tags

Learn the ins and outs of custom tag library communication Contents:
Brief overview
Jeff K. Wilson (wilsonje@us.ibm.com)
E-business architect, IBM Controlling presentation
January 2002 logic, not just style
JavaServer Pages technology serves a crucial function for Web developers, but many Benefits and examples
don't leverage its full power. Author Jeff Wilson, e-business architect (and member of
Example custom tags
the esteemed DragonSlayers team at IBM), shows you how to customize JSP tags to get
even more out of this technology. Using the techniques he details in this article, you can Wrapup
add more complex logic to your JSPs, take firmer control of data display, and share data Resources
among tags -- all without having to teach your front-end Web developers how to write
Java code. The article includes sample tags and tag-handling classes to give you a feel About the author
for how it all works. Share your thoughts on this article with the author and other readers Rate this article
in the discussion forum by clicking Discuss at the top or bottom of the article.

If you are involved with Web development at all, you're well aware of the fact that Web-based Related content:
applications today require more dynamically generated content and personalized data than ever JSP taglibs: Better usability
before. Architecting a user-friendly interface means that the front-end developer must not only by design
be proficient in the skills of visual design but also in managing and utilizing the flow of
content. Also in the Java zone:
Tutorials
Custom JSP tags give those front-end developers the means to control how data is processed in
back-end Java components without requiring any Java code in the JSP page. Tools and products
Code and components
In this article, we will be focusing on how custom tags communicate with each other, and how
combining them increases reusability and flexibility. We will also walk through a few Articles
examples.
Brief overview of custom tags
Custom tags are more advanced and flexible than typical JSP tags like <jsp:useBean .../> and
<jsp:getProperty .../>. One key benefit that custom tags have over typical JSP tags is that by using custom tags,
JSP developers can pass input through by placing data either in tag attributes or between opening and closing tags.
Custom JSP tags are composed of three parts:
● The JSP page that the tag is used in

● The tag handler, a Java class that processes the tag

● The tag library descriptor, an XML file that groups tags into a "library" and describes the specifics about each tag,
such as its attributes, the tag handle name, short name, and so forth
Custom tags can be configured to run their processes based on the input supplied through a tag's attributes, eliminating the
need for embedded Java code within the JSP page.
Let's look at an example. Listing 1 shows a shopping cart tag that produces one table row for every product selected by a
user:
Listing 1. Shopping cart tag

http://www-106.ibm.com/developerworks/library/j-taglib/ (1 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags

<table width="100%" border="0">


<user:getUserShoppingList userId="13">
<tr>
<td>
<a href="/servlet/productDataServlet?prodID=$_productId">$_productName</a>
</td>
<td>$_productDescription</td>
</tr>
</user:getUserShoppingList>
</table>

In this case, the tag handler class expects both HTML and the user's ID to be passed in as a template for the resulting output
(a table row, in this case). The various $_product... references will be replaced by actual values from the products
looped through in the tag handler -- the Java class that implements the tag.
This demonstrates another key benefit of custom tags: Java programmers don't need to know how to format the data before
sending it back to the client. Additionally, as new pages are developed that require data that is similar in content but
formatted differently, or as the look of current pages change, the Java components won't need updating.
Controlling presentation logic, not just style
Another very important advantage of custom tags is their ability to communicate with other tags on the same page. With
traditional JSP tags, developers can set properties to control the behavior of a JavaBean component, but the bean simply does
what it does on its own. By breaking down processes into smaller components, JSP developers can mix and match custom
tags to build more complex processes for greater control of dynamic content.
Using the output of one custom tag as the input for another increases the tags' reusability. For instance, in our previous
example, the user shopping cart tag held all the information about the products purchased. A better design might have the
user tag hold only product IDs and let another tag -- a product tag -- manage the product data as needed. Once you separate
out the process that collects the details of a product, you have a product tag that can be used with other tags for other
purposes.
This produces an object-oriented approach to controlling the dynamic data that is retrieved -- and front-end developers can
follow this approach without knowing any programming.
The code in Listing 2 shows this approach in action. Also, notice that the user's shopping list tag implements another tag,
called error:setErrorTemplate. If no products are found in this example, we might want to show an error message.
It's easy to see that the two-column table needed for our product list won't be that appropriate for an error message.
Listing 2. Object-oriented approach

<table width="100%" border="0">


<tr class="headerRow">
<td>Product Name</td>
<td>Product Description</td><tr>
</tr>
<user:getUserShoppingList userId="13">
<products:getProductData productId="$_productId"/>
<tr>
<td>
<a href="/servlet/productDataServlet?$_productId">$_productName</a>
</td>
<td>$_productDescription</td>
</tr>
<error:setErrorTemplate>
<tr class="errorRow">
<td colspan="2">You have nothing in your shopping cart...</td>
</tr>

http://www-106.ibm.com/developerworks/library/j-taglib/ (2 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags
</error:setErrorTemplate>
</user:getUserShoppingList>
</table>

The tag handler class can be designed to handle alternate formatting under certain predefined circumstances. This is a good
example of how JSP developers can control the logical flow of the data without using if statements or other Java code in the
JSP page. With the custom tag, the JSP developer can decide how to determine what gets displayed, not just how it is
displayed.
In another situation, the same product data tag can be reused with other tags that list products. Notice in Listing 3 that not
only does another tag (<products:getProductData category="fitness">) initiate the list, but the output will
be formatted differently, because different HTML is passed into the tag.
Listing 3. Product data tag used with product list

<table width="100%" border="0">


<products:getProductList category="fitness">
<products:getProductData productId="$_productId"/>
<tr>
<td rowspan="2">
<a href="/servlet/productDataServlet?$_productId"><img
src="$_productImage" border="0"></a></td>
<td>
<a href="/servlet/productDataServlet?$_productId">$_productName</a>
</td>
</tr>
<tr>
<td>$_productDescription: $_productPrice</td>
</tr>
<error:setErrorTemplate>
<tr>
<td colspan="2" class="errorRow">Sorry, no products in this category...</td>
</tr>
</error:setErrorTemplate>
</user:getUserShoppingList>
</table>

Methods of tag communication: Benefits and examples


There are a few ways in which custom tags can reference each other and share data. The appropriate method will of course
depend on the situation.
Nesting tags
A tag is said to be nested when it is completely surrounded by another tag:
<outer:tag><inner:tag/></outer:tag>

No special setup or coding is required to put one tag within another. A tag can be nested in one place and on its own in
another. Some tags, of course, will be designed to be nested within others, but nothing is explicitly required to declare a tag
as nestable.
You can think of HTML table, table row, and table cell tags as nested tags. An example of shared data in table tags is the
table's background color (the bgcolor attribute). If the background is set in the table tag <table
bgcolor="blue">...</table>, all the rows and cells will be set to blue unless the bgcolor attribute is overridden
by an individual tag (for example, <table bgcolor="blue">...<td
bgcolor="red">...</td>...</table>).
In its most basic implementation, the evaluated inner tag may simply be body input for the outer tag. However, a nested tag
might also reference the tags that enclose it (such as parent tags and grandparent tags), allowing linked classes to call each

http://www-106.ibm.com/developerworks/library/j-taglib/ (3 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags
other's methods and properties. In this way, the child and parent tags may share data.
Ancestor tags can be referenced by nesting tags using one of two methods:
● TagSupport.getParent(): Returns the parent tag; that is, the enclosing tag that immediately surrounds the tag.

● TagSupport.findAncestorWithClass(from,class): Used when the specific hierarchy of the tags is not


known or necessarily preset. The arguments for findAncestorWithClass(from,class) indicate what class
to start from and what class to search for, respectively. For instance, in an HTML table tag hierarchy, a table cell tag
accessing the table tag would look like this:

TableTag table = (TableTag)findAncestorWithClass(this, TableTag.class);

If the current tag was not enclosed in a tag whose tag handler was the class specified (TableTag.class, in this case) or if
getParent() was called and it had no parent at all, both methods would return null.
Referencing tags with IDs
Another way to share data is to register a class with an ID that can then be retrieved by another tag's handler class. Using this
method, a JSP developer cannot simply set an ID in any custom tag if the tag is not specifically programmed to accept it.
An ID property is already declared within TagSupport for this very purpose and available to any tag handler class.
However, to use the ID property to store the object for other tags to access, two steps must be taken:
1. An ID attribute must be specified in the tag library descriptor (the required node can be set to either true or false).

2. The tag handler must specifically set itself to an attribute of the pageContext.
Sharing tag objects with registered IDs may be necessary if the tags cannot easily be nested.
Let's refer back to our example of a user's shopping cart. Consider that the <user:getUserShoppingList .../> in
Listing 4 below holds various information about a shopping list, including a method that returns a list of product IDs called
getProductIds(). Somewhere else in the JSP page, the <products:getProductData> ...
</products:getProductData> tag will take a list of product IDs, retrieve product details for each product, and
format them before sending them back to the client.
The user:getUserShoppingList tag will execute and store itself as an attribute of the pageContext named
userShoppingList. The product:getProductData tag will retrieve the value of the attribute and call the method
getProductIds() from the getUserShoppingList object.
Listing 4. getUserShoppingList

<user:getUserShoppingList userId="13" id="userShoppingList"/>


...
<products:getProductData productData="userShoppingList">
<!-- Some formatting template -->
...
</products:getProductData>

The tag library descriptor for the tag getUserShoppingList might look like Listing 5:
Listing 5. Library descriptor for getUserShoppingList

http://www-106.ibm.com/developerworks/library/j-taglib/ (4 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags

<tag>
<name>getUserShoppingList</name>
<tagclass>com.taglib.UserShoppingListTag</tagclass>
<bodycontent>JSP</bodycontent>
<attribute>
<name>userId</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>

The getShoppingList tag handler would contain the following line once the tag completed all of its processing (perhaps
in the doEndTag() method):
pageContext.setAttribute(getId(),this);

getId() retrieves the ID set in the tag (userShoppingList) and this refers to the entire class itself.
Once the userShoppingList tag is stored in the pageContext, the getProductData tag handler class can access
it using the ID passed into it with the productData attribute. The handler class of the getProductData tag will use
that ID (retrieved with the method getProductData()) to find the attribute in the pageContext and cast it back into a
UserShoppingListTag object. The code in Listing 6 declares a List called productList and calls the user class
method getProductIds() to extract the product list.
Listing 6. Extracting a product list

UserShoppingListTag userShoppingList =
(UserShoppingListTag)pageContext.getAttribute(getProductData());
List productList = (List)userShoppingList.getProductIds();

Referencing tags in the page and session context


Storing an entire tag object can be useful for giving other tags free reign over the properties and methods in it. But you can
also choose to expose only parts of the object. In fact, a limitation of the previous example is that the product tag is expecting
the product list to come from the UserShoppingListTag object.
Perhaps a better approach is to have the user tag, getShoppingList, simply "export" the product list to the
pageContext for any other tag to use. The advantage of this is that other tags won't require prior knowledge of the
method that returns product lists, or even knowledge of the object from which the lists originate. If the label for the data
stored in the pageContext were provided by the attribute productData, the tag handler for the product tag would look like
this:

List productList = (List)pageContext.getAttribute(getProductData());

This technique would work for shopping list tags and others, like a tag that calls sale items or products from a given
category.
If the data were stored in a session, it would like this:

http://www-106.ibm.com/developerworks/library/j-taglib/ (5 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags

HttpSession session = pageContext.getSession();


List productList = (List)session.getAttribute(getProductData());

Walking through example custom tags


In the Resources section below, you'll find a link to a set of example custom tags. Download the code package and have a
look at them. In the final section of this article, I'll use these examples to show you some of the benefits you can achieve by
using custom tags.
Overview of the example tags
The idea behind the sample tags is fairly simple and straightforward. In total, there are seven custom tags, one JSP file, and
one tag library descriptor (a .tld file).
The tags work together to display one of three things: a welcome screen, a login screen, or, if an error occurs, a login error
message. (The actual login process is not handled by the tags -- we will mimic the process for simplicity's sake by setting
session and request variables that would otherwise be set by a servlet or JavaBean component).
As Listing 7 shows, there are two main tags: getUserData and nestedLogin. The first gets the user and the second
displays the appropriate HTML based on whether or not the user, John Q. Citizen, has logged in.
These two tags represent a way that one tag, nestedLogin, can access another tag, getUserData, which was stored in
the pageContext.
The nestedLogin tag also demonstrates the process of nesting other tags within a tag; it allows other tags to access its
methods. The three possible displays are represented by three other tags: isLoggedInHTML, notLoggedInHTML, and
logInFailureHTML. These three tags provide access to properties in the nestedLogin tag; the appropriate block of
code will be determined and displayed by nestedLogin.
The remaining two tags, getUserName and getLoginError, demonstrate two ways of using nested tags: as simple
body content and as a means of accessing methods in ancestor tags. Neither of them overrides their ancestor tags; they
simply pull data -- namely, the user's name and a login error, if either has been set -- from their ancestors.
Listing 7. The example JSP code

<HTML>
<HEAD>
<TITLE>Custom Tag Communication</TITLE>
</HEAD>

<BODY bgcolor="#ffffff">

<!-- LOAD TAG LIBRARY -->


<%@ taglib uri="goforit.tld" prefix="goforit" %>

<!-- SET THE USER -->


<goforit:getUserData id="user"/>

<!-- SET THE LOGIN HTML BASED ON WHETHER OR NOT THE USER IS LOGGED IN -->
<!-- ONE OF THE NESTED NODES WILL BE DISPLAYED ACCORDINGLY -->
<goforit:nestedLogin userDataID="user">

<goforit:isLoggedIn>
<!-- THE HTML IN THIS NODE IS DISPLAYED IF THE USER IS LOGGED IN -->
</goforit:isLoggedIn>

<goforit:notLoggedIn>
<!-- THE HTML IN THIS NODE IS DISPLAYED IF THE USER IS NOT LOGGED IN -->
</goforit:notLoggedIn>

http://www-106.ibm.com/developerworks/library/j-taglib/ (6 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags

<goforit:loginFailure>
<!-- THE HTML IN THIS NODE IS DISPLAYED IF THERE WAS A LOGIN ERROR -->
</goforit:loginFailure>

</goforit:nestedLogin>

</BODY>
</HTML>

The tag library descriptor


Listing 8 shows the descriptors for the two main tags. Note the required id attribute in getUserData and userDataID
in nestedLogin. These are used to register the user object in the pageContext and to retrieve it in other classes.
Listing 8. Tag descriptors

<tag>
<name>getUserData</name>
<tagclass>com.taglibrarycommunication.taglib.GetUserDataTag</tagclass>
<info></info>
<bodycontent>JSP</bodycontent>
<attribute>
<name>id</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>

<tag>
<name>nestedLogin</name>
<tagclass>com.taglibrarycommunication.taglib.NestedLoginTag</tagclass>
<info></info>
<bodycontent>JSP</bodycontent>
<attribute>
<name>userDataID</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>

The tag handlers


The following sections show some of the important aspects of communication between classes.
GetUserData
This tag handler class retrieves the user data to be used by the other tags.
Note: Because our tags do not handle the login process, these are constructed to look for a logged-in user stored in the
session and errors stored in the request. Because we are not actually logging people in, the beginning of this tag mimics the
three possible scenarios by setting someone to the session or an error to the request. The code shown in Listing 9 controls the
three scenarios -- if both lines below remain commented out, the user is considered not logged in:
Listing 9. Code that controls example scenarios

http://www-106.ibm.com/developerworks/library/j-taglib/ (7 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags

// UNCOMMENT TO MIMIC A LOGGED IN USER STORED IN SESSION


//session.setAttribute("user","John Q. Citizen");

// UNCOMMENT TO MIMIC LOGIN ERROR STORED IN REQUEST


//pageContext.getRequest().setAttribute("loginError","Password incorrect");

The key to registering the user data is in the doStartTag() method:


Listing 10. doStartTag()

public int doStartTag() {

session = pageContext.getSession();

... SET VARIOUS PROPERTIES BASED ON THE USER ...

// THIS IS THE LINE THAT SAVES THIS CLASS TO pageContext


pageContext.setAttribute(id,this);

return SKIP_BODY;
}

NestedLoginTag
This class, shown in Listing 11, determines which of three properties are returned to the client, based on whether or not the
user is logged in or if there is an error. The values of these three properties are determined by other tags nested within the
class in the JSP page. NestedLoginTag determines which tag to display by first pulling in the user registered to the
pageContext in the previous tag. It then attempts to retrieve the username and any error that might have occurred. If both
are blank, it assumes that the user has not logged in. If the error message is not blank, clearly an error occurred. If the user's
name was set, the user was successfully logged in.
Listing 11. NestedLoginTag

// PULL THE userData OUT OF THE pageContext


// WITH THE userDataID SUPPLIED THROUGH THE CUSTOM TAG
GetUserDataTag userData =
(GetUserDataTag) pageContext.getAttribute(getUserDataID());

// SET userName AND loginError FROM VALUES IN userData OBJECT


setUserName(userData.getUserName());
SetLoginError(userData.getLoginError());

...

if (getUserName()!="" &&
getLoginError()==""){
// IF userName IS SET PERSON IS LOGGED IN
pageContext.getOut().print(getIsLoggedInHTML());
} else {
if (getLoginError()=="")
// IF NO userName SET BUT NO loginError SHOW LOGIN
pageContext.getOut().print(getNotLoggedInHTML());
else
// IF loginError SHOW LOGIN AND ERROR
pageContext.getOut().print(getLogInFailureHTML());

http://www-106.ibm.com/developerworks/library/j-taglib/ (8 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags
}

IsLoggedInTag, NotLoggedInTag, and LogInFailureTag


The three tags in Listing 12 are the tags nested within nestedLogin. They all function similarly but set different
properties of nestedLogin. Their body content allows the JSP developer to access and set the isLoggedInHTML,
notLoggedInHTML, and logInFailureHTML properties of nestedLogin.
Listing 12. Accessing a parent tag

// THIS LINE ACCESSES THE PARENT CLASS NestedLoginTag


NestedLoginTag parent = (NestedLoginTag) getParent();

if (parent != null){
BodyContent bc = getBodyContent();
String body = bc.getString();

// SET THE isLoggedInHTML PROPERTY OF THE PARENT CLASS


// WITH THE BODY SUPPLIED THROUGH THE CUSTOM TAG
parent.setIsLoggedInHTML(body);
}

GetUserNameTag and GetLoginErrorTag


The tags in Listing 13 simply retrieve the userData object from the pageContext and pull out a property of it.
Listing 13. Accessing objects stored in the pageContext

GetUserDataTag userData =
(GetUserDataTag) pageContext.getAttribute(getUserDataID());

...

if (userData.getUserName() !=null){
pageContext.getOut().print(userData.getUserName());
}

Wrapup
JSP pages separate client-side display from server-side logic, and put the power of Java technology at the disposal of Web
designers who may not be Java programmers. By using custom tags, you can give more choices to developers working on
both tiers of a Web application, and impose an object-oriented approach on Web developers that will encourage the reuse of
code modules and tags. Once you've examined the sample tag library included with this article, you should be ready to start
using custom tags with your own applications.
Resources
● Participate in the discussion forum on this article by clicking Discuss at the top or bottom of the article.

● You can download all the code for this article to help you get started on your own custom tag library.

● In "JSP taglibs: Better usability by design" (developerWorks, December 2001), Noel J. Bergman teaches you how to
get the most out of the Java taglib facility.

● Using VisualAge for Java and WebSphere Studio? Find out how to integrate JSPs and custom tags into your projects
in this article from the WebSphere developer domain.

● If you're using custom tag libraries with VisualAge for Java, this article can show you how to fully unit-test your code.

http://www-106.ibm.com/developerworks/library/j-taglib/ (9 of 10) [1/29/2002 12:35:21 PM]


developerWorks: Java technology : Take control of your JSP pages with custom tags

● Sun offers its own tag libraries tutorial at java.sun.com.

● JSPTags.com offers a directory of resources related to JavaServer Pages, with an emphasis on JSP tag libraries.

● This article, " Custom JSP Tags and JSP Tag Libraries" at the Lotus Developer Network, offers a good overview of
implementing custom tags.

● Apache maintains Jakarta Taglibs, an open-source repository for JSP custom tag libraries.

● Find other Java resources on the developerWorks Java technology zone.


About the author
Jeff Wilson is an e-business architect for the DragonSlayers, a group of consultants, educators, and evangelists
within IBM's developer relations division. Contact Jeff at wilsonje@us.ibm.com.

What do you think of this article?

Killer! (5) Good stuff (4) So-so; not bad (3) Needs work (2) Lame! (1)

Send us your comments or click Discuss to share your comments with others.

Submit feedback

About IBM | Privacy | Legal | Contact

http://www-106.ibm.com/developerworks/library/j-taglib/ (10 of 10) [1/29/2002 12:35:21 PM]