Chapter 8

Tag Files

You have seen in Chapter 7, “Writing Custom Tags” that custom tags enable you to write script-free JSP pages, thus promoting separation of labor, which means the page designer and the Java coder can work simultaneously. However, you have also learned that writing custom tags is a tedious chore, involving authoring and compiling tag handlers and defining the tags in the tag library descriptor.

Starting from JSP 2.0, you can use tag files, which are custom actions without tag handlers and tag library descriptors. With tag files no compilation is necessary and no tag library descriptor is required.

This chapter discusses tag files in detail. It starts with an introduction to tag files and then covers several aspects of writing custom tags using tag files only. The doBody and invoke standard actions are also discussed in the sections towards the end of the chapter.

Introduction to Tag Files

Tag files simplify the process of writing custom tags in two ways. First, tag files don’t need to be compiled as they are compiled the first time they are invoked. In addition, with tag files tag extensions can be written using JSP syntax alone. This means, someone who does not know Java can also write tag extensions!

Secondly, no tag library descriptor is needed. The tag element in the tag library descriptor describes the name to be used in a JSP page to reference the custom action. Using tag files, the name of a custom action is the same as the tag file representing the action, thus eliminating the need for the tag library descriptor.

JSP containers may choose to compile tag files into Java tag handlers or interpret the tag files. For example, Tomcat translates tag files into simple tag handlers that implement the javax.servlet.jsp.tagext.SimpleTag interface.

A tag file looks like a JSP page. It can have directives, scripts, EL expressions, standard actions, and custom tags. A tag file has a tag or tagx extension and can also include other files that contain a common resource. An include file for a tag file has tagf extension.

In order to work, tag files must be placed in the WEB-INF/tags directory of an application directory or a subdirectory under it. Just like tag handlers, tag files can be packaged into jar files.

A number of implicit objects are available from inside a tag file. You can access these objects from a script or an EL expression. Table 8.1 lists the implicit objects available in tag files. These implicit objects are similar to JSP implicit objects, discussed in Chapter 4, “JavaServer Pages.”

Object

Type

request

javax.servlet.http.HttpServletRequest

response

javax.servlet.http.HttpServletResponse

out

javax.servlet.jsp.JspWriter

session

javax.servlet.http.HttpSession

application

javax.servlet.ServletContext

config

javax.servlet.ServletConfig

jspContext

javax.servlet.jsp.JspContext

Table 8.1: Implicit objects available in tag files

Your First Tag File

This section shows how easy it is to write a tag file and use it. The example consists of one tag file and one JSP page that uses the tag file. It can be found in project tagfiles that accompanies this book. The directory structure for the application is depicted in Figure 8.1.

Figure 8.1: The directory structure of the tagfiles application

The tag file is called firstTag.tag and is printed in Listing 8.1.

Listing 8.1: The firstTag.tag File

<%@ tag import="java.util.Date" import="java.text.DateFormat"%>
<%
    DateFormat dateFormat = 
            DateFormat.getDateInstance(DateFormat.LONG);
    Date now = new Date(System.currentTimeMillis());
    out.println(dateFormat.format(now));
%>

As you can see in Listing 8.1, a tag file looks like a JSP page. The firstTag.tag file contains a tag directive with two import attributes and a scriptlet. The output of this tag file is the current date in long format. To use this tag file as a tag extension, all you need to do is save it in the WEB-INF/tags directory of your application. The tag file name is important because it indicates the tag name. The tag name for the firstTag.tag file is firstTag.

Listing 8.2 presents a firstTagTest.jsp page that uses the firstTag.tag file.

Listing 8.2: The firstTagTest.jsp Page

<%@ taglib prefix="easy" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head><title>Testing firstTag</title></head>
<body>
Today is <easy:firstTag/>
</body>
</html>

You can invoke firstTagTest.jsp with this URL:

http://localhost:8080/tagfiles/firstTagTest.jsp

Tag File Directives

Just like JSP pages, tag files can use directives to control how the JSP container will compile or interpret the tag files. Tag file directives have the same syntax as JSP directives:

<%@ directive (attribute="value")* %>

The asterisk (*) means that what is enclosed in the brackets can be repeated zero or more times. The syntax can be re-written in a more informal way as follows:

<%@ directive attribute1="value1" attribute2="value2" ... %>

Attributes must be enclosed with single quotes or double quotes, and white spaces after the opening <%@ and before the closing %> are optional but can improve readability.

All JSP directives except page are available in tag files. Instead of page, you have the tag directive at your disposal. Also, in tag files, there are two more directives you can use, attribute and variable. Table 8.2 lists all the directives that can appear in a tag file.

Directive

Description

tag

This directive is similar to the page directive for JSP pages.

include

Use this directive to include other resources from the tag file

taglib

Use this directive to use a custom tag library from inside the tag file

attribute

Use this directive to declare an attribute in a tag file.

variable

Use this directive to define a variable that you can expose to the calling JSP page.

Table 8.2: Tag file directives

Each of the directives is given in a separate section below.

The tag Directive

The tag directive is similar to the page directive you use in JSP pages. Here is the syntax of the tag directive:

<%@ tag (attribute="value")* %>

The syntax can be expressed in the following more informal form:

<%@ tag attribute1="value1" attribute2="value2" ... %>

The attributes for the tag directive are given in Table 8.3. All attributes are optional.

Attribute

Description

display-name

A short name to be displayed by an XML tool. The default value is the tag file name, without tag extension.

body-content

The information about the body content of this tag. The value can be empty, tagdependent, or scriptless (default).

dynamic-attributes

Indicates the support for dynamic attributes. The value identifies a scoped attribute in which to place a Map containing the names and values of the dynamic attributes passed during this invocation.

small-icon

A context-relative path, or a path relative to the tag source file, of a small image file to be used by XML tools. You don’t normally use this attribute.

large-icon

A context-relative path, or a path relative to the tag source file, of an image containing a large icon to be used by XML tools. You don’t normally use this attribute either.

description

A string describing this tag.

example

An informal description of an example of a use of this action.

language

The scripting language used in the tag file. The value for this attribute for the current version of JSP must be “java”

import

Used to import a Java type. The same as the import attribute in the page directive.

pageEncoding

Describes the character encoding for this tag file. The value is of the form “CHARSET”, which must be the IANA name for a character encoding. This attribute is the same as the pageEncoding attribute of the page directive.

isELIgnored

Indicates whether EL expressions are ignored or evaluated. The default value for this attribute is “false”, which means EL expressions are evaluated. This attribute is the same as the isELIgnored attribute of the page directive.

Table 8.3: Attributes for the tag directive

Except for the import attribute, all other attributes can only appear once within a tag directive or in multiple tag directives in the same tag file. For example, the following tag file is invalid because the body-content attributes appear more than once in multiple tag directives:

<%@ tag display-name="first tag file" body-content="scriptless" %>
<%@ tag body-content="empty" %>

The following is a valid tag directive even though the import attribute appears twice. This is because import can appear as many times as desired.

<%@ tag import="java.util.ArrayList" import="java.util.Iterator" %>

The following is also valid:

<%@ tag body-content="empty" import="java.util.Enumeration" %>
<%@ tag import="java.sql.*" %>

The include Directive

The include directive for a tag file is the same as the include directive for a JSP page. You use this directive to include the contents of other files in the current tag file. It is useful when you have a common resource that will be used by more than one tag files. The included resource can be static (e.g. an HTML file) or dynamic (e.g. another tag file).

As an example, the includeDemoTag.tag page in Listing 8.3 shows a tag file that includes a static resource (included.html) and a dynamic resource (included.tagf).

Listing 8.3: The includeDemoTag.tag file

This tag file shows the use of the include directive. 
The first include directive demonstrates how you can include
a static resource called included.html.
<br/>
Here is the content of included.html:
<%@ include file="included.html" %>
<br/>
<br/>
The second include directive includes another dynamic resource: 
included.tagf.
<br/>
<%@ include file="included.tagf" %>

The included.html and included.tagf files are given in Listings 8.4 and 8.5, respectively. Both are to be saved in the same directory as the includeDemoTag.tag file.

Note that the recommended extension for a segment for a tag file is tagf.

Listing 8.4: The included.html file

<table>
<tr>
    <td><b>Menu</b></td>
</tr>
<tr>
    <td>CDs</td>
</tr>
<tr>
    <td>DVDs</td>
</tr>
<tr>
    <td>Others</td>
</tr>
</table>

Listing 8.5: The included.tagf file

<%
    out.print("Hello from included.tagf");
%>

To test the includeDemoTag.tag file, use the includeDemoTagTest.jsp page in Listing 8.6.

Listing 8.6: The includeDemoTagTest.jsp page

<%@ taglib prefix="easy" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head><title>Testing includes</title></head>
<body>
<easy:includeDemoTag/>
</body>
</html>

You can invoke the includeDemoTagTest.jsp page using the following URL:

http://localhost:8080/tagfiles/includeDemoTagTest.jsp

The result is shown in Figure 8.2.

Figure 8.2: Including other resources from a tag file.

For more information on the include directive, see Chapter 4, “JavaServer Pages.”

The taglib Directive

You can use custom tags from your tag file using the taglib directive. The taglib directive has the following syntax:

<%@ taglib uri="tagLibraryURI" prefix="tagPrefix" %>

The uri attribute specifies an absolute or relative URI that uniquely identifies the tag library descriptor associated with this prefix.

The prefix attribute defines a string that will become the prefix to distinguish a custom action.

With the taglib directive, you can use a custom tag of the following format for a custom tag that does not have a content body:

<prefix:tagName/>

Or, you can use this format for a custom tag that has a content body:

<prefix:tagName>body</prefix:tagName>

The taglib directive in a tag file is the same as the taglib directive in a JSP page.

As an example, consider the taglibDemo.tag file in Listing 8.7.

Listing 8.7: The taglibDemo.tag file

<%@ taglib prefix="simple" tagdir="/WEB-INF/tags" %>
The server's date: <simple:firstTag/>

It uses the firstTag.tag file in Listing 8.1 to display the server’s date. The taglibDemo.tag file is used by the taglibDemoTest.jsp page in Listing 8.8.

Listing 8.8: The taglibDemoTest.jsp page

<%@ taglib prefix="easy" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head><title>Testing taglib</title></head>
<body>
<easy:taglibDemo/>
</body>
</html>

You can invoke this JSP page using the following URL:

http://localhost:8080/tagfiles/taglibDemoTest.jsp

The attribute Directive

The attribute directive supports the use of attributes in a tag file. It is equivalent to the attribute element in the tag library descriptor. Here is the syntax of the attribute directive:

<%@ attribute (attribute="value")* %>

The syntax can be expressed in the following more informal form:

<%@ attribute attribute1="value1" attribute2="value2" ... %>

The attributes for the attribute directive is given in Table 8.4. The only required attribute is the name attribute.

Attribute

Description

name

The name for the attribute that this tag file accepts. The value for the name attribute must be unique throughout the current tag file.

required

Indicates whether this attribute is required. The value can be true or false (default)

fragment

Indicates whether this attribute is a fragment to be evaluated by the tag handler or a normal attribute to be evaluated by the container prior to being passed to the tag handler. The value is either true or false (default). The value is true if this attribute is to be evaluated by the tag handler.

rtexprvalue

Specifies whether the attribute value may be dynamically calculated at runtime by a scriplet expression. The value is either true (default) or false.

type

The type of the attribute value. The default is java.lang.String.

description

The description of this attribute.

Table 8.4: Attributes for the attribute directive

As an example, consider the encode.tag file in Listing 8.9 that can be used to HTML-encode a string. This encode tag defines an attribute, input, which is of type java.lang.String.

Listing 8.9: The encode.tag file

<%@ attribute name="input" required="true" %>
<%!
    private String encodeHtmlTag(String tag) {
        if (tag==null) {
            return null;
        }
        int length = tag.length();
        StringBuilder encodedTag = new StringBuilder(2 * length);
        for (int i=0; i<length; i++) {
            char c = tag.charAt(i);
            if (c=='<') {
                encodedTag.append("&lt;");
            } else if (c=='>') {
                encodedTag.append("&gt;");
            } else if (c=='&') {
                encodedTag.append("&amp;");
            } else if (c=='"') {
                encodedTag.append("&quot;");  
            } else if (c==' ') {
                encodedTag.append("&nbsp;");
            } else {
                encodedTag.append(c);
            }
        }
        return encodedTag.toString();
    }
%>
<%=encodeHtmlTag(input)%>

To test the encode.tag file, use the encodeTest.jsp page in Listing 8.10.

Listing 8.10: The encodeTest.jsp page

<%@ taglib prefix="easy" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head><title>Testing encode</title></head>
<body>
<easy:encode input="<br/> means changing line"/>
</body>
</html>

You can invoke the encodeTagTest.jsp page using the following URL:

http://localhost:8080/tagfiles/encodeTest.jsp

The result is shown in Figure 8.3.

Figure 8.3: Using attributes in a tag file.

The variable Directive

It is sometimes useful to expose values in a tag file to the calling JSP page. This is possible through the use of the variable directive in the tag file. In a tag file, the variable directive is analogous to the variable element in the tag library descriptor and defines the details of a variable in the tag handler that is accessible from the calling JSP page. Because a tag file can have multiple variable directives, it is possible to provide multiple values to the calling JSP page. Compare variable with the attribute directive that you use to pass a value from a JSP page to a tag file.

The syntax of the variable directive is as follows:

<%@ variable (attribute="value")* %>

The syntax can be expressed in the following more informal form:

<%@ variable attribute1="value1" attribute2="value2" ... %>

The attributes for the variable directive are given in Table 8.5.

Attribute

Description

name-given

The variable name that will be available to the scripting language or EL expressions in the calling JSP page. If the name-from-attribute is used, the name-given attribute must not be present, and vice-versa. The value for name-given must not be the same as any of the attributes in this tag file.

name-from-attribute

This attribute is similar to the name-given attribute. However, the value for this attribute is the name of an attribute whose value at the start of the tag invocation will give the name of the variable. A translation error will result if both or neither of the name-given and name-from-attribute attributes is specified.

alias

A locally scoped attribute to hold the value of this variable.

variable-class

The type of this variable. The default is java.lang.String.

declare

Indicates whether the variable is declared in the calling page or tag file after this tag invocation. The default is true.

scope

The scope of the scripting variable defined. The possible values are AT_BEGIN, AT_END, and NESTED (default).

description

The description of this variable.

Table 8.5: Attributes for the variable directive

You probably ask why you need the variable directive at all if you can just print the processing result to the JspWriter of the calling JSP page. This is because simply sending a String to the JspWriter deprives the calling JSP page of flexibility on how to use the result. As an example, the firstTag.tag file in Listing 8.1 outputs the server’s current date in long format. If you want to also provide the server’s current date in short format, then you’ll have to write another tag file. Having two tag files that perform similar functionality adds unnecessary maintenance headache. Alternatively, you can expose two variables in the tag file, longDate and shortDate.

The tag file in Listing 8.11 provides the server’s current date in two formats: long and short. It has two variables called longDate and shortDate.

Listing 8.11: The varDemo.tag

<%@ tag import="java.util.Date" import="java.text.DateFormat"%>
<%@ variable name-given="longDate" %>
<%@ variable name-given="shortDate" %>
<%
    Date now = new Date(System.currentTimeMillis());
    DateFormat longFormat =
            DateFormat.getDateInstance(DateFormat.LONG);
    DateFormat shortFormat = 
            DateFormat.getDateInstance(DateFormat.SHORT);
    jspContext.setAttribute("longDate", longFormat.format(now));
    jspContext.setAttribute("shortDate", shortFormat.format(now));
%>
<jsp:doBody/>

Notice that you set a variable using the setAttribute method on the JspContext of the tag. The jspContext implicit object represents this object. (See the section, “Implicit Objects” later in this chapter). The set tag in the JSP Standard Tag Library (JSTL) encapsulates this functionality. If you are familiar with JSTL, you can use this tag instead of the setAttribute method. JSTL was discussed in length in Chapter 6, “JSTL.”

Also note that you must use the doBody standard action to invoke the tag body. For more information, see the sections doBody and invoke later in this chapter.

To test the varDemo.tag file, use the varDemoTest.jsp page in Listing 8.12.

Listing 8.12: The varDemoTest.jsp page

<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head><title>Testing variable</title></head>
<body>
Today's date:
<br/>
<tags:varDemo>
In long format: ${longDate}
<br/>
In short format: ${shortDate}
</tags:varDemo>
</body>
</html>

You can invoke the varDemoTest.jsp page using the following URL:

http://localhost:8080/tagfiles/varDemoTest.jsp

Figure 8.4 shows the result.

Figure 8.4: The result of varDemoTest.jsp

There are many cases in which you would want to use variables. As another example, suppose you want to write a custom action that fetches the details of a product from the database given a product identifier. To solve this problem, you can use an attribute to pass the product identifier. For each piece of information, you provide a variable to store that information. Therefore, you’d end up with the following variables: name, price, description, imageUrl, etc.

doBody

The doBody standard action can only be used from inside a tag file. You use it to invoke the body of a tag. You’ve seen doBody in action in the tag file in Listing 8.11. In this section you’ll learn about doBody in more detail.

The doBody action can have attributes. You use these attributes if you want to direct the output of the tag invocation to a variable. If used without an attribute, the doBody standard action writes the output to the JspWriter of the calling JSP page.

The doBody standard action’s attributes are given in Table 8.6. All attributes are optional.

Attribute

Description

var

The name of a scoped attribute to store the output of the tag body invocation. The value is stored as a java.lang.String. Only one of the var or varReader attribute may be present.

varReader

The name of a scoped attribute to store the output of the tag body invocation. The value is stored as a java.io.Reader. Only one of the var or varReader attribute may be present.

scope

The scope for the resulting variable.

Table 8.6: Attributes for the doBody action

The following example shows how to use doBody to invoke a tag body and store the output in a session-scoped variable called referer. Suppose you have a web site for selling toys and you advertised your web site heavily in many search engines. Of course, you would want to know which search engine redirects the most traffic that results in a sale. To find out, you could record the referer header of the main page of your web application. You use a tag file to store the value of the referer header as a session attribute. Later, if the user decides to purchase a product, you can obtain the session attribute value and insert it into a database table.

The example consists of an HTML file (searchEngine.html), two JSP pages (main.jsp and viewReferer.jsp), and one tag file (doBodyDemo.tag). The main.jsp page is the main page for the web site. It uses the doBodyDemo custom tag to store the referer header. To view the referer header value, you use the viewReferer.jsp page. If you invoke the main.jsp page by directly typing its URL, the referer header will be null. Therefore, you have to use the searchEngine.html file to go to the main.jsp page.

The doBodyDemo.tag file is given in Listing 8.13.

Listing 8.13: The doBodyDemo.tag

<jsp:doBody var="referer" scope="session"/>

That’s right. The doBodyDemo.tag file consists only of one line: a doBody standard action. What it does is invoke the body of the tag and store the output in a session attribute called referer.

The main.jsp page is presented in Listing 8.14.

Listing 8.14: The main.jsp page

<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head><title>Testing doBody</title></head>
<body>
Your referer header: ${header.referer}
<br/>
<tags:doBodyDemo>
    ${header.referer}
</tags:doBodyDemo>
<a href="viewReferer.jsp">View</a> the referer as a Session attribute.
</body>
</html>

The main.jsp page prints the value of the referer header, using text and an EL expression:

Your referer header: ${header.referer}
<br/>

It then uses the doBodyDemo tag, passing the referer header as the body.

<tags:doBodyDemo>
    ${header.referer}
</tags:doBodyDemo>

Next it prints a link to the viewReferer.jsp page for your convenience:

<a href="viewReferer.jsp">View</a> the referer as a Session attribute.

The viewReferer.jsp page is shown in Listing 8.15.

Listing 8.15: The viewReferer.jsp page

<!DOCTYPE html>
<html>
<head><title>referer</title></head>
<body>
The referer header of the previous page is ${sessionScope.referer}
</body>
</html>

The viewReferer.jsp page prints the value of a session attribute called referer using an EL expression.

Last, the searchEngine.html is given in Listing 8.16:

Listing 8.16: The searchEngine.html file

<!DOCTYPE html>
<html>
<head><title>searchEngine</title></head>
<body>
Please click <a href="main.jsp">here</a>
</body>
</html>

To test the example, first invoke the searchEngine.html file using the following URL:

http://localhost:8080/tagfiles/searchEngine.html

You’ll see the searchEngine.html page in Figure 8.5.

Figure 8.5: The searchEngine.html page

Now, click the link to go to the main.jsp page. The referer header of the main.jsp page will be the URL of the searchEngine.html. Figure 8.6 shows the content of the main.jsp page.

Figure 8.6: The main.jsp page

The main.jsp page invoke the doBodyDemo custom action that stores the referer session attribute. Now, click the view link in the main.jsp page to see the session attribute value. You’ll see something similar to Figure 8.7.

Figure 8.7: The viewReferer.jsp page

invoke

The invoke standard action is similar to doBody and can be used in a tag file to invoke a fragment attribute. Recall that an attribute can have a fragment attribute whose value is either true or false. If the fragment attribute value is true, the attribute is a fragment attribute, which you can invoke as many times as you want from a tag file. invoke can have attributes too. The attributes for invoke are presented in Table 8.7. Note that only the fragment attribute is required.

Attribute

Description

fragment

The name used to identify this fragment during this tag invocation.

var

The name of a scoped attribute to store the output of the tag body invocation. The value is stored as a java.lang.String. Only one of the var or varReader attribute can be present.

varReader

The name of a scoped attribute to store the output of the tag body invocation. The value is stored as a java.io.Reader. Only one of the var or varReader attribute can be present.

scope

The scope for the resulting variable.

Table 8.7: Attributes for the invoke action

As an example, consider the invokeDemo.tag file in Listing 8.17.

Listing 8.17: The invokeDemo.tag file

<%@ attribute name="productDetails" fragment="true" %>
<%@ variable name-given="productName" %>
<%@ variable name-given="description" %>
<%@ variable name-given="price" %>
<%
    jspContext.setAttribute("productName", "Pelesonic DVD Player");
    jspContext.setAttribute("description", 
        "Dolby Digital output through coaxial digital-audio jack," + 
        " 500 lines horizontal resolution-image digest viewing");
    jspContext.setAttribute("price", "65");
%>
<jsp:invoke fragment="productDetails"/>

The invokeDemo.tag file uses the attribute directive and its fragment attribute is set to true. It also defines three variables and sets the value for those variables. The last line of the tag file invoke the fragment productDetails. Because there is no var or varReader attribute in the invoke standard action, the result of tag invocation will be directed to the JspWriter of the calling JSP page.

To test the tag file, use the invokeTest.jsp page in Listing 8.18.

Listing 8.18: The invokeTest.jsp page

<%@ taglib prefix="easy" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html>
<html>
<head>
<title>Product Details</title>
</head>
<body>
<easy:invokeDemo>
    <jsp:attribute name="productDetails">
        <table width="220" border="1">
        <tr>
            <td><b>Product Name</b></td>
            <td>${productName}</td>
        </tr>
        <tr>
            <td><b>Description</b></td>
            <td>${description}</td>
        </tr>
        <tr>
            <td><b>Price</b></td>
            <td>${price}</td>
        </tr>
        </table>
    </jsp:attribute>
</easy:invokeDemo>
</body>
</html>

You can use the following URL to call the invokeTest.jsp page.

http://localhost:8080/tagfiles/invokeTest.jsp

The result is shown in Figure 8.8.

Figure 8.8: Using the fragment attribute

Summary

In this chapter you have learned about tag files and how they make writing tag extensions much simpler. With tag files, you don’t need the tag library descriptor and you don’t even need to compile the tag handler. You have also seen how to use the invoke and doBody standard actions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.15.94