Nested Custom Tags
Of particular importance is the fact that you can nest JSP custom tags within other JSP custom tags. You can design such nested tags so that they share a context and a design. The inner tags can find the Tag Handler class instances representing the outer tags, and they can share variable data from these enclosing tags. Various Tag Handler classes can work in concert. A tree of nested tags can accomplish a coordinated custom action, much as many HTML tags do (such as form element tags).
We will illustrate the richness that markup in body content makes possible by reproducing here a complete sample JSP from the Jakarta Taglib Project. The example is provided under the Apache Software License. It is quite valuable to download the Jakarta Taglib Project. You can find links to it at the Apache XML Web site (http://jakarta.apache.org/taglibs/index.html).
The Taglib Project download is also available from the Sun Developer Connection Web site (http://www.sun.com/developers/). After installing the download, you can find the following sql tag library example in something like the file C:\jakarta-taglibs\sql\examples\web\test.jsp.
NOTE
Note that the sql tag libraries are deprecated, and might not be available in future versions of jakarta taglibs. As an alternative, you can examine the DBTags taglib.
Using the sql and other tag libraries, you can learn more about JSP custom tags than we could ever cover in this article. By the way, an appendix of the JSP 1.1 specification also features SQL tags as an example. Here is the JSP file we mentioned, showing nested tags with body content (for some code lines that should be all on one line, space constraints required showing the line's continuation by indenting several spaces):
<%@ taglib uri="http://jakarta.apache.org/taglibs/sql-1.0" prefix="sql" %> <html> <head> <title>Examples of JSPSPEC SQL Tag Library Tag Usage</title> </head> <body bgcolor="white"> <sql:connection id="conn1" > <sql:dburl><%= request.getParameter("dburl") %></sql:dburl> <sql:driver><%= request.getParameter("driver") %></sql:driver> <sql:userid><%= request.getParameter("userid") %></sql:userid> <sql:password><%= request.getParameter("password") %></sql:password> </sql:connection> <sql:query id="getBoxen" connection="conn1" visibility="table"> SELECT * FROM <%= request.getParameter("table") %> <% if( request.getParameter("where") != null && request.getParameter("where") != "" ) { %> WHERE <%= request.getParameter("where") %> <% } %> </sql:query> </body> </html>
As you can see, all six custom tags work together to display data from a database using an SQL query. All the tags have body content, which in different places includes text, JSP scriptlets, JSP expressions, and nested tags. We will not discuss the entire sql tag library, but we will show you the primary mechanism by which the nested tags here work together.
Let's take a look at the dburl tag, nested within the connection tag. At request time, the expression in the dburl tag body was replaced by the value of the dburl request parameter, which could be from an HTML form. In the source code for the dburl Tag Handler class, DburlTag.java, we can find the following:
connectionTag.setDburl( bodyContent.getString() );
It appears that the dburl tag handler is capable of calling a "setter" method on the enclosing connection tag's handler, to set its dburl property to the body content of the dburl tag (that is, the request parameter value). But how does the dburl tag handler find the connection tag handler? It uses the findAncestorWithClass() method of the TagSupport class. This is a mechanism of choice in the nested-tag arsenal of the JSP taglib API (note that this code line should be all one line; space constraints required showing the line's continuation by indented lines):
ConnectionTag connectionTag = (ConnectionTag) TagSupport.findAncestorWithClass( this, org.apache.taglibs.sql.ConnectionTag.class );
Another important mechanism for nesting JSP tags is provided by the BodyContent class, which allows each nesting level to have its own JspWriter object, with the JSP container taking care of a runtime execution stack of such objects.
Also important to the nesting capability of JSP tags is the parent property of the Tag interface, which is what makes nesting possible. If a tag is nested in another, the child tag gets this property set to its parent very soon after being instantiated in the JSP servlet's _jspService() method. Only the pageContext property is set before that.