Encapsulating Reusable Content Using Tag Files
A tag file is a source file that contains a fragment of JSP code that is reusable as a custom tag. Tag files allow you to create custom tags using JSP syntax. Just as a JSP page gets translated into a servlet class and then compiled, a tag file gets translated into a tag handler and then compiled.
The recommended file extension for a tag file is
.tag. As is the case with JSP files, the tag can be composed of a top file that includes other files that contain either a complete tag or a fragment of a tag file. Just as the recommended extension for a fragment of a JSP file is.jspf, the recommended extension for a fragment of a tag file is.tagf.The following version of the Hello, World application introduced in Chapter 3 uses a tag to generate the response. The
responsetag, which accepts two attributes--a greeting string and a name--is encapsulated inresponse.tag:<%@ attribute name="greeting" required="true" %> <%@ attribute name="name" required="true" %> <h2><font color="black">${greeting}, ${name}!</font></h2>The highlighted line in the
greeting.jsppage invokes theresponsetag if the length of theusernamerequest parameter is greater than0:<%@ taglib tagdir="/WEB-INF/tags" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <html> <head><title>Hello</title></head> <body bgcolor="white"> <img src="duke.waving.gif"> <c:set var="greeting" value="Hello" /> <h2>${greeting}, my name is Duke. What's yours?</h2> <form method="get"> <input type="text" name="username" size="25"> <p></p> <input type="submit" value="Submit"> <input type="reset" value="Reset"> </form> <c:if test="${fn:length(param.username) > 0}" ><h:response greeting="${greeting}" name="${param.username}"/></c:if> </body> </html>A sample
hello3.waris provided in<INSTALL>/j2eetutorial14/examples/web/provided-wars/. To build thehello3application, follow these steps:To package and deploy the example using
asant, follow these steps:To learn how to configure the example, use
deploytoolto package and deploy it:
- Start the Application Server.
- Start
deploytool.- Create a web application called
hello3by running the New Web Component wizard. Select FileNew
Web Component.
- In the New Web Component wizard:
- Select the Create New Stand-Alone WAR Module radio button.
- In the WAR File field, enter
<INSTALL>/j2eetutorial14/examples/web/hello3/hello3.war. The WAR Display Name field will showhello3.- In the Context Root field, enter
/hello3.- Click Edit Contents.
- In the Edit Contents dialog, navigate to
<INSTALL>/j2eetutorial14/examples/web/hello3/build/.Selectduke.waving.gif,greeting.jsp, andresponse.tagand click Add. Click OK.- Click Next.
- Select the No Component radio button and click Next.
- Click Finish.
- Set
greeting.jspto be a welcome file (see Declaring Welcome Files).- Select File
Save.
- Deploy the application.
To run the example, open your browser to http://localhost:
8080/hello3Tag File Location
Tag files can be placed in one of two locations: in the
/WEB-INF/tags/directory or subdirectory of a web application or in a JAR file (see Packaged Tag Files) in the/WEB-INF/lib/directory of a web application. Packaged tag files require a tag library descriptor (see Tag Library Descriptors), an XML document that contains information about a library as a whole and about each tag contained in the library. Tag files that appear in any other location are not considered tag extensions and are ignored by the web container.Tag File Directives
Directives are used to control aspects of tag file translation to a tag handler, and to specify aspects of the tag, attributes of the tag, and variables exposed by the tag. Table 15-1 lists the directives that you can use in tag files.
taglibtaglibdirective (see Declaring Tag Libraries) for JSP pages.includeincludedirective (see Reusing Content in JSP Pages) for JSP pages. Note that if the included file contains syntax unsuitable for tag files, a translation error will occur.tagpagedirective in a JSP page, but applies to tag files instead of JSP pages. As with thepagedirective, a translation unit can contain more than one instance of thetagdirective. All the attributes apply to the complete translation unit. However, there can be only one occurrence of any attribute or value defined by this directive in a given translation unit. With the exception of theimportattribute, multiple attribute or value (re)definitions result in a translation error.Also used for declaring custom tag properties such as display name. See Declaring Tags.attributevariable
Declaring Tags
The
tagdirective is similar to the JSP page's page directive but applies to tag files. Some of the elements in thetagdirective appear in thetagelement of a TLD (see Declaring Tag Handlers). Table 15-2 lists the tag directive attributes.
display-name.tag.body-contentempty,tagdependent, orscriptless. A translation error will result ifJSPor any other value is used. Defaults toscriptless. See body-content Attribute .dynamic-attributesMapcontaining the names and values of the dynamic attributes passed during invocation of the tag.A translation error results if the value of thedynamic-attributesof atagdirective is equal to the value of aname-givenof avariabledirective or the value of anameattribute of anattributedirective.small-iconlarge-icondescriptionexamplelanguagelanguageattribute of thepagedirective.importimportattribute of thepagedirective.pageEncodingpageEncodingattribute in thepagedirective.isELIgnoredisELIgnoredattribute of thepagedirective.
body-content Attribute
You specify the type of a tag's body content using the
body-contentattribute:You must declare the body content of tags that do not accept a body as
empty. For tags that have a body there are two options. Body content containing custom and standard tags and HTML text is specified asscriptless. All other types of body content--for example, SQL statements passed to thequerytag--is specified astagdependent. If no attribute is specified, the default isscriptless.Declaring Tag Attributes in Tag Files
To declare the attributes of a custom tag defined in a tag file, you use the
attributedirective. A TLD has an analogousattributeelement (see Declaring Tag Attributes for Tag Handlers). Table 15-3 lists theattributedirective attributes.
Declaring Tag Variables in Tag Files
Tag attributes are used to customize tag behavior much as parameters are used to customize the behavior of object methods. In fact, using tag attributes and EL variables, it is possible to emulate various types of parameters--
IN,OUT, and nested.To emulate
INparameters, use tag attributes. A tag attribute is communicated between the calling page and the tag file when the tag is invoked. No further communication occurs between the calling page and the tag file.To emulate
OUTor nested parameters, use EL variables. The variable is not initialized by the calling page but instead is set by the tag file. Each type of parameter is synchronized with the calling page at various points according to the scope of the variable. See Variable Synchronization for details.To declare an EL variable exposed by a tag file, you use the
variabledirective. A TLD has an analogousvariableelement (see Declaring Tag Variables for Tag Handlers). Table 15-4 lists thevariabledirective attributes.
Variable Synchronization
The web container handles the synchronization of variables between a tag file and a calling page. Table 15-5 summarizes when and how each object is synchronized according to the object's scope.
jsp:invokeorjsp:doBody(see Evaluating Fragments Passed to Tag Files)page
page
page
page
If
name-givenis used to specify the variable name, then the name of the variable in the calling page and the name of the variable in the tag file are the same and are equal to the value ofname-given.The
name-from-attributeandaliasattributes of thevariabledirective can be used to customize the name of the variable in the calling page while another name is used in the tag file. When using these attributes, you set the name of the variable in the calling page from the value ofname-from-attributeat the time the tag was called. The name of the corresponding variable in the tag file is the value ofalias.Synchronization Examples
The following examples illustrate how variable synchronization works between a tag file and its calling page. All the example JSP pages and tag files reference the JSTL core tag library with the prefix
c. The JSP pages reference a tag file located in/WEB-INF/tagswith the prefixmy.AT_BEGIN Scope
In this example, the
AT_BEGINscope is used to pass the value of the variable namedxto the tag's body and at the end of the tag invocation.<%-- callingpage.jsp --%> <c:set var="x" value="1"/> ${x} <%-- (x == 1) --%> <my:example> ${x} <%-- (x == 2) --%> </my:example> ${x} <%-- (x == 4) --%> <%-- example.tag --%> <%@ variable name-given="x" scope="AT_BEGIN" %> ${x} <%-- (x == null) --%> <c:set var="x" value="2"/> <jsp:doBody/> ${x} <%-- (x == 2) --%> <c:set var="x" value="4"/>NESTED Scope
In this example, the
NESTEDscope is used to make a variable namedxavailable only to the tag's body. The tag sets the variable to2, and this value is passed to the calling page before the body is invoked. Because the scope isNESTEDand because the calling page also had a variable namedx, its original value,1, is restored when the tag completes.<%-- callingpage.jsp --%> <c:set var="x" value="1"/> ${x} <%-- (x == 1) --%> <my:example> ${x} <%-- (x == 2) --%> </my:example> ${x} <%-- (x == 1) --%> <%-- example.tag --%> <%@ variable name-given="x" scope="NESTED" %> ${x} <%-- (x == null) --%> <c:set var="x" value="2"/> <jsp:doBody/> ${x} <%-- (x == 2) --%> <c:set var="x" value="4"/>AT_END Scope
In this example, the
AT_ENDscope is used to return a value to the page. The body of the tag is not affected.<%-- callingpage.jsp --%> <c:set var="x" value="1"/> ${x} <%-- (x == 1) --%> <my:example> ${x} <%-- (x == 1) --%> </my:example> ${x} <%-- (x == 4) --%> <%-- example.tag --%> <%@ variable name-given="x" scope="AT_END" %> ${x} <%-- (x == null) --%> <c:set var="x" value="2"/> <jsp:doBody/> ${x} <%-- (x == 2) --%> <c:set var="x" value="4"/>AT_BEGIN and name-from-attribute
In this example the
AT_BEGINscope is used to pass an EL variable to the tag's body and make to it available to the calling page at the end of the tag invocation. The name of the variable is specified via the value of the attributevar. The variable is referenced by a local name,result, in the tag file.<%-- callingpage.jsp --%> <c:set var="x" value="1"/> ${x} <%-- (x == 1) --%> <my:example var="x"> ${x} <%-- (x == 2) --%> ${result} <%-- (result == null) --%> <c:set var="result" value="invisible"/> </my:example> ${x} <%-- (x == 4) --%> ${result} <%-- (result == `invisible') --%> <%-- example.tag --%> <%@ attribute name="var" required="true" rtexprvalue="false"%> <%@ variable alias="result" name-from-attribute="var" scope="AT_BEGIN" %> ${x} <%-- (x == null) --%> ${result} <%-- (result == null) --%> <c:set var="x" value="ignored"/> <c:set var="result" value="2"/> <jsp:doBody/> ${x} <%-- (x == `ignored') --%> ${result} <%-- (result == 2) --%> <c:set var="result" value="4"/>Evaluating Fragments Passed to Tag Files
When a tag file is executed, the web container passes it two types of fragments: fragment attributes and the tag body. Recall from the discussion of fragment attributes that fragments are evaluated by the tag handler as opposed to the web container. Within a tag file, you use the
jsp:invokeelement to evaluate a fragment attribute and use thejsp:doBodyelement to evaluate a tag file body.The result of evaluating either type of fragment is sent to the response or is stored in an EL variable for later manipulation. To store the result of evaluating a fragment to an EL variable, you specify the
varorvarReaderattribute. Ifvaris specified, the container stores the result in an EL variable of typeStringwith the name specified byvar. IfvarReaderis specified, the container stores the result in an EL variable of typejava.io.Reader, with the name specified byvarReader. TheReaderobject can then be passed to a custom tag for further processing. A translation error occurs if bothvarandvarReaderare specified.An optional
scopeattribute indicates the scope of the resulting variable. The possible values arepage(default),request,session, orapplication. A translation error occurs if you use this attribute without specifying thevarorvarReaderattribute.Examples
Simple Attribute Example
The Duke's Bookstore
shipDatetag, defined inshipDate.tag, is a custom tag that has a simple attribute. The tag generates the date of a book order according to the type of shipping requested.<%@ taglib prefix="sc" tagdir="/WEB-INF/tags" %> <h3><fmt:message key="ThankYou"/> ${param.cardname}.</h3><br> <fmt:message key="With"/> <em><fmt:message key="${param.shipping}"/></em>, <fmt:message key="ShipDateLC"/> <sc:shipDate shipping="${param.shipping}" />The tag determines the number of days until shipment from the
shippingattribute passed to it by the pagebookreceipt.jsp. From the number of days, the tag computes the ship date. It then formats the ship date.<%@ attribute name="shipping" required="true" %> <jsp:useBean id="now" class="java.util.Date" /> <jsp:useBean id="shipDate" class="java.util.Date" /> <c:choose> <c:when test="${shipping == 'QuickShip'}"> <c:set var="days" value="2" /> </c:when> <c:when test="${shipping == 'NormalShip'}"> <c:set var="days" value="5" /> </c:when> <c:when test="${shipping == 'SaverShip'}"> <c:set var="days" value="7" /> </c:when> </c:choose> <jsp:setProperty name="shipDate" property="time" value="${now.time + 86400000 * days}" /> <fmt:formatDate value="${shipDate}" type="date" dateStyle="full"/>.<br><br>Simple and Fragment Attribute and Variable Example
The Duke's Bookstore
catalogtag, defined incatalog.tag, is a custom tag with simple and fragment attributes and variables. The tag renders the catalog of a book database as an HTML table. The tag file declares that it sets variables namedpriceandsalePriceviavariabledirectives. The fragmentnormalPriceuses the variableprice, and the fragmentonSaleuses the variablespriceandsalePrice. Before the tag invokes the fragment attributes using thejsp:invokeelement, the web container passes values for the variables back to the calling page.<%@ attribute name="bookDB" required="true" type="database.BookDB" %> <%@ attribute name="color" required="true" %> <%@ attribute name="normalPrice" fragment="true" %> <%@ attribute name="onSale" fragment="true" %> <%@ variable name-given="price" %> <%@ variable name-given="salePrice" %> <center> <table> <c:forEach var="book" begin="0" items="${bookDB.books}"> <tr> <c:set var="bookId" value="${book.bookId}" /> <td bgcolor="${color}"> <c:url var="url" value="/bookdetails" > <c:param name="bookId" value="${bookId}" /> </c:url> <a href="${url}">< strong>${book.title} </strong></a></td> <td bgcolor="${color}" rowspan=2> <c:set var="salePrice" value="${book.price * .85}" /> <c:set var="price" value="${book.price}" /> <c:choose> <c:when test="${book.onSale}" > <jsp:invoke fragment="onSale" /> </c:when> <c:otherwise> <jsp:invoke fragment="normalPrice"/> </c:otherwise> </c:choose>  </td> ... </table> </center>The page
bookcatalog.jspinvokes thecatalogtag that has the simple attributesbookDB, which contains catalog data, andcolor, which customizes the coloring of the table rows. The formatting of the book price is determined by two fragment attributes--normalPriceandonSale--that are conditionally invoked by the tag according to data retrieved from the book database.<sc:catalog bookDB ="${bookDB}" color="#cccccc"> <jsp:attribute name="normalPrice"> <fmt:formatNumber value="${price}" type="currency"/> </jsp:attribute> <jsp:attribute name="onSale"> <strike> <fmt:formatNumber value="${price}" type="currency"/> </strike><br/> <font color="red"> <fmt:formatNumber value="${salePrice}" type="currency"/> </font> </jsp:attribute> </sc:catalog>The screen produced by
bookcatalog.jspis shown in Figure 15-2. You can compare it to the version in Figure 12-2.

Dynamic Attribute Example
The following code implements the tag discussed in Dynamic Attributes. An arbitrary number of attributes whose values are colors are stored in a
Mapnamed by thedynamic-attributesattribute of thetagdirective. The JSTLforEachtag is used to iterate through theMapand the attribute keys and colored attribute values are printed in a bulleted list.