Practical JSTL - Part II

By Sue Spielman

 

In part I of this series, we took a look at the basic idea behind the JSTL and the powerful standard actions that are provided within it. We had an overview of the functionality of the Core tag library, as well as how you can use the EL. In part II, we’ll take a look at some of the other functionality provided for us. We’ll touch base on the available standard actions contained within the JSTL in the XML, I18N, and SQL libraries.

 

The following sections are excerpted from various sections and chapters within the ‘JSTL: Practical Guide for JSP Programmers. You can find complete details of all of the standard actions available in the JSTL, as well as a developer’s quick reference guide, provided in the book.

 

Working with the XML Actions

 

The XML tag library brings us to actions that deal with XML manipulations. I am hard pressed to think of any application that I’ve developed in the last few years that didn’t use XML to represent the data in the web tier. XML is the data format of choice for exchanging information. Keeping this in mind, it’s relevant to discuss the number of actions that JSTL provides to help a page author deal with XML. You will find a strong similarity between the XML core actions and the actions provided in the Core tag library. But there is a difference; that being that the XML core actions use XPath for their expression language.

 

Using the Select Attribute

All of the XML actions of JSTL allow a way to specify XPath expressions. This is accomplished by using the select attribute. The select attribute is always specified as a string literal that is evaluated by the XPath engine. It was decided to have a dedicated attribute for XPath expressions so as to avoid confusion. Since some of the XML actions have similar functions to the Core actions, it was important not to get the XPath expression confused with the JSTL expression language. The select attribute is shown in this simple sample where the XPath expression specifies the title to be selected from the XML document and output to the JspWriter.

 

<x:out select=“$catalog/book/title”/>

 

Accessing Resources

 

When using XML actions, obviously one of the first things we want to do is access some

type of resource like an existing XML document. This is done by importing resources using the Core URL action <c:import>. The resource can then be used by such XML actions as <x:parse> and <x:transform>. For example, we can import a URL resource and then export it into a variable named xml. This variable is then used as the XML document to the parse action as shown in the sample below.

 

<c:import url="http://www.mkp.com/book?id=12345" var="xml"/>

<x:parse xml="${xml}" var="doc"/>

 

Parsing XML Documents

 

The first step required before being able to access any of the information contained in an

XML document is that it must be parsed. Usually there is an existing document that you want to be working with. This document might be the result of some business logic that was performed in the business tier of your application. We want now to deal with it in the presentation tier so that we can display the results appropriately. Using the <x:parse> action is how we get the information from XML format into some format that can be used by XPath, and XSLT. <x:parse> takes a source XML document, parses it, and produces a scoped variable that holds the results. The variable can be defined by either using the var or varDom attribute. There are two different types of attributes because there are a number of ways to represent XML documents. JSTL provides the flexibility for the implementer of the specification to return an object of its choosing in the var attribute.

 

<x:parse> Action

 

The <x:parse> action is used to parse an XML document. The resulting object is then saved into a scoped variable as defined by either the var or the varDom attribute. The varDom attribute is a String that holds the name of the scoped variable. The type of the scoped variable is an org.w3c.dom.Document. The type of the var attribute depends on the implementation of the <x:parse> action, so you will need to consult the documentation for it. In the reference implementation of the JSTL, the type of the scoped variable as defined by var is also of type org.w3c.dom.Document. The <x:parse> action performs the parse on the document; it does not perform any validation against Document Type Definition files (DTDs) or Schemas. The XML document to be used for the parse can either be specified with the xml attribute, or it can be specified inline by including it the action’s body content.

 

The varDom attribute exposes a DOM document, making it possible to use the variable for collaboration with other custom actions you might have created. Objects exposed by

var and varDom can be used to set the context of an XPath expression. This is exactly what we’ll see in our <x:set> and <x:out> example when we reference the $doc in the select attribute. In the sample below, we import a document using the <c:import> action. Then we use that XML document for the parse. The results are stored in the var attribute of the parse action. We then use doc as the context for our other XML actions.

 

<c:import url="http://www.mkp.com/catalog.xml" var="xml"/>

 

 

<x:parse source="${xml}" var="doc"/>

<x:out select="$doc/catalog/book/title"/>

 

If your source XML document is null or empty, a JspException will be thrown.

 

A common way to identify the XML file is to use the parse to expose it as an imported resource. By using the <c:import> action, we access the XML file and then use the EL to pass it to the <x:parse>. This is shown in Example 1.

 

Example 1 <x:parse> Using an Imported XML Document

 

<c:import var="xmlfile" url="/people.xml" />

<x:parse var="doc" xml="${xmlfile}" />

Hello <x:out select="$doc/person/firstname" />

 

Using XML Documents to Determine Flow Control

 

While the XML core actions provide the basic functionality to parse and access XML data, the XML flow control actions are used to do conditional processing and iterations. The same way that we used various Core actions for flow control in our JSPs can be applied to the conditional actions available in the XML tag library. In fact, the XML actions mimic the Core actions. The actions available are:

 

<x:if>

<x:choose>

<x:when>

<x:otherwise>

<x:forEach>

 

The only difference between the two libraries, which you might have guessed by now, is the fact that the select attribute uses XPath instead of the EL when working with the <x> actions. Using XPath expressions, the XML control flow actions determine whether to process JSP code. These actions act in much the same way as the Core tag library flow control actions we already talked about, except for the utilization of XPath instead of the expression language. Therefore, to avoid redundant information, I am going to point out the differences between the XML and the Core actions (<c:if>, <c:choose>, and <c:forEach>), where appropriate.

 

The biggest difference is that the select attribute is evaluated to a boolean expression according to the semantics of the XPath boolean() function. Otherwise, everything that you’ve already learned applies to the control flow actions can be applied here as well. You’ll notice that before you do any type of control flow, you always have to have a document available. This means that you always have to do an <x:parse> on the document so that it can be accessed through a variable.

 

The XML actions play an important role in today’s web applications. Since XML is omnipresent, dealing with XML documents becomes much easier with the actions provided in the XML tag library. Using the XML actions, it’s possible to do all sorts of data comparison, iteration, and transformations using XSLT. All of these actions should make your page authoring that much easier. In order to make the best use of the XML actions, it is important to have a firm understanding of XPath and XSL at the very least.

Working with the Internationalization and Formatting Actions

More than likely, the application you are developing today will have to be internationalized tomorrow. Wouldn’t it be great if the effort required to internationalize your application could be reduced to zero? Well okay, that might be too optimistic to hope for since anyone who has developed applications for international use knows there is always something that needs to be tweaked. Luckily, the internationalization and formatting actions provided in the JSTL are a comprehensive set of actions that can be used to minimize the headaches of having to internationalize your application. These actions come under the functionality of the I18N umbrella. I18N, which refers to the 18 letters between the I and the N in internationalization, is a common acronym used when talking about internationalization features. It is also common to use the term L10N, for localization. In this chapter, we’ll explore these internationalization actions. All of the actions related to I18N are contained in the custom tag library with the URI http://java.sun.com/jstl/fmt and are frequently accessed by using the fmt prefix x.

The I18N functional area can be broken down into two main areas:

1.Locale and resource bundles that include such actions as:

·        <fmt:setlocale>

·        <fmt:bundle>

·        <fmt:setBundle>

·        <fmt:message>

·        <fmt:param>

·        <fmt:requestEncoding>

 

2.Formatting for numbers, dates, and currency, which includes such actions as:

·        <fmt:timeZone>

·        <fmt:setTimezone>

·        <fmt:formatNumber>

·        <fmt:parseNumber>

·        <fmt:formatDate>

·        <fmt:parseDate>

 

To address both of these functional areas, let’s first take a cursory look at what pieces are involved in creating international applications. Then we’ll look at how these pieces can be put to work using the various actions available in the JSTL.

First,the <fmt:message>Action

Before we start talking about the various actions available in the I18N, let’s introduce the <fmt:message>action. If you really wanted to do the bare-bones amount of work necessary to build an internationalized application,<fmt:message>is the only action that you’ll need to consider. The <fmt:message>action takes advantage of the LocalizationContext. By using the <fmt:message>,you can output values from your resource bundles as simply as:

<fmt:message key=”welcome”/>

The appropriate resource bundle will be used to look up the key “welcome” and the translated string will be provided. This is about as easy as it gets to incorporate international support into your application. The <fmt:message>action also supports parameterized content, also called parametric replacement. For example, you can provide variables that will be used within the string used by the key attribute. Say we want to personalize our welcome page and pass the name of a user so that we can welcome them. To do this, we use the <fmt:param> subtag. A quick example, so that you are familiar with the format, the action might look like:

<fmt:message key=”welcome”>

<fmt:param value=”${userNameString}”/>

</fmt:message>

 

In this example, we would be accessing a variable already set, called userNameString , that would then be used as a parameter to the message. If we were accessing the English version of the resource bundle,Welcome Sue would appear in the JspWriter .

Author Note: Chapter 6 of the JSTL: Practical Guide -  Working with the Internationalization and Formatting Actions - continues by going into great detail on how to work with Locales, resource bundles, and all of the I18N standard actions.

 

Using the SQL Actions

The JSTL includes a number of actions that provide a mechanism for interacting with databases. The previous sentence should, at a very minimum, send up a red flag in your architectural visions. One might ask, “Do I really want to be able to perform SQL actions such as queries, updates, and transactions from my JSP? Isn’t that business logic that belongs in the model? The answer is yes. Yes, yes, yes. To follow a Model-View-

Controller (MVC) architecture, which is the predominant design pattern used in building web applications today, you definitely want to keep your model information in your business logic. This means that you don ’t want it in your JSPs. Why then are these actions even provided in the JSTL? Good question and one that I’ve discussed with various members of the JSR-53 expert group. The reason is the “C” or community in the Java Community Process (JCP). The community has asked for it, the community has gotten it.

 

Many feel that for prototyping, small-scale,and/or very simple applications, or if you just don’t have the engineering staff to implement a full MVC model, then the SQL actions might prove useful. While I can (barely) see the point being made for use of the SQL actions for prototyping or small-scale applications, I can’t ever validate the argument that you just don’t have the time to implement an MVC model correctly. If that is the one and only reason why you are choosing to use the SQL actions, then I suggest that you investigate using such frameworks as Struts which is part of the Jakarta projects and can be found at http://jakarta.apache.org/struts/index.html . Struts is an MVC framework that can be learned quickly and will provide a much cleaner architecture than having Model information located throughout your JSPs. For a complete discussion on Struts 1.1 along with a full sample application, refer to The Struts Framework: Practical Guide for Java Programmers.

If you are careful about how you code your SQL actions, it should be easy enough to pull out the code and put it into classes that represent the Model interaction at a later point. I am not going to go into the various design patterns that can be applied for doing business or integration tier access. But if you consider using the SQL actions in your application, it would be wise at least to familiarize yourself with such common patterns as Transfer Objects, JDBC for Reading, Data Transfer Object (DTO) Factory, Data Transfer Hashmap,and Data Transfer Rowset. Doing so may help you avoid embedding the business logic/data access into your JSPs so deeply that you are left with a tangled mess.

With that said, I don’t consider it an architectural flaw to have the SQL actions included in the JSTL. However, I do consider it an architectural flaw to use them in your application development. It is up to the page author and application architect to make sure that the design patterns are being adhered to correctly, if not for the maintenance issue of the application then for the practice of good engineering. However, since these actions are included in the JSTL, I must make sure you understand them and their features so that you can make an informed decision.

The JSTL SQL actions provide functionality that allows for:

·        Making database queries

·        Accessing query results

·        Performing database modifications

·        Database transactions

 

What all of the SQL actions have in common is that they work against a specific data source.

The Available <SQL>Actions

There are six actions provided in this tag library:

·        <sql:setDataSource>for exporting a variable that defines a data source

·        <sql:query>for querying to the database

·        <sql:update>for updating the database

·        <sql:transaction>for establishing a transaction context for doing queries and updates

·        <sql:param>for setting parameter markers (“?”) used in SQL statements.

 

<sql:setDataSource>

The <sql:setDataSource> is used to export a data source either as a scoped variable

or as the javax.servlet.jsp.jstl.sql.dataSource data source configuration variable.

Using the var and scope attributes, the data source specified (either as a DataSource

object or as a String) is exported. If no var is specified, the data source is exported in

the javax.servlet.jsp.jstl.sql.dataSource configuration variable.

 

The data source may be specified by using the dataSource attribute. This can be specified as a DataSource object, as a Java Naming and Directory Interface (JNDI) relative path, or using a JDBC parameters string. If you don’t want to use the dataSource attribute, it is also possible to specify the data source by using the four JDBC parameter attributes. All four of the parameters are just String types. These attributes are driver, url, user, and password. Using the JDBC attributes is just an easier way to configure the data source than specifying the values in the string syntax for the dataSource attribute. In Example 2 we see how to specify a data source using the JDBC parameters. We are making this data source available as an exported variable called datasource. This can then be used by other actions if they want to use this particular data source, as shown by the <sql:query> action.

 

Example 2  Setting a Data Source

 

<sql:setDataSource var="datasource"

driver="org.gjt.mm.mysql.driver"

url="jdbc:mysql://localhost/db"

user="guest"

password="guest"/>

<sql:query datasource="${datasource}" … />

 

 

<sql:query> Action

 

No mystery here, the <sql:query> action is used to query a database. There are a number of attributes that are used with this action. It is possible to specify a data source by using the dataSource attribute. If present, it will override the default data source. If the dataSource is null, then a JspException is thrown. If a dataSource is specified, then the <sql:query> action must be specified inside of a <sql:transaction> action. We won’t go into details about the <sql:transaction> in this article, but you can find out the details in chapter 7 of the JSTL: Practical Guide.

 

A single result set is returned from a query. If the query produces no results, an empty Result object (of size zero) is returned. This would be the case for a SQL statement that contained an INSERT, DELETE, UPDATE, or any SQL statement that returns nothing such as a SQL DDL statement. Returning an object of size zero is consistent with the way return values are handled by the executeUpdate() method of the JDBC Statement class. This result set contains rows of data if there are results. The data is then stored in a scoped variable that is defined by the var and scope attributes. The default scope is page.

Obviously, there must be a way to specify the SQL query to be used. This can be done by using the sql attribute, or by including the SQL statement in the action’s body content.

The code in Example 3 and that in Example 4 do exactly the same thing.

 

Example 3 SQL Defined in Attribute

<sql:query sql="SELECT * FROM books WHERE title = ‘JSTL’ ORDER BY author"

  var="titles" dataSource="${datasource}" >

</sql:query>

 

Example 4 SQL In Body Content

<sql:query var="titles" dataSource="${datasource}" >

SELECT * FROM books WHERE title = ‘JSTL’ ORDER BY author

</sql:query>

 

Summary

At this point, you should have a full appreciation for the power that the JSTL can provide. By reading both of the excerpt articles, hopefully you have seen that this is just the tip of the iceberg. There are so many projects out there that have JSP code that can utilize the JSTL; a great place to start is just refactoring some of the pages you might already have. You’ll see how easy and efficient it is using the JSTL compared to debugging through scriptlet code that might be scattered throughout the pages. I hope that the JSTL: Practical Guide for JSP Programmers helps you get a head start on everything you need to know about the JSTL to get rolling.

 

Sue Spielman is president and senior consulting engineer, of Switchback Software LLC, http://www.switchbacksoftware.com . Switchback Software specializes in architecture/design and development of enterprise, web, and wireless applications. Sue is the author of ‘The Struts Framework: Practical Guide for Java Programmers’, ‘JSTL: Practical Guide for JSP Programmers’ and ‘The Web Conferencing Book’. She can be found speaking at various technical conferences around the country. You can reach her at sspielman at switchbacksoftware.com