Thursday, March 11, 2010

Designing JSP Custom Tag Libraries

Categories: , , ,


In this article you'll learn

  • what a custom tag library is,
  • why you want to use a custom tag library,
  • the composition of a tag library, and
  • how to build and use a complete library.

What a Custom Tag Library Is

If you've ever had the opportunity to build a web application using Java technology, chances are you have used Java Server Pages (JSP) for content display. JSP is the technology that helps separate the front end presentation from the middle and backend tiers. The custom tag library is a powerful feature of JSP v1.1 that aids in that separation. This technology is valuable to anyone who is building production-quality web applications, and it is very applicable in today's market.
Custom tag libraries allow the Java programmer to write code that provides data access and other services, and they make those features available to the JSP author in a simple to use XML-like fashion. An action in a web application -- for example, gaining database access -- can be customized by using a custom tag in a JSP page. The JSP author doesn't have to understand the underlying detail to complete the action. In short, a tag library is a collection of custom actions presented as tags.
Custom tags have many features that make them attractive to use from any JSP. Custom tags can
  • be customized via attributes passed from the calling page, either staticly or determined at runtime;
  • have access to all the objects available to JSP pages including request, response, in and out;
  • modify the response generated by the calling page;
  • communicate with each other; you can create and initialize a JavaBeans component, create a variable that refers to that bean in one tag, and then use the bean in another tag;
  • be nested within one another, allowing for complex interactions within a JSP page; and
  • encapsulate both simple and complex behaviors in an easy to use syntax and greatly simplify the readability of JSP pages.
Any of these points is reason enough to consider using a tag library.
Let's look at what makes up a tag library and build one step by step.

The Composition of a Tag Library

There are two types of components for a tag library: the tag library descriptor file and the tag handlers. With these a JSP is able to use tags contained in the library within its page.
The TLD File
A tag library descriptor (TLD) file is an XML document that describes the library. A TLD contains information about the library as a whole and about each tag contained in the library. TLDs are used by a JSP container to validate the tags.
There is typically some header information followed by elements used to define the tag library. The elements are
< taglib>
The tag library itself.
< tlibversion>
The tag library's version.
< jspversion>
The JSP specification version the tag library depends on.
< shortname>
A simple default name with a mnemonic value. For example, may be used as the preferred prefix value in taglib directives and/or to create prefixes for IDs.
< uri>
A optional URI that uniquely identifies the tag library.
< info>
Descriptive information about the tag library.

Then each tag contained in the library is described. There can be one or many tags per library. There is only one TLD element required for all tags, and that is the one used to specify a tag handler's class: < tagclass>classname
There are various other elements used to describe tags. Which elements a tag uses will depend on how the tag is implemented in the handler. We'll get to that discussion in the section below.
If a tag has attributes associated with it, then each attribute must be described within the < tag> element. If an attribute is required by a tag, < required> is set to "true" or "yes". To allow a runtime expression value to be used by the tag, the< rtexpvalue> is set to "true" or "yes". For each attribute of a tag, a Bean-like getter/setter method needs to be defined in the handler class. It's also possible to define scripting variables for use in tags. This is accomplished using a TagExtraInfo class and will be discussed in the tag handler section. If a TagExtraInfo is to be used, the class must be defined using the< teiclass>classname< teiclass> within the tag definition.

A sample TLD named oreillySample.tld looks like
< ?xml version="1.0" encoding="ISO-8859-1" ?>
< !DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" 
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
< taglib>
 < tlibversion>1.0
 < jspversion>1.1
 < shortname>oreillySamples
 < info>OReilly Sample Tag library
  < !-A Simple tag -->
  < tag>
    < name>hello
    < tagclass>oreilly.examples.Hello < /tagclass>
  < !--Body content can have a value of 
    empty: no body 
      JSP: body that is evaluated by container, then possibly processed by the tag 
      tagdependent: body is only processed by tag; JSP in body is not evaluated.
   -- >
    < bodycontent>empty
    < info>
 This is a simple hello tag.
    < /info>
  < !-- Optional attributes  -->
  < !- personalized name -->
  < attribute>
      < name>name< /name>
      < required>false< /required>
      < rtexpvalue>false< /rtexpvalue>
  < /attribute>
< /tag>
< /taglib>
The Tag Handler
The tag is defined in a handler class. TagSupport is the base class used for simple tags. It can be found in thejavax.servlet.tagext package. What your tag is implementing will depend on what methods could potentially be called and what needs to be implemented. TagSupport and TagBodySupport supply default implementations of the methods listed below.

If your Tag Handler:
You need to implement the following methods:
has no attributes and no body
doStartTag, doEndTag, release
has attributes
doStartTag, doEndTag, set/getAttribute1...N
has a body with no interaction
doStartTag, doEndTag, release
has a body with interaction
doStartTag, doEndTag, release, doInitBody, doAfterBody

A more advanced feature is the use of scripting variables. Typically an attribute is passed to the tag that contains the ID of the object to be used. The usual operation is that the tag handler retrieves a scripting variable value object usingpageContext.getAttribute(name), performs some processing on it, and then sets the scripting variable's value using thepageContext.setAttribute(name, object). In addition to setting the value of the variable within the tag handler, you must define a class derived from TagExtraInfo that provides information to the JSP container about the nature of the variable. That class is then listed in the  attribute of the tag.
The Java code for the tag defined in the oreillySample.tld file would look like

package oreilly.examples
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
/**
 * This is a simple tag example to show how content is added to the
 * output stream when a tag is encountered in a JSP page. 
 */
public class Hello extends TagSupport {
 private String name=null;
    /**
      * Getter/Setter for the attribute name as defined in the tld file 
      * for this tag
      */
public void setName(String value){
    name = value;
}

 public String getName(){
          return(name);
       }
/**
* doStartTag is called by the JSP container when the tag is encountered
*/
    public int doStartTag() {
   try {
        JspWriter out = pageContext.getOut();
        out.println("< table border="\1\">");
      if (name != null)
       out.println("< tr>< td> Hello " + name + " < /td>< /tr>");
        else
       out.println("< tr>< td> Hello World < /td>< /tr>");
   } catch (Exception ex) {
     throw new Error("All is not well in the world.");
   }
   // Must return SKIP_BODY because we are not supporting a body for this 
   // tag.
   return SKIP_BODY;
    }
/**
 * doEndTag is called by the JSP container when the tag is closed
 */
 public int doEndTag(){
    try {
         JspWriter out = pageContext.getOut();
        out.println("< /table>");
    } catch (Exception ex){
      throw new Error("All is not well in the world.");
    }
 }
}
The JSP

Once your TLD and tag handlers are created, you can begin accessing the tags in your JSP. You declare that a JSP page will use tags defined in a tag library by including a taglib directive in the page before any custom tag is used. The prefix attribute is a shortcut to referencing the library throughout the page.
Sample Hello.jsp:
< %@ taglib uri="/oreillySample.tld" prefix="sample" %>
< html>
        < head>
                < title>Your Standard Hello World Demo
        < /head>
        < body bgcolor="#ffffff">
                < hr />
                < sample:hello name="Sue"/>
                < hr />
        < /body>
< /html>
The HTML source output from this JSP would look like:
< html>
        < head>
                < title>Your Standard Hello World Demo< /title>
        < /head>
        < body bgcolor="#ffffff">
                < hr />
        < table border="1">
          < tr>< td> Hello Sue < /td>< /tr>
                < /table>
                < hr />
        < /body>
< /html>
You can see how the tag was evaluated and the contents of the tag inserted into the output stream.
If you wanted to add functionality to our tag to make it more flexible, say to evaluate a body a certain number of times and make the name attribute evaluated at runtime, you can do so fairly easily with a few changes. First you would make the following changes to the TLD file. The tag definition would look like
  < tag>
    < name>hello
    < tagclass>oreilly.examples.Hello < /tagclass>
 < !-- Allow for a body to be included for this tag -->
    < bodycontent>JSP
    < info>
 This is a simple hello tag.
    < /info>
    
    < !-- Optional attributes  -->
    < !-- personalized name -->
    < attribute>
      < name>name< /name>
      < required>false< /required> 
    < rtexpvalue>true< /rtexpvalue>
    < /attribute>
    < !-allow for the jsp coder to specify how many times to iterate -->
    < attribute>
      < name>iterations< /name>
      < required>false< /required> 
    < rtexpvalue>false< /rtexpvalue>
    < /attribute>

< /tag>
Then you must alter the handler class by extending TagBodySupport and implementing the body methods if you wanted different behavior from that provided in the base class implementation. The handler class would now look like
public class Hello extends BodyTagSupport {
 private String name=null;
    private int iterations=1;

 /**
     * Getter/Setter for the attribute name as defined in the tld file 
     * for this tag
     */
 public void setName(String value){
  name = value;
 }

 public String getName(){
  return(name);
 }
 /**
     * Getter/Setter for the attribute iterations as defined in the tld file 
     * for this tag
     */

 public void setIterations(String value){
     try {
       iterations = Integer.parseInt(value);
     } catch(NumberFormatException nfe) {
       iterations = 1;
     } 
   }

 public String getIterations(){
  return(Integer.toString(iterations));
 }

    public int doStartTag() throws JspTagException{
   try {
        JspWriter out = pageContext.getOut();
        out.println("< table border=\"1\">");
      if (name != null)
       out.println("< tr>< td> Hello " + name + " < /td>< /tr>");
        else 
       out.println("< tr>< td> Hello World < td>< /tr>");
   } catch (Exception ex) {
     throw new JspTagException("All is not well in the world." + ex );
   }
   // Evaluate the body if there is one
   return EVAL_BODY_TAG;
    }

 public int doEndTag()throws JspTagException {
    try {
         JspWriter out = pageContext.getOut();
        out.println("< /table>");
    } catch (Exception ex){
      throw new JspTagException("All is not well in the world." + ex);
    }
 }

 public int doAfterBody() throws JspTagException {
    if (iterations-- >= 1) {
      BodyContent body = getBodyContent();
      try {
  // Make sure we put anything in the output stream in the 
  // body to the output stream of the JSP
        JspWriter out = body.getEnclosingWriter();
        out.println(body.getString());
        body.clearBody(); // Clear for next evaluation
      } catch(IOException ioe) {
        throw new JspTagException("Error in Hello tag doAfterBody " + ioe);
      }
      return(EVAL_BODY_TAG);
    } else {
      return(SKIP_BODY); 
 }
}
Now let's make the simple changes in the JSP file. Our sample Hello.jsp looks like
< %@ taglib uri="/oreillySample.tld" prefix="sample" %>
< %!
    // allow a username to be passed in the request
    String userName = request.getParameter("NAME");
% >

< html>
        < head>
                < title>Your Standard Hello World Demo < /title>
        < /head>
        < body bgcolor="#ffffff">
                < hr />
                < sample:hello name="" iterations="2" >
   < tr>< td>Have a nice day< /b>< /td>
   < /sample:hello>
                < hr />
        < /body>
< /html>
If our JSP page was called like hello.jsp?NAME=Sue our output would look like
< html>
        < head>
                < title>Your Standard Hello World Demo
        < / head>
        < body bgcolor="#ffffff">
                < hr />
        < table border="1">
          < tr>< td> Hello Sue < /td>< /tr>
     < tr>< td>< b>Have a nice day< /b>< /td>< /tr>
     < tr>< td>< b>Have a nice day< /b>< /td>< /tr>
                < /table>
                < hr />
        < /body>
< /html>
This simple example is but a small glimpse at the power of custom tag libraries. We examined how to create and use a simple tag library and then easily extend its functionality. The next article will examine some of the advanced features of tags, including defining scripting variables and cooperating tags. It will also go through working examples of each.


Spread The Love, Share Our Article

Related Posts

No Response to "Designing JSP Custom Tag Libraries"

Post a Comment