Creating a Tag Library: (Final Edits)

Last Updated Monday, January 08, 2002


 

This document will walk you through the basics for creating a simple tag library to execute queries against a database and displaying the results in a table using the default column headers and the result set. The TagLibrary also supports using a predefined data source or direct connection to the database.

 

This library and all of the associated documentation was written to help me understand the process and see if there was a better way to implement the solution. I find that by doing I learn and by documenting I get better.

 

If you found this helpful or if you think there is a way I could have implemented it better, please feel free to contact me, enjoy!

 

mailto:aaronksaunders@hotmail.com

 

 

OVERVIEW

 

Developing the Tag Library

Creating The Java Server Page to Test the Tag Library

Entering Test Data For Use With Tag Library

Creating The Tag Library Descriptor File

Deploying the Tag Library, and a test application

Executing the Test Application

Deploying on the Java Reference Implementation

Using Ant for Build and Deployment

Final Comments

Miscellaneous Links

Complete Source Code Listings

 

 

 

Developing the Tag Library

 

Tag Libraries are relatively simple to write and should be utilized for exactly what they are called, "Libraries!" seperate out the code from  the display,make the code easier to maintain and.... pretty much just make your life simpler. See Code before Tag Library

 

The code was separated into two files to support different types of tags. I separated the code logically, the functions specific to the Tag Library are in the TableDisplayQuery class while the utility functions of creating and displaying the output are in the TableTagUtils class. I choose this division because there are other tags I have written that utilize the same utility functions.

 

The bulk of the work in setting up the tag library is in two steps (1) getting the attributes passed in (2) performing some action based on the type of tag implemented. Since I have implemented a simple attribute based tag, I only need to focus on the doStartTag() and the set<AttributeName>() functions method of the tag library.

 

 


// Simple setter of attribute value...

/**

*
* called to get the connection URL attribute defined in the tag.
*
* @params String theURL connection URL needed by the driver manager
* to make the connection. This paramater is onlye used when the dataSource
* is not. Use of this parameter, requires the use of setJDBCClass
* @return void
* @exception Nothing
* @see my.package.TableDisplayQuery.setJDBCClass
*/

public void setConnectionURL( String theURL ) { connectionURL = theURL; }

 

// More complex setter of attribute value...

/**
* called to get the datasource attribute defined in the tag.
* @params String dsName name of datasource defined on app server
* @return void
* @exception javax.servlet.jsp.JspException if cannot get the specified datasource
*/
public void setDataSource( String dsName ) throws javax.servlet.jsp.JspException
{
    try {
        Context ic = new InitialContext();
        ds = (javax.sql.DataSource) ic.lookup(dsName);
    } catch (Exception e) {
        throw new javax.servlet.jsp.JspException(e.getMessage());
    }
}
 

 

For the simple tag I created, all I need to do is get my attributes/parameters, as described above, and now execute my business logic on in the "doStartTag" method.

 

 /**
* Method called at start of tag. this is where the magic happens
* @return SKIP_BODY
* @exception javax.servlet.jsp.JspException - on any error, with the
* specified errormessage from the exception
*/
public int doStartTag() throws JspException
{

    try {
        // if there is no dataSource defined, then I need all the other params
        if ( ds == null ) {
            mypackage.TableTagUtils.checkStringVars(JDBCClass, "JDBCClass");
            mypackage.TableTagUtils.checkStringVars(connectionURL,"connectionURL");
            mypackage.TableTagUtils.checkStringVars(userName,"userName");

            Class.forName(JDBCClass);
            conn = DriverManager.getConnection(connectionURL,userName, password);
        } else {
            conn = this.ds.getConnection();
        }

        resultSet = executeTheQuery();
        if ( columnTitles == null ) {

            columnTitles = mypackage.TableTagUtils.generateColumnTitles(resultSet);

        }
        TableTagUtils.writeTheOutput( pageContext.getOut(), resultSet, columnTitles );
    } catch (Exception e) {
        throw new javax.servlet.jsp.JspException(e.toString());
    } finally {
        try { if (resultSet != null) resultSet.close(); } catch ( Exception e) {};
        try { if (conn != null) conn.close();} catch ( Exception e) {};
    }

    return SKIP_BODY;
}
 

 

The important point here to remember is that the doStartTag method returns the constant SKIP_BODY with tell the application to move on and process the end tag and the the tag processing is complete. In a later update,  I will show a simple tag that includes body processing.

 

Creating The Java Server Page to Test the Tag Library

 

The page is very simple so I will only touch on the important elements.

 

First, you must tell page where to find the information regarding the tag library. This is accomplished by entering the following page directive in the top of the .jsp page:

 

<%@ page contentType="text/html;charset=windows-1252"%>

<%@ taglib uri="WEB-INF/TableDisplay.tld" prefix="mytags"%>

--- rest of the page ---

 

The “URI” attribute tells the server where to look for the specific library descriptor and the “prefix” attribute indicates the namespace where the tag exists.

 

Then we enter the specific tag and attributes as defined in the descriptor file. For my tag library, we need to enter the connectionURL, how you connect to the database (see JDBC Tutorial for additional information on connecting to databases with JDBC). After the connection url we need the class name of the JDBC driver we are using to connect to the database. This is accomplished through the JDBCClass attribute. This specific driver requires both a userName and password attribute to be defined also. The final attribute is the queryString.

 

 

 

--- rest of the page ---

<HTML>

<BODY>

<mytags:TableDisplayQuery connectionURL= "jdbc:rmi://localhost:1099/jdbc:cloudscape:CloudscapeDB;create=true"

  JDBCClass="COM.cloudscape.core.RmiJdbcDriver"

  userName="APP" password=””

  queryString="SELECT * FROM USER_INFO" />

</BODY>

</HTML>

--- rest of the page ---

 

 

 

 

Entering Test Data For Use With Tag Library

 

I chose to use Hypersonic SQL/hsqldb because it was free, downloadable and easily integrated into my existing development environment. I will not go into the installation and configuration issues at this time since that is all available at the company’s website: http://hsqldb.sourceforge.net/

 

For the purpose of the example and simple integration with the java reference implementation, I have included the SQL scripts for adding the data to a Cloudscape database. There are subtle difference between Cloudscape and hsqldb so I do not guarantee the scripts on  Hypersonic SQL/hsqldb.

 

The data that you enter into the database will affect the queries you can execute and the class names that are used to load the necessary drivers.

 

My test data is as follows:

 

 

DROP TABLE USER_INFO;

                                                                                                                                                                        

CREATE TABLE USER_INFO (

            ACCOUNTID INTEGER NOT NULL PRIMARY KEY,

            FIRSTNAME VARCHAR(20) NOT NULL,

            LASTNAME VARCHAR(20) NOT NULL,

            USERNAME VARCHAR(40) NOT NULL,

            UNIQUE(USERNAME)

);

 

INSERT INTO USER_INFO VALUES(21,'Aaron',' Saunders','Aaron21');

INSERT INTO USER_INFO VALUES(22,'Catherine',' Saunders','Catherine22');

 

 

You can use any database management utility to execute the scripts above to load the data.

 

 

Creating The Tag Library Descriptor File

 

The descriptor file is completely documented and can be viewed here (TableDisplay.tld).

I have include in the descriptor all of my parameters

 

dataSource

the name of the dataSource as defined on the application server. If this parameter is used, then the "JDBCClass" and the "connectionURL" parameters are ignored.

userName

user name to login to the server as

password

password for login

JDBCClass

class name used to load the driver

connectionURL

url string, see driver documentation

queryString

standard SQL to execute.

 

 

 <!-- PLEASE NOTE THIS IS NOT THE COMPLETE .TLD, SEE FULL SOURCE CODE FOR LISTING -->

<tag>
    <name>TableDisplayQuery</name>
    <tagclass>mypackage.TableDisplayQuery</tagclass>
    <bodycontent>JSP</bodycontent>
        <attribute>
            <name>dataSource</name>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>userName</name>
            <rtexprvalue>true</rtexprvalue>
       </attribute>
       <attribute>
            <name>password</name>
            <rtexprvalue>true</rtexprvalue>
       </attribute>
       <attribute>
            <name>JDBCClass</name>
            <rtexprvalue>true</rtexprvalue>
       </attribute>
       <attribute>
            <name>connectionURL</name>
            <rtexprvalue>true</rtexprvalue>
       </attribute>
       <attribute>
       <name>queryString</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
       </attribute>
</tag>

 

 

The important point to notice here is the use of the "rtexprvalue" tag. This tag allows for a runtime evaluation of the value passed into the attribute. Without this being set, the tag library can only accept simple types as parameters for the specified attribute.

 

 

Deploying the Tag Library, and a test application

 

Overview of the directory structure: The .ear and the .war files are created using the jar tool. See the Java Tutorial for addition information on using the Jar Tool. (Note that the “WEB-APPLICATION.WAR” file is included inside of the “APPLICATION.EAR” file.)

 

I have written another not on how to deploy this application using the Ant utility. This note can be viewed by here.

 

TAGLIB.EAR

      /META-INF

            - application.xml

      TAGLIB.WAR

            TestTagLib.jsp

            /WEB-INF

                  web.xml

                  TableDisplay.tld

                  /CLASSES

                        mypackage

                              TableDisplayQuery.class

                              TableTagUtils.class

 

 

The WEB-APPLICATION.WAR file is created with the following command:

            jar –cf TAGLIB.WAR WEB-INF TestTagLib.jsp

 

Then the overall APPLICATION.EAR file is created with this command:

            jar –cf TAGLIB.EAR META-INF WEB-APPLICATION.WAR

 

This will create the .ear file containing the .war file for deployment on the application server. The directions for deploying on the Java Reference Implementation are much easier and are described at the end of this document.

 

 

Executing the test application

 

After the application has been successfully deployed, enter the following url, assuming you are using the java reference implementation, http://localhost:8000/TagLib/TestTagLib.jsp and you should see results similar to those listed below.

 

ACCOUNTID

FIRSTNAME

LASTNAME

USERNAME

21

Aaron

Saunders

Aaron21

22

Catherine

Saunders

Catherine22

 

 

Deploying on the Java Reference Implementation

 

Follow the basic instructions for installing and configuring the J2EE Reference Implementation (Additional information on the java reference implementation). After the installation is complete, be sure to launch the Cloudscape RMI Server as specified in the documentation so you do not get an error when attempting to connect to the database.

 

I have used a java based tool to do simple database manipulations, Cloudscape comes with one, but I prefer to use a tool called squirrel. (Download site for Squirrel)

 

Deploy the data source: open the file “resource.properties” in your J2EE_HOME\config directory and make the following changes to the file. I have displayed them in bold+italic for clarity. Please not that I have excluded the entire contents of the resource.properties file for simplicity

           

jdbcDataSource.0.name=jdbc/Cloudscape

jdbcDataSource.0.url=jdbc:cloudscape:rmi:CloudscapeDB;create=true

jdbcDataSource.1.name=jdbc/DB1

jdbcDataSource.1.url=jdbc:cloudscape:rmi:CloudscapeDB;create=true

jdbcDataSource.2.name=jdbc/MoneyPlanDS

jdbcDataSource.2.url=jdbc:cloudscape:rmi:MoneyPlanDS;create=true

jdbcDriver.0.name=COM.cloudscape.core.RmiJdbcDriver

jdbcDriver.1.name=com.pointbase.jdbc.jdbcUniversalDriver

 

 

Launch the deployTool that is included with the J2EE Reference implementation. Select File->Open and choose the .ear file created previously.

 

The tool will load the .ear and allow you to make some basic changes and verify the file. There should be no need for any of this so let’s move on.

 

The final step is top deploy the application and the library, to do this select Tools->Deploy. There are no changes necessary so you can click the “Finish” button and the application will be deployed.

 

Final Comments

 

 

Miscellaneous Links

 

Information on Custom Tags from java.sun.com

Hypersonic SQL/hsqldb, java database Download Site

Basic Java Server Pages Tutorial from java.sun.com

Basic JDBC Tutorial I found somewhat helpful?

Java Tutorial for addition information on using the Jar Tool

Additional information on the java reference implementation

Download site for Squirrel

  

 

[ Cover Letter]  [ Resume ]  [ Home Page ] [ mailto:AaronKSaunders@Hotmail.com ]