Oracle9iAS Containers for J2EE Support for JavaServer Pages Reference Release 2 (9.0.2) Part Number A95882-01 |
|
This chapter discusses custom tag libraries, covering the basic framework that vendors can use to provide their own libraries. It then concludes with a discussion of OC4J tag handler features, and a comparison of standard runtime tags versus vendor-specific compile-time tags. The chapter is organized as follows:
For complete information about the tag libraries provided with OC4J, see the Oracle9iAS Containers for J2EE JSP Tag Libraries and Utilities Reference.
Standard JavaServer Pages technology allows vendors to create custom JSP tag libraries.
A tag library defines a collection of custom actions. The tags can be used directly by developers in manually coding a JSP page, or automatically by Java development tools. A tag library must be portable between different JSP container implementations.
For information beyond what is provided here regarding tag libraries and the standard JavaServer Pages tag library framework, refer to the following resources:
javax.servlet.jsp.tagext
package, at the following Web site:
http://java.sun.com/j2ee/j2sdkee/techdocs/api/javax/servlet/jsp/tagext/package-summary.html
A custom tag library is imported into a JSP page using a taglib
directive of the following general form:
<%@ taglib uri="URI" prefix="prefix" %>
Note the following general points about a tag library implementation and usage:
taglib
directive specifies where to find the tag library description file, as described in "The taglib Directive". It is possible to use URI shortcuts, as described in "Use of web.xml for Tag Libraries".
taglib
directive is a string of your choosing that you use in your JSP page with any tag from the library.
Assume the taglib
directive specifies a prefix oracust
:
<%@ taglib uri="URI" prefix="oracust" %>
Further assume that there is a tag mytag
in the library. You might use mytag
as follows:
<oracust:mytag attr1="...", attr2="..." />
Using the oracust
prefix informs the JSP translator that mytag
is defined in the tag library description file that can be found at the URI specified in the above taglib
directive.
mytag
does), and the names of those attributes.
As seen above, a tag without a body is used as in the following example:
<oracust:mytag attr1="...", attr2="..." />
By contrast, a tag with a body is used as in the following example:
<oracust:mytag attr1="...", attr2="..." > ...body... </oracust:mytag>
Details regarding the scripting variables that a custom tag uses are defined in a tag-extra-info class. This is described in "Scripting Variables and Tag-Extra-Info Classes".
A tag can create scripting variables with syntax such as in the following example, which creates the object myobj
:
<oracust:mytag id="myobj" attr1="...", attr2="..." />
The sections that follow provide more information about these topics.
A tag handler describes the semantics of the action that results from use of a custom tag. A tag handler is an instance of a Java class that implements one of two standard Java interfaces, depending on whether the tag processes a body of statements (between a start tag and an end tag).
Each tag has its own handler class. By convention, the name of the tag handler class for a tag abc
, for example, is AbcTag
.
The tag library description file of a tag library specifies the name of the tag handler class for each tag in the library. (See "Tag Library Description Files".)
A tag handler instance is a server-side object used at request-time. It has properties that are set by the JSP container, including the page context object for the JSP page that uses the custom tag, and a parent tag handler object if the use of this custom tag is nested within an outer custom tag.
See "Sample Tag Handler Class: ExampleLoopTag.java" for sample code of a tag handler class.
Note: The Sun Microsystems JavaServer Pages Specification, Version 1.1 does not mandate whether multiple uses of the same custom tag within a JSP page should use the same or different tag handler instances--this is left to the discretion of JSP vendors. See "OC4J JSP Tag Handler Features" for information about the Oracle implementation. |
Custom tags, as with standard JSP tags, may or may not have a body. In the case of a custom tag, even when there is a body, it may not need special processing by the tag handler.
There are three possible situations:
In this case, there is just a single tag, as opposed to a start tag and end tag. Following is a general example:
<oracust:abcdef attr1="...", attr2="..." />
In this case, there is a start tag and end tag with a body of statements in between, but the tag handler does not process the body--body statements are passed through for normal JSP processing only. Following is a general example:
<foo:if cond="<%= ... %>" > ...body executed if cond is true, but not processed by tag handler... </foo:if>
In this case also, there is a start tag and end tag with a body of statements in between; however, the tag handler must process the body.
<oracust:ghijkl attr1="...", attr2="..." > ...body processed by tag handler... </oracust:ghijkl>
The tag handling interfaces that are described in the following sections specify a doStartTag()
method (further described below) that you must implement to return an appropriate int
constant, depending on the situation. The possible return values are as follows:
SKIP_BODY
if there is no body or if evaluation and execution of the body should be skipped
EVAL_BODY_INCLUDE
if there is a body that does not require special processing by the tag handler
EVAL_BODY_TAG
if there is a body that requires special processing by the tag handler
For a custom tag that does not have a body, or has a body that does not need special processing by the tag handler, the tag handler class must directly or indirectly implement the following standard interface:
The following standard support class implements the Tag
interface and can be used as a base class:
The Tag
interface specifies a doStartTag()
method and a doEndTag()
method. The tag developer provides code for these methods in the tag handler class, as appropriate, to be executed as the start tag and end tag, respectively, are encountered. The JSP page implementation class generated by the JSP translator includes appropriate calls to these methods.
Action processing--whatever you want the action tag to accomplish--is implemented in the doStartTag()
method. The doEndTag()
method implements any appropriate post-processing. In the case of a tag without a body, essentially nothing happens between the execution of these two methods.
The doStartTag()
method returns an integer value. For a tag handler class implementing the Tag
interface (either directly or indirectly), this value must be either SKIP_BODY
or EVAL_BODY_INCLUDE
(described in "Integer Constants for Body Processing" above). EVAL_BODY_TAG
is illegal for a tag handler class implementing the Tag
interface.
For a custom tag with a body that requires special processing by the tag handler, the tag handler class must directly or indirectly implement the following standard interface:
The following standard support class implements the BodyTag
interface and can be used as a base class:
The BodyTag
interface specifies a doInitBody()
method and a doAfterBody()
method in addition to the doStartTag()
and doEndTag()
methods specified in the Tag
interface.
Just as with tag handlers implementing the Tag
interface (described in the preceding section, "Handlers for Tags That Do Not Process a Body"), the tag developer implements the doStartTag()
method for action processing by the tag, and the doEndTag()
method for any post-processing.
The doStartTag()
method returns an integer value. For a tag handler class implementing the BodyTag
interface (directly or indirectly), this value must be either SKIP_BODY
or EVAL_BODY_TAG
(described in "Integer Constants for Body Processing"). EVAL_BODY_INCLUDE
is illegal for a tag handler class implementing the BodyTag
interface.
In addition to implementing the doStartTag()
and doEndTag()
methods, the tag developer, as appropriate, provides code for the doInitBody()
method, to be invoked before the body is evaluated, and the doAfterBody()
method, to be invoked after each evaluation of the body. The body could be evaluated multiple times, such as at the end of each iteration of a loop. The JSP page implementation class generated by the JSP translator includes appropriate calls to all of these methods.
After the doStartTag()
method is executed, the doInitBody()
and doAfterBody()
methods are executed if the doStartTag()
method returned EVAL_BODY_TAG
.
The doEndTag()
method is executed after any body processing, when the end tag is encountered.
For custom tags that must process a body, the javax.servlet.jsp.tagext.BodyContent
class is available. This is a subclass of javax.servlet.jsp.JspWriter
that you can use to process body evaluations so that they can be re-extracted later. The BodyTag
interface includes a setBodyContent()
method that the JSP container can use to give a BodyContent
handle to a tag handler instance.
A custom tag action can create one or more server-side objects, known as scripting variables, that are available for use by the tag itself or by other scripting elements, such as scriptlets and other tags.
Details regarding scripting variables that a custom tag defines must be specified in a subclass of the standard javax.servlet.jsp.tagext.TagExtraInfo
abstract class. This document refers to such a subclass as a tag-extra-info class.
The JSP container uses tag-extra-info instances during translation. The tag library description file, specified in the taglib
directive that imports the library into a JSP page, specifies the tag-extra-info class to use, if applicable, for any given tag.
A tag-extra-info class has a getVariableInfo()
method to retrieve names and types of the scripting variables that will be assigned during HTTP requests. The JSP translator calls this method during translation, passing it an instance of the standard javax.servlet.jsp.tagext.TagData
class. The TagData
instance specifies attribute values set in the JSP statement that uses the custom tag.
This section covers the following topics:
Objects that are defined explicitly in a custom tag can be referenced in other actions through the page context object, using the object ID as a handle. Consider the following example:
<oracust:foo id="myobj" attr1="..." attr2="..." />
This statement results in the object myobj
being available to any scripting elements between the tag and the end of the page. The id
attribute is a translation-time attribute. The tag developer provides a tag-extra-info class that will be used by the JSP container. Among other things, the tag-extra-info class specifies what class to instantiate for the myobj
object.
The JSP container enters myobj
into the page context object, where it can later be obtained by other tags or scripting elements using syntax such as the following:
<oracust:bar ref="myobj" />
The myobj
object is passed through the tag handler instances for the foo
and bar
tags. All that is required is knowledge of the name of the object (myobj
).
Note that id
and ref
are merely sample attribute names; there are no special predefined semantics for these attributes. It is up to the tag handler to define attribute names and create and retrieve objects in the page context.
Specify the scope of a scripting variable in the tag-extra-info class of the tag that creates the variable. It can be one of the following int
constants:
NESTED
--if the scripting variable is available between the start tag and end tag of the action that defines it
AT_BEGIN
--if the scripting variable is available from the start tag until the end of the page
AT_END
--if the scripting variable is available from the end tag until the end of the page
You must create a tag-extra-info class for any custom tag that creates scripting variables. The class describes the scripting variables and must be a subclass of the standard javax.servlet.jsp.tagext.TagExtraInfo
abstract class.
The key method of the TagExtraInfo
class is getVariableInfo()
, which is called by the JSP translator and returns an array of instances of the standard javax.servlet.jsp.tagext.VariableInfo
class (one array instance for each scripting variable the tag creates).
The tag-extra-info class constructs each VariableInfo
instance with the following information regarding the scripting variable:
See "Sample Tag-Extra-Info Class: ExampleLoopTagTEI.java" for sample code of a tag-extra-info class.
Where nested custom tags are used, the tag handler instance of the nested tag has access to the tag handler instance of the outer tag, which may be useful in any processing and state management performed by the nested tag.
This functionality is supported through the static findAncestorWithClass()
method of the javax.servlet.jsp.tagext.TagSupport
class. Even though the outer tag handler instance is not named in the page context object, it is accessible because it is the closest enclosing instance of a given tag handler class.
Consider the following JSP code example:
<foo:bar1 attr="abc" > <foo:bar2 /> </foo:bar1>
Within the code of the bar2
tag handler class (class Bar2Tag
, by convention), you can have a statement such as the following:
Tag bar1tag = TagSupport.findAncestorWithClass(this, Bar1Tag.class);
The findAncestorWithClass()
method takes the following as input:
this
object that is the class handler instance from which findAncestorWithClass()
was called (a Bar2Tag
instance in the example)
bar1
tag handler class (presumed to be Bar1Tag
in the example), as a java.lang.Class
instance
The findAncestorWithClass()
method returns an instance of the appropriate tag handler class, in this case Bar1Tag
, as a javax.servlet.jsp.tagext.Tag
instance.
It is useful for a Bar2Tag
instance to have access to the outer Bar1Tag
instance in case the Bar2Tag
needs the value of a bar1
tag attribute or needs to call a method on the Bar1Tag
instance.
A tag library description (TLD) file is an XML-style document that contains information about a tag library and individual tags of the library. The name of a TLD file has the .tld
extension.
A JSP container uses the TLD file in determining what action to take when it encounters a tag from the library.
A tag entry in the TLD file includes the following:
Here is a sample TLD file entry for the tag myaction
:
<tag> <name>myaction</name> <tagclass>examples.MyactionTag</tagclass> <teiclass>examples.MyactionTagExtraInfo</teiclass> <bodycontent>JSP</bodycontent> <attribute> <name>attr1</name> <required>true</required> </attribute> <attribute> <name>attr2</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
According to this entry, the tag handler class is MyactionTag
and the tag-extra-info class is MyactionTagExtraInfo
. The attribute attr1
is required; the attribute attr2
is optional and can take a real-time expression as its value.
The bodycontent
parameter indicates how the tag body (if any) should be processed. There are three valid values:
empty
indicates that the tag uses no body.
JSP
indicates that the tag body should be processed as JSP source and translated.
tagdependent
indicates that the tag body should not be translated. Any text in the body is treated as static text.
The taglib
directive in a JSP page informs the JSP container where to find the TLD file. (See "The taglib Directive".)
For more information about tag library description files, see the Sun Microsystems JavaServer Pages Specification, Version 1.1.
The Sun Microsystems Java Servlet Specification, Version 2.2 (and higher) describes a standard deployment descriptor for servlets--the web.xml
file. JSP pages can use this file in specifying the location of a JSP tag library description file.
For JSP tag libraries, the web.xml
file can include a <taglib>
element and two subelements:
The taglib-location
subelement indicates the application-relative location (by starting with "/") of the tag library description file.
The <taglib-uri>
subelement indicates a "shortcut" URI to use in taglib
directives in your JSP pages, with this URI being mapped to the TLD file location specified in the accompanying <taglib-location>
subelement. (The term URI, universal resource indicator, is somewhat equivalent to the term URL, universal resource locator, but is more generic.)
Following is a sample web.xml
entry for a tag library description file:
<taglib> <taglib-uri>/oracustomtags</taglib-uri> <taglib-location>/WEB-INF/oracustomtags/tlds/MyTLD.tld</taglib-location> </taglib>
This entry makes /oracustomtags
equivalent to /WEB-INF/oracustomtags/tlds/MyTLD.tld
in taglib
directives in your JSP pages. See "Using a Shortcut URI for the TLD File" for an example.
See the Sun Microsystems Java Servlet Specification, Version 2.2 or Version 2.3, and the Sun Microsystems JavaServer Pages Specification, Version 1.1 for more information about the web.xml
deployment descriptor and its use for tag library description files.
Import a custom library into a JSP page using a taglib
directive, of the following form:
<%@ taglib uri="URI" prefix="prefix" %>
For the URI, you have the following options:
web.xml
file. (See "Use of web.xml for Tag Libraries".)
Assume the following web.xml
entry for a tag library defined in the tag library description file MyTLD.tld
:
<taglib> <taglib-uri>/oracustomtags</taglib-uri> <taglib-location>/WEB-INF/oracustomtags/tlds/MyTLD.tld</taglib-location> </taglib>
Given this example, the following directive in your JSP page results in the JSP container finding the /oracustomtags
URI in web.xml
and, therefore, finding the accompanying name and location of the tag library description file (MyTLD.tld
):
<%@ taglib uri="/oracustomtags" prefix="oracust" %>
This statement allows you to use any of the tags of this custom tag library in a JSP page.
If you do not want your JSP application to depend on a web.xml
file for its use of a tag library, the taglib
directive can fully specify the name and location of the tag library description file, as follows:
<%@ taglib uri="/WEB-INF/oracustomtags/tlds/MyTLD.tld" prefix="oracust" %>
The location is specified as an application-relative location (by starting with "/", as in this example). See "Requesting a JSP Page" for related discussion.
Alternatively, you can specify a .jar
file instead of a .tld
file in the taglib
directive, where the .jar
file contains a tag library description file. The tag library description file must be located and named as follows when you create the JAR file:
META-INF/taglib.tld
Then the taglib
directive might be as follows, for example:
<%@ taglib uri="/WEB-INF/oracustomtags/tlds/MyTLD.jar" prefix="oracust" %>
This section provides an end-to-end example of the definition and use of a custom tag, loop
, that is used to iterate through the tag body a specified number of times.
Included in the example are the following:
Sample code here uses extended datatypes in the
Note:
oracle.jsp.jml
package. There is an overview of these types in "Extended Type JavaBeans". For more information, refer to the Oracle9iAS Containers for J2EE JSP Tag Libraries and Utilities Reference.
Following is a sample JSP page, exampletag.jsp
, that uses the loop
tag, specifying that the outer loop be executed five times and the inner loop three times:
<%@ taglib uri="/WEB-INF/exampletag.tld" prefix="foo" %> <% int num=5; %> <br> <pre> <foo:loop index="i" count="<%=num%>"> body1here: i expr: <%=i%> i property: <jsp:getProperty name="i" property="value" /> <foo:loop index="j" count="3"> body2here: j expr: <%=j%> i property: <jsp:getProperty name="i" property="value" /> j property: <jsp:getProperty name="j" property="value" /> </foo:loop> </foo:loop> </pre>
This section provides source code for the tag handler class, ExampleLoopTag
. Note the following:
doStartTag()
method returns the integer constant EVAL_BODY_TAG
, so that the tag body (essentially, the loop) is processed.
doAfterBody()
method increments the counter. It returns EVAL_BODY_TAG
if there are more iterations left, and SKIP_BODY
after the last iteration.
Here is the code:
package examples; import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; import java.util.Hashtable; import java.io.Writer; import java.io.IOException; import oracle.jsp.jml.JmlNumber; public class ExampleLoopTag extends BodyTagSupport { String index; int count; int i=0; JmlNumber ib=new JmlNumber(); public void setIndex(String index) { this.index=index; } public void setCount(String count) { this.count=Integer.parseInt(count); } public int doStartTag() throws JspException { return EVAL_BODY_TAG; } public void doInitBody() throws JspException { pageContext.setAttribute(index, ib); i++; ib.setValue(i); } public int doAfterBody() throws JspException { try { if (i >= count) { bodyContent.writeOut(bodyContent.getEnclosingWriter()); return SKIP_BODY; } else pageContext.setAttribute(index, ib); i++; ib.setValue(i); return EVAL_BODY_TAG; } catch (IOException ex) { throw new JspTagException(ex.toString()); } } }
This section provides the source code for the tag-extra-info class that describes the scripting variable used by the loop
tag.
A VariableInfo
instance is constructed that specifies the following for the variable:
index
attribute.
oracle.jsp.jml.JmlNumber
, which you must specify as a fully qualified class name.
NESTED
.
In addition, the tag-extra-info class has an isValid()
method that determines whether the count
attribute is valid--it must be an integer.
package examples; import javax.servlet.jsp.tagext.*; public class ExampleLoopTagTEI extends TagExtraInfo { public VariableInfo[] getVariableInfo(TagData data) { return new VariableInfo[] { new VariableInfo(data.getAttributeString("index"), "oracle.jsp.jml.JmlNumber", true, VariableInfo.NESTED) }; } public boolean isValid(TagData data) { String countStr=data.getAttributeString("count"); if (countStr!=null) // for request-time case { try { int count=Integer.parseInt(countStr); } catch (NumberFormatException e) { return false; } } return true; } }
This section presents the tag library description (TLD) file for the tag library. In this example, the library consists of only the one tag, loop
.
This TLD file specifies the following for the loop
tag:
examples.ExampleLoopTag
examples.ExampleLoopTagTEI
bodycontent
specification with a value of JSP
This means the JSP translator should process and translate the body code.
index
and count
, both mandatory
The count
attribute can be a request-time JSP expression.
Here is the TLD file:
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <!-- a tag library descriptor --> <taglib> <!-- after this the default space is "http://java.sun.com/j2ee/dtds/jsptaglibrary_1_2.dtd" --> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>simple</shortname> <info> A simple tag library for the examples </info> <!-- example tag --> <!-- for loop --> <tag> <name>loop</name> <tagclass>examples.ExampleLoopTag</tagclass> <teiclass>examples.ExampleLoopTagTEI</teiclass> <bodycontent>JSP</bodycontent> <info>for loop</info> <attribute> <name>index</name> <required>true</required> </attribute> <attribute> <name>count</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
This section describes OC4J JSP features for tag handler pooling and code generation size reduction.
You can specify whether JSP tag handler instances are pooled in a particular JSP page, always in the application
scope, by setting the oracle.jsp.tags.reuse
attribute in the JSP page context. Set it to true
to enable pooling, or to false
to disable pooling. For example:
pageContext.setAttribute("oracle.jsp.tags.reuse", new Boolean(true));
You can use separate settings in different pages, or even in different sections of the same page.
The default is according to the setting of the tags_reuse_default
JSP configuration parameter, or true
if there is no tags_reuse_default
setting. See "JSP Configuration Parameters" for further information about this parameter and how to set it.
The JSP implementation in Oracle9iAS release 2 reduces the code generation size for custom tag usage. In addition, there is a JSP configuration flag, reduce_tag_code
, that you can set to true
for even further size reduction.
Be aware, however, that when this flag is enabled, the code generation pattern does not maximize tag handler reuse. Although you can still improve performance by setting tags_reuse_default
to true
as described in "Disabling or Enabling Tag Handler Instance Pooling" above, the effect is not maximized when reduce_tag_code
is also true.
See "JSP Configuration Parameters" for further information about these parameters and how to set them.
Standard tag libraries, as described in the Sun Microsystems JavaServer Pages Specification, Version 1.1, use a runtime support mechanism. They are typically portable, not requiring any particular JSP container.
It is also possible, however, for vendors to support custom tags through vendor-specific functionality in their JSP translators. Such tags are not portable to other containers.
It is generally advisable to develop standard, portable tags that use the runtime mechanism, but there may be scenarios where tags using a compile-time mechanism are appropriate, as discussed in this section.
The JSP 1.1 specification describes a runtime support mechanism for custom tag libraries. This mechanism, using an XML-style tag library description file to specify the tags, is covered in "Standard Tag Library Framework".
Creating and using a tag library that adheres to this model assures that the library will be portable to any standard JSP environment.
There are, however, reasons to consider compile-time implementations:
In the future, Oracle may offer a general framework for creating custom tag libraries with compile-time tag implementations. Because such implementations would depend on the OC4J JSP translator, they would not be portable to other JSP environments.
OC4J provides a portable tag library called the JSP Markup Language (JML) library. This library uses the standard JSP 1.1 runtime mechanism.
However, the JML tags are also supported through a compile-time mechanism. This is because the tags were first introduced with JSP implementations that preceded the JSP 1.1 specification, when the runtime mechanism was introduced. The compile-time tags are still supported for backward compatibility.
The general advantages and disadvantages of compile-time implementations apply to the Oracle JML tag library as well. There may be situations where it is advantageous to use the compile-time JML implementation. There are also a few additional tags in that implementation, and some additional expression syntax that is supported.
Both the runtime version and the compile-time version of the JML library are described in the Oracle9iAS Containers for J2EE JSP Tag Libraries and Utilities Reference.
|
Copyright © 2000, 2002 Oracle Corporation. All Rights Reserved. |
|