JSP and custom tags

This article was originally published in VSJ, which is now part of Developer Fusion.

Programming JSP is simple. JSP is significantly easier to learn and master than formal programming languages such as Java. However, the creation of any non-trivial JSP program depends heavily on custom tags. A tag library, a collection of custom tags, is the main mechanism of extending JSP to give it additional functionality beyond the minimum delivered by basic JSP. Unfortunately, creating a custom tag is a topic reserved for advanced level Java programmers. JSP 2 breaks through this barrier and gives non-Java programmers an easy-to-use way of creating their own tag libraries. This new JSP 2 extension mechanism is called “tag files”.

This article explores how re-usable fragments of JSP can be packaged as custom tags in tag files. A practical application, solving a web page layout management problem, serves as the hands-on example and illustrates JSP tag creation techniques.

Working with JSP 2 Tag Files

Prior to JSP 2, tags had to be written using the Java programming language. The API for tag creation is quite complicated, and the interaction with embedded scripting code is very difficult to manage. Figure_1A illustrates the creation of conventional tags.

JSP 2 is the first version of JSP to support extension using tags written in JSP itself. This mechanism is called tag files in JSP 2. Tag files are just JSP files with the .tag file extension. Each tag encapsulates a re-usable piece of JSP code. Figure_1B illustrates the creation of tag files.

Figure 1: Writing tags before and after JSP 2

Tag files must be placed in specific locations on the server in order for the JSP container to find them. Two locations are possible, one is typically used during development, and the other for production JAR files. Table 1 reveals the two locations.

Table 1: Tag file locations

Usage Scenario

Location

During development

Under the /WEB-INF/tags directory of the web application. A TLD (Tag Library Descriptor) need not be created in this case.

Final production JAR library file

Under the /META-INF/tags directory of a JAR file. A TLD must be created when tag files are bundled in JAR files.

In this article, it is assumed that you’ll place all your tag files under the WEB-INF/tags directory. This is the most convenient location when creating, modifying, and testing tag files.

Setting up a working JSP 2 environment

If you are running Java 2, download the latest 5.0.x release. If you are running Java 5 (formerly 1.5), download the latest 5.5.x release of Tomcat.

The Tomcat 5 servers fully support the JSP 2 specification, including full support for JSTL, EL, and (of course) tag files.

Flexible Web Page Layout using Tags

The web application example in this article will use custom tags in the creation of an electronic catalogue. Three different layouts will be supported as illustrated in Figure_2. Each layout provides a different appearance to the end user. However, the operation of the catalogue remains the same. The user may click on one of the product categories displayed in the “menu pane” and see all the products displayed in the “listing pane” of the layout. Ideally, the web site designer or JSP developer can easily switch between the different layouts by simply using a different tag.

Figure 2: The three layouts supported in the creation of the electronic catalogue

The rest of this article shows step-by-step how to build such a set of custom tags. The most frequently used features and techniques for creation of tag files are demonstrated.

Printing horizontal and vertical menus

First, the focus will be on the menu pane of the application. Here, a list of categories is printed either horizontally or vertically. Each category is a hyperlink, and clicking on it will cause the catalogue to display the items in the category. At this point, however, do not worry about hyper-linking. First, after installing the application, try the URL:

http://localhost:8080/vsjtag/
testmenu.jsp

This test program uses a single custom tag, called menu, that simply prints the two categories vertically.

The first taglib directive includes the core JSTL tags, part of every JSP 2 compliant container. The second taglib directive shows how you tell the container to look for your tag files under the /WEB-INF/tags directory. Note that all of the custom tags are prefixed by the tags prefix. In the body of testmenu.jsp, the custom <tags:menu/> tag is called.

A very simple tag

If you look under /WEB-INF/tags, you will find the source code of menu.tag. This is what you will find:

Software<br/>
Hardware

Note that this tag is trivial. It does not have any active JSP element. In essence, the static text is “included” into testmenu.jsp. In fact, either the <%@ include %> directive, or the <jsp:include> action could have been used instead. However, this trivial tag shows how to create a tag file and how to use a tag file with minimal complications.

Tag file only directives

There exists a set of JSP directives that can only be used within tag files. These include <%@ attribute %> to specify attributes for tags, <%@ variable %> to create variable in the calling JSP page, and <%@ tag %> to specify tag specific options. You will see the use of these directives in the examples.

Adding an attribute to a tag

Next, an attribute will be added to the tag. Since the menu may be printed horizontally or vertically, an orientation attribute is added to the tag. The new tag with the additional attribute is called menup. Find the source code under WEB-INF/tags as menup.tag:

In this implementation, you see the use of JSTL’s <c:choose> construct to select between the two orientations, and to print the appropriate menu. Note the use of the attribute directive. This is one of the many directives that can only be used within tag files. It tells the container to expect an attribute for the tag. If you look at a test page for the menup tag, you can see how the orientation attribute is given a value. A test page is available at testmenup.jsp:

In this test, the menu is first printed horizontally, and then vertically. Both times, the menup tag is used, but with a different value for the orientation attribute.

Access the test URL using:

http://localhost:8080/vsjtag/
testmenup.jsp

The resulting page shows the menu printed both ways, as in Figure_3.

Figure 3: Horizontal and vertical menus

Creating a menu of varying length

Thus far, the categories in the menu have been limited to two: Software and Hardware. While this keeps things simple in the tag files, it isn’t very realistic. Ideally, it should be possible to call the menu tag and supply it with as many categories as needed. JSP 2’s dynamic attributes can be used to achieve this.

Specifying dynamic attribute for a tag file

Dynamic attributes are attributes that are not yet known at the time of tag file creation. This means that, unlike the orientation attribute of the menup tag, an <%@ attribute %> directive cannot be used to declare the attribute in advance. Instead, the container can provide the attributes in a Java Map data structure (a Map in Java is a list in which each entry has a String “key” associated with a “value” object). To see how dynamic attributes can solve our menu problem, see the menupd.tag tag file in the WEB-INF/tags directory:

The dynamic-attributes attribute of the <%@ tag %> directive is used to specify the name of the variable that will hold the map containing all the dynamic attribute values. The map will be contained in the menuItems map. The <%@ tag %> is a directive that can only be used within a tag file. All the attributes of this menupd tag will be in the menuItems map except for the explicitly specified attribute(s). In this case the orientation attributes is such a required attribute, and it will not be part of the menuItems map.

In the body of the tag, JSTL’s <c:forEach> tag is used to iterate through all the entries in the map. Each time through the iteration, the current map entry is assigned to a variable called item. Inside the loop, item.key can be used to obtain the name of the associated attribute while item.value can be used to render the actual attribute value. Since the categories are all specified as attribute values, only item.value needs to be rendered. To see how a tag with dynamic attributes is used, take a look at the testmenupd.jsp page:

Note the additional item1/item2/item3 attributes in the menupd tag. In fact, the name of these attributes can be called anything since the tag does not check them. Only the value is used to print out the categories. You can try adding more attributes and see that the tag can handle as many categories as you need. Test this page by going to the URL:

http://localhost:8080/vsjtag/
testmenupd.jsp

The resulting page shows the menu with dynamic categories printed both ways, as in Figure_4.

Figure 4: Dynamic menus

Dynamic attributes are often used in the creation of tags that replace or mimic HTML tags. Since most HTML tags can take a lot of optional attributes, using dynamic attributes allows you to deal only with the set that the user actually specifies.

Designing three different layouts

Turning our attention away from the menu implementation, let us look at the tags that display the different layouts. These tags are in the WEB-INF/tags directory, and are layout1.tag, layout2.tag, and layout3.tag respectively. layout1.tag is shown here, the other two are similar.

This tag has two attributes, menucolor and bgcolor, that affect the colour of the menu pane and the listing pane respectively. An HTML table is rendered by this tag, with substitution of the attribute values at the appropriate places. The interesting aspect of this tag, however, is the existence of the <jsp:doBody/> tag.

Tags that process a tag body

A tag can use the <jsp:doBody> action, an action that is only allowed in tag files, to ask the container to render the body content of the tag. To see how this works, take a look at the testlayout1.jsp:

Note how the layout1 tag’s two attributes, bgcolor and menucolor, are specified. Note that this tag now has a body, as highlighted, and this body will be rendered at the location of where the <jsp:doBody/> action is within the layout1.tag.

Try out testlayout1.jsp using the URL:

http://localhost:8080/vsjtag/
testlayout1.jsp

This will result in a display of the layout as in Figure_5, in which you also see the testlayout2.jsp and testlayout3.jsp in action. You can examine the JSPs, and the associated tag implementations, on your own.

Adding Menus to the Layout

The layout1.tag does not display a menu in the menu pane. Since the listing pane is already rendered using the body of the layout1 tag, you need another way to pass another body of JSP code into the tag for rendering. This is done by passing a fragment of JSP as an attribute to the tag. The tags that implement this are layout1f.tag, layout2f.tag, and layout3f.tag respectively. You can find these tags under the WEB-INF/tags directory.

Using JSP Fragments as Tag Attributes

The listing below shows layout1f.tag, the other tags are similarly implemented:

Note how the menu attribute is specified as a fragment via the fragment attribute. The calling JSP page can then supply a JSP fragment as the value for this attribute. The other highlighted section, the <jsp:invoke> action, is where the rendering of the fragment occurs. This approach allows you to supply multiple JSP fragments to your custom tags. To see how this is used, see the testlayout1f.jsp, testlayout2f.jsp, and testlayout3.jsp respectively. testlayout1f.jsp is shown here:

Nesting JSP tag file invocations

In the preceding code, in order to specify the menu attribute as a JSP fragment, the <jsp:attribute> standard action is used. Note how the original body is specified using the <jsp:body> standard action. Using this technique, it is possible to call a tag that may take multiple fragments of JSP for different attributes. Note that the value of the menu attribute is actually a call to our tag file <tags:menupd>. This illustrates how custom tag file invocations can be nested one inside another. You can try this JSP page out using the URL:

http://localhost:8080/vsjtag/
testlayout1f.jsp

Figure_6 shows how the result looks. There is also a corresponding testlayout2f.jsp and testlayout3f.jsp for your exploration.

Figure 6: The result of nested tags

Adding Hyper-links to Menu

The final set of JSP test pages puts everything together and add some new code. The code additions include those shown in Table 2.

Table 2: Code additions

New Code

Description

menupdurl.tag

changing menupd.tag to support a list of clickable hyper-links instead of static text

fetchContent.tag

create a tag that will decode incoming action request parameter, and set a variable to the appropriate category listing (simulated, in production this implementation can query a database)

testlayout1s.jsp

using layout 1f, display the final clickable catalog (testlayout2s.jsp and testlayout3s.jsp are similarly included)

Using JSTL <c:url> and the EL string function

First, let’s take a look at menupdurl.tag in the WEB-INF/tags directory:

This is a modification of the menupd.tag shown earlier. It makes use of the JSTL <c:url> tag to create the hyper-links. An EL function for string processing is used to split the incoming menu item values into two parts. The first part will be the name of the category, the second part after a separator “|”, will be the four letter code used as a request parameter in the URL created. Apart from this, the logic of this code remains the same as the original menupd.tag.

Handling incoming action request parameters

The fetchContent.tag implementation will examine an attribute called action, and set a variable to different values depending on the action. In real application, this tag may perform a database search. The incoming action attribute should specify the category of products to search for, then this tag would search a database for all the products that match.
The code of fetchContent.tag is:

Passing values to the calling JSP via tag file Variables

In the preceding code, note the first use of the <%@ variable %> directive. While attributes are used to pass data from a JSP page into a tag, variables are used to pass data out to the calling JSP. The scope AT_END tells the container that the variable called pageContent should be made available and synchronized at the end of the execution of this tag. During execution, each tag has its own context and any variables created must be explicitly synchronized by the container if they are to be accessible outside the tag.

In the preceding code, the action attribute is used to determine the HTML text that the pageContent variable will be set to. This is accomplished via the JSTL <c:choose> construct.

Note the new value for the item1, item2, and item3 attributes of the menupdurl tag. These values encode both the category names, and the value of the action request parameter, separated by “|”.

The <tags:fetchContent> tag is used to determine what to render in the listing pane. The request parameter, action, is passed as an attribute. After execution of the <tags:fetchContent> tag, the pageContent variable will be available in testlayout1s.jsp. The value of this variable is then rendered using EL. To try out this final version, use the URL:

http://localhost:8080/vsjtag/
testlayout1s.jsp

Figure_7 shows the final resulting page. You may want to click the hyper-links in the menu. The content pane should change accordingly.

Figure 7: The completed page

You should also examine and try out testlayout2s.jsp and testlayout3s.jsp to test the other two layouts.

Conclusions

The tag file mechanism in JSP 2 is a long-awaited addition to the JSP standard. It allows non-Java programmers to create re-usable JSP tags easily. Any JSP code may be wrapped up as a custom JSP tag, bundled in a tag library, and then re-used in other projects.

A set of directives, available only within tag files, enables the specification of attributes for passing data into the tags, as well as passing data from the tag using variables. Attributes can be pre-specified or dynamic. Dynamic attributes enable the use of an unlimited number of attributes with names not known in advance. The body of a custom tag can contain other custom tags. Complete JSP fragments can be passed into a custom tag as an attribute.

Sing Li is a consultant, system architect, open source software contributor, and freelance writer specialising in Java technology, embedded and distributed systems design. He has authored or co-authored several books on the topic, including Professional Apache Tomcat (Wrox), Professional JSP 2 (Apress), Early Adopter JXTA (Wrox), and Professional Jini (Wrox).

Over 60 recipes to help you speed up the development of your Java web applications using the Spring Roo development tool *Learn what goes on behind the scenes when using Spring Roo and how to migrate your existing Spring applications to use Spring R...