Writing a Custom JSP Tag Library

Yesterday you learned about the support provided by Java to embed special tags in an HTML file that allowed you to include Java code in the HTML file. This hybrid HTML file, called a JavaServer Page, was then parsed and compiled by the JSP engine in the WebLogic Server to generate a servlet.

The special tags that you could add are defined in the JSP specification. Suppose you wanted to add your own tags. Would you be able to do so? For example, to display the name of the logged-in user, typically you would use the expression tag <%=myName%> to retrieve the name from a Java variable. It would be much more intuitive to a developer to use your own tag called <name/>. The second tag is easier to understand (because it represents the business meaning) than the normal JSP expression tag.

The JSP specification does allow you to extend the JSP function to add custom tags in the JSP page. To develop custom tags, you need to write a custom JSP tag library to support the custom tags because the JSP engine that parses the JSP will have no idea how to interpret and process the custom tags. Prior to custom tags, you would have had to implement the functionality in the JSP page using a combination of embedded JavaBeans (using the useBean tag) and scriptlets.

The application areas of custom tags are many. Remember the BookShoppingJSP that you developed yesterday? The Java code embedded in the JSP was extensive. As a JSP application grows in functionality, the JSP becomes more and more complicated, making it unreadable for developers to maintain. Using custom tags alleviates this complexity to a large extent because you can remove the Java code and place it in separate Java classes. Your JSP will simply contain the special tags that you define. The JSP becomes a lot simpler and more readable now. Custom tags find use in places where you need to encapsulate database access functionality, access control mechanisms, HTML form data validation and preprocessing, and lots of other areas.

Advantages and Disadvantages of Custom Tags

The primary advantage offered by custom tags is the encapsulation of complex processing code into a separate Java class. This encapsulation also enables the processing logic (and hence the custom tags) to be reusable across different JSPs in the application.

The behavior of the custom tags, that is, its processing logic, can be customized with the ability to pass attributes to the Java class performing the processing for the custom tags. This is an added benefit to the reusable feature of custom tags.

Developing a custom tag library is an elaborate process (as you shall see!). But on the flip side, effort spent in developing a custom tag library is worth the savings in effort in a large project because of the reusable nature of the tags.

Features of Custom Tags

Now take a look at the following features of custom tags:

  • XML syntax for custom tags makes it standardized (readable) with the rest of the code in the JSP. Tags can be either simple <tagname/> or nested <tagname>...</tagname>. Both of these types will be studied in the next section.

  • Ability to customize the processing (behavior) of the custom tags by specifying attributes for the custom tags. This is similar to the attributes that were used for the JSP specification tags.

  • The custom tags can access all the implicit variables available in JSP, such as request, response, session, page, and so on.

  • A special functionality used by custom tags is access to the content of the JSP page using the pageContext implicit variable. This will be looked at in the coming section.

  • Custom tags in the JSP page can communicate with each other. For example, a variable can be created and initialized by one custom tag and is then available to all the custom tags in the JSP.

To use custom tags, you need to create a JSP custom tag library. From Figure 6.2, you can see that the main components of the custom tag library are the tag handler, the tag library interfaces, and the tag library descriptor mapping file.

Figure 6.2. Block diagram of custom tag library components.

graphics/06fig02.gif

The tag handler Java class must implement methods of the tag library interfaces. The tag library interfaces are the only connection between the JSP engine and the custom tags apart from the tag library descriptor mapping file.

The custom tag library is included in the JSP using a special directive called the <taglib> directive. The <taglib> directive indicates to the JSP engine to include the Java classes of the JSP custom tag library, which are then used to generate the output in place of the custom tags. The <taglib> directive also specifies a tag prefix that is used as a reference handle to indicate which custom tags belong to which JSP custom tag library. You will study the structure and use of the <taglib> directive in the section titled "taglib Directive."

Types of Custom Tags

The custom tags that you can develop in JSP fall under two basic categories: simple tags and tags with a body. Counting variations, there are four different types of custom tags. Now study each of these types of custom tags.

Simple Custom Tag

The easiest custom tag that can be developed is the simple custom tag. On finding a custom tag embedded in the JSP, the JSP engine invokes the Java class that is mapped to this tag in the tag library descriptor mapping file. The Java class performs the processing on behalf of the custom tag. The output generated is placed where the tag is located in the JSP. A tag handler for this tag type either implements the methods of the Tag interface or extends the TagSupport class.

The structure of the simple custom tag consists of a tagPrefix (indicating the tag library to which the tag belongs) followed by the tagName, which represents the name of the tag:

 <tagPrefix:tagName/>  

Here's an example:

 Book Name: <myTagPrefix:bookName/>  

The preceding code snippet shows the bookName tag is a part of the tag library whose prefix is myTagPrefix. The bookName tag is parsed by the JSP engine, and the Java tag handler class mapped to this tag is invoked. The methods doStartTag(), doEndTag(), and release() of the tag handler Java class are invoked; the output generated by the methods doStartTag() and doEndTag() is put in place of the custom tag in the output generated for the JSP. If the doStartTag() method generates Teach Yourself WebLogic in 21 Days as the output, this will be placed in the JSP output. The final JSP output will be as follows:

 Book Name: Teach Yourself WebLogic in 21 Days  
The doStartTag() Method

The doStartTag() method of the tag handler for the custom tag is invoked by the JSP engine when it encounters a custom tag in the JSP. You can write the processing for your custom tag in this method. For the simple custom tag, the doStartTag() method can write to the JSP output. The JSP output stream is obtained by executing the getOut() method of the implicit variable pageContext. Recall that the custom tag handlers can access the implicit variables of JSP. The method must return the constant SKIP_BODY at the end of the processing. This indicates to the JSP engine to ignore processing of the body contents because no body exists for the simple tag. Here is a code snippet:

 ...  public int doStartTag() throws JspException {     pageContext.getOut().print("Teach Yourself WebLogic in 21 Days");     return SKIP_BODY; } ... 
The doEndTag() Method

The doEndTag() is executed as a postprocessing of the custom tag. For simple tags, you don't need to add any code in the doEndTag(); just return the constant EVAL_PAGE. The EVAL_PAGE constant indicates to the JSP engine to continue the processing of the JSP page. Isn't this similar to the servlet and filter chaining? Yes, it is! Custom tag output processing can also be chained, and any custom tag can break the chain of processing if the EVAL_PAGE constant is not returned. A code snippet is given here:

 ...  public int doEndTag() throws JspException {     return EVAL_PAGE; } ... 
The release() Method

The release() method is used to free any resources used by the tag handler class. The JSP engine guarantees invocation of the release method at the end of processing the JSP page. A code snippet is given here:

 ...  public void release() throws JspException {     // free up any resources used } ... 
Simple Custom Tag with Attributes

The simple custom tag that was discussed in the previous section can be extended to customize the output generated by passing attributes and values to the custom tag. The tag handler class for the custom tag receives the values for these attributes and uses the values to process and customize the output. This helps you to extend the functionality of the custom tag from a simple output generation to a conditional output generation. The output generated is placed where the tag is located in the JSP. A tag handler for this tag type either implements the methods of the Tag interface or extends the TagSupport class.

The structure of the simple custom tag with attributes consists of a tagPrefix (indicating the tag library to which the tag belongs) followed by the tagName, which represents the name of the tag and a set of attribute-value pairs:

 <tagPrefix:tagName attrib1="value1", attrib2="<%=testInp1%>"          ..attribN="<%=(String)req.getParameter(param1)%>"/> 

The attributes are similar to parameter names for the tag handler class supporting this tag, with the attribute values being the parameter values. A code snippet is given here:

 Book Name: <myTagPrefix:bookName book displayFontName="arial"/>  

The preceding code snippet shows that the bookName tag is a part of the tag library whose prefix is myTagPrefix. The bookName tag is parsed by the JSP engine; the Java tag handler class mapped to this tag is invoked. Two attributes, bookID with the value 123 and displayFont with the value Arial, are passed to the tag handler class. The methods doStartTag(), doEndTag(), and release() of the tag handler Java class are invoked by the JSP engine. In addition to these methods, two other methods are used for each attribute defined in the custom tag: setAttributeXXX() and getAttributeXXX(). These methods enable setting and retrieving the values passed for these attributes in the tag handler class.

The output generated by the methods doStartTag() and doEndTag() is put in place of the custom tag in the output generated for the JSP. If the doStartTag() method generates Teach Yourself WebLogic in 21 Days as the output retrieved for bookID 123, this will be placed in the JSP output. In addition, the output will be formatted with the font HTML tag. The name of the font is the other parameter passed to the tag handler class. The final JSP output will be as follows:

 Book Name: <font name="arial">Teach Yourself WebLogic in 21 Days</font>  
The doStartTag() Method

The doStartTag() method of the tag handler for the simple custom tag with attributes functions similarly to the simple custom tag type. The method also returns the constant SKIP_BODY at the end of the processing because no body exists for the simple custom tag with attributes. A code snippet is given here:

 ...  public int doStartTag() throws JspException {     pageContext.getOut().print("<font name=" + displayFontName +">" +             retBookName + "</font>");     return SKIP_BODY; } ... 

In the preceding code snippet you are printing in the JSP output, the value of the variable displayFontName set by the attribute in the custom tag. The variable retBookName is a local variable of the tag handler class whose value is retrieved from a hashtable of book IDs and book names. The book name is retrieved by passing the attribute bookID. The value for the bookID attribute is also specified in the custom tag. Hence, customize the output generated by the tag handler based on the attributes and their values that was set in the custom tag in the JSP.

The doEndTag() Method

The doEndTag() performs similarly to the doEndTag() that was discussed for the simple custom tag. The doEndTag() method returns the constant EVAL_PAGE:

 ...  public int doEndTag() throws JspException {     return EVAL_PAGE; } ... 
The setAttrib1..N() Method

The setAttribute1..N() method is used by the tag handler to set the value of the attribute passed by the custom tag. This enables the customization and change in processing of the tag handler class by the custom tag. A code snippet is given here:

 ...  private String bookID = null; private String displayFontName = null; private String retBookName = null; // setter method for the bookID attribute public void setBookID(String inpVal) throws JspException {     bookID = inpVal;     // based on the input bookID value,     //retrieve the retBookName from the hashtable bookList     retBookName = (String)bookList.get(bookID); } // setter method for the displayFontName attribute public void setDisplayFontName(String inpVal) throws JspException {     displayFontName = inpVal; } ... 
The getAttrib1..N() Method

The getAttribute1..N() method is used to retrieve values of an attribute to the custom tag. A code snippet is given here:

 ...  // continuing the previous code snippet // getter method for the bookID attribute public String getBookID() throws JspException {     return bookID; } // getter method for the displayFontName attribute public String getDisplayFontName() throws JspException {     return displayFontName; } ... 
Simple Custom Tag with Attributes: Defining Scripting Variables

A variation of the simple custom tag with attributes is the ability to instantiate a scripting variable whose value is initialized by the tag handler class. The scripting variable can then be used as any other scripting variable in any scriptlet or expression tags in the JSP page. This type of tag behaves exactly like the simple custom tag with attributes. A tag handler for this tag type either implements the methods of the Tag interface or extends the TagSupport class.

The structure of this tag is similar to the structure of the simple custom tag with attributes with one important variation, the use of the id and type attributes:

 <tagPrefix:tagName  type="myClassName" attribute1="value1"          attribute2="value2" .../> 

Recall from the previous day's session that the id attribute for the useBean tag was used to define a variable and the type attribute indicates the data type of the variable. A code snippet is given here:

 <tagPrefix:tagName  type="java.lang.String" book/>  <%     // use the scriptVarObj created by the class "tagName"     //from the above custom tag     Obj myObj = bookNameObj ... %> 

In your code snippet, the bookNameObj variable of String data type is created by the tag handler as a result of passing the bookID attribute to the custom tag. The bookNameObj is then used as a normal scripting variable in the scriptlet shown in the code snippet.

Methods

The doStartTag() and doEndTag() methods behave exactly like those discussed earlier for the simple tag with attributes.

Custom Tag with Body: Noninteractive

Until now you have seen custom tags with no explicit start and end tags. Hence, you did not utilize the doEndTag() method. The custom tag with body has, as the name suggests, enclosing start and end tags with a body of content between the tags. But the tag handler implementing this tag does not in any way read or modify the body contents between the start and end tags; hence, it is called noninteractive. A tag handler for this tag type either implements the methods of the Tag interface or extends the TagSupport class.

The structure of this tag is as follows:

 <tagPrefix:tagName>  <%=paramBody1%> <%=paramBody2%> <%=paramBody3%> </tagPrefix:tagName> 

Because this tag type does not interact with the body contents between the start and end tags, the body contents remain unchanged.

Methods

The custom tag with a noninteractive body tag implements the doStartTag(), doEndTag(), and release() methods which were discussed earlier. Hence, these methods will not be discussed again. Consider this tag to be a different representation of the simple custom tag type.

Custom Tag with Body: Interactive

The most useful and most powerful tag in the JSP custom tag library is the custom tag that interacts (reads and modifies) the body content in the tags. A tag handler for this tag type either implements the methods of the BodyTag interface or extends the BodyTagSupportTag class. This tag type is extremely useful when any iterative actions have to be performed, such as reading the retrieved data from a database result set, a Vector, or a collection of values.

The tag's structure is as follows:

 <tagPrefix:tagName>      <% ... //scriptlet statements that retrieve the data sent by the // tag handler using the getAttribute() method of the // pageContext implicit variable     %>     <%     // Use the returned value to modify the body content     %> </tagPrefix:tagName> 

A code snippet is given shortly. The bookName is retrieved from the pageContext using the getAttribute() method which returns the value for the myCustomTagVar. The custom tag handler sets the value for the myCustomTagVar variable using the setAttribute() method of the pageContext implicit variable in the doAfterBody() method:

 <tagPrefix:tagName>  <% bookName = pageContext.getAttribute("myCustomTagVar"); %> Book Name: "<%=bookName%>" <% </tagPrefix:tagName> 
The doStartTag() Method

The doStartTag() method is similar to the doStart() tag method for the tag types discussed previously. The major difference for this tag type is that the doStartTag() method returns the constant EVAL_BODY_TAG. This indicates to the JSP engine that the body content needs to be evaluated. Hence, the JSP invokes the doInitBody() and doAfterBody() methods after invoking the doStartTag() method.

The doInitBody() Method

The doInitBody() method is invoked when the doStartTag() method returns an EVAL_BODY_TAG. The JSP engine calls this method before evaluating the body contents. This makes it most useful to perform any initialization required before processing of the body contents begins. The doInitBody() method is invoked only once.

The doAfterBody() Method

The doAfterBody() method is invoked multiple times as long as this method returns the constant value EVAL_BODY_TAG. The invoking of the doAfterBody() method stops when this method returns the constant value SKIP_BODY_TAG.

The doEndTag() Method

The doEndTag() method is similar to the doEndTag() method that was discussed earlier.

The release() Method

The release() method is similar to the release() method that was discussed earlier.

Cooperating Custom Tags

Intercommunication between custom tags on the same page is possible with shared objects as long as the object references are used correctly.

Such tags use the following two structure types:

 <tagPrefix:tagName1  type="myPackage.myClass"          attrib1="value1"/> <tagPrefix:tagName2 attrib2="scriptVarObj" /> 

You can see that the first tag creates an object scriptVarObj using the Simple Custom Tag with Attributes: Defining Scripting Variables tag type. The second tag uses the scriptVarObj shared object as an input attribute and uses it for processing.

Methods

These tags have the same doStartTag(), doEndTag(), release(), doInitBody(), and doAfterBody() methods as seen previously.

Tag Handler Interfaces and Classes

In order to provide the functionality behind a custom tag, you need to write a special class called the tag handler. The JSP engine communicates with the tag handler via two special interfaces: Tag interface and TagBody interface. If the custom tag has body content and interacts with it, then you should use the TagBody interface. For all other custom tag types, the Tag interface is sufficient. These two tag interfaces are the design contract between the JSP engine and the custom tag handler class. This means that these interfaces are the well defined interfaces for communication, that is, the passing of data between the JSP engine and the tag handler.

A tag handler class using the TagBody interface or the BodyTagSupport class extensively uses the pageContext implicit variable. To get a handle to write to the JSP's output stream, the tag handler can invoke the getOut() method of the pageContext variable. The getOut() method returns the JspWriter object, which is a reference to the output stream.

Tag Interface

The Tag interface contains the doStartTag(), doEndTag(), and release() methods. The custom tag handler must implement all the methods of the Tag interface:

  • The doStartTag() method is called by the JSP engine on the first occurrence of the custom tag in the JSP. This method must return the SKIP_BODY_TAG constant because the custom tag does not have a body.

  • The doEndTag() method is called by the JSP engine at the end of the custom processing. This method is called once the doStartTag() method returns the SKIP_BODY_TAG constant value.

  • The release() method can be used to perform any cleanup of resources used by the tag handler class. The JSP engine guarantees execution of the release() method.

The Tag interface should be used in cases where your existing Java class already has the functionality and needs to be converted into a tag handler class. For this, the Java class just needs to implement the Tag interface to convert it into a custom tag handler!

TagSupport Class

The TagSupport class provides default implementations for all the methods of the Tag interface. The methods implemented by the TagSupport class are

  • doStartTag()

  • doEndTag()

  • release()

Your tag handler class can extend the TagSupport class and override the doStartTag(), doEndTag(), and release() methods as required. The TagSupport class is normally used when you are developing a brand-new custom tag handler. For existing classes that need to be converted into a tag handler, it may not be possible to extend from the TagSupport class if the existing class already extends from another class. Remember, Java does not support multiple inheritance!

TagBody Interface

The TagBody interface is implemented by custom tag handlers for custom tags with body content. The TagBody interface contains the methods doStartTag(), doEndTag(), and release() that are present in the Tag interface. In addition, there are two other methods in the TagBody interface: the doInitBody() and doAfterBody() methods. You have already seen the doStartTag(), doEndTag(), and release() methods. The only variation for the doStartTag() method is that the custom tag handler implementing this method needs to return the constant value EVAL_BODY_TAG if it needs to process and modify the body content. The custom tag handler implementing the BodyTag interface can perform powerful and repetitive processing using the BodyTag interface. Now look at the doInitBody() and doAfterBody() methods.

The doInitBody() Method

The doInitBody() method is called by the JSP engine on the first occurrence of the custom tag with body content. If the doStartTag() method returns the constant value EVAL_BODY_TAG, the JSP engine invokes the doInitBody() method before evaluating the statements in the body content. The doInitBody() method is normally used for the initialization of variables or resources used in the doAfterBody() method. The doInitBody() method is invoked only once by the JSP engine.

The doAfterBody() Method

The doAfterBody() method is called by the JSP engine after evaluating the statements in the body content. The doAfterBody() method is where the major processing takes place in the custom tag handler. The special feature of the doAfterBody() method is that it is called recurrently by the JSP engine as long as the method returns the constant value EVAL_BODY_TAG. When the doAfterBody() method returns the constant value SKIP_BODY_TAG, the JSP engine stops invocation of this method and executes the doEndTag() method of the custom tag handler.

The doAfterBody() method can interact with the body contents using the pageContext implicit variable. The pageContext object provides the getAttribute() and setAttribute() methods to enable the custom tag handler to retrieve and set values for the body content. The contents of the body within the tag can be accessed using the bodyContent object. To write to the JSP's output stream, the doAfterBody() method uses the getOut() method of the pageContext object. The getOut() method returns a reference to the JspWriter object.

BodyTagSupport Class

The BodyTagSupport class provides the default implementation for all the methods of the BodyTag interface. If a new custom tag handler is to be developed, then it should ideally extend the BodyTagSupport class and override the doStartTag(), doEndTag(), doInitBody(), doAfterBody(), and release() methods.

Tag Library Descriptor

A tag library descriptor (TLD) file is used to register the details about the tag handler class. Ideally, you should begin the development of your custom tag by defining the details and structure of the tag in the TLD file. This gives you an idea of what tag handler class needs to be developed and the attributes (if any) required for the custom tag and the tag handler. A TLD file is essentially an XML file where the tag handler information can be listed using the predefined tags as in the JSP specification.

Look at the different tags available in the TLD file:

  • <taglib></taglib> The enclosing tags for all the predefined tags in the TLD file. All the tags discussed after this will be nested within the <taglib></taglib> tags. This is a mandatory tag.

  • <tlib-version></tlib-version> Used to define a version number for the tag library. This is a mandatory tag.

  • <jsp-version>1.2</jsp-version> Defines the version number of the JSP specification with which the tag library is compatible. The default value is 1.2, indicating that the tag library is compatible with the JSP 1.2 specification. This is a mandatory tag.

  • <shortname></shortname> Defines a short name for the tag library. The name defined in the shortname tag is used as a reference handle for any tags or variables defined or created by the tag library. This is a mandatory tag.

  • <uri></uri> Defines the location of the tag handler classes or the Java archive/Web application archive. This is a mandatory tag.

  • <tag></tag> The enclosing tags for the entire information related to the tag. You can define multiple <tag></tag> tags within the <taglib></taglib> tags. Now look at the different tags available within the <tag></tag> tags.

    • <name></name> Defines the name of the tag. The name defined in these tags is used in the JSP along with the name defined in the <shortname></shortname> tags. This is a mandatory tag.

    • <tagclass></tagclass> Defines the fully qualified class name of the tag handler class. The tag handler class implements the actual functionality behind the custom tag. This is a mandatory tag.

    • <attribute></attribute> Defines any optional attributes for the custom tag. The attributes for a custom tag listed here are used in the JSP along with the custom tag and processed by the tag handler. The <attribute></attribute> tags enclose two optional tags within them, the <required></required> tags and the <rtexprvalue></rtexprvalue> tags. The <required> and <rtexpvalue> tags are used to indicate whether or not the attribute is required. By default, these tags have the value false.

taglib Directive

The taglib directive is used in the JSP page to indicate to the JSP engine which custom tag library is used in the JSP. The structure of the taglib directive is given here:

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

The taglib directive has two attributes, uri and prefix. The uri attribute takes the relative URL path of the custom tag library whose tags will be used in the JSP. The other attribute is the prefix, whose value is used within the JSP as a handle to the tags of the tag library in the JSP.



Sams Teach Yourself BEA WebLogic Server 7. 0 in 21 Days
Sams Teach Yourself BEA WebLogic Server 7.0 in 21 Days
ISBN: 0672324334
EAN: 2147483647
Year: 2002
Pages: 339

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net