Chapter 29. Extending JSP with New Tags

In this chapter

Many times, you need a Web designer to design your Java Server Pages. The designer might be an expert with HTML, but might not know anything about Java. The <jsp:useBean>, <jsp:setProperty>, and <jsp:getProperty> tags allow you to make parts of your application accessible through tags, but you can't invoke bean methods without using either the <% or <%= tags. You can also provide some additional flexibility with the <jsp:include> and <jsp:forward> tags, but these tags are often overkill. You need a way to allow a Web designer to perform a specific operation without knowing any Java.

JSP Tag Extensions let you create new tags that a Web designer can insert directly into a Java Server Page. Through Tag Extensions, you can define tags that let you insert data into the output stream, include sections of a page only if certain conditions are met, and even modify the contents of the page itself before they are sent back to the browser.

A "Hello World" Tag

To create a custom JSP tag, you must first create a Java class that acts as a tag handler. Whenever your custom tag appears in a Java Server Page, the JSP engine invokes your tag handler. If your custom tag doesn't care about the body text between its opening and closing tags, you can use the simple TagSupport class, which implements the Tag interface. If you need to access and possibly change the body text within the opening and closing tags, you must subclass the BodyTagSupport class instead. The BodyTagSupport class implements the BodyTag interface, which allows you to access body text.

For example, suppose you define a custom tag named <mytags:DoSomething> and you use it this way:

<mytags:DoSomething>
   Here is some text
</mytags:DoSomething>

If your tag handler only implements the Tag interface, it can't see the body text (that is, "Here is some text"). All it can do is decide whether you can see the body text or not. Your custom tag can also generate its own output.

Listing 29.1 shows the HelloWorldTagHandler class that inserts the familiar "Hello World!" message into the JSP response. Because it doesn't need to access its body text, it subclasses TagSupport.

Example 29.1. Source Code for HelloWorldTag.java

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloWorldTag extends TagSupport
{
    public int doStartTag()
        throws JspException
    {
        try
        {
            JspWriter out = pageContext.getOut();

            out.println("<h1>Hello World!</h1>");
        }
        catch (IOException ioExc)
        {
            throw new JspException(ioExc.toString());
        }

        return SKIP_BODY;
    }

public int doEndTag()
    {
        return EVAL_PAGE;
    }
}
					

Note

Don't worry about the SKIP_BODY and EVAL_PAGE return values just yet. You'll see what they mean shortly.

Listing 29.2 shows a JSP that calls HelloWorldTag via a tag named <mytag:hello>. At this point, you don't know how to relate HelloWorldTag to <mytag:hello>. You will see that in the next section.

Example 29.2. Source Code for TestHello.jsp

<%@ taglib uri="/hello" prefix="mytag" %>
<html>
<body>
<mytag:hello/>
</body>
</html>

Figure 29.1 shows the output from TestHello.jsp.

Custom tags can insert text into the response.

Figure 29.1. Custom tags can insert text into the response.

Packaging and Installing a Tag

When you create a custom tag library you must also create a Tag Library Descriptor (TLD) that describes each tag in your tag library. Listing 29.3 shows the TLD for the HelloWorldTag Java class.

Example 29.3. Source Code for hello.tld

<?xml version="1.0"?>
<!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
    "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>
    <tlibversion>1.0</tlibversion>
    <jspversion>1.1</jspversion>
    <shortname>hello</shortname>
    <uri></uri>
    <info>
        An example Hello World tag
    </info>

    <tag>
        <name>hello</name>
        <tagclass>HelloWorldTag</tagclass>
    </tag>
</taglib>
					

The first few lines of hello.tld are pretty standard for an XML file. You must start with the <?xml?> tag, of course. The next line defines the location of the Document Type Definition for this kind of document. The <!DOCTYPE tag should be the same for all your TLDs.

<taglib> is the root tag for a TLD and encloses all the other tags. Remember an XML document has a single root tag that encloses everything else in the document. The next few tags describe the tag library.

The <tlibversion> tag describes the version number of the tag library, and the <jspversion> tag indicates which version of JSP the tag library requires. The <shortname> tag gives a short name for the tag library that might be used within a JSP Page Authoring tool. The idea is that you would load various tag libraries and see a list of the available libraries. The short name is the name you would see in the list. The <info> tag gives the long description of the tag library. Finally, the <uri> tag gives the normal URI for this tag library. Again, the URI is handy for a page authoring tool where you might have a local copy of the library, but when you build a JSP that uses the tag library, you might want to put the normal URI into the library. In other words, the page authoring tool might see the tag library on the hard drive with a path like c: taglibs hello.tld. You don't want the JSP to refer to the tag library with a URI of file:///c/taglibs/hello.tlb, because the JSP might be deployed on a machine that doesn't have a c: taglibs directory. You want a URI that works no matter where the JSP is deployed.

After the initial information describing the tag library, you can list the tags contained in the library. This tag library contains a single tag with a name of hello (as indicated by the <name> tag). The tag name, along with the prefix for the tag library, make up the full tag that you put in the JSP. In other words, you take the tag name hello and combine it with the prefix specified in the JSP (mytag in Listing 29.1) to get the full name of the tag, which is <mytag:hello>.

Note

The reason for splitting the naming into two parts is that several people might make a tag named hello in their tag libraries. You need a way to specify which tag you mean, so you must use a prefix to indicate which library you are referring to.

Finally, the <tagclass> tag indicates the fully qualified pathname of the class that implements this tag.

Now that you have created the TLD file, you must deploy the tag library and your test Web page as a Web application. Create a directory called WEB-INF and in the WEB-INF directory, create a file called web.xml that looks like the file in Listing 29.4.

Example 29.4. Source Code for web.xml

<?xml version="1.0"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">

<web-app>
    <display-name>Tag Demo</display-name>
    <description>An application for testing custom tags</description>
    <taglib>
        <taglib-uri>/hello</taglib-uri>
        <taglib-location>/WEB-INF/tld/hello.tld</taglib-location>
    </taglib>
</web-app>
					

Most of the web.xml file should be familiar from the example in Chapter 28, "Packaging a JSP Application," where you packaged a Web application into a WAR file. There are a few tags that you haven't seen before, however. The <taglib> tag defines a tag library that the Web application uses. The <taglib-uri> tag defines the name that a JSP would use as the URI for this tag library. Look back at Listing 29.2 and you can see that TestHello.jsp specifies /hello as the URI for the tag library, which matches what you see in web.xml. The <taglib-location> tag specifies the location of the hello.tld file, which is the file from Listing 29.3. According to the web.xml file, hello.tld should be stored in a directory called tld that is below the WEB-INF directory.

Now, under the WEB-INF directory, create a classes directory and copy the HelloWorldTag.class file to the classes directory. Make sure that TestHello.jsp is in the same directory as the WEB-INF directory. Now, create a file called tagdemo.war by going to the directory where WEB-INF and TestHello.jsp are located and entering the following command:

jar cvf tagdemo.war WEB-INF TestHello.jsp

The jar command should respond with something like this:

added manifest
adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/HelloWorldTag.class(in = 839) (out= 486)(deflated 42%)
adding: WEB-INF/tld/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/tld/hello.tld(in = 457) (out= 268)(deflated 41%)
adding: WEB-INF/web.xml(in = 441) (out= 262)(deflated 40%)
adding: TestHello.jsp(in = 87) (out= 68)(deflated 21%)

Now follow the procedure from Chapter 28 to install the WAR file in your Web server. After the file is installed, you should be able to access TestHello.jsp and see the output shown previously in Figure 29.1.

Source Code for web.xmllistingsweb.xml, deploying tag librariesweb.xmldeploying tag librariestag librariesdeployingdeployingtag librarieslibrariestagdeploying If you are having trouble installing your custom tag library, see "Install Problems" in the "Troubleshooting" section at the end of this chapter.

Conditional Includes Using Custom Tags

Earlier in Listing 29.1, you saw that the doStartTag method in the custom tag returns a value of SKIP_BODY and the doEndTag method returns a value of EVAL_PAGE. These values tell the JSP engine how to handle the content between the start and end of the custom tag, and also whether to continue evaluating the rest of the page after the custom closing tag. When doStartTag returns SKIP_BODY, it tells the JSP engine to ignore the content between the start and end of the custom tag. If the doStartTag returns EVAL_BODY_INCLUDE, the data between the start and end tags is copied to the response and any nested tags are evaluated.

When doEndTag returns EVAL_PAGE, it tells the JSP engine to continue evaluating the rest of the page. If doEndTag returns SKIP_PAGE, the JSP engine ignores everything else in the JSP after the closing tag and returns the response to the browser.

Because you can control whether the JSP engine includes body text between the start and end of a tag, you can create tags that include text only if certain conditions are met.

Listing 29.5 shows a custom tag that only includes its content when the time of day is between 6 a.m. and 6 p.m.

Example 29.5. Source Code for DayTag.java

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.util.*;

public class DayTag extends TagSupport
{
    public int doStartTag()
        throws JspException
    {
// Get the time of day
        GregorianCalendar currTime = new GregorianCalendar();

// Get the hour of day
        int hour = currTime.get(Calendar.HOUR_OF_DAY);

// If the time is between 6AM and 6PM, tell the JSP engine to
// include the text between the start and end tag
        if ((hour >= 6) && (hour <= 18))
        {
            return EVAL_BODY_INCLUDE;
        }
        else
        {
// Otherwise, ignore the body text
            return SKIP_BODY;
        }
    }

    public int doEndTag()
    {
        return EVAL_PAGE;
    }
}
					

You can easily make a NightTag class that does the same test except that it only includes the body content when the hour is less than 6 or greater than 18. Listing 29.6 shows the daynight.tld file describing the DayTag class and its companion NightTag class.

Example 29.6. Source Code for daynight.tld

<?xml version="1.0"?>
<!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
    "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>
    <tlibversion>1.0</tlibversion>
    <jspversion>1.1</jspversion>
    <shortname>daynight</shortname>
    <uri></uri>
    <info>
        day tag to include text between 6am and 6pm, night to include
        text otherwise
    </info>

    <tag>
        <name>day</name>
        <tagclass>DayTag</tagclass>
    </tag>

    <tag>
        <name>night</name>
        <tagclass>NightTag</tagclass>
    </tag>
</taglib>
					

The daynight.tld file should seem pretty familiar now. It doesn't contain any tags that you haven't already seen from the hello.tld file; it just defines two tags instead of one. Listing 29.7 shows a JSP that tests the day and night tags to make sure they work.

Example 29.7. Source Code for TestDayNight.jsp

<%@ taglib uri="/daynight" prefix="dn" %>
<html>
<body>

<dn:day>
<h1>My, what a beautiful day it is!</h1>
</dn:day>

<dn:night>
<h1>I hate night, it's too dark for golf!</h1>
</dn:night>

</body>
</html>

Figure 29.2 shows the output from TestDayNight.jsp when run during the day.

A custom tag can choose whether to include its body content.

Figure 29.2. A custom tag can choose whether to include its body content.

Figure 29.3 shows the output from TestDayNight.jsp when run at night. Notice that the text between the <dn:day> and </dn:day> doesn't show up.

The <xx:night> tag only shows up at night.

Figure 29.3. The <xx:night> tag only shows up at night.

Accessing Tag Attributes

Just like regular tags, custom tags can have attribute values. You need to provide get and set methods for each attribute. Although you enclose each attribute in quotes, you can have numeric attributes in your custom tag. The JSP engine performs the conversion automatically. Listing 29.8 shows a custom tag to display a checkerboard. The board has several options that can be changed by various attributes in the <xx:checkerboard> tag.

Example 29.8. Source Code for CheckerboardTag.java

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;
public class CheckerboardTag extends TagSupport
{
// Variables to hold the attributes for the checkerboard

    protected int width = 40;
    protected int height = 40;
    protected int rows = 8;
    protected int cols = 8;
    protected String darkColor = "#000040";
    protected String lightColor = "#FFFFC0";

    public int doStartTag()
        throws JspException
    {
        try
        {
            JspWriter out = pageContext.getOut();

            out.println("<table>");

// Count down so the bottom row is row 0 (it helps for
// calculating the colors, the bottom left should be dark)

            for (int i=rows-1; i >= 0; i—)
            {
// Start a new row with the specified height
                out.print("<tr height=""+height+"">");

// Loop through the columns
                for (int j=0; j < cols; j++)
                {

// Start making the cell for this square
                    out.print("<td width=""+width+"" bgcolor="");

// If row+column is even, make the square dark. The lower-left
// corner should always be dark

                    if ((i + j) % 2 == 0)
                    {
                        out.print(darkColor);
                    }
                    else
                    {
                        out.print(lightColor);
                    }
                        out.print("">&nbsp;</td>");
                    }
                    out.println("</tr>");
                }
                out.println("</table>");
            }
            catch (IOException ioExc)

        {
            throw new JspException(ioExc.toString());
        }

        return SKIP_BODY;
    }

    public int doEndTag()
    {
        return EVAL_PAGE;
    }

// Get/set methods, just like in a bean

    public int getHeight() { return height; }
    public void setHeight(int aHeight) { height = aHeight; }

    public int getWidth() { return width; }
    public void setWidth(int aWidth) { width = aWidth; }

    public int getRows() { return rows; }
    public void setRows(int aRows) { rows = aRows; }

    public int getCols() { return cols; }
    public void setCols(int aCols) { cols = aCols; }

    public String getDarkColor() { return darkColor; }
    public void setDarkColor(String aDarkColor)
    {
        darkColor = aDarkColor;
    }

    public String getLightColor() { return lightColor; }
    public void setLightColor(String aLightColor)
    {
        lightColor = aLightColor;
    }
}
					

Now, just putting the attributes in the tag is not enough. You must also configure the attributes in the TLD file. Each attribute is defined using an <attribute> tag. Within the <attribute> tag there is a <name> tag defining the name of the attribute, a <required> tag indicating whether the attribute is required, and a tag called <rtexprvalue>. You might have noticed other JSP examples where the value of a tag attribute was specified using a JSP expression (the <%= tag). Evaluating custom tags where the attribute value can be generated at runtime is a difficult task for the JSP engine. Rather than allow all attribute expressions to be computed at runtime, the JSP engine wants you to explicitly mark the attributes whose values can be generated at runtime. Set the value of <rtexprvalue> to yes or true if you need the attribute to be evaluated at runtime. The value is false by default.

For the <required> tag, you can use values of yes, no, true, or false. The <required> tag is false by default, meaning that if you don't explicitly say otherwise, an attribute is optional.

Listing 29.9 shows the TLD file for the CheckerboardTag class.

Example 29.9. Source Code for checkerboard.tld

<?xml version="1.0"?>
<!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
    "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>
    <tlibversion>1.0</tlibversion>
    <jspversion>1.1</jspversion>
    <shortname>checkerboard</shortname>
    <uri></uri>
    <info>
        A tag that prints out a checkerboard pattern
    </info>

    <tag>
        <name>checkerboard</name>
        <tagclass>CheckerboardTag</tagclass>
        <attribute>
            <name>width</name>
            <required>no</required>
        </attribute>
        <attribute>
            <name>height</name>
            <required>no</required>
        </attribute>
        <attribute>
            <name>rows</name>
            <required>no</required>
        </attribute>
        <attribute>
            <name>cols</name>
            <required>no</required>
        </attribute>
        <attribute>
            <name>darkColor</name>
            <required>no</required>
        </attribute>
        <attribute>
            <name>lightColor</name>
            <required>no</required>
        </attribute>
    </tag>
</taglib>
					

The checkerboard.tld file is similar to the other TLD files you have seen except that this one defines attributes for its tag. Listing 29.10 shows a JSP that tests out the CheckerboardTag class.

Example 29.10. Source Code for TestCheckerboard.jsp

<%@ taglib uri="/checkerboard" prefix="cb" %>
<html>
<body>
<cb:checkerboard width="50" height="50" rows="8" cols="8"
    darkColor="#000000" lightColor="#ffffff"/>

</body>
</html>

Figure 29.4 shows the output from TestCheckerboard.jsp.

You can use attributes to change the behavior of a custom tag.

Figure 29.4. You can use attributes to change the behavior of a custom tag.

You can use attributes to change the behavior of a custom tag. If you are having trouble setting attribute values in a custom tag, see "Attribute Values" in the "Troubleshooting" section at the end of this chapter.

Processing Body Content with a Custom Tag

One of the most interesting features of the JSP tag extension mechanism is that the tags can access their own body content. That is, a tag can see the text contained between its begin and end tags and even modify that text.

Processing body text is a little more involved and requires a specialized tag interface. A basic tag implements an interface called Tag and usually inherits from the TagSupport class. A tag that processes its body text must implement the BodyTag interface and usually inherits from BodyTagSupport.

Because the BodyTag interface extends the Tag interface, it includes the doStartTag and doEndTag methods. A tag implementing the BodyTag interface might still return SKIP_BODY from the doStartTag method to indicate that the JSP engine should not evaluate the text between the beginning and end of the tag. Instead of returning EVAL_BODY_INCLUDE, however, a body tag must return EVAL_BODY_TAG to include its body text.

Note

A custom tag that implements the BodyTag must not return EVAL_BODY_INCLUDE, otherwise the JSP engine reports an error. If a custom tag that only implements the Tag interface returns EVAL_BODY_TAG, the JSP engine also reports an error. In other words, EVAL_BODY_INCLUDE can only be used with non-body tags and EVAL_BODY_TAG can only be used with a body tag.

Body tags have a very peculiar way of operating on body text. When the JSP engine first starts evaluating the body text, it calls the doInitBody method in the custom tag. There is no return value for doInitBody and it is intended for you to perform initialization in this method. After the JSP engine evaluates the body content, it calls doAfterBody in the custom tag. Whenever doAfterBody is called, the custom tag can access the current body content by calling getBodyContent. The peculiar thing is that if doAfterBody returns EVAL_BODY_TAG, the JSP engine re-evaluates the current body content and calls doAfterBody again! The JSP engine finally accepts the content after doAfterBody returns SKIP_BODY .

That sounds very counter-intuitive, and it is. Before delving into some of the complexities, take a look at a very minimal body tag. Listing 29.11 shows a body tag that prints its body text to the response (in other words, it shows the text between its begin and end tags as if the tags weren't there).

Example 29.11. Source Code for TestBodyTag.java

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class TestBodyTag extends BodyTagSupport
{
    public int doStartTag()
        throws JspException
    {
        return EVAL_BODY_TAG;
    }

    public int doEndTag()
    {
        return EVAL_PAGE;
    }

    public void doInitTag()
    {
    }
    public int doAfterBody()
        throws JspException
    {
// Get the current body content
        BodyContent body = getBodyContent();

        try
        {
// Ask the body content to write itself out to the response
            body.writeOut(body.getEnclosingWriter());
        }
        catch (IOException exc)
        {
            throw new JspException(exc.toString());
        }
// Tell the JSP engine that the body content has been evaluated
        return SKIP_BODY;
    }
} java
					

Source Code for TestBodyTag.javacustom tagsbody contentprocessingprocessingbody contentcustom tagsbody contentcustom tagsprocessingtagscustomprocessing body contentlistingsTestBodyTag.java, processing body contentTestBodyTag.java, processing body content If you are having trouble getting a body tag to work, see "Body Tags" in the "Troubleshooting" section at the end of this chapter.

In Listing 29.11, you see that you can write the body content into the response by calling body.writeOut(body.getEnclosingWriter()). The body.writeOut method writes the contents of the body to any Writer object. The getEnclosingWriter method returns the writer for the section of the response that this body tag is contained in. You can use body.getReader to get a Reader object that lets you read the contents of the body, or just call body.getString to get the contents as a string. In fact, an alternate way to write out the contents of a body is

body.getEnclosingWriter().println(body.getString());

Caution

Make sure you always have a case where your doAfterBody method returns SKIP_BODY. If you only return EVAL_TAG_BODY, the JSP engine will get stuck in an infinite loop calling your doAfterBody method over and over.

The odd looping behavior with doAfterBody gets even more confusing with the fact that the JSP engine does not re-parse the body content after each call to doAfterBody. In other words, if you write out some additional text or tags, those do not get added to the current body content. Why have this looping structure at all, then? Why can't you just use a for-loop? The reason for the looping behavior is that you might have a body tag with some nested custom tags that change the values of some variables, like this java:

<xx:bodyTag>
   Some HTML text
   <xx:computeNewValue/>
   Some more text
</xx:bodyTag>

In this example, the <xx:computeNewValue> tag calculates some value that helps determine when the <xx:bodyTag> tag should stop looping. It doesn't really matter what the values are; the important point is that the tag handler for <xx:computeNewValue> is called every time the body text is re-evaluated. If you tried to do a for-loop to print out the body text, you wouldn't have a way to call the tag handler for <xx:computeNewValue> java.

Adding Scripting Variables

Your custom tags can define scripting variables that are accessible to your Java Server Pages. In fact, you can even get the JSP engine to add a Java variable to the generated servlet to hold the value of your script variable. All you need to do is create a special TagExtraInfo class that describes the scripting variables your tag might define.

Listing 29.12 shows a subclass of TagExtraInfo that defines a scripting variable called scriptVar.

Example 29.12. Source Code for ScriptExtraInfo.java

import javax.servlet.jsp.tagext.*;
public class ScriptExtraInfo extends TagExtraInfo
{
public VariableInfo[] getVariableInfo(TagData data)
    {
        return new VariableInfo[] {
                new VariableInfo("scriptVar", "java.lang.String",
                true, VariableInfo.AT_END) } ;
    }
}
					

The tag itself doesn't need to know about the extra info class, but it does need to put the scripting variables into the page context so the Java Server Page can extract the value of each variable and place it in a local Java variable. Listing 29.13 shows a custom tag that puts a value into the page context.

Example 29.13. Source Code for ScriptTag.java

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;
public class ScriptTag extends TagSupport
{
    public int doStartTag()
        throws JspException
    {
        pageContext.setAttribute("scriptVar", "This is the script variable");

        return SKIP_BODY;
    }

    public int doEndTag()
    {
        return EVAL_PAGE;
    }
}
					

Listing 29.14 shows a Java Server Page that calls the ScriptTag custom tag and then accesses scriptVar as if it were a local variable.

Example 29.14. Source Code for TestScriptTag.jsp

<%@ taglib uri="/scripttag" prefix="xx" %>
<html>
<body>
<xx:setVar/>
<h1><%= scriptVar %></h1>
</body>
</html>
					

Note

You might be wondering how a value gets from the page context into a Java variable automatically. It isn't as automatic as you might think. According to the JSP specification, the JSP engine is responsible for getting the value from the page context and copying it to the local variable. If you examine the servlet generated from a JSP using a tag-generated scripting variable, you'll see a line that copies the value out of the page context.

To match a TagExtraInfo class to its associated tag, you must include a <teiclass> tag in the Tag Library Descriptor for the custom tag. Listing 29.15 shows the TLD for the ScriptTag class.

Example 29.15. Source Code for scripttag.tld

<?xml version="1.0"?>
<!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
    "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>
    <tlibversion>1.0</tlibversion>
    <jspversion>1.1</jspversion>
    <shortname>scripttag</shortname>
    <uri></uri>
    <info>
        An example scripting variable tag
    </info>

    <tag>
       <name>setVar</name>
       <tagclass>ScriptTag</tagclass>
       <teiclass>ScriptExtraInfo</teiclass>
    </tag>
</taglib>
					

Source Code for scripttag.tldlistingsscripttag.tld, adding script variablesscripttag.tld, adding script variablesaddingscripting variablescustom tagscustom tagsscripting variablesaddingvariablesscriptingadding to custom tagstagscustomadding scripting variablesTLDsscripttag.tld, adding script variables If you are having trouble defining scripting variables, see "Scripting Variables" in the "Troubleshooting" section at the end of this chapter.

The TagExtraInfo class actually serves two purposes. In addition to defining scripting variables, it has an isValid method that allows you to validate attribute values at JSP compile time. The isValid method takes an argument of type TagData and returns true if the combination of attributes in TagData is valid, or false if there is an error in the attributes. The idea here is that you can't define what constitutes a good attribute value or a good set of values without evaluating the values. By evaluating them when the JSP is compiled, you avoid any unnecessary runtime overhead.

The TagData class contains the following methods for examining the attributes for a tag:

Object getAttribute(String attrName)
Enumeration getAttributes()
String getAttributeString(String attrName)
String getId()
void setAttribute(String attrName, Object value)

Most of these methods are self-explanatory. The getId method is a shortcut for getAttributeString. ("id")

Because some attribute values must be evaluated at request time instead of compile time, the getAttribute method returns a special object named TagData.REQUEST_TIME_VALUE for any value that must be evaluated at request time. A request time attribute value is a value that can be described using the <%= %> tag pair.

Troubleshooting

Install Problems

Q1:

Why do I see my custom tag in the HTML output?

A1:

You most likely forgot to put the taglib directive at the top of the page. You also might not have remembered to use the prefix you defined in the taglib directive, or you mistyped the prefix or the tag name.

Q2:

Why do I get a compile error when I use a custom tag?

A2:

Well, the first thing to check is that it's really the tag that's causing the problem. Try removing the tag and see if that clears up the problem. Next, make sure that you have installed the tag library on the Web server. The class files should be under the WEB-INF/classes directory (WEB-INF must be capitalized, so don't count on web-inf working the same way). Also make sure you have a TLD file and that the web.xml file in the WEB-INF directory has the correct pathname for the TLD. Because custom tags are a very recent addition, not all JSP engines implement them the same way (some might not even implement them correctly). You might need to consult the documentation for your JSP engine to see if there are any additional notes for installing custom tag libraries.

Attribute Values

Q1:

Why do I get a runtime error when I try to set an attribute value?

A1:

There is probably some mismatch between the attribute type in the custom tag and the attribute value you are trying to set. For instance, trying to store the string "Fred" into an integer value isn't going to work.

Q2:

I created get and set methods, so why doesn't the JSP engine recognize my attributes?

A2:

Don't forget that you must also define the names of the attributes in the TLD file.

Body Tags

Q1:

When I use a body tag, why does the JSP engine stop responding?

A1:

You are probably stuck in an infinite loop caused by your doAfterBody method returning EVAL_BODY_TAG over and over instead of returning SKIP_BODY.

Q2:

I tried to write out some code in <% %> and re-evaluated the body text; why do the <% %> tags show up in the output?

A2:

Remember, the JSP engine only parses the body text one time. It might evaluate custom tags in the body text multiple times, but after the text is parsed, that's it.

Q3:

I rewrote the body text and returned EVAL_BODY_TAG; why do I still see the original body text?

A3:

Again, the JSP engine only parses the body text once. You will always receive the original body text in doAfterBody.

Scripting Variables

Q1:

I put a value in the page context, so why doesn't the JSP have a variable to hold the value?

A1:

You might have forgotten to create the TagExtraInfo object, or you forgot to link the TagExtraInfo object to the tag class by adding a <teiclass> item in the TLD file.

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

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