Tag ReuseResin 3.0
Resin 3.0

Features
Installation
Configuration
Web Applications
IOC/AOP
Resources
JSP
Servlets and Filters
Portlets
Databases
Admin (JMX)
CMP
EJB
Amber
EJB 3.0
Security
XML and XSLT
XTP
JMS
Performance
Protocols
Third-party
Troubleshooting/FAQ

Introduction
JSP Compilation
Reference
Tutorials
Articles
FAQ

JSP Page Creation
Request
Topics
Tag Libraries

Tag Reuse
Hello Tag
Tag Attributes
Mail Tag
Tag Files
Tag Libraries
Tag Libraries
Hello Tag

Find this tutorial in: /usr/local/resin/webapps/resin-doc/jsp/tutorial/taglib-reuse
Try the Tutorial

Tag libraries must follow important conventions for initializing tag fields. The JSP specification lets a JSP container, like Resin, reuse tag handler instances for efficiency and performance. Because this optimization restricts how tags can use fields, even experienced developers will benefit from this tutorial.

  1. Files in this tutorial
  2. Resin reuses tag handler instances
    1. Lifecycle
  3. Treat attributes as read-only
  4. Initializing member variables in doStartTag
  5. Initializing member variables in doEndTag
  6. Default values for attributes

Files in this tutorial

index.jsp The jsp page that uses the tags
WEB-INF/message.tld The taglib descriptor
WEB-INF/classes/example/taglib/MessageTag.java The class corresponding to <msg:message>
WEB-INF/classes/example/taglib/MessageAddTag.java The class corresponding to <msg:add>, used within the body of <msg:message>

Resin reuses tag handler instances

tag handler instance
An instance of the class that is associated with an xml-style custom JSP tag.

Resin aggressively reuses tag handler instances. Any tag with the same set of attributes is a candidate for reuse. For example, a tag <msg:message> with an attribute title="Test-1" may share the same tag handler instance as a <msg:message> with an attribute title="Test-2".

This ability for Resin to reuse instances of the tag handler is described in the JSP specification.

From the JSP 2.0 specification: "The JSP container may reuse classic tag handler instances for multiple occurrences of the corresponding custom action, in the same page or in different pages, but only if the same set of attributes are used for all occurrences."

In this tutorial, the <msg:message> prints its id to show the instance of the object that is created.

See it in: index.jsp
  <msg:message title="Test Message">
    <msg:add text="Hello"/>
    <msg:add text="World"/>
  </msg:message>

  <msg:message>
    <msg:add text="Hello Again"/>
    <msg:add text="World"/>
  </msg:message>

  <msg:message title="Test Message">
    <msg:add text="Goodbye"/>
    <msg:add text="World"/>
  </msg:message>

The instance created for the first <msg:message> tag, MessageTag@10000, is reused for the third <msg:message> tag. Resin can reuse the tag handler instance the attributes set for the first and third objects are the same: {title}. The second tag uses a new instance, MessageTag@100000, because it has a different attribute set: {text}.

 +--------------------------------------------+
 | instance: example.taglib.MessageTag@10000  |
 |--------------------------------------------|
 | Test Message                               |
 |--------------------------------------------|
 | Hello                                      |
 | World                                      |
 +--------------------------------------------+

 +---------------------------------------------+
 | instance: example.taglib.MessageTag@29000   |
 |---------------------------------------------|
 | default title                               |
 |---------------------------------------------|
 | Hello Again                                 |
 | World                                       |
 +---------------------------------------------+

 +--------------------------------------------+
 | instance: example.taglib.MessageTag@10000  |
 |--------------------------------------------|
 | Test Message                               |
 |--------------------------------------------|
 | Goodbye                                    |
 | World                                      |
 +--------------------------------------------+

Lifecycle

  1. Handle the first <msg:message> tag:
    1. Instantiate the tag handler instance, MessageTag@9681e0
    2. Set the attributes, setTitle("Test Message")
    3. Call the doStartTag method.
    4. Process the contents
    5. Call the doEndTag method.
  2. Handle the second <msg:message> tag
  3. Handle the third <msg:message> tag:
    1. Set any attribute values which differ from the first tag. In this case, all the values are the same the same, so Resin doesn't call any setter.
    2. Call the doStartTag method.
    3. Process the contents
    4. Call the doEndTag method.
  4. At the end of the page, clean up the tag handler instances:
    1. Call release() for the first instance, MessageTag@10000
    2. Call release() for the second instance, MessageTag@29000
    3. Call release() for the <msg:add> instances.

Resin does not call release() between the first and third <msg:message> tags. It only calls release() at the end of the page. This behavior follows the JSP spec, but surprises some tag library developers.

Treat attributes as read-only

Since tag handler instances are reused, the fields corresponding to tag attributes must be read-only. Only Resin may call the attribute setters; the tag's code must never modify the corresponding fields.

See it in: WEB-INF/classes/example/taglib/MessageTag.java
  /* tag attributes
   *
   * member variables to store the value of tag attributes are treated
   * as read-only.  Resin will set the values using setXXXX() based on
   * the values passed as attributes to the tag, and the code in the
   * class will never change the values.
   */
  private String _attrTitle;
  
  public void setTitle(String title) 
  {
    // this is the only place where _attrTitle is ever set
    _attrTitle = title;
  }

Initializing member variables in doStartTag

Tags must initialize internal variables in the first action method called, for example doStartTag. Because of tag instance reuse, the tag must assume that all internal variables are unset, i.e. set to unknown, bogus values. The initialization code must initialize those values.

Often in a tag it is necessary to have additional member variables other than those that hold the value of tag attributes. In this case, the only safe way to initialize the variables is in the doStartTag(), before anything else is done.

Because the tag instance will be reused, you cannot simply initialize the tag in the constructor. And, because the release() method is only called at the end of the page, the tag cannot call initialization code in the release() method. There may be many calls to doStartTag() and doEndTag() before release() is called.

In this tutorial, an init() method is used for initialization of these internal member variables, and a call to init() is the first thing done in doStartTag().

See it in: WEB-INF/classes/example/taglib/MessageTag.java
  String _title;
  StringBuffer _msg;

  void init()
  {
    _title = _attrTitle;
    if (_title == null)
      _title = "Default Title";

    _msg = new StringBuffer();

  }

  public int doStartTag() 
    throws JspException 
  {
    // initialize internal member variables
    init();

    return EVAL_BODY_BUFFERED;
  }

Initializing member variables in doEndTag

Tag libraries need to initialize their variables in the first tag method called. Most often, this will be in doStartTag, but some tags only implement doEndTag. Tags which only have a doEndTag may initialize in doEndTag.

Because Resin can analyze which methods are implemented by a tag and generated better code for the default TagSupport methods, it's a good idea to only implement those tag methods which are absolutely necessary.

Default values for attributes

If an attribute of a tag is not used, the corresponding setter will not be called. In many causes you will want to provide a default value for the attribute, and then the default value will be dependent on other member variables. Even though it is not always necessary, the best way to set a default value for a missing attribute is the same way the internal member variables are set in the previous example.

See it in: WEB-INF/classes/example/taglib/MessageTag.java
  // read-only attribute field
  private String _attrTitle;

  // tag field initialized by init()
  private String _title;
  
  public void setTitle(String title) 
  {
    _attrTitle = title;
  }

  public int doStartTag() 
    throws JspException 
  {
    // initialize internal member variables
    init();

    ... // main tag processing

    return EVAL_BODY_BUFFERED;
  }

  protected void init()
  {
    _title = _attrTitle;
    if (_title == null)
      _title = "Default Title";

    _msg = new StringBuffer();
  }

Try the Tutorial


Tag Libraries
Tag Libraries
Hello Tag
Copyright © 1998-2005 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark, and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc.