BEA Home | Events | Solutions | Partners | Products | Services | Download | Developer Center | WebSUPPORT
| WebLogic Server Doc Home | JSP Tag Extensions | Previous Topic | Next Topic | Contents | Index | View as PDF

Implementing the Tag Handler

The following sections describe how to write Java classes that implement the functionality of an extended tag:

- Tag Handler API

- Tag Handler Life Cycle

- Iteration Over a Body Tag

- Handling Exceptions within a Tag Body

- Using Tag Attributes

- Defining New Scripting Variables

- Writing Cooperative Nested Tags

- Using a Tag Library Validator

Tag Handler API

The JSP 1.1 API defines a set of classes and interfaces that you use to write custom tag handlers. Documentation for the `javax.servlet.jsp.tagext` API is available at http://java.sun.com/j2ee/j2sdkee/techdocs/api/index.html.

Your tag handler must implement one of two interfaces:

  `Tag`

  Implement the `javax.servlet.jsp.tagext.Tag` interface if your custom tag is an empty-body tag. The API also provides a convenience class `TagSupport` that implements the `Tag` interface and provides default empty methods for the methods defined in the interface.

  `BodyTag`

  Implement the `javax.servlet.jsp.tagext.BodyTag` interface if your custom tag needs to use a body. The API also provides a convenience class `BodyTagSupport` that implements the `BodyTag` interface and provides default empty methods for the methods defined in the interface. Because `BodyTag` extends `Tag` it is a super set of the interface methods.

Tag Handler Life Cycle

The methods inherited from either the `Tag` or `BodyTag` interfaces and implemented by the tag handler class are invoked by the JSP engine at specific points during the processing of the JSP page. These methods signify points in the life cycle of a tag and are executed in the following sequence:

1. When the JSP engine encounters a tag in a JSP page, a new tag handler is initialized. The `setPageContext()` and `setParent()` methods of the `javax.servlet.jsp.tagext.Tag` interface are invoked to set up the environment context for the tag handler. As a tag developer, you need not implement these methods if you extend the `TagSupport` or `BodyTagSupport` base classes.

2. The `setXXXX()` JavaBean-like methods for each tag attribute are invoked. For more details, see Handling Exceptions within a Tag Body.

3. The `doStartTag()` method is invoked. You can define this method in your tag handler class to initialize your tag handler or open connections to any resources it needs, such as a database.

   At the end of the `doStartTag()` method, you can determine whether the tag body should be evaluated by returning one of the following value constants from your tag handler class:

   `SKIP_BODY`

     Directs the JSP engine to skip the body of the tag. Return this value if the tag is an empty-body tag. The body-related parts of the tag's life cycle are skipped, and the next method invoked is `doEndTag()`.

   `EVAL_BODY_INCLUDE`

     Directs the JSP engine to evaluate and include the content of the tag body. The body-related parts of the tag's life cycle are skipped, and the next method invoked is `doEndTag()`.

     You can only return this value for tags that implement the `Tag` interface. This allows you to write a tag that can determine whether its body is included, but is not concerned with the contents of the body. You cannot return this value if your tag implements the `BodyTag` interface (or extends the `BodyTagSuport` class).

   `EVAL_BODY_TAG`

     Instructs the JSP engine to evaluate the tag body, then invokes the `doInitBody()` method. You can only return this value if your tag implements the `BodyTag` interface (or extends the `BodyTagSupport` class).

4. The `setBodyContent()` method is invoked. At this point, any output from the tag is diverted into a special `JspWriter` called `BodyContent`, and is not sent to the client. All content from evaluating the body is appended to the `BodyContent` buffer. This method allows the tag handler to store a reference to the `BodyContent` buffer so it is available to the `doAfterBody()` method for post-evaluation processing.

   If the tag is passing output to the JSP page (or the surrounding tag scope if it is nested), the tag must explicitly write its output to the parent-scoped `JspWriter` between this point in the tag life cycle and the end of the `doEndTag()` method. The tag handler can gain access to the enclosing output using the `getEnclosingWriter()` method.

   You do not need to implement this method if you are using the `BodyTagSupport` convenience class, because the tag keeps a reference to the `BodyContent` and makes the reference available through the `getBodyContent()` method.

5. The `doInitBody()` method is invoked. This method allows you to perform some work immediately before the tag body is evaluated for the first time. You might use this opportunity to set up some scripting variables, or to push some content into the `BodyContent` before the tag body. The content you prepend here will not be evaluated as JSP—unlike the tag body content from the JSP page.

   The significant difference between performing work in this method and performing work at the end of the `doStartTag()` method (once you know you are going to return `EVAL_BODY_TAG`) is that with this method, the scope of the tag's output is nested and does not go directly to the JSP page (or parent tag). All output is now buffered in a special type of `JspWriter` called `BodyContent`.

6. The `doAfterBody()` method is invoked. This method is called after the body of the tag is evaluated and appended to the `BodyContent` buffer. Your tag handler should implement this method to perform some work based on the evaluated tag body. If your handler extends the convenience class `BodyTagSupport`, you can use the `getBodyContent()` method to access the evaluated body. If you are simply implementing the `BodyTag` interface, you should have defined the `setBodyContent()` method where you stored a reference to the `BodyContent` instance.

   At the end of the `doAfterBody()` method, you can determine the life cycle of the tag again by returning one of the following value constants:

   `SKIP_BODY`

     Directs the JSP engine to continue, not evaluating the body again. The life cycle of the tag skips to the `doEndTag()` method.

   `EVAL_BODY_TAG`

     Directs the JSP engine to evaluate the body again. The evaluated body is appended to the `BodyContent` and the `doAfterBody()` method is invoked again.

   At this point, you may want your tag handler to write output to the surrounding scope. Obtain a writer to the enclosing scope using the `BodyTagSupport.getPreviousOut()` method or the `BodyContent.getEnclosingWriter()` method. Either method obtains the same enclosing writer.

   Your tag handler can write the contents of the evaluated body to the surrounding scope, or can further process the evaluated body and write some other output. Because the `BodyContent` is appended to the existing `BodyContent` upon each iteration through the body, you should only write out the entire iterated body content once you decide you are going to return `SKIP_BODY`. Otherwise, you will see the content of each subsequent iteration repeated in the output.

7. The `out` writer in the `pageContext` is restored to the parent `JspWriter`. This object is actually a stack that is manipulated by the JSP engine on the `pageContext` using the `pushBody()` and `popBody()` methods. Do not, however, attempt to manipulate the stack using these methods in your tag handler.

8. The `doEndTag()` method is invoked. Your tag handler can implement this method to perform post-tag, server side work, write output to the parent scope `JspWriter`, or close resources such as database connections.

   Your tag handler writes output directly to the surrounding scope using the `JspWriter` obtained from `pageContext.getOut()` in the `doEndTag()` method. The previous step restored `pageContext.out` to the enclosing writer when `popBody()` was invoked on the `pageContext`.

   You can control the flow for evaluation of the rest of the JSP page by returning one of the following values from the `doEngTag()` method:

   `EVAL_PAGE`

     Directs the JSP engine to continue processing the rest of the JSP page.

   `SKIP_PAGE`

     Directs the JSP engine to skip the rest of the JSP page.

9. The `release()` method is invoked. This occurs just before the tag handler instance is de-referenced and made available for garbage collection.

Iteration Over a Body Tag

A tag that implements the `javax.servlet.jsp.tagext.IterationTag` interface, has a method available called `doAfterBody()` that allows you to conditionally re-evaluate the body of the tag. If `doAFterBody()` returns `IterationTag.EVAL_BODY_AGAIN` , the body is re-evaluated, if `doAFterBody()` returns `Tag.SKIP_BODY` , the body is skipped and the `doEndTag()` method is called. For more information, see the J2EE Javadocs for this interface. (You can download the Javadocs from Sun Microsystems at http://java.sun.com/products/jsp/download.html.)

Note: The `IterationTag` interface is a new feature of the JSP 1.2 specification from Sun Microsystems. Version 1.2 of the specification is a proposed final draft of the specification and is subject to change. If you are planning to use JSP 1.2 features in your application, note that the specification has not been finalized and could change in the future.

Handling Exceptions within a Tag Body

You can catch exceptions thrown from within a tag by implementing the `doCatch()` and `doFinally()` methods of the `javax.servlet.jsp.tagext.TryCatchFinally` interface. For more information, see the J2EE Javadocs for this interface. (You can download the Javadocs from Sun Microsystems at http://java.sun.com/products/jsp/download.html.)

Note: The `TryCatchFinally` interface is a new feature of the JSP 1.2 specification from Sun Microsystems. Version 1.2 of the specification is a proposed final draft of the specification and is subject to change. If you are planning to use JSP 1.2 features in your application, note that the specification has not been finalized and could change in the future.

Using Tag Attributes

Your custom tags can define any number of attributes that can be specified from the JSP page. You can use these attributes to pass information to the tag handler and customize its behavior.

You declare each attribute name in the TLD, in the `<attribute>` element. This declares the name of the attribute and other attribute properties.

Your tag handler must implement setter and getter methods based on the attribute name, similar to the JavaBean convention. For example, if you declare an attribute named `foo`, your tag handler must define the following public methods:

>     public void setFoo(String f);
>     public String getFoo();

Note that the first letter of the attribute name is capitalized after the set/get prefix.

The JSP engine invokes the setter methods for each attribute appropriately after the tag handler is initialized and before the `doStartTag()` method is called. Generally, you should implement the setter methods to store the attribute value in a member variable that is accessible to the other methods of the tag handler.

Defining New Scripting Variables

Your tag handler can introduce new scripting variables that can be referenced by the JSP page at various scopes. Scripting variables can be used like implicit objects within their defined scope.

Define a new scripting variable by using the `<teiclass>` element to identify a Java class that extends `javax.servlet.jsp.tagext.TagExtraInfo`. For example:

>     <teiclass>weblogic.taglib.session.ListTagExtraInfo</teiclass>

Then write the `TagExtraInfo` class. For example:

>     package weblogic.taglib.session;
>     import javax.servlet.jsp.tagext.*;

>     public class ListTagExtraInfo extends TagExtraInfo {

>       public VariableInfo[] getVariableInfo(TagData data) {
>         return new VariableInfo[] {
>                new VariableInfo("username",
>                                 "String",
>                                 true,
>                                 VariableInfo.NESTED),
>                new VariableInfo("dob",
>                                 "java.util.Date",
>                                 true,
>                                 VariableInfo.NESTED)
>              };
>       }
>     }

The example above defines a single method, `getVariableInfo()`, which returns an array of `VariableInfo` elements. Each element defines a new scripting variable. The example shown above defines two scripting variables called `username` and `dob`, which are of type `java.lang.String` and `java.util.Date`, respectively.

The constructor for `VariableInfo()` takes four arguments.

- A `String` that defines the name of the new variable.

- A `String` that defines the Java type of the variable. Give the full package name for types in packages other than the `java.lang` package.

- A `boolean` that declares whether the variable must be instantiated before use. Set this argument to "true" unless your tag handler is written in a language other than Java.

- An `int` declaring the scope of the variable. Use a static field from `VariableInfo` shown here:

  `VariableInfo.NESTED`

    Available only within the start and end tags of the tag.

  `VariableInfo.AT_BEGIN`

    Available from the start tag until the end of the page.

  `VariableInfo.AT_END`

    Available from the end tag until the end of the page.

Configure your tag handler to initialize the value of the scripting variables via the page context. For example, the following Java source could be used in the `doStartTag()` method to initialize the values of the scripting variables defined above:

>     pageContext.setAttribute("name", nameStr);
>     pageContext.setAttribute("dob", bday);

Where the first parameter names the scripting variable, and the second parameter is the value assigned. Here, the Java variable `nameStr` is of type `String` and `bday` is of type `java.util.Date`.

You can also access variables created with the `TagExtraInfo` class by referencing it the same way you access a JavaBean that was created with `useBean`.

Dynamically Named Scripting Variables

It is possible to define the name of a new scripting variable from a tag attribute. This definition allows you to use multiple instances of a tag that define a scripting variable at the same scope, without the scripting variables of the tag clashing. In order to achieve this from your class that extends `TagExtraInfo`, you must get the name of the scripting variable from the `TagData` that is passed into the `getVariableInfo()` method.

From `TagData`, you can retrieve the value of the attribute that names the scripting variable using the `getAttributeString()` method. There is also the `getId()` method that returns the value of the `id` attribute, which is often used to name a new implicit object from JSP tag.

Defining variables in the Tag Library Descriptor

You can define variables in the TLD. For more information, see Define scripting variables (optional)." on page 3-5.

Writing Cooperative Nested Tags

You can design your tags to implicitly use properties from tags they are nested within. For example, in the code example called SQL Query (see the `samples/examples/jsp/tagext/sql` directory of your WebLogic Server installation) a `<sql:query>` tag is nested within a `<sql:connection>` tag. The query tag searches for a parent scope connection tag and uses the JDBC connection established by the parent scope.

To locate a parent scope tag, your nested tag uses the static `findAncestorWithClass()` method of the `TagSupport` class. The following is an example taken from the `QueryTag` example.

>     try {
>       ConnectionTag connTag = (ConnectionTag)
>         findAncestorWithClass(this,
>           Class.forName("weblogic.taglib.sql.ConnectionTag"));
>       } catch(ClassNotFoundException cnfe) {
>         throw new JspException("Query tag connection "+
>                                "attribute not nested "+
>                                "within connection tag");
>     }

This example returns the closest parent tag class whose tag handler class matched the class given. If the direct parent tag is not of this type, then it is parent is checked and so on until a matching tag is found, or a `ClassNotFoundException` is thrown.

Using this feature in your custom tags can simplify the syntax and usage of tags in the JSP page.

Using a Tag Library Validator

Note: The JSP Tag Library Validator is a new feature of the JSP 1.2 specification from Sun Microsystems. Version 1.2 of the specification is a proposed final draft of the specification and is subject to change. If you are planning to use JSP 1.2 features in your application, note that the specification has not been finalized and could change in the future.

A Tag Library Validator is a user-written Java class that you can use to perform custom validation on a JSP page. The validator class takes the entire JSP page as an input stream and you can validate the page based on criteria that you write into the validator class. A common use of a validator is to use an XML parser in the validator class to validate the page against a document type definition (DTD). The validator class is called at page translation time (when the JSP is converted to a servlet) and returns a `null` string if the page is validated or a string containing error information it the validation fails.

To implement a Tag Library Validator:

1. Write the validator class. A validator class extends the `javax.servlet.jsp.tagext.TagLibraryValidator` class.

2. Reference the validator in the tag library descriptor. For example:

       <validator>
         <validator-class>
                 myapp.tools.MyValidator
           </validator-class>
       </validator>

3. (Optional) Define initialization parameters. Your validator class can get and use initialization parameters. For example:

       <validator>
         <validator-class>
                 myapp.tools.MyValidator
           </validator-class>
           <init-param>
                 <param-name>myInitParam</param-name>
                 <param-value>foo</param-value>
           </init-param>
       </validator>

4. Package the validator class in the `WEB-INF/classes` directory of a Web Application.You can also package the classes in a tag library jar file; for more information, see Deploying a JSP Tag Library as a JAR File" on page 5-2

Copyright © 2001 BEA Systems, Inc. All rights reserved. Required browser: Netscape 4.0 or higher, or Microsoft Internet Explorer 4.0 or higher.