A tag handler is a runtime server-side object that is created to help evaluate actions during the execution of a JSP page. A tag handler supports a runtime protocol that facilitates passing information from the JSP page to the handler. A tag handler is a server-side invisible JavaBeans component, but it implements an additional interface to indicate that it has a richer runtime protocol. There are two interfaces that describe a tag handler: Tag is used for simple tag handlers that are not interested in manipulating their body content (if any); BodyTag is an extension of Tag and gives a tag handler access to its body. The TagSupport and BodyTagSupport classes can be used as base classes when creating new tag handlers. JSP.5.4.1 PropertiesA tag handler has some properties that are set by the JSP container (usually through the JSP page implementation class) using setter methods :
A tag handler may have additional properties, as any other JavaBean component. These properties will have setters and getter methods, as described in the JavaBeans component specification and used throughout the Java platform. All attributes of a custom action must be JavaBeans component properties, although some properties may not be exposed as attributes in the tag library descriptor. Additional translation time information ( TagExtraInfo ) associated with the action indicates the name of the variables it introduces, their types, and their scope. At specific moments (after processing the start tag; after processing the end tag), the JSP container can automatically synchronize the PageContext information with variables in the scripting language so they can be made available directly through the scripting elements. JSP.5.4.2 Basic Protocol: Tag InterfaceThis section describes the Tag interface which defines the basic contract for all tag handlers. See Section JSP.5.4.7 for a summary of the life-cycle issues. A tag handler has some properties that must be initialized before it can be used. It is the responsibility of the JSP container to invoke the appropriate setter methods to initialize these properties. Once properly set, these properties are expected to be persistent, so that if the JSP container ascertains that a property has already been set on a given tag handler instance, it need not set it again. These properties include the properties in the Tag interface as well as other properties. Once initialized, the doStartTag and doEndTag methods can be invoked on the tag handler. Between these invocations, the tag handler is assumed to hold a state that must be preserved. After the doEndTag invocation, the tag handler is available for further invocations (and it is expected to have retained its properties). Once all invocations on the tag handler are completed, the release method is invoked on it. Once a release method is invoked, all properties are assumed to have been reset to an unspecified value. PropertiesAll tag handlers must have the following properties: pageContext and parent . When setting properties, the order is always pageContext and parent . The Tag interface specifies the setter methods for all properties and the getter method for parent.
MethodsThere are two main action methods and one method for releasing all resources owned by a tag handler.
Simple Actions with Non-Empty BodiesIf a tag library descriptor maps an action with a non-empty body to a tag handler that implements the Tag interface, the tag handler cannot manipulate this body because there is no mechanism for the tag handler to access that body. To make the situation more explicit, the return value of doStartTag is either SKIP_BODY , EVAL_BODY_INCLUDE or EVAL_BODY_TAG . The meanings are as follows :
A typical use for EVAL_BODY_INCLUDE could be a conditional inclusion action tag. Since the body is to be passed through directly, there is no need for the tag handler to manipulate it, and thus the tag handler need not implement BodyTag . To help in catching errors, EVAL_BODY_INCLUDE is not valid in a tag handler that implements BodyTag , while EVAL_BODY_TAG is not valid in a tag handler that implements Tag but does not implement BodyTag . JSP.5.4.3 The TagSupport Base ClassThe TagSupport class is a utility class intended to be used as the base class for new tag handlers. The TagSupport class implements the Tag interface and adds additional convenience methods including getter methods for the properties in Tag . TagSupport has one static method that is included to facilitate coordination among cooperating tags.
The return value of the doStartTag() method is SKIP_BODY . The return value of the doEndTag( ) method is EVAL_PAGE . JSP.5.4.4 Body Protocol: BodyTag InterfaceThe BodyTag interface extends Tag with methods to manipulate the body of an action. These methods act on the bodyContent property of a BodyTag instance. It is the responsibility of the tag handler to manipulate the body content. For example, the tag handler may take the body content, convert it into a String using the bodyContent.getString method, and then use it. Or the tag handler may take the body content and write it out into its enclosing JspWriter using the bodyContent.writeOut method. A tag handler that implements BodyTag is treated as one that implements Tag , except that the doStartTag method can return either SKIP_BODY or EVAL_BODY_TAG , not EVAL_BODY_INCLUDE . If EVAL_BODY_TAG is returned, then a bodyContent object will be created to capture the body evaluation. This object is obtained by calling the pushBody method of the current pageContext , which additionally has the effect of saving the previous out value. The object is returned through a call to the popBody method of the PageContext class; the call also restores the value of out . PropertiesThere is only one additional property: bodyContent
MethodsThere are two action methods:
JSP.5.4.5 The BodyContent ClassThe BodyContent is a subclass of JspWriter that can be used to process body evaluations so they can be retrieved later on. The class has methods to convert its contents into a String , to read its contents, and to clear the contents. The buffer size of a BodyContent object is "unbounded." A BodyContent object cannot be in autoFlush mode. It is not possible to invoke flush on a BodyContent object, as there is no backing stream. This means that it is not legal to do a jsp:include when out is not bound to the top-level JspWriter . Instances of this class are created by invoking the pushBody and popBody methods of the PageContext class. A BodyContent is enclosed within another JspWriter (maybe another BodyContent object) following the structure of their associated actions. The BodyContent type contains four main methods:
JSP.5.4.6 The BodyTagSupport Base ClassThe BodyTagSupport class is a utility class intended to be used as the base class for new tag handlers implementing BodyTag . The BodyTagSupport class implements the BodyTag interface and adds additional convenience methods including getter methods for the bodyContent property and methods to get at the previous out JspWriter . The return value of the doStartTag() method is EVAL_BODY_TAG . The return value of the doEndTag( ) method is EVAL_PAGE . The return value of the doAfterBody() method is SKIP_BODY . JSP.5.4.7 Life-Cycle ConsiderationsAt execution time the implementation of a JSP page will use an available Tag instance with the appropriate prefix and name that is not being used, initialize it, and then follow the protocol described below. Afterwards, it will release the instance and make it available for further use. This approach reduces the number of instances that are needed at a time. Initialization is done by setting the properties pageContext and parent , in that order, while release is done by invoking release() . An Execution TraceThe following example shows the runtime trace for two actions supported by a tag handler implementing BodyTag ; setters are in italics, while actions are not. The inner boxes highlight the portion of the protocol used to interact with the body of the tag. In this example, we are assuming that the second action has the same parent but one different attribute values. h.setPageContext(pageContext); h.setParent(parent); h.setAttribute1(value1); h.setAttribute2(value2);... h.doStartTag() _______________________________________________ out = pageContext.pushBody() h.setBodyContent(out) h.doInitBody() [BODY] h.doAfterBody() .... Body Actions [BODY] h.doAfterBody() ...... out = pageContext.popBody() _______________________________________________ h.doEndTag(); h.setAttribute2(value3); h.doStartTag() _______________________________________________ out = pageContext.pushBody() h.setBodyContent(out) h.doInitBody() [BODY] h.doAfterBody() .... Body Actions [BODY] h.doAfterBody() ...... out = pageContext.popBody() _______________________________________________ h.doEndTag(); h.release() |