Download
FAQ History |
API
Search Feedback |
Programming Tags That Accept Scripting Elements
Tags that accept scripting elements in attribute values or in the body cannot be programmed as simple tags; they must be implemented as classic tags. The following sections describe the TLD elements and JSP tag extension API specific to classic tag handlers. All other TLD elements are the same as for simple tags.
TLD Elements
You specify the character of a classic tag's body content using the
body-content
element:You must declare the body content of tags that do not have a body as
empty
. For tags that have a body, there are two options. Body content containing custom and core tags, scripting elements, and HTML text is categorized asJSP
. All other types of body content--for example, SQL statements passed to thequery
tag-- are labeledtagdependent
.Tag Handlers
The classes and interfaces used to implement classic tag handlers are contained in the
javax.servlet.jsp.tagext
package. Classic tag handlers implement either theTag
, theIterationTag
, or theBodyTag
interface. Interfaces can be used to take an existing Java object and make it a tag handler. For newly created classic tag handlers, you can use theTagSupport
andBodyTagSupport
classes as base classes. These classes and interfaces are contained in thejavax.servlet.jsp.tagext
package.Tag handler methods defined by the
Tag
andBodyTag
interfaces are called by the JSP page's servlet at various points during the evaluation of the tag. When the start element of a custom tag is encountered, the JSP page's servlet calls methods to initialize the appropriate handler and then invokes the handler'sdoStartTag
method. When the end element of a custom tag is encountered, the handler'sdoEndTag
method is invoked for all but simple tags. Additional methods are invoked in between when a tag handler needs to manipulate the body of the tag. For further information, see Tags with Bodies. To provide a tag handler implementation, you must implement the methods, summarized in Table 16-2, that are invoked at various stages of processing the tag.
A tag handler has access to an API that allows it to communicate with the JSP page. The entry points to the API are two objects: the JSP context (
javax.servlet.jsp.JspContext)
for simple tag handlers and the page context (javax.servlet.jsp.PageContext)
for classic tag handlers.JspContext
provides access to implicit objects.PageContext
extendsJspContext
with HTTP-specific behavior. A tag handler can retrieve all the other implicit objects (request, session, and application) that are accessible from a JSP page through these objects. In addition, implicit objects can have named attributes associated with them. Such attributes are accessed using[set|get]Attribute
methods.If the tag is nested, a tag handler also has access to the handler (called the parent) associated with the enclosing tag.
How Is a Classic Tag Handler Invoked?
The
Tag
interface defines the basic protocol between a tag handler and a JSP page's servlet. It defines the life cycle and the methods to be invoked when the start and end tags are encountered.The JSP page's servlet invokes the
setPageContext
,setParent
, and attribute-setting methods before callingdoStartTag
. The JSP page's servlet also guarantees thatrelease
will be invoked on the tag handler before the end of the page.Here is a typical tag handler method invocation sequence:
ATag t = new ATag(); t.setPageContext(...); t.setParent(...); t.setAttribute1(value1); t.setAttribute2(value2); t.doStartTag(); t.doEndTag(); t.release();The
BodyTag
interface extendsTag
by defining additional methods that let a tag handler access its body. The interface provides three new methods:A typical invocation sequence is as follows:
t.doStartTag(); out = pageContext.pushBody(); t.setBodyContent(out); // perform any initialization needed after body content is set t.doInitBody(); t.doAfterBody(); // whiledoAfterBody
returnsEVAL_BODY_AGAIN
we // iterate body evaluation ... t.doAfterBody(); t.doEndTag(); out = pageContext.popBody(); t.release();Tags with Bodies
A tag handler for a tag with a body is implemented differently depending on whether or not the tag handler needs to manipulate the body. A tag handler manipulates the body when it reads or modifies the contents of the body.
Tag Handler Does Not Manipulate the Body
If the tag handler does not need to manipulate the body, the tag handler should implement the
Tag
interface. If the tag handler implements theTag
interface and the body of the tag needs to be evaluated, thedoStartTag
method must returnEVAL_BODY_INCLUDE
; otherwise it should returnSKIP_BODY
.If a tag handler needs to iteratively evaluate the body, it should implement the
IterationTag
interface. The tag handler should returnEVAL_BODY_AGAIN
from thedoAfterBody
method if it determines that the body needs to be evaluated again.Tag Handler Manipulates the Body
If the tag handler needs to manipulate the body, the tag handler must implement
BodyTag
(or must be derived fromBodyTagSupport
).When a tag handler implements the
BodyTag
interface, it must implement thedoInitBody
and thedoAfterBody
methods. These methods manipulate body content passed to the tag handler by the JSP page's servlet.Body content supports several methods to read and write its contents. A tag handler can use the body content's
getString
orgetReader
method to extract information from the body, and thewriteOut(out)
method to write the body contents to anout
stream. The writer supplied to thewriteOut
method is obtained using the tag handler'sgetPreviousOut
method. This method is used to ensure that a tag handler's results are available to an enclosing tag handler.If the body of the tag needs to be evaluated, the
doStartTag
method must returnEVAL_BODY_BUFFERED
; otherwise, it should returnSKIP_BODY
.doInitBody Method
The
doInitBody
method is called after the body content is set but before it is evaluated. You generally use this method to perform any initialization that depends on the body content.doAfterBody Method
The
doAfterBody
method is called after the body content is evaluated.doAfterBody
must return an indication of whether to continue evaluating the body. Thus, if the body should be evaluated again, as would be the case if you were implementing an iteration tag,doAfterBody
should returnEVAL_BODY_AGAIN
; otherwise,doAfterBody
should returnSKIP_BODY
.The following example reads the content of the body (which contains an SQL query) and passes it to an object that executes the query. Because the body does not need to be reevaluated,
doAfterBody
returnsSKIP_BODY
.public class QueryTag extends BodyTagSupport { public int doAfterBody() throws JspTagException { BodyContent bc = getBodyContent(); // get the bc as string String query = bc.getString(); // clean up bc.clearBody(); try { Statement stmt = connection.createStatement(); result = stmt.executeQuery(query); } catch (SQLException e) { throw new JspTagException("QueryTag: " + e.getMessage()); } return SKIP_BODY; } }release Method
A tag handler should reset its state and release any private resources in the
release
method.Cooperating Tags
Tags cooperate by sharing objects. JSP technology supports two styles of object sharing.
The first style requires that a shared object be named and stored in the page context (one of the implicit objects accessible to JSP pages as well as tag handlers). To access objects created and named by another tag, a tag handler uses the
pageContext.getAttribute(name,
scope)
method.In the second style of object sharing, an object created by the enclosing tag handler of a group of nested tags is available to all inner tag handlers. This form of object sharing has the advantage that it uses a private namespace for the objects, thus reducing the potential for naming conflicts.
To access an object created by an enclosing tag, a tag handler must first obtain its enclosing tag using the static method
TagSupport.findAncestorWithClass(from,
class)
or theTagSupport.getParent
method. The former method should be used when a specific nesting of tag handlers cannot be guaranteed. After the ancestor has been retrieved, a tag handler can access any statically or dynamically created objects. Statically created objects are members of the parent. Private objects can also be created dynamically. Such objects can be stored in a tag handler using thesetValue
method and can be retrieved using thegetValue
method.The following example illustrates a tag handler that supports both the named approach and the private object approach to sharing objects. In the example, the handler for a query tag checks whether an attribute named
connectionId
has been set. If theconnection
attribute has been set, the handler retrieves the connection object from the page context. Otherwise, the tag handler first retrieves the tag handler for the enclosing tag and then retrieves the connection object from that handler.public class QueryTag extends BodyTagSupport { public int doStartTag() throws JspException { String cid = getConnectionId(); Connection connection; if (cid != null) { // there is a connection id, use it connection =(Connection)pageContext. getAttribute(cid); } else { ConnectionTag ancestorTag = (ConnectionTag)findAncestorWithClass(this, ConnectionTag.class); if (ancestorTag == null) { throw new JspTagException("A query without a connection attribute must be nested within a connection tag."); } connection = ancestorTag.getConnection(); ... } } }The query tag implemented by this tag handler can be used in either of the following ways:
<tt:connection cid="con01" ... > ... </tt:connection> <tt:query id="balances" connectionId="con01"> SELECT account, balance FROM acct_table where customer_number = ? <tt:param value="${requestScope.custNumber}" /> </tt:query> <tt:connection ... > <tt:query cid="balances"> SELECT account, balance FROM acct_table where customer_number = ? <tt:param value="${requestScope.custNumber}" /> </tt:query> </tt:connection>The TLD for the tag handler use the following declaration to indicate that the
connectionId
attribute is optional:Tags That Define Variables
The mechanisms for defining variables in classic tags are similar to those described in Chapter 15. You must declare the variable in a
variable
element of the TLD or in a tag extra info class. You use PageContext().setAttribute(name, value) orPageContext.setAttribute(name,
value,
scope)
methods in the tag handler to create or update an association between a name that is accessible in the page context and the object that is the value of the variable. For classic tag handlers, Table 16-3 illustrates how the availability of a variable affects when you may want to set or update the variable's value.
A variable defined by a custom tag can also be accessed in a scripting expression. For example, the Web service described in the preceding section can be encapsulated in a custom tag that returns the response in a variable named by the
var
attribute, and thenvar
can be accessed in a scripting expression as follows:<ws:hello var="response" name="<%=request.getParameter("username")%>" /> <h2><font color="black"><%= response %>!</font></h2>Remember that in situations where scripting is not allowed (in a tag body where the
body-content
is declared asscriptless and
in a page where scripting is specified to be invalid), you wouldn't be able to access the variable in a scriptlet or an expression. Instead, you would have to use the JSP expression language to access the variable.
Download
FAQ History |
API
Search Feedback |
All of the material in The J2EE(TM) 1.4 Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.