All Examples  All JSP Examples

JSP Tag Extension examples

This directory contains several JSP tag library examples. These show you how to define custom JSP tags that may be used in your JSP pages. Each example is contained in its own directory.

Here are the examples in order of complexity, and a brief description of the features they demonstrate:

counter
This example implements two simple empty-body Tags. One simply calls some server side code to increment a counter. The other displays the counter in a JSP page.

quote
This example demonstrates a body-tag that interprets the contents of its body and writes content out to the JSP page. The tag also uses optional attributes to configure its behavior. This example can be used for presenting a Java listing in an HTML page.

session
This example demonstrates how to use a body-tag to iterate over the contents of its body. The tag uses the ExtraTagInfo class to define new scripting variables that are available to the tag body content. Each time the body is evaluated, the value of the scripting variable is different, resulting in a different result output of the body evaluation.

This example iterates through the contents of an HTTP Session, displaying them in a table. The body of the tag defines each row of the table. The example allows you to add and remove attributes in the session.

sql
This example illustrates a set of nested tags that cooperate with one another. The <sql:query> tag uses the id attribute to configure the name of a nested scripting variable that is made available to its body. This is used by the <sql:results> tag, which iterates over a named result set generated from the query.

The <sql:query> tag is able to find the <sql:connection> tag that it is nested within by using the findAncestorWithClass() method of the TagSupport super class. This method finds the closest surrounding tag handler class of a specific type.

Both the <sql:connection> and <sql:query> tags can only be referenced from within their tag body. This is convenient to ensure that the JDBC Connection or ResultSet is closed when the closing tag is reached. A <query> tag must be nested within a <connection> tag, and a <result> tag must be nested within a named <query> tag.

the examples in detail

This section progressively describes the important aspects of each example and explains how the examples are executed within the Tag Extension framework. Read each example in turn, since each explanation will assume knowledge you have gained from the previous examples, and that you have understood the JSP and HTTP Servlet examples.

The Counter example

The counter example is located in the sub-directory counter. Unlike the other examples described here, it is not implemented as a Web Application to demonstrate that you don't have to use a Web Application format in order to use JSP tag extensions. It introduces the following tag extension library concepts:

setting up and running the example . . .

To run the counter example, follow these steps:

  1. Set up a development shell, as described in Setting your development environment. Change to the counter sub-directory and compile the classes into the SERVLET_CLASSES directory with:
     $  javac -d %SERVLET_CLASSES% *.java

  2. Copy the pagehits.jsp file and the entire directory images/ to the document root of the WebLogic Server.

  3. In the document root directory, create a subdirectory called WEB-INF. Copy the counter.tld file into the WEB-INF directory.

  4. Enable JSP pages in the WebLogic Server. For details, see Setting up WebLogic JSP in the Administrators Guide, "Setting WebLogic properties".

  5. Start (or restart) the WebLogic Server.

  6. In a web browser, request the URL:
      http://localhost:7001/pagehits.jsp

The example will create a new file called count.tmp in a temporary working directory determined by the servlet context. It uses this to keep track of the number of page hits. You may want to remove this file once you have run the example.

how it works . . .

Here are the points of interest about this example, and how they work.

The  pagehits.jsp  file

pagehits.jsp uses the following directive to include the counter tag library:

  <%@ taglib uri="/counter.tld" prefix="counter" %>

The JSP engine searches for the tag library descriptor file in a number of ways. For this example, you placed the counter.tld file in the WEB-INF sub-directory WEB-INF in the document root of the server.

The counter.tld file is the tag library descriptor for the tags used in the pagehits.jsp page. This directive associates the JSP keyword counter with this tag library. We could have chosen any other non-reserved word.

Now, in the rest of the JSP page, we can use the new tags from the counter tag library as shown here:

  <counter:increment/>
This will invoke the increment tag that is described in the counter.tld file.
  <counter:display/>
This will invoke the display tag that is described in the counter.tld file.

The  counter.tld  file

The counter.tld file, defines the tag library and the tags it contains. The following section defines the display tag.

  <tag>
    <name>display</name>
    <tagclass>weblogic.taglib.counter.Display</tagclass>
    <bodycontent>empty</bodycontent>
  </tag>

The <tagclass> element defines a Java class that implements the functionality of the display tag -- also referred to as the tag handler. This class is defined by the Display.java source file. We compiled the class into the servlet classpath.

The tag handler classes

This example uses two custom tags that are implemented by the tag handler classes Display and Increment. Since both of these tags are simple empty-body tags, their tag handlers must implement the javax.servlet.jsp.tagext.Tag interface, or the convenience class javax.servlet.jsp.tagext.TagSupport.

Both tag handlers only override the doStartTag() method, which is invoked when the tag is reached in the JSP page. The Increment class increments the current page hits count, via the Count class. The Display class looks up the current count, and inserts a sequence of numeral images into the JSP page that represent the current count. These images are located in the "images/" directory of the document root.

The page-hits count is maintained in a file named "count.tmp" on the file system of the server. This file is located in a temporary working directory that is determined by the ServletContext attribute javax.servlet.context.tempdir. The tag handler classes look up this attribute value using the following code:

    File tempDir = (java.io.File) pageContext.getServletContext().
       getAttribute("javax.servlet.context.tempdir");
This provides a deployment-independent location to store temporary working files.


The Quote example

The quote example is located in the sub-directory quote. It is implemented as a simple un-archived Web Application directory structure where the quote directory is the root of the Web Application. It introduces the following tag extension library concepts:

The quote example defines a body-tag that processes its body content as a Java source listing. The Java source is modified for presentation in a web browser so that it uses legal HTML.

The content of the tag body is evaluated as JSP, allowing the content to be included directly from the Java source file using a JSP include directive. The body can also simply be included in-line in the JSP page. The evaluated body content is processed so that its characters appear as expected in the browser. For example, "<" signs are interpreted into "&amp;" escape characters in the output. Java comments and quoted text are also highlighted by including the appropriate HTML <font> tags.

It's possible to choose the colors used for highlighting and the font used in the listing by setting tag attributes from the JSP page.

setting up and running the example . . .

Here, we describe how to set up and run this Web Application example from the examples directory. You do not need to copy the files to another location on your host server. To try out this example, follow these steps:

  1. First you must build the tag handler Java classes. Set up your development environment, as described in Setting your development environment. Change to the "examples/jsp/tagext/quote/WEB-INF/" directory. Now, compile the CodeTag class using the following command:
     $  javac -d ./classes CodeTag.java

  2. Next, register the example Web Application in the weblogic.properties file using the line:
      weblogic.httpd.webApp.quote=/weblogic/examples/jsp/tagext/quote
    Where /weblogic/examples/jsp/tagext/quote is the root directory of the example Web Application. Here, we presume that you have installed the WebLogic Server on your file system under the root directory /weblogic for simplicity. You should alter the location as necessary.

    This property maps the example Web Application to the servlet context path URI quote. For more details on the servlet context path, see the Developers Guide Writing a Web Application.

  3. Start (or restart) the WebLogic Server and request the following URL from a web browser:
    http://localhost:7001/quote/showcode.jsp

The custom tag extension quotes and highlights the included Java code. The Java code presented is the actual implementation of the tag handler that is being used in this example.

how it works . . .

Here are the points of interest in this example, and how they work.

The directory structure

This example is implemented as a Web Application, with the quote directory as the root directory of the servlet context. For more details on the structure of a Web Application, see the Developers Guide Writing a Web Application.

The showcode.jsp page in the root directory references the tag extension library using the JSP directive:

  <%@ taglib uri="/weblogic/taglib/quote" prefix="quote" %>

In the previous example, we used a simple URI that gave the location of the Tag Library Descriptor from the document root. In a Web Application you can use another level of indirection. The taglib uri given above matches the <taglib-uri> pattern given in the <taglib> declaration in the web.xml configuration file. This file is found in the WEB-INF directory. Here is the relevant section from the file:

    <taglib>
        <taglib-uri>
            /weblogic/taglib/quote
        </taglib-uri>
        <taglib-location>
           /WEB-INF/quote.tld
        </taglib-location>
    </taglib>
Here, the uri need not point to a valid URI location. It is simply used as a string to identify the configuration in the web.xml file. This declaration gives the location of the Tag Library Descriptor file (found at /WEB-INF/quote.tld file), which declares the new extensions for the tag library. For more details on the syntax of a web.xml file, see the Developers Guide, Writing a Web Application.

The tag handler is implemented by the Java class located under in the WEB-INF/classes directory, under the full package name weblogic.taglib.quote.CodeTag. The Java source code for this class is in the WEB-INF directory.

Using tag attributes

Tag attributes allow the JSP page to pass String values into the tag handler. These can be used to configure the behavior of the tag. This example defines three attributes:

The Tag Library Descriptor declares each attribute for the tag within the <tag> element using an <attribute> tag for each attribute as follows:

  <attribute>
    <name>commentColor</name>
    <required>false</required>
    <rtexprvalue>true</rtexprvalue>
  </attribute>

The tag handler must implement setter and getter methods for each attribute, similar to those found in a Java Bean component. The first letter of the attribute is capitalized after the get/set word in the method name. For example, the attribute commentColor must have the following methods defined in the tag handler:

  public void setCommentColor(String col) { commentColor = col; }
  public String getCommentColor(String col) { return commentColor; }

The JSP container uses these methods to inform the tag handler instance of the attribute values before the doStartTag() method is invoked. The class need not have instance variables named exactly after the attributes, and may respond to the method invocations however it wishes, but it must provide these methods.

In this example, we store the given attribute values in instance variables, and refer to them from other methods in the tag handler class. This tag handler instance will only be used during the life cycle of this tag, so we don't need to worry about multi-threaded access to the same instance.

Defining a body-tag

The CodeTag class implements the BodyTagSupport class, which is used by JSP tag extensions that operate on their body content. This is a convenience class that implements default behavior for the BodyTag interface. This example overrides the doAfterBody() method, which is invoked after the body has been evaluated. An evaluated body is the result of processing the tag body content, which can include other nested JSP tags.

In the doAfterBody() method, the example obtains the content of the evaluated body as a String using the following line of code:

  String body = getBodyContent().getString();
The string is processed, and the result is sent back to the page via the JspWriter obtained from the getPreviousOut() method. This represents an output stream to the surrounding tag context, allowing the body of a nested tag to be evaluated before it is presented to the tag it is nested within. In fact, even if we used the pageContext to obtain the JspWriter of the response, our content will not be written directly to the response, but is caught and passes to the surrounding tag if we are in a nested tag. Otherwise, the output might appear out-of-order in the response page. The scope of getPreviousOut() used in a non-nested tag refers to the content of the JSP page.

The doAfterBody() method returns the control code SKIP_BODY, indicating that the JSP engine continues evaluating the JSP page. It is possible to cause the body to be re-evaluated at this point, which is illustrated in the Session example.


The Session example

The session example is located in the sub-directory session. It is implemented as a simple Web Application directory structure where the session directory is the root of the Web Application. It introduces the following tag extension library concepts:

setting up and running the example . . .

Here, we describe how to set up and run the example from the examples directory. You do not need to copy the files to another location on your host server. To try out this example, follow these steps:

  1. First you must build the tag handler Java classes. Set up your development environment, as described in Setting your development environment. Change to the session/WEB-INF/ directory. Now, compile the Java classes using the following command:
     $  javac -d ./classes *.java

  2. Next, register the example Web Application in the weblogic.properties file using the line:
      weblogic.httpd.webApp.session=/weblogic/examples/jsp/tagext/session
    Where /weblogic/examples/jsp/tagext/session is the root directory of this example Web Application. Here, we presume that you have installed the WebLogic Server on your file system under the root directory /weblogic for simplicity. You should alter the location in the property as necessary.

    This property maps the example Web Application to the servlet context path URI session. For more details on the servlet context path, see the Developers Guide Writing a Web Application.

  3. Start (or restart) the WebLogic Server and request the following URL from a web browser:
    http://localhost:7001/session/SessionList.jsp

The JSP page lists the contents of the HTTP session, and allows you to add new name=value pairs or remove existing ones. This reflects the fundamental behavior of a shopping cart.

how it works . . .

The tag handler is implemented by the Java class located under in the WEB-INF/classes directory, under the full package name weblogic.taglib.session.ListTag. The Java source code for this class is in the WEB-INF directory.

Iteration over body evaluation

This example uses the return value of the doAfterBody() method call to control whether it should re-evaluate the body of the custom tag. For each evaluation of the body, the tag extracts a name and value pair from the HTTP session and makes them available through scripting variables. This is described in more detail in the next section. The scripting variables contain a different value for each evaluation of the body.

Like the previous example, the ListTag tag handler extends the BodyTagSupport class, allowing it to process its body content.

The doStartTag() method obtains the HTTP session from the inherited pageContext instance variable. This provides information about the JSP page that uses the tag. If the session contains values, the first two values are extracted, stored as attributes in the page context, and EVAL_BODY_TAG is returned to indicate that the body should be evaluated. Note that the Enumeration from session.getAttributeNames() is stored in the tag handler instance variable names. This variable is accessed by other methods later in the tag handler's life cycle. The same tag handler class instance is used throughout the tag's lifecycle and is not shared by other tag instances.

If the session does not contain any name/value pairs, the control value SKIP_BODY is returned to indicate that the body should not be evaluated. The tag will not produce any output in this case.

If the body is evaluated, it may reference the two scripting variables which contain the session name and value. In this example, these are compiled into an HTML table. Once the body is evaluated, the doAfterBody() method is invoked. This method checks for the next elements in the enumerated name list and if present, it updates the values of the scripting variables and returns EVAL_BODY_TAG to indicate that the tag body should be re-evaluated again. The doAfterBody() method will be invoked again once the body has been re-evaluated.

When there are no more elements to process in the names enumeration, the contents of BodyContent are written to the surrounding output stream scope using:

  getBodyContent().writeOut(getPreviousOut());
Note that the value of BodyContent is automatically accumulated upon each evaluation of the body and is only written out to the surrounding scope when the tag has finished iterating over the body. The method then returns SKIP_BODY indicating not to evaluate the body again.

Defining new scripting variables

As the tag iterates over the session name/value pairs, it makes their values available to the tag body through scripting variables. The changing values of the scripting variables cause the body to have different results upon each evaluation.

A tag declares its scripting variables through a separate class that extends TagExtraInfo class. We declare the TagExtraInfo class in the Tag Library Descriptor file "session.tld" with the line:

  <teiclass>weblogic.taglib.session.ListTagExtraInfo</teiclass>
The JSP engine invokes the getVariableInfo() method on the class to discover what new scripting variables are available. This example defines two scripting variables in the ListTagExtraInfo class by returning an array of type VariableInfo as shown here:
  return new VariableInfo[] {
    new VariableInfo("name",
                     "String",
                     true,
                     VariableInfo.NESTED),
    new VariableInfo("value",
                     "String",
                     true,
                     VariableInfo.NESTED)           
  };
This declares two variables of type String named "name" and "value". Their scope is declared as nested, meaning that they are only valid within the body of the tag.

The tag handler class initializes these scripting variables in the doStartTag() and doAfterBody() methods with the following code:

  pageContext.setAttribute("name", name);
  pageContext.setAttribute("value", value);

The JSP page references the new scripting variables within the body of the tag using the standard JSP expression syntax, inserting their values into HTML table data elements. The use of the scripting variables is highlighted in red in the listing below:

  <session:list>
    <tr>
      <td><%= name %></td>     
      <td><%= value %></td>
      <td><a href="<%=request.getRequestURI()%>?action=delete&delName=<%=name%>">
          <img border=0 src="<%= request.getContextPath() %>/images/trash.gif"> delete
          </a>
      </td>
    </tr>
  </session:list>

In this example, the scripting variables are always called "name" and "value". The SQL example illustrates how to declare a dynamically named scripting variable using the "id" tag attribute.


The SQL example

The SQL example is located in the sub-directory sql. It is implemented as a simple un-archived Web Application where the sql directory is the root of the Web Application. It introduces the following tag extension library concepts:

The SQL example is a comprehensive use of the tag extension library, and uses most of the features from the API. This example presumes that you have understood the concepts introduced in the previous examples. This example defines three new JSP tags to simplify the use of a JDBC query in a JSP page. These tags are as follows:

<sql:connection>
This tag takes a required attribute "poolName" that identifies the name of a JDBC connection pool to obtain a connection from. The pool must be setup in the weblogic.properties file.

<sql:query>
A <query> tag must be nested within a <connection> tag. It uses the connection of the surrounding tag to make a query to a database and stores the result in a scripting variable named by the "id" attribute that represents a JDBC ResultSet.

<sql:results>
The <results> tag iterates through a JDBC ResultSet named by the tag attribute "fromQuery". This should correspond to a ResultSet from a surrounding <query> tag.

The tags make efficient use of nested tag bodies to clarify when to close JDBC resources. When the closing </connection> tag is reached, the connection is closed, returning the resource to the connection pool. When the </query> tag is reached, the JDBC ResultSet is closed.

setting up and running the example . . .

You can set up and run this Web Application example from the examples directory. You do not need to copy the files to another location on your host server. To try out this example, follow these steps:

  1. First you must build the tag handler Java classes. Set up your development environment, as described in Setting your development environment. Change to the "sql/WEB-INF/" sub-directory. Now, compile the Java classes using the following command:
     $  javac -d ./classes *.java

  2. Next, register the example Web Application in the weblogic.properties file using the line:
      weblogic.httpd.webApp.sql=/weblogic/examples/jsp/tagext/sql
    Where /weblogic/examples/jsp/tagext/sql is the root directory of the Web Application. Here, we presume that you have installed the WebLogic Server on your file system under the root directory "/weblogic" for simplicity. You should alter the property as necessary.

    This property maps the Web Application to the servlet context path URI "sql"emp. For more details on the servlet context path, see the Developers Guide Writing a Web Application.

  3. In the weblogic.properties file search for and uncomment the property to configure the "demoPool". It should appear as shown below:
      weblogic.jdbc.connectionPool.demoPool=\
        url=jdbc:cloudscape:demo,\
        driver=COM.cloudscape.core.JDBCDriver,\
        initialCapacity=1,\
        maxCapacity=2,\
        capacityIncrement=1,\
        props=user=none;password=none;server=none
    
      # Add an ACL for the connection pool:
      weblogic.allow.reserve.weblogic.jdbc.connectionPool.demoPool=everyone
    

  4. Start (or restart) the WebLogic Server and request the following URL from a web browser:
    http://localhost:7001/sql/query.jsp

The JSP page opens a connection to the JDBC connection pool "demoPool" defined in the weblogic.properties file. It makes a query on the "emp" database, and iterates through the results, displaying them in a table.

how it works . . .

The tag handlers for this example are implemented by the Java classes located under the WEB-INF/classes directory, under the package name weblogic.taglib.sql. The Java source code for these classes is in the WEB-INF directory. Each new tag is declared in the sqltags.tld Tag Library Descriptor file, also located in the WEB-INF directory.

Using the findAncestorWithClass() method

The <query> tag uses the inherited findAncestorWithClass() method of the TagSupport class to search for a surrounding scope tag handler of the <connection> tag (ConnectionTag). This allows us to implicitly infer which JDBC connection the SQL query should use. Here's the code that searches for the surrounding <connection> tag class:
      try {
        ConnectionTag connTag = (ConnectionTag)
             findAncestorWithClass(this, 
                     Class.forName("weblogic.taglib.sql.ConnectionTag"));
        if (connTag != null) {
          conn = connTag.getConnection();
        }
      } catch(ClassNotFoundException cnfe) {
        throw new JspException("Query tag connection attribute not set "+
                               "AND not nested within connection tag");
      }

Naming scripting variables with "id"

A JSP page might want to make multiple queries on the same page and combine the results, so we have used the "id" attribute to demonstrate how a tag can define a dynamically-named scripting variable. The same approach might be used for the connection tag, where multiple connections to different resources that are created by different <sql:connection> tags could be combined at the same scope. We omitted the use named scripting variables in the <sql:connection> tag for simplicity, and to show that you can use the findAncestorWithClass() method as an alternative.

Every TagSupport class implicitly has an instance variable called "id" and a setTagId() method that is invoked to initialize the "id" attribute value. This works in much the same way as regular tag attributes, except that the "id" attribute is implicitly supported. The setTagId() method does not follow the same Java Bean naming convention, but is invoked since it is a special case.

The "id" attribute can be used to dynamically name a new scripting variable, since it is passed to the ExtraTagInfo class method getVariableInfo() method in the TagData parameter. Any tag attribute can be used to name a scripting variable since all of the tag attributes are available through the TagData.getAttributes() method. The "id" attribute is more convenient since its value can be retrieved via the TagData.getId() method. The following code declares the new scripting variable in the QueryExtraInfo Java class:

  public VariableInfo[] getVariableInfo(TagData data) {
    return new VariableInfo[] {
        // We assign the name given by the 'id' attribute to this variable name
        new VariableInfo(data.getId(), 
                         "java.sql.ResultSet",
                         true,
                         VariableInfo.NESTED) };
  }
Here, we call the getId() method to declare the name of the scripting variable dynamically.

In the doStartTag() method of the QueryTag class, we assign the ResultSet from the JDBC query to the scripting variable named by the "id" attribute:

  pageContext.setAttribute(id, results);

Later in the tag handler for the <sql:results> tag (ResultsTag), we access the ResultSet scripting variable named by the fromQuery attribute. The name of the scripting variable is first initialized via the setFromQuery() method, which is invoked by the JSP engine. In the doStartTag(), we retrieve the named scripting variable from the page context with the following code:

  results = (ResultSet)pageContext.getAttribute(rName);
where rName is the instance variable where we stored the string value of the fromQuery attribute.

Note that tag attributes can only hold String values, but these String values can be used to look up named scripting variables. Scripting variables can be of any Java type, where you define the full package name of the type in the ExtraTagInfo class where they are declared.

Using request-time attribute values

The JSP page uses a scriptlet variable to specify the JDBC query made by the <sql:query> tag. To enable this property in the tag, we must declare the attribute as capable of using a request-time value in the tag library descriptor, shown here in bold:

  <attribute>
    <name>sql</name>
    <required>true</required>
    <rtexprvalue>true</rtexprvalue>
  </attribute>
In the JSP page, the request-time value must be a quoted JSP expression as shown here:
  <sql:query id="employees" sql="<%= query %>" >

there's more . . .

Copyright © 1999 BEA Systems, Inc. All rights reserved.

Last updated 12/18/1999