© Luciano Manelli and Giulio Zambon 2020
L. Manelli, G. ZambonBeginning Jakarta EE Web Developmenthttps://doi.org/10.1007/978-1-4842-5866-8_6

6. JSP in Action

Luciano Manelli1  and Giulio Zambon2
(1)
Taranto, Italy
(2)
Harrison, ACT, Australia
 

In Chapter 2, you learned that there are three types of JSP elements: scripting, directives, and actions. I described the first two types directly in Chapter 2, and the time has come to look at JSP actions. Actions, like scriptlets, are processed when a page is requested. In this chapter, you will learn how to use JSP standard actions, how to create actions of your own design, and how to use some of the actions contained in the JSP Standard Tag Library. Besides small specific examples, you will also learn the role of actions in the eshop application that I introduced in the previous chapter. Actions can do everything that scripting elements can do, as you will see at the end of the next chapter, when I will tell you how to write JSP code without any scripting element at all.

JSP Standard Actions

While Tomcat executes directive elements when translating a page, it executes action elements when processing a client’s HTTP request.

JSP actions specify activities to be performed when a page is requested and can therefore operate on objects and affect the response. They normally take the following form:
<jsp:action-name attr1="value1" [attr2="value2"...]> ... </jsp:action-name>
However, actions can also have a body, like in the following example:
<jsp:action-name attribute-list>
  <jsp:subaction-name subaction-attribute-list/>
  </jsp:action-name>

There are eight JSP standard actions (forward, include, useBean, setProperty, getProperty, element, text, and plugin) and five additional actions that can only appear in the body of other actions (param, params, attribute, body, and fallback). There are also two additional action elements—invoke and doBody—that you cannot invoke from within JSP pages. There is also a further standard action—root—that I will explain at the end of the next chapter.

Actions: forward, include, and param

The forward action lets you abort execution of the current page and transfer the request to another page:
<jsp:forward page="myOtherPage.jsp">
  <jsp:param name="newParName" value="newParValue"/>
  </jsp:forward>

The include action is similar to forward, the main difference being that it returns control to the including page after the included page has completed execution. The output of the included page is appended to the output generated by the including page up to the point where the action is executed.

As shown in the example, jsp:param lets you define a new parameter for the invoked page, which also has access to the parameters already available to the invoking page.

Here is another example of a forward action:
<% String dest = "/myJspPages/" + someVar; %>
<jsp:forward page="<%=dest%>">
  <jsp:param name="newParName" value="newParValue"/>
  </jsp:forward>
This is 100 percent equivalent to the following scriptlet:
<%
  String dest = "/myJspPages/" + someVar;
  RequestDispatcher rd = application.getRequestDispatcher(dest + "?newParName=newParValue");
  rd.forward(request, response);
  %>

Tomcat clears the output buffer upon executing the forward action. Therefore, the HTML code generated up to that point by the current page is lost. But if the current page has already filled the response buffer by the time it is aborted with forward, that part of the response will have already left the server. This will probably result in a bad page sent to the client. Therefore, you have to be very careful when invoking forward from within a page that generates a large output.

You don’t have to worry about such a problem with include, because Tomcat doesn’t clear the output buffer when it executes that action.

With both forward and include , the destination page must be a well-formed and complete JSP page. The forward action must satisfy the additional requirement of generating a complete and valid HTML page, because the output of the destination page is what goes back to the client’s browser in the HTML response. The destination page of an include action might even generate only a single character, although in most cases it provides HTML code. For example, the top bar of the eshop application is generated in the page TopMenu.jsp (see Listing 6-1) and included in seven JSP pages with this code:
<jsp:include page="TopMenu.jsp" flush="true"/>
The flush attribute (default false) ensures that the HTML generated so far by the including page is sent to the client before executing the included page. Note that the included page is not allowed to change the response headers or the status code.
<%@page language="java" contentType="text/html"%>
<%
  String base = (String)application.getAttribute("base");
  String imageUrl = (String)application.getAttribute("imageUrl");
  %>
<div class="header">
  <div class="logo">
    <p>e-Shopping Center</p>
    </div>
  <div class="cart">
    <a class="link2" href="<%=base%>?action=showCart">Show Cart
      <img src="<%=imageUrl%>/cart.gif" border="0"/></a>
    </div>
  </div>
Listing 6-1

TopMenu.jsp

TopMenu.jsp generates the HTML code in Listing 6-2 (shown after I removed the empty lines).
<div class="header">
  <div class="logo">
    <p>e-Shopping Center</p>
    </div>
  <div class="cart">
    <a class="link2" href="/eshop/shop?action=showCart">Show Cart
      <img src="/eshop/images/cart.gif" border="0"/></a>
    </div>
  </div>
Listing 6-2

HTML Generated by TopMenu.jsp

Notice that TopMenu.jsp uses styles (such as class="header") that aren’t loaded or defined within the same file. If you’re wondering how that’s possible, you probably don’t clearly understand the distinction between source JSP and output HTML. The JSP code in TopMenu.jsp is executed on the server, and it produces HTML code, which is then appended to the output buffer. JSP doesn’t need style sheets. It is the generated HTML that needs them when it’s interpreted by the client’s browser.

You might think that <jsp:include page="..."/> is the same as <%@include file="..."%>, but this is definitely not the case. The most important difference is that while the include directive includes the content of a file without any processing, the include action includes the output of the included resource. If the resource is a JSP page, this makes a big difference. In practical terms, this also explains why JSP pages to be included with jsp:include must be well-formed and complete pages rather than simply JSP fragments.

To illustrate a subtle consequence of the different mechanisms of inclusion, I have prepared a small test page (see Listing 6-3). To try it out, you can copy to the tests Tomcat folder (webappsROOT ests) the folder named jsp_include that you will find in the software package for this chapter, or better, you can create a new web project “tests” in Eclipse and copy the same jsp_include folder in the WebContent folder (you can do this by simply copying the folder from the software package and pasting it in the folder in Eclipse environment).

Then type http://localhost:8080/tests/jsp_include/includes.jsp in a web browser.
<%@page language="java" contentType="text/html"%>
<html><head><title>A</title></head><body>
<table border="1">
  <tr><th>incl B</th><th>incl C</th><th>C contains</th></tr>
  <tr><td>jsp:include</td><td>jsp:include</td><td><jsp:include page="d/b_act.jsp"/></td></tr>
  <tr><td>jsp:include</td><td>@include</td><td><jsp:include page="d/b_dir.jsp"/></td></tr>
  <tr><td>@include</td><td>jsp:include</td><td><%@include file="d/b_act.jsp"%></td></tr>
  <tr><td>@include</td><td>@include</td><td><%@include file="d/b_dir.jsp"%></td></tr>
  </table>
</body></html>
Listing 6-3

includes.jsp

As you can see, I first included the d/b_act.jsp and d/b_dir.jsp files with an include action and then with an include directive. The two files contain these lines, respectively:
<%@page language="java" contentType="text/html"%><jsp:include page="c.txt"/>
<%@page language="java" contentType="text/html"%><%@include file="c.txt"%>
I placed a c.txt file (only containing the letter A) in the directory of includes.jsp and a second c.txt file (only containing the letter B) in the d directory. Figure 6-1 shows the result of running includes.jsp.
../images/309332_3_En_6_Chapter/309332_3_En_6_Fig1_HTML.jpg
Figure 6-1

The output of includes.jsp

As you can see, includes.jsp displays the letter B in all cases except when you implement the outer inclusion with the directive and the inner inclusion with the action. This means that only with that particular combination of file inclusions, includes.jsp accesses the c.txt file that is in the same directory. In the other three cases, includes.jsp accesses the c.txt file that is in the d directory, together with b_act.jsp and b_dir.jsp. To understand these results, you have to know that when Tomcat translates a JSP page into a Java class, it replaces <jsp:include page="fname"/> with an execution of the method org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "fname", out, false), while <%@include file="fname"%> results in the copying of the content of the fname file. Therefore, in the third case of the example, the <jsp:include page="c.txt"/> inside b_act.jsp is replaced with an include(request, response, "c.txt", out, false), and then the whole b_act.jsp is copied into includes.jsp. That’s why the servlet picks up the file in the directory of includes.jsp. The fact that b_act.jsp was in a different directory was lost when its include directive was replaced by the file content.

I decided to spend a bit of time on this issue because the inclusion mechanism is often misunderstood and causes many people to knock their heads against the wall when files seem to disappear.

Action: useBean

The useBean action declares a new JSP scripting variable and associates a Java object to it. For example, the following code declares the variable dataManager of type eshop.model.DataManager:
<jsp:useBean id="dataManager" scope="application" class="eshop.model.DataManager"/>
This is the same data manager instantiated and configured in ShopServlet.java as you saw in Chapter 5 (Listing 5-1). JSP uses this variable to access the data without having to worry about its location and implementation. Within eshop, this is the only way for JSP (the View) to interact with the data manager (the Model). For example, when a user selects a book and clicks the link to add it to the shopping cart, the controller servlet executes ShoppingCart.jsp with an argument set to the book identifier. Then, ShoppingCart.jsp executes a method of the data manager (see Table 5-1) to obtain the book details, which are actually stored in a MySQL database:
Book book = dataManager.getBookDetails(bookId);

The result is stored in an object of type book, from which JSP can obtain individual book attributes by executing simple get methods such as book.getTitle() and book.getAuthor().

jsp:useBean accepts the attributes beanName, class, id, scope, and type, of which only id is mandatory.

If you type <jsp:useBean id="objName"/>, Tomcat will check whether an object named objName exists in pageContext. If it exists, Tomcat will create a variable named objName of the same type as the object, so that you can access the object in subsequent JSP scripting elements. If the object doesn’t exist, Tomcat will throw a java.lang.InstantiationException.

If you type <jsp:useBean id="objName" scope="aScope"/> with aScope set to one of the words page, request, session, or application, Tomcat will behave as described in the previous paragraph, but it will look for the objName object in the given scope rather than in the page context. In other words, page is the default scope.

Also jsp:useBean can create new objects. Whether useBean does it and what type of variable it makes available for JSP scripting depends on the three remaining attributes: class, type, and beanName.

If you specify class and set it to a fully qualified class name (i.e., with its package, as in java.lang.String) but specify neither type nor beanName, Tomcat will instantiate an object of the given class in the scope you specify with the attribute scope (or in the page scope by default).

If together with class you also specify type, Tomcat will set the data type of the new object to the value of the type attribute. You can set the type attribute to the same class as the class attribute (which is equivalent to omitting type), to a superclass of class, or to an interface implemented by class.

If instead of class you specify the beanName attribute, Tomcat will behave as if you had specified class, but only after attempting to find a serialized bean of that class. Serializing a bean means that the object’s data is converted to a byte stream and saved in a file with the extension ser. Tomcat expects to find serialized objects in the same folder containing the application classes. For example, a serialized bean of the xxx.yyy.Zzz class is expected to be in the WEB-INFclassesxxxyyyzz.ser file. This mechanism lets you save an object in a file and then load it into your JSP page. You can actually have several serialized beans of the same class (e.g., Zzz.ser, Zzz_tests.ser, Zzz25.ser, and Abc.ser). Fortunately, the designers of JSP have thought this issue through and allowed you to set the value of beanName at request time (the other attributes must be hard-coded), so that you can parameterize your page for what concerns loading serialized objects.

Finally, pay attention that the servlet creates the objects in the correct scope. In the previous chapter, the initialization method of the eshop servlet (see Listing 5-1) first instantiated the dataManager object and then saved it in the application scope.

Caution

Don’t confuse the scope of a bean as specified with the useBean attribute scope with the scope of the scripting variable that Tomcat associates to the bean.

As an example of useBean scopes, the following code instantiates a MyClass object that remains available as long as the session remains valid:
<jsp:useBean class="myPkg.MyClass" id="myObj" scope="session"/>
You’ll be able to access it via a scripting variable named myObj in any page within the same session with the following statement:
<jsp:useBean id="myObj" type="myPkg.MyClass" scope="session"/>

However, the scope of the scripting variable myObj is determined by where within your page you execute useBean , as with the declaration of any other scripting variable. If you find this confusing, consider this: in the page containing the second useBean, you don’t have access to the scripting variable myObj until you execute the useBean action. Before that, the scripting variable is undefined, although the bean called myObj already exists, as it was instantiated by the first useBean in a previously executed page. This tells you that the scripting variable referring to the object and the actual object are two different things with two different scopes, even if they share the same name.

Incidentally, the first useBean (with class, id, and scope) is completely equivalent to this:
<%
MyClass myName = new MyClass();
session.setAttribute("myObj", myObj);
%>
and the second useBean (with id, type, and scope) is the same as this:
<%
MyClass myObj = (MyClass)session.getAttribute("myObj");
%>

This representation should make completely clear that the object and the scripting variable are two different entities. In the second scriptlet, you could even decide to call the scripting variable with a different name.

Because of all the options implemented by combining its attributes, as I said at the beginning, useBean is somewhat tricky to use. But you can always come back to this page in case of doubt!

Actions: setProperty and getProperty

A bean property is nothing else than an attribute of a bean’s class, but only when you define for that attribute the standard get and set methods. To make it completely clear, both get and set must be there. Otherwise, that class attribute is not a bean property.

Additionally, you must name the two methods respectively get and set, followed by the full name of the attribute with the first letter capitalized. For example, if you define the attribute named myAttr, you must name the two attributes getMyAttr and setMyAttr. Otherwise, again, Tomcat will not recognize the attribute as a bean property.

An example from the eshop application will convince you that you are better off if Tomcat recognizes an attribute as a property. The JSP page OrderConfirmation.jsp has the following two elements:
<jsp:useBean id="customer" class="eshop.beans.Customer"/>
<jsp:setProperty property="*" name="customer"/>
The useBean action instantiates an object of type Customer and assigns it to the variable named customer. The action is equivalent to
Customer customer = new Customer();
By defining property="*", the setProperty action tells Tomcat to set all bean properties of the newly created object. What setProperty does not say is to what values they should be set. This is because the values come from request parameters named exactly like the properties. Check out the definition of the Customer class, shown in Listing 6-4.
package eshop.beans;
public class Customer {
  private String contactName = "";
  private String deliveryAddress = "";
  private String ccName = "";
  private String ccNumber = "";
  private String ccExpiryDate = "";
  public String getContactName() {
    return contactName;
    }
  public void setContactName(String contactName) {
    this.contactName = contactName;
    }
  public String getDeliveryAddress() {
    return deliveryAddress;
    }
  public void setDeliveryAddress(String deliveryAddress) {
    this.deliveryAddress = deliveryAddress;
    }
  public String getCcName() {
    return ccName;
    }
  public void setCcName(String ccName) {
    this.ccName = ccName;
    }
  public String getCcNumber() {
    return ccNumber;
    }
  public void setCcNumber(String ccNumber) {
    this.ccNumber = ccNumber;
    }
  public String getCcExpiryDate() {
    return ccExpiryDate;
    }
  public void setCcExpiryDate(String ccExpiryDate) {
    this.ccExpiryDate = ccExpiryDate;
    }
  }
Listing 6-4

Customer.java

As you can see, the Customer class defines private attributes and then the methods to access them, so that they can be recognized as properties.

It is interesting the setProperty action
<jsp:setProperty property="*" name="customer"/>
is equivalent to the following code:
customer.setContactName(request.getParameter("contactName");
customer.setDeliveryAddress(request.getParameter("deliveryAddress");
customer.setCcName(request.getParameter("ccName");
customer.setCcNumber(request.getParameter("ccNumber"));
customer.setCcExpiryDate(request.getParameter("ccExpiryDate"));

The implementation with the action is more compact and, most importantly, it remains valid regardless of whether you add or remove customer attributes. And that’s what makes setProperty worthwhile.

Also jsp:getProperty is useful, because it sends the value of a property to the output. For example, suppose you define MyClass as shown in Listing 6-5.
package tests.mclasses;
import java.io.Serializable;
public class MyClass implements java.io.Serializable {
  public static final long serialVersionUID = 1L;
  private int i;
  public MyClass() {i = 0;}
  public void setI(int i) {this.i = i;}
  public int getI() {return i;}
  }
Listing 6-5

MyClass.java

As you can see, the integer attribute i is a property. Listing 6-6 shows the JSP page that uses both getProperty and setProperty.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"  pageEncoding="ISO-8859-1"%>
<%@page import=" java.util.*, tests.myclasses.MyClass"%>
<%@page trimDirectiveWhitespaces="true"%>
<html><head><title>myObj</title></head><body>
<jsp:useBean id="obj" class=" tests.myclasses.MyClass" scope="session">
   <jsp:setProperty name="obj" property="i" value="11"/>
</jsp:useBean>
<jsp:getProperty name="obj" property="i"/>
<jsp:setProperty name="obj" property="i" value="22"/>
<jsp:getProperty name="obj" property="i"/>
</body></html>
Listing 6-6

myObj.jsp

To try it out, create a new class “MyClass” in the created Eclipse project “tests” unsder the package tests.myclasses and then copy the code in the folder named jsp_getProperty that you will find in the software package for this chapter. Do the same thing for the JSP page. Type in a browser http://localhost:8080/tests/myObj.jsp.

As you can see, myObj.jsp instantiates the bean object with useBean and initializes its attribute by executing setProperty within the body of useBean. The advantage of doing it that way is that Tomcat only attempts to execute the sub-action setProperty if the instantiation of the bean succeeds.

The two executions of getProperty send the value of i to the output. As a result, myObj.jsp generates the following HTML page:
<html><head><title>myObj</title></head><body>
1122</body></html>

The example also shows that in setProperty you can replace the value attribute with param. Then, Tomcat sets the attribute to the value of the identically named request parameter. Notice how the page directive with trimDirectiveWhitespaces set to true only leaves a single newline, after <body>, because it is in the HTML template. It results in 11 and 22 being “fused” into 1122. Not necessarily what you would like to have.

Actions: element, attribute, and body

With the actions element, attribute, and body , you can define XML elements dynamically within a JSP page. One reason why you might like to define XML elements dynamically is that your JSP page, instead of generating a web page to be displayed in a browser, might need to generate an XML file used to exchange data with other modules and applications. The word dynamically is important, because it means that you can generate the XML elements at request time rather than statically at compile time.

The JSP page shown in Listing 6-7 generates the HTML output shown in Listing 6-8. It is a meaningless page, only designed to show you how to use these actions. Don’t look for a meaning that doesn’t exist!
<%@page language="java" contentType="text/html"%>
<html>
<head><title>Action elements: element, attribute</title></head>
<body>
<jsp:element name="myElem">
  <jsp:attribute name="myElemAttr">myElemAttr's   value</jsp:attribute>
  <jsp:body>myElem's body</jsp:body>
</jsp:element>
<br/>
<jsp:include page="text.txt"/>
<br/>
<jsp:include>
  <jsp:attribute name="page">text.txt</jsp:attribute>
  </jsp:include>
</body>
</html>
Listing 6-7

actel_element_attribute.jsp

<html>
<head><title>Action elements: element, attribute</title></head>
<body>
<myElem myElemAttr="myElemAttr's value">myElem's body</myElem>
<br/>
This is inside the test file text.txt
<br/>
This is inside the test file text.txt
</body>
</html>
Listing 6-8

The Output of actel_element_attribute.jsp

You can test it at http://localhost:8080/tests/actel_element_attribute.jsp.

I have highlighted two parts of the listings. The first highlight shows how to use the actions element, attribute, and body to generate an XML element. Be aware that if you drop the action body, the XML element generated by element will have an empty body, as in the following example:
<myElem myElemAttr="myElemAttr's value"/>

The second highlight shows how you can use attribute to move the page attribute of include to be inside the body of the include action. The content of the file text.txt is unimportant. You’ll find a one-line file in the jsp_element folder of the software package for this chapter (you can copy it in the Eclipse project named “tests”).

Action: text

You can use the jsp:text action to write template text. Its syntax is straightforward:
<jsp:text>Template data</jsp:text>

Its body cannot contain other elements; it can only contain text and EL expressions.

Actions: plugin, params, and fallback

These three actions let you embed an object in a web page when there is a need of a plug-in to run. Its syntax is straightforward:
<jsp:plugin type="applet/bean" code="objectcode" codebase="objectcodebase">
  <jsp:params>
     <jsp:param name="name" value="value"/>
  </jsp:params>
     <jsp:fallback>Unable to start plugin</jsp:fallback>
</jsp:plugin>

Here the type specifies either an object or a bean, code specifies the class name of the object, and at last the codebase specifies the URL containing the files of the class. The syntax shows also how to pass params and how to inform the user with fallback if the object fails to start.

Comments and Escape Characters

The comment delimiters <%-- .. --%> have in JSP the same function as /* .. */ in Java. You can also use them to “switch off” JSP elements, as shown here:
<%-- <jsp:include page="whatever.jsp"/> --%>

They can also span over several lines.

Note

Regular HTML comments such as <!-- ... --> won’t work with JSP.

JSP comments have the advantage over HTML comments in that they are not sent to the client. Their content is therefore invisible to the user.

To include the sequence of characters <% and %> in template text, you have to “break” them with a backslash, like in <\% and %>, so that the JSP engine doesn't interpret them as the beginning and end of scripting elements. Alternatively, you can replace the inequality signs with their corresponding HTML entities, as in <% and %>.

JSP’s Tag Extension Mechanism

You can define your own actions to replace lengthy scriptlets. By “hiding” functions behind custom tags, you can increase modularity and maintainability of your pages.

To write in a JSP page a statement like
<myPrefix:myActionTag attributeName="myAttributeName"/>
you need to follow the following steps:
  1. 1.

    Define Java classes that provide the functionality of the new actions, including the definition of their attributes (e.g., myAttributeName). These classes are called tag handlers .

     
  2. 2.

    Provide a formalized description of your action elements, so that Tomcat knows how to handle them. For example, you need to specify which actions can have a body and which attributes can be omitted. Such a description is called a tag library descriptor (TLD).

     
  3. 3.

    In the JSP pages, tell Tomcat that the pages need your tag library and specify the prefix that you want to identify those custom tags with.

     

I will take you through these steps, beginning with bodyless actions, which are simpler to implement.

Bodyless Custom Actions

A bodyless action is an element that, not having an end tag, cannot enclose a body between start and end tags. As an example, let’s say you want to develop an action that prints the day of the week of any given date:
<wow:weekday date="date"/>

with the date attribute accepting values in the form yyyy-mm-dd and defaulting to the current date. All the examples of this section on bodyless actions and the following section of bodied actions are in the software package for this chapter. To test them, import the project tldtest in Eclipse.

Step 1: Define the Tag Handler

A tag handler for a bodyless custom tag is a class that implements the interfaces java.io.Serializable and javax.servlet.jsp.tagext.Tag. Remember that to satisfy an interface, you have to implement all the methods it defines.

To satisfy Serializable, you only need to define a unique identifier, like this:
static final long serialVersionUID = 1L;
The value identifies the version of your class and the objects you instantiate from it. It is then used when deserializing objects to check that class and object match. As long as you don’t have several versions of the class and swap objects between JVMs, you don’t really need to worry about it. However, to satisfy the Tag interface, you have to define the methods listed in Table 6-1.
Table 6-1

The Methods of the Tag Interface

Method

Description

int doEndTag()

Processes the end tag

int doStartTag()

Processes the start tag

Tag getParent()

Provides a reference to the closest enclosing tag handler

void release()

Removes all the references to objects

void setPageContext(PageContext pc)

Sets the current page context

void setParent(Tag t)

Sets the closest enclosing tag handler

Fortunately, the javax.servlet.jsp.tagext.TagSupport class makes life easier by implementing the Tag interface with default methods and other useful methods. Therefore, you only need to extend TagSupport and overwrite the methods you need for your weekday action. You certainly don’t need getParent, because the action isn’t going to be used in the body of other actions. You don’t need doStartTag either, because the action is bodyless, and, as a consequence, you don’t have separate start and end tags. In conclusion, you only need to overwrite doEndTag with a method containing all the functionality of the weekday tag.

Listing 6-9 shows you the code of the whole tag handler.
package tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class WeekdayTag extends TagSupport {
  static final long serialVersionUID = 1L;
  static final String[] WD = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  private String date;
  public void setDate(String date) {
    this.date = date;
    }
  public int doEndTag() throws JspException {
    GregorianCalendar cal = new GregorianCalendar();
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
    fmt.setLenient(true);
    if (date != null && date.length() > 0) {
      Date d = new Date();
      try {
        d = fmt.parse(date);
        }
      catch (Exception e) {
        throw new JspException("Date parsing failed: " + e.getMessage());
        }
      cal.setTime(d);
      }
    try {
      pageContext.getOut().print(WD[cal.get(Calendar.DAY_OF_WEEK)]);
      }
    catch (Exception e) {
      throw new JspException("Weekday writing failed: " + e.getMessage());
      }
    return EVAL_PAGE;
    }
  }
Listing 6-9

WeekdayTag.java

You need the setDate method because Tomcat uses it to pass the value of the action’s date attribute to the tag handler. The corresponding getDate method isn’t present, because it is never used and can be omitted. That said, you might argue that working with incomplete Java beans, sooner or later, will get you into trouble. If the action is executed without the date attribute, the date variable defined in doEndTag remains set to null, and the calendar cal, which is used to determine the day of the week, remains set to the current date. On the other hand, if a date attribute is specified in the action, its value is parsed and used to set the calendar.

Notice that the tag handler is named like the tag but with the first letter capitalized and with the Tag suffix. This is a good practice to follow, although you can name your handlers whatever you like. You’ll see in a moment how to make the association between a tag and its handler.

The return value EVAL_PAGE means that execution should continue with the page code following the custom action. Use SKIP_PAGE to abort the page.

Step 2: Define the TLD

The TLD is an XML file that describes your tags so that Tomcat knows how to deal with them. Listing 6-10 shows the full TLD for the custom-tag library.
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns:="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
      version="2.1">
<description>Example of a simple tag library</description>
  <tlib-version>1.0</tlib-version>
  <short-name>wow</short-name>
  <tag>
    <description>Displays the day of the week</description>
    <display-name>weekday</display-name>
    <name>weekday</name>
    <tag-class>tags.WeekdayTag</tag-class>
    <body-content>empty</body-content>
    <attribute>
      <name>date</name>
      <rtexprvalue>true</rtexprvalue>
      <type>java.lang.String</type>
      </attribute>
    </tag>
  </taglib>
Listing 6-10

wow.tld

As you can see, the outermost element is taglib, which contains a tag element for each custom action (in this case, only weekday). Apart from tag, all taglib sub-elements in the example are for information purposes or to be used by tools and can be omitted.

The tag element contains an attribute sub-element for each action attribute (in this case, only date). Of the tag sub-elements in the example, you can omit description and display name . The sub-element name defines the custom action name; tag class specifies the fully qualified class name of the tag handler; and body content specifies the action to be bodyless.

The sub-element tag class is what gives you the freedom to name your tag handlers anything you like. The sub-element body content is mandatory and can only have one of the following three values: empty, scriptless, or tagdependent. The value scriptless is the default and means that the body cannot contain scripting elements, while EL expressions and JSP actions are accepted and processed normally. The value tagdependent means that the body content is passed to the tag handler as it is, without any processing. This is useful if the body contains character sequences, such as <%, that would confuse Tomcat.

The attribute element in the example has three sub-elements: name, which sets the action attribute name; type, which sets the class name of the attribute value; and rtexprvalue, which decides whether the attribute accepts values at request time.

If you had used a type other than String, the value passed to the tag handler would have been of that type. For example, with an attribute defined like this:
<attribute>
  <name>num</name>
  <type>java.lang.Integer</type>
  </attribute>
you would have included the following code in the tag handler:
private int num;
public void setNum(Integer num) {
  this.num = num.intValue();
  }

When processing the start tag of the custom action, Tomcat would have parsed the string passed to the action (as in num="23") to obtain the Integer value for the tag handler.

If you had omitted the rtexprvalue sub-element or set it to false, you would have been forced to pass to the date attribute only constant values, such as "2007-12-05", instead of runtime values such as "<%=aDate%>" (rtexpr stands for real-time expression).

Inside WEB-INF, create a folder named tlds and place wow.tld there.

Step 3: Use the Custom Action

Listing 6-11 shows you a simple JSP page to test the weekday custom action.
1: <%@page language="java" contentType="text/html"%>
2: <%@taglib uri="/WEB-INF/tlds/wow.tld" prefix="wow"%>
3: <% String d = request.getParameter("d"); %>
4: <html><head><title>weekday bodyless tag</title></head><body>
5: weekday today: <wow:weekday/><br/>
6: weekday <%=d%>: <wow:weekday date="<%=d%>"/>
7: </body></html>
Listing 6-11

weekday.jsp

Line 2 contains the taglib directive, line 4 uses weekday without the date attribute, and line 6 passes the request parameter d to the action. It’s as simple as that.

If you type in your browser http://localhost:8080/tldtest/weekday.jsp?d=2012-12-25, you get two lines, such as Today: Wed and 2012-12-25: Tue. If you type the URL without the query, the second line of the output becomes null: Wed. You can execute the example by typing in your browser http://localhost:8080/tldtest/weekday.jsp.

On the other hand, if you type a query with a bad date, such as d=2012-1225, Tomcat shows you an error page with a back trace that begins as follows:

../images/309332_3_En_6_Chapter/309332_3_En_6_Figa_HTML.gif

You can execute the example by typing in your browser http://localhost:8080/tldtest/weekday.jsp?d=2012-1225.

Bodied Custom Actions

To show you the differences from the bodyless action, I will implement a version of the weekday action that expects the date in its body instead of in an attribute:
<wow:weekdayBody>date</wow:weekdayBody>

Step 1: Define the Tag Handler

Similar to bodyless actions, the tag handlers for bodied actions need to implement an interface, only this time it’s javax.servlet.jsp.tagex.BodyTag instead of Tag. Again, similarly to bodyless actions, the API provides a convenient class that you can use as a basis: javax.servlet.jsp.tagext.BodyTagSupport. However, as opposed to what you did in the tag handler for a bodyless action, you cannot simply replace the doEndTag method, because the action body will have come and gone by the time you reach the end tag. You first have to overwrite doAfterBody.

An additional complication concerns the default date: if you write the action with an empty body, as follows:
<wow:weekdayBody></wow:weekdayBody>

the method doAfterBody won’t be executed at all. How can you then print out the default day?

The answer is simple: you have to overwrite the doEndTag method and write the default date from there in case there is no body. Listing 6-12 shows the end result.
package tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class WeekdayBodyTag extends BodyTagSupport {
  static final long serialVersionUID = 1L;
  static final String[] WD = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  private boolean bodyless = true;  /* 1 */
  public int doAfterBody() throws JspException {
    String date = getBodyContent().getString();  /* 2 */
    if (date.length() > 0) {
      GregorianCalendar cal = new GregorianCalendar();
      Date d = new Date();
      SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
      fmt.setLenient(true);
      try {
        d = fmt.parse(date);
        }
      catch (Exception e) {
        throw new JspException("Date parsing failed: " + e.getMessage());
        }
      cal.setTime(d);
      try {
          getPreviousOut().print(WD[cal.get(Calendar.DAY_OF_WEEK)]);  /* 3 */
          }
        catch (Exception e) {
          throw new JspException("Weekday writing failed: " + e.getMessage());
          }
      bodyless = false;  /* 4 */
      }
    return SKIP_BODY;
    }
  public int doEndTag() throws JspException {
    if (bodyless) {  /* 5 */
      GregorianCalendar cal = new GregorianCalendar();
      try {
        pageContext.getOut().print(WD[cal.get(Calendar.DAY_OF_WEEK)]);
        }
      catch (Exception e) {
        throw new JspException("Weekday writing failed: " + e.getMessage());
        }
      }
    return EVAL_PAGE;
    }
  }
Listing 6-12

WeekdayBodyTag.java

Lines 1, 4, and 5 implement the mechanism to ensure that you write the default date but only when the body is empty. In line 1, you define a boolean instance variable called bodyless and set it to true. If there is no body to process, doAfterBody does not run, and doEndTag in line 5 prints the default day of the week. If, on the other hand, there is a body to process, doAfterBody in line 4 sets bodyless to false, and doEndTag does nothing.

Line 2 shows you how to get the body content and line 3 how to get the method to print the date while processing the body. The method has been named getPreviousOut to remind you that there can be actions within actions, in which case you’ll want to append the output of an inner action to that of an outer one.

Step 2: Define the TLD

To define the new action, you only need to add the <tag> shown in Listing 6-13 after the <tag> for the bodyless weekday action.
  <tag>
    <description>Displays the day of the week</description>
    <display-name>weekdayBody</display-name>
    <name>weekdayBody</name>
    <tag-class>tags.WeekdayBodyTag</tag-class>
    <body-content>scriptless</body-content>
    </tag>
Listing 6-13

The tag Element for weekdayBody

Notice that you define the body-content sub-element as scriptless even though it is the default. The purpose is to make the code more readable. It’s just a matter of taste.

Step 3: Use the Custom Action

Listing 6-14 shows a modified version of weekday.jsp to handle the bodied tag.
<%@page language="java" contentType="text/html"%>
<%@taglib uri="/WEB-INF/tlds/wow.tld" prefix="wow"%>
<html><head><title>weekday bodied tag</title></head><body>
weekdayBody today: <wow:weekdayBody></wow:weekdayBody><br/>
weekdayBody ${param.d}: <wow:weekdayBody>${param.d}</wow:weekdayBody><br/>
</body></html>
Listing 6-14

weekday_b.jsp for the Bodied Action

Notice that I replaced the request.getParameter("d") logic with the simpler and more elegant EL expression ${param.d}. You have to use an EL expression in any case, because scripting elements aren’t allowed in the body of an action. Therefore, you couldn’t have used <%=d%>. You will learn how to use EL in the next section of this chapter.

Tag Files

Tag files are special JSP files that replace tag handlers written in Java. After all, JSP basically is Java.

Do you remember when I told you in Chapter 2 that the only available directive elements are page, include, and taglib? Well, I lied. There are three more directives: tag, attribute, and variable. The reason I didn’t mention them is that you can only use them in tag files. Now that you know how to develop custom-tag libraries with Java, I can tell you how to develop them using the JSP syntax and the newly revealed directives. The examples of this section are in the folder tagtest of the software package for this chapter. To install them, import the package into Eclipse.

Bodyless Tag

Listing 6-15 shows the tag-file version of the tag handler WeekdayTag.java that you saw in Listing 6-9.
<%@tag import="java.util.Date, java.text.SimpleDateFormat"
       import="java.util.Calendar, java.util.GregorianCalendar"%>
<%@attribute name="date" required="false"%>
<%
  final String[] WD = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  GregorianCalendar cal = new GregorianCalendar();
  if (date != null && date.length() > 0) {
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
    fmt.setLenient(true);
    Date d = fmt.parse(date);
    cal.setTime(d);
    }
  out.print(WD[cal.get(Calendar.DAY_OF_WEEK)]);
  %>
Listing 6-15

weekday.tag

The tag directive of a tag file replaces the page directive of a JSP page, and the attribute directive lets you define an input parameter. As Tomcat handles the tag exceptions for us, I removed the try/catch constructs, which certainly makes the code more readable. Another simplification is in sending the result to the output, because in the tag file the implicit variable out makes it unnecessary to invoke pageContext.getOut().

Listing 6-16 shows how you modify weekday.jsp of Listing 6-11 to use the tag file.
<%@page language="java" contentType="text/html"%>
<%@taglib tagdir="/WEB-INF/tags" prefix="wow"%>
<% String d = request.getParameter("d"); %>
<html><head><title>weekday bodyless tag</title></head><body>
weekday today: <wow:weekday/><br/>
weekday <%=d%>: <wow:weekday date="<%=d%>"/><br/>
</body></html>
Listing 6-16

weekday_t.jsp

As you can see, the only difference is that the attribute uri="/WEB-INF/tlds/wow.tld" of the taglib directive has become tagdir="/WEB-INF/tags".

To keep the uri attribute, you need to declare the tag file in a TLD, as shown in Listing 6-17.
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns:="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ~CCC
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_1.xsd"
    version="2.1">
  <description>My library of tag files</description>
  <tlib-version>1.0</tlib-version>
  <short-name>wow</short-name>
  <uri>tagFiles</uri>
  <tag-file>
    <description>Displays the day of the week</description>
    <display-name>weekday</display-name>
    <name>weekday</name>
    <path>/WEB-INF/tags/weekday.tag</path>
    </tag-file>
  </taglib>
Listing 6-17

wow.tld for a Tag File

Then, in the taglib directive of weekday_t.jsp, you can replace tagdir="/WEB-INF/tags" with uri="tagFiles" .

As an example of the variable directive, replace in weekday.tag the line
out.print(WD[cal.get(Calendar.DAY_OF_WEEK)]);
with the following two:
%><%@variable name-given="dayw" scope="AT_END"%><%
jspContext.setAttribute("dayw", WD[cal.get(Calendar.DAY_OF_WEEK)]);
The action will then save the string with the day of the week into the attribute dayw instead of sending it directly to the output. To display the action’s result from within weekday_t.jsp, insert the following expression element after executing the action:
<%=pageContext.getAttribute("dayw")%>

As you will see later in this chapter, you can also replace the somewhat cumbersome expression element with the more compact EL expression ${dayw}.

Bodied Tag

Listing 6-18 shows the tag file equivalent to the tag handler WeekdayBodyTag.java, which you saw in Listing 6-12. I wrote it by modifying the tag file weekday.tag that implemented the bodyless tag as shown in Listing 6-15. Listing 6-19 is the tag file equivalent to weekday_b.jsp (see Listing 6-14), which invoked the bodied tag handler. I wrote it by modifying weekday_t.jsp of Listing 6-16, which used the bodyless tag file.
<%@tag import="java.util.Date, java.text.SimpleDateFormat"
       import="java.util.Calendar, java.util.GregorianCalendar"%>
<jsp:doBody var="dateAttr"/>
<%
  String date = (String)jspContext.getAttribute("dateAttr");
  final String[] WD = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  GregorianCalendar cal = new GregorianCalendar();
  if (date.length() > 0) {
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
    fmt.setLenient(true);
    Date d = fmt.parse(date);
    cal.setTime(d);
    }
  out.print(WD[cal.get(Calendar.DAY_OF_WEEK)]);
  %>
Listing 6-18

weekdayBody.tag

The standard action element jsp:doBody evaluates the body of the weekdayBody action and stores its output as a string into the page-scoped attribute dateAttr. The first line of the scriptlet then copies the attribute into the JSP variable named date. After that, the bodied tag file is identical to the bodyless one. This was not really necessary, but the subsequent code accesses the date twice, first to check that it isn’t empty and then to parse it. I didn’t like to invoke the getAttribute method twice. It seemed less tidy.

If you omit the attribute var, doBody sends the body’s result to the output; if you replace var with varReader, the result is stored as a java.io.Reader object instead of a java.lang.String; and if you add the attribute scope, you can specify var/varReader to be defined as a request, session, or application attribute, instead of in the page scope.

You should know that jsp:invoke is very similar to jsp:doBody but operates on a JSP fragment instead of the action body. For example, by writing the following two lines in a tag file
<%@attribute name="fragName" fragment="true"%>
<jsp:invoke fragment="fragName"/>
you pass to it a JSP fragment. Like doBody, invoke admits the attributes var, varReader, and scope. Both standard actions can only be used within tag files.
<%@page language="java" contentType="text/html"%>
<%@taglib tagdir="/WEB-INF/tags" prefix="wow"%>
<html><head><title>weekday bodied tag</title></head><body>
weekdayBody today: <wow:weekdayBody></wow:weekdayBody><br/>
weekdayBody ${param.d}: <wow:weekdayBody>${param.d}</wow:weekdayBody><br/>
</body></html>
Listing 6-19

weekday_bt.jsp

You can import the project tagtest in Eclipse and test the example by typing in your browser http://localhost:8080/tldtest/weekday.jsp?d=2012-1225.

The tag Directive

In the previous section, you encountered the import attribute of the tag directive . Table 6-2 lists the other attributes that are available. They are all optional.
Table 6-2

Attributes of the tag Directive

Attribute

Description

description

The name says it all.

display-name

A short name intended for tools. The default is the name of the tag file without the .tag extension.

body-content

Same as the <body-content> tag in a TLD (see the comments after Listing 6-11).

dynamic-attributes

If the attribute is present, its value identifies a scoped attribute where you store a map with names and values of the dynamic attributes you use when executing the tag.

example

A string with a brief description of an example.

small-icon

Path, relative from the tag file, of a small icon intended for tools.

large-icon

Yes, you guessed correctly!

language

Equivalent to its namesake of the page directive.

pageEncoding

Ditto.

isELIgnored

Ditto.

The attribute Directive

You have already encountered the attributes name and required. Table 6-3 briefly describes the remaining ones (all optional).
Table 6-3

Attributes of the attribute Directive

Attribute

Description

description

This attribute is almost universal.

rtexprvalue

Same as the equally-named tag in a TLD (see the comments after Listing 6-11).

type

Ditto.

fragment

If set to true, it means that the attribute is a JSP fragment to be evaluated by the tag file. If false (the default), the attribute is a normal one and is therefore evaluated by Tomcat before being passed to the tag file. Do not specify rtexprvalue or type when you set fragment to true. Tomcat will set them for you, respectively, to true and javax.servlet.jsp.tagext.JspFragment.

example

A string with a brief description of an example.

small-icon

Path, relative from the tag file, of a small icon intended for tools.

There are also two mutually exclusive pairs of attributes that are associated with JavaServer Faces: deferredValue/deferredValueType and deferredMethod/deferredMethodSignature. Let’s not put the cart before the oxen.

The variable Directive

Table 6-4 briefly describes all the attributes.
Table 6-4

Attributes of the variable Directive

Attribute

Description

description

No surprises here.

name-given / name-from-attribute

You have seen name-given in the example. One of these two attributes must be present. The value of name-given cannot be the same of the value of the name attribute of an attribute directive or the value of a dynamic-attributes attribute of a tag directive. See after the end of this table for an explanation of how to use name-from-attribute.

alias

It works together with name-from-attribute. Again, see the following details.

scope

Can be AT_BEGIN, AT_END, or NESTED (the default). Once more, too much text to keep it in this table. See the following details.

variable-class

The name of the class of the variable (default is java.lang.String).

declare

Set to false (the default is true) if the variable is not declared.

While name-given provides the name of a JSP attribute (which, as you will see in the next section, coincides with the name of an EL variable), name-from-attribute provides the name of another JSP attribute containing the name of the JSP attribute you are interested in. Then, alias provides the name of an EL variable local to the tag file that Tomcat synchronizes with the JSP attribute. For example, if you declare
<%@variable alias="ali" name-from-attribute="attrName"%>
Tomcat, before continuing execution of the tag file, makes available to it the page-scoped attribute named ali and sets it to the value of the attribute named attrName. This name redirection makes possible for JSP pages that use differently named attributes to use the same tag file. For example, a.jsp might include the line
session.setAttribute("greet", "Good morning!");
and b.jsp might have
application.setAttribute("novel", "Stranger in a Strange Land");
If a.jsp contains
pageContext.setAttribute("attrName", "greet");
and b.jsp
pageContext.setAttribute("attrName", "novel");

they can both invoke the tag file that includes the variable directive shown earlier. The tag file will then have an ali attribute containing "Good morning!" in the first case and "Stranger in a Strange Land" in the second case.

The attribute scope tells when Tomcat creates or updates the attribute in the calling page with the value of the attribute that is local to the tag file (perhaps a name like synchronization would have been clearer than scope). With AT_BEGIN, Tomcat does it before the tag file invokes a segment or immediately before exiting the tag file; with NESTED, only before invoking a segment; and with AT_END, only before leaving the tag file. Additionally, with NESTED, Tomcat saves the value of the calling-page attribute upon entering the tag file and restores it upon leaving it. But this only if an attribute with the given name exists in the calling page before entering the tag file.

JSTL and EL

Many developers have implemented similar custom actions to remove or at least reduce the need for scripting elements. Eventually, a new effective standard known as JavaServer Pages Standard Tag Library (JSTL) was born.

To use this distribution with your web applications, you have to download the following JAR (or the equivalent files for the version that will be current when you will be reading this book) from https://tomcat.apache.org/taglibs/standard/ and add files to the /WEB-INF/lib directory of your application:
   - taglibs-standard-spec-1.2.5.jar
   - taglibs-standard-impl-1.2.5.jar

However, JSTL is of little use without the Expression Language (EL), which lets you access and manipulate objects in a compact and efficient way and can be used within the body of actions. I will first introduce you to EL, so that you’ll be well prepared to understand the JSTL examples.

JSP Expression Language

EL was introduced in JSP 2.0 as an alternative to the scripting elements. You can use EL expressions in template text and also in action attributes specified to be capable of accepting runtime expressions.

EL Expressions

EL supports two representations: ${expr} and #{expr}. To explain when you can or should use them, I must first clarify the distinction between lvalues and rvalues.

The l stands for left, and the r stands for right. These values refer to the fact that in most computer languages, the assigned value is on the right-hand side of an assignment statement, while the value to be assigned to it is on the left-hand side. For example, the Java statement
ka[k] = j*3;

means that the result of the evaluation of j*3 (an rvalue) is to be assigned to the value resulting from the evaluation of ka[k] (an lvalue). Clearly, an lvalue must be a reference to something you can assign values to (a variable or some attribute of an object), while there is no such restriction on rvalues.

Suppose that you have a page with a form. Wouldn’t it be nice if you could specify directly in the input elements of the form the references to where the user’s inputs should be stored? For example, it’d be nice to specify something like <input id="firstName" value="variableName">, with variableName specifying where you want to store the input typed by the user. Then, when the form is submitted, there should be a mechanism to automatically take the user’s input and store it where you specified. Perhaps you could also define a new attribute of the input element to provide a validating method. Inside the input element, you would then already have everything you need to accept the user’s input, validate it, and store it away.

This sounds great, but if you set the value attribute of the input element to ${formBean.firstName}, this evaluates to an rvalue. The value of the firstName attribute of formBean is assigned to the value attribute of the input element, and that’s it. You need a way of deferring evaluation of formBean.firstName and use it as an lvalue when you really need it, that is, when you handle the form that was submitted.

You achieve that by replacing the $ before the EL braces with a #. The # tells Tomcat to defer evaluation and use its result as an lvalue or an rvalue, depending on the context. EL expressions with the dollar sign are evaluated like everything else. In any other aspect, parsing and evaluation of the two representations are identical. You will use the # representation when we will talk about JSF. For now, you can learn about EL using the $ representation.

Using EL Expressions

The expr in ${expr} can contain literals, operators, and references to objects and methods. Table 6-5 shows some examples and their results.
Table 6-5

EL Expressions

EL Expression

Result

${1 <= (1/2)}

false

${5.0 > 3}

true

${100.0 == 100}

true

${'a' < 'b'}

true

${'fluke' gt 'flute'}

false

${1.5E2 + 1.5}

151.5

${1 div 2}

0.5

${12 mod 5}

2

${empty param.a}

true if the request parameter a is null or an empty string

${sessionScope.cart.nItems}

The value of the nItems property of the session-scoped attribute named cart

${aBean.aProp}

The value of the aProp property of the aBean bean

${aMap[entryName]}

The value of the entry named entryName in the map named aMap

The operators behave in general like in Java, but with one important difference: the equality operator (==) applied to string variables compares their contents, not whether the variables refer to the same instance of a string. That is, it behaves like Java’s String.equals() method.

In addition to EL operators identical to Java operators, you also have most of their literal equivalents: not for !, div for /, mod for %, lt for <, gt for >, le for <=, ge for >=, eq for ==, ne for !=, and for &&, and or for ||. You also have the unary operator empty, to be used as shown in one of the examples in Table 6-2.

The EL operators '.' (i.e., the dot) and [] (i.e., indexing) are more powerful and forgiving than the corresponding Java operators.

When applied to a bean, as in ${myBean.prop}, the dot operator is interpreted as an indication that the value of the property should be returned, as if you’d written myBean.getProp() in a scripting element. As a result, for example, the line of code
${pageContext.servletContext.servletContextName}
is equivalent to this:
<%=pageContext.getServletContext().getServletContextName()%>

Furthermore, ${first.second.third}, equivalent to <%=first.getSecond().getThird()%>, returns null when first.second evaluates to null, although in the expression, we try to dereference it with .third. The JSP scripting equivalent would throw a NullPointerException. For this to work, all classes must implement the getter methods of properly formed Java beans.

Array indexing allows you to try to access an element that doesn’t exist, in which case it simply evaluates to null. For example, if you have an array of ten elements, the EL expression ${myArray[999]} returns null instead of throwing an ArrayIndexOutOfBoundsException, as Java would have done. It is not as bad as in the plain old “C” language, in which an index out of bounds would have returned the value it found in memory. With EL, you can check for null. And in general, you should do so, because you cannot rely on an exception being thrown, as it would be in Java.

You can use both the dot and indexing operator to access maps. For example, the following two EL expressions both return the value associated with the key named myKey :
${myMap.myKey}
${myMap["myKey"]}

There is a tiny difference, though: you cannot use the dot operator if the name of the key contains a character that confuses EL. For example, ${header["user-agent"]} is OK, but ${header.user-agent} doesn’t work, because the dash between user and agent in the second expression is interpreted as a minus sign. Unless you have a variable named agent, both header.user and agent evaluate to null and, according to the EL specification document, ${null - null} evaluates to zero. Therefore, the second expression would return a zero. You would encounter a different, but potentially more serious, problem if you had a map key containing a dot. For example, you could use ${param["my.par"]} without problems, but ${param.my.par} would probably result in a null or, almost certainly, in something other than what you are looking for. This would be bad in any case, because null is a possible valid outcome. I suggest you use the bracketed form in all occasions and simply forget this issue.

Similar to JSP, EL contains implicit objects, which you find listed in Table 6-6.
Table 6-6

EL’s Implicit Objects

Object

Description

pageContext

The context of the JSP page. In particular, pageContext.servletContext gives you a reference to the same object referenced in JSP by the implicit variable application. Similarly, pageContext.session is equivalent to JSP’s session, pageContext.request to JSP’s request, and pageContext.response to JSP’s response.

Param

Maps a request parameter name to its first value.

paramValues

Maps a request parameter name to an array of its values.

header

Maps a request header name to its first value.

headerValues

Maps a request header name to an array of its values.

Cookie

Maps a cookie name to a single cookie.

initParam

Maps the name of a context initialization parameter to its value.

pageScope

Maps page-scoped variable names to their values.

requestScope

Maps request-scoped variable names to their values.

sessionScope

Maps session-scoped variable names to their values.

${aBean.aProp}

The value of the aProp property of the aBean bean.

applicationScope

Maps application-scoped variable names to their values.

Caution

You cannot use JSP scripting variables within EL expressions.

You’ve probably noticed that EL doesn’t include any way of declaring variables. Within EL expressions, you can use variables set with the c:set JSTL core action (which I will describe in the next section) or scoped attributes. For example, all of the following definitions let you use the EL expression ${xyz}:
<c:set var="xyz" value="33"/>
<% session.setAttribute("xyz", "44"); %>
<% pageContext.setAttribute("xyz", "22"); %>

However, you have to pay attention to scope precedence. The variable set with c:set and the attribute in pageContext are the same variable. That is, c:set defines an attribute in the page context. The attribute in sessionContext is a different variable, and you cannot access it with ${xyz} because it is “hidden” behind the attribute with the same name in the page context. To access a session attribute, you have to prefix its name with sessionScope, as in ${sessionScope.xyz}. If you don’t specify a scope, EL looks first in the page, then in the request, then in the session, and finally in the application scope.

Caution

You cannot nest EL expressions. Expressions such as ${expr1[${expr2}]} are illegal.

You can make composite expressions consisting of several EL expressions and additional text, as in the following example:
<c:set var="varName" value="Welcome ${firstName} ${lastName}!"/>

However, you cannot mix the ${} and #{} forms.

JSP Standard Tag Library

JSTL consists of five tag libraries, as listed in Table 6-7. If you are wondering, i18n stands for internationalization, abbreviated by replacing the eighteen letters in the middle with the number 18.
Table 6-7

JSTL Tag Libraries

Area

Functionality

core

Variable support, flow control, URL management, and miscellaneous

i18n

Locale, message formatting, and number and date formatting

functions

String manipulation and length of collection objects

SQL

Handling of databases

XML

XML core, flow control, and transformation

Table 6-8 lists all the tags defined in the five libraries.
Table 6-8

The JSTL Tags

Core

i18n

Functions

Database

XML

c:catch

fmt:bundle

fn:contains

sql:dateParam

x:choose

c:choose

fmt:formatDate

fn:containsIgnoreCase

sql:param

x:forEach

c:forEach

fmt:formatNumber

fn:endsWith

sql:query

x:if

c:forTokens

fmt:message

fn:escapeXml

sql:setDataSource

x:otherwise

c:if

fmt:param

fn:indexOf

sql:transaction

x:out

c:import

fmt:parseDate

fn:join

sql:update

x:param

c:otherwise

fmt:parseNumber

fn:length

 

x:parse

c:out

fmt:requestEncoding

fn:replace

 

x:set

c:param

fmt:setBundle

fn:split

 

x:transform

c:redirect

fmt:setLocale

fn:startsWith

 

x:when

c:remove

fmt:setTimeZone

fn:substring

  

c:set

fmt:timeZone

fn:substringAfter

  

c:url

 

fn:substringBefore

  

c:when

 

fn:toLowerCase

  
  

fn:toUpperCase

  
  

fn:trim

  
As you have already seen in a couple of examples, to use the JSTL libraries in JSP pages, you must declare them in taglib directives as follows:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql"%>
<%@taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml"%>

I will describe JSTL-XML and JSTL-SQL in the next chapters, while in the following sections of this chapter, I will describe JSTL-core and JSTL-i18n. I will not talk about the functions because they are pretty self-explanatory.

The Core Library

To explain some of the most used actions, I will go back to the example req_params.jsp of Chapter 1 (Listing 1-10) and add new scriptlets with JSTL actions in the same Eclipse project “test”. You can copy the code in the folder named jstl that you will find in the software package for this chapter. Listing 6-20 shows you how you do it.

c:out, c:set, and c:forEach (and fn:length)

01: <%@page language="java" contentType="text/html"%>
02: <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
03: <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
04: <html><head><title>Request Parameters with JSTL</title></head><body>
05:   Map size = <c:out value="${fn:length(paramValues)}"/>
06:   <table border="1">
07:     <tr><td>Map element</td><td>Par name</td><td>Par value[s]</td></tr>
08:     <c:set var="k" value="0"/>
09:     <c:forEach var="par" items="${paramValues}"><tr>
10:       <td><c:out value="${k}"/></td>
11:       <td><c:out value="'${par.key}'"/></td>
12:       <td><c:forEach var="val" items="${par.value}">
13:         <c:out value="'${val}'"/>
14:         </c:forEach></td>
15:       <c:set var="k" value="${k+1}"/>
16:       </tr></c:forEach>
17:     </table>
18: </body></html>
Listing 6-20

req_params_jstl.jsp

Notice that, as there are no scripting elements, I have removed the importing of Java libraries.

Lines 02 and 03 show the taglib directives for JSTL core and functions. In line 05, you can see how to use the fn:length function to determine the size of the EL implicit object paramValues and the c:out action to send the value of an EL expression to the output. You could have just written the naked EL expression, but c:out automatically converts characters that have special HTML meaning to the corresponding HTTP entities. For example, it writes & instead of &. Therefore, it’s better to use c:out.

c:set initializes an index in line 08 and increments it in line 15. In lines 09 and 12, c:forEach lets you go through the elements of maps and arrays.

If you type in your browser
http://localhost:8080/test/req_params_jstl.jsp?a=b&c=d&a=zzz&empty=&empty=
you’ll get the same output shown in Figure 6-2 for req_params.jsp (see Figure 1-24).
../images/309332_3_En_6_Chapter/309332_3_En_6_Fig2_HTML.jpg
Figure 6-2

Output of req_params_jstl.jsp

In essence, c:out is for EL expressions what an expression scripting element is for JSP (i.e., Java) expressions. Besides the attribute value, it supports default, to provide a fallback output, and escapeXml that you set to false to prevent the escaping of XML characters, which are escaped by default.

With c:set, besides defining var and value, you can also specify the scope of the variable with the attribute scope. Finally, in alternative to var, you can use the pair of attributes property and target to specify which property of which object you want to modify.

In the example, you have seen that c:forEach lets you loop over a list of objects with the two attributes var and items. Alternatively, you can go through a list by means of the attributes begin, where 0 indicates the first element, end, and step. Further, if you define the name of a variable by setting the attribute varStatus, c:forEach will store in it an object of type javax.servlet.jsp.jstl.core.LoopTagStatus.

As these attributes are pretty straightforward, the best way for you to become familiar with them is to write a small page and see what happens when you set them to different values.

Before moving on, have a look at Table 6-9. It lists what types of objects you can assign to the attribute items and, correspondingly, what type of objects you get in the variable defined through var.
Table 6-9

c:forEach Types

Items

var

Array of instances of class C

Instance of C

Array of primitive values (e.g., of int)

Wrapped element (e.g., in Integer)

String of comma-delimited substrings

Substring

java.util.Collection

Element obtained by invoking iterator()

java.util.Map

Instance of java.util.Map.Entry

java.util.Iterator

An Iterator element

java.util.Enumeration

An Enumeration element

javax.servlet.jsp.jstl.sql.Result

SQL rows

c:if, c:choose, c:when, and c:otherwise

The JSTL versions of Java’s if and switch are particularly useful tags. For example, the body of the following action is executed only if the EL expression calculates to true:
<c:if test="EL-expression"> ... </c:if>
Unfortunately, there is no c:else, but the JSTL version of switch (c:choose) is much more powerful than its Java counterpart. In fact, it’s more like a chain of if .. else:
<c:choose>
  <c:when test="EL-expression-1"> ... </c:when>
  <c:when test="EL-expression-2"> ... </c:when>
  ...
  <c:otherwise> ... </c:otherwise>
  </c:choose>

Besides test, which lets you define the condition you want to test, c:if supports the two attributes var and scope, which c:if uses to store the condition’s result.

There is no attribute supported by c:choose and c:otherwise, and c:when only supports test.

c:catch, c:remove, and c:url

With c:catch you can catch the exceptions that occur within its body. It accepts a var attribute, where it stores the result of the exception, of type java.lang.Throwable. For example, the following two lines will insert into the output the string "java.lang.ArithmaticException: / by zero":
<c:catch var="e"><% int k = 1/0; %></c:catch>
<c:if test="${e != null}"><c:out value="${e}"/></c:if>

c:remove lets you remove the variable defined in its pair of attributes var and scope.

c:url formats a string into a URL, which it then inserts into the output, like in the following example:
<a href="<c:url value="/tests/hello.jsp"/>">Hello World</a>

Notice the nested double quotes. This is not a problem, because Tomcat processes the action on the server and replaces it with a string representing the URL. The client doesn’t see the inner double quotes.

You can also specify a var/scope pair of attributes to store the generated URL into a scoped variable and the attribute context to refer to another application. If you use the bodied form of c:url, you can define with c:param additional parameters that will be appended to the URL.

c:import, c:redirect, and c:param

c:import and c:redirect are generalized versions of the standard actions jsp:include and jsp:forward. The main difference is that the JSTL actions are not limited to the scope of the current application. They let you include or forward to any URL via the attribute url, which is in both cases the only attribute required.

The general syntax of c:import is as follows:
<c:import url="expr1" context="expr2" charEncoding="expr3" var="name" scope="scope">
  <c:param name="expr4" value="expr5"/>
  ...
  </c:import>

By now, everything should be pretty clear to you. The only thing worth mentioning is that the default value for charEncoding is "ISO-8859-1". I prefer to use UTF-8 because it is equally supported by all operating systems. Also, UTF-8 can handle non-European languages and has become the de facto standard on the Web. In case you are curious, UTF stands for UCS Transformation Format, where UCS means Universal Character Set.

c:redirect is equivalent to invoking javax.servlet.http.HttpServletResponse.sendRedirect and only admits the two attributes url and context. When designing a website, you might find it useful to remember that c:redirect changes the page that the user sees, thereby affecting the setting of bookmarks, while with jsp:forward, the user remains unaware of the page change.

c:forTokens

In addition to c:forEach, the JSTL provides a form of string tokenizer, which lets you easily extract from a string the substrings separated by one or more delimiters.

If you have a comma as a single delimiter, you can use c:forEach, but if you have more than one delimiter, or if the only delimiter is not a comma, c:forTokens is for you.

The general syntax of c:forTokens is as follows:
<c:forTokens var="name" items="expr1" delims="expr2" varStatus="name"
    begin="expr3" end="expr4" step="expr5">
  ...
</c:forTokens>

The i18n Library: Writing Multilingual Applications

You can take one of two approaches to internationalizing a web application: you can either provide a different version of the JSP pages for each locale and select them via a servlet when processing each request, or you can save locale-specific data in separate resource bundles and access them via i18n actions . The JSTL internationalization actions support both, but I will concentrate on the second approach, where the work of switching between languages is actually done in JSP.

fmt:setLocale, fmt:setBundle, fmt:setMessage, and fmt:param

Suppose that you want to support English and Italian. The first thing you have to do is identify all the strings that are going to be different in the two languages and define two bundles, one for each language (see Listings 6-21 and 6-22).
package myPkg.i18n;
import java.util.*;
public class MyBundle_en extends ListResourceBundle {
  public Object[][] getContents() {return contents;}
  static final Object[][] contents = {
    {"login.loginmess","Please login with ID and password"},
    {"login.submit","Submit"},
    {"login.choose","Choose the language"},
    {"login.english","English"},
    {"login.italian","Italian"}
    };
  }
Listing 6-21

MyBundle_en.java

package myPkg.i18n;
import java.util.*;
public class MyBundle_it extends ListResourceBundle {
  public Object[][] getContents() {return contents;}
  static final Object[][] contents = {
    {"login.loginmess","Loggati con ID e password"},
    {"login.submit","Invia"},
    {"login.choose","Scegli la lingua"},
    {"login.english","Inglese"},
    {"login.italian","Italiano"}
    };
  }
Listing 6-22

MyBundle_it.java

As you can see, a bundle is nothing other than a Java class that extends the class java.util.ListResourceBundle. In this example, you will only find a simple login page, but in reality, you’ll have to include all the language-specific messages of your application. I used the prefix login to show you that it’s possible to group messages within a bundle.

Listing 6-23 shows the login page that supports two languages. To try it out, copy the folder named international from the software package international for this chapter and import it in Eclipse. Then type in your browser http://localhost:8080/international.
01: <%@page language="java" contentType="text/html"%>
02: <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
03: <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
04: <c:set var="langExt" value="en"/>
05: <c:if test="${param.lang!=null}">
06:   <c:set var="langExt" value="${param.lang}"/>
07:   </c:if>
08: <fmt:setLocale value="${langExt}"/>
09: <fmt:setBundle basename="myPkg.i18n.MyBundle"
10:   var="lang" scope="session"/>
11: <html><head><title>i18n</title></head><body>
12: <h1><fmt:message key="login.loginmess" bundle="${lang}"/></h1>
13: <form method="post" action="home.jsp">
14:   <input name=id>
15:   <input name=passwd>
16:   <input type="submit"
17:     value="<fmt:message key="login.submit" bundle="${lang}"/>"
18:     >
19: <h2><fmt:message key="login.choose" bundle="${lang}"/></h2>
20: <a href="index.jsp?lang=en">
21:   <fmt:message key="login.english" bundle="${lang}"/>
22:   </a>
23: &nbsp;
24: <a href="index.jsp?lang=it">
25:   <fmt:message key="login.italian" bundle="${lang}"/>
26:   </a>
27: </body></html>
Listing 6-23

index.jsp of a Multilingual Application

Lines 04–07 ensure that the page variable langExt is not null by setting it to en when the page is requested the first time. Line 08 sets the locale to the requested language code. The list of valid language codes is defined in the International Organization for Standardization (ISO) 639 standard. They’re in lowercase (e.g., it for Italian), so you can’t confuse them with the country codes defined in the ISO 3166 standard, which are in uppercase (e.g., IT for Italy).

In line 09, you set the bundle. Notice that it looks like the fully qualified class name of the two bundle classes but without the trailing underscore and language code. This is exactly how it should be done. Otherwise, the JSTL won’t find your messages. After executing fmt:setBundle, the session variable lang points to the bundle in the correct language, thanks to the locale and the basename attribute.

After that, an element like the following one will insert in the appropriate language the message identified by the value of the key attribute:
<fmt:message key="keyName" bundle="${lang}"/>

Notice how the double quotes are nested in line 17 without causing any problem. This is because the actions are processed first. By the time Tomcat arrives to process the HTML, only the outer double quotes remain.

Figure 6-3 shows what the page looks like the first time you view it.
../images/309332_3_En_6_Chapter/309332_3_En_6_Fig3_HTML.jpg
Figure 6-3

The first time you view index.jsp

Figure 6-4 shows how the page looks when you choose Italian by clicking the corresponding bottom link.
../images/309332_3_En_6_Chapter/309332_3_En_6_Fig4_HTML.jpg
Figure 6-4

The Italian version of index.jsp

If Tomcat cannot find a bundle, it will display the key name preceded and followed by three question marks, as shown in Figure 6-5. This indicates that you must have made a mistake in the directory names.
../images/309332_3_En_6_Chapter/309332_3_En_6_Fig5_HTML.jpg
Figure 6-5

index.jsp cannot find the messages

Besides value, fmt:setLocale admits two additional attributes. The first one, scope, defines the scope of the locale. In the example, the default (i.e., page) is used, but scope lets you, for example, save the locale as a session attribute. The remaining attribute, variant, lets you specify nonstandardized locales.

fmt:setMessage also supports a var/scope pair of attributes to let you store the generated string into a scoped variable. You can also place the sub-action fmt:param inside the body of fmt:message and set its attribute value to a string that you want to append to the message.

fmt:bundle, fmt:setTimeZone, and fmt:timeZone

Similar to fmt:SetBundle is fmt:bundle, but while you choose the basename the same way you do with fmt:setBundle, you cannot store your choice in a scoped variable. Instead, the basename you choose applies to all elements inside the body of fmt:bundle. Additionally, fmt:bundle also supports the attribute prefix, which extends the basename. For example, if you replace lines 09–10 in Listing 6-23 with
<fmt:bundle basename="myPkg.i18n.MyBundle" prefix="login.">
and insert </fmt:bundle> immediately above the last line, you then replace the existing line 21
<fmt:message key="login.english" bundle="${lang}"/>
with
<fmt:message key="english"/>
fmt:setTimeZone sets the current time zone to what specified in the attribute value, like in
<fmt:setTimeZone value="America/Los_Angeles"/>

but it can also store a time zone into a scoped variable specified by the var/scope attribute pair.

When you define a time zone with fmt:timeZone, on the other hand, it only applies to the elements that appear in the body of the action.

fmt:parseNumber and fmt: formatNumber

fmt:parseNumber and fmt:formatNumber deal with numbers, percentages, and currencies. Both actions can store their result into a scoped variable through the usual var/scope pair of attributes or send it to the output if those attributes are missing.

Note that fmt:formatNumber is bodyless and expects to find the number to be formatted in the value attribute. fmt:parseNumber also supports value in its bodyless form, but if the attribute is missing, it takes as input the content of its body.

Both actions support a type attribute that can have the values "number", "currency", or "percent".

Both actions also support a pattern attribute that lets you specify in detail a custom format. Table 6-10 lists the available symbols.
Table 6-10

Pattern Symbols for the Number Actions

Symbol

Meaning

0

A digit

E

Exponential form

#

A digit; 0 when absent

.

Decimal period

,

Group of digits separator

;

Format  separator

-

Default negative prefix

%

Displays a percent sign after multiplying the number by 100

?

Displays a per mille sign after multiplying the number by 1000

¤

Place marker for the actual currency sign

X

Place marker for any other character used in the prefix or suffix

'

To quote special characters in the prefix or suffix

Try out fmt:formatNumber with different patterns and see what you get. Some symbols are obvious, others, less so.

Additionally, fmt:parseNumber supports the attributes parseLocale, integerOnly (that you must set to false when parsing a floating-point number), and timeZone.

Yet, on the other hand, fmt:formatNumber supports the attributes currencyCode (only when type is set to "currency"), currencySymbol (ditto), groupingUsed (set to false if you don’t want a separator between triplets of integer digits), maxIntegerDigits, minIntegerDigits, maxFractionDigits, and minFractionDigits. The last four attributes specify the maximum and minimum number of digits you want before and after the decimal point.

fmt:ParseDate, fmt:formatDate, and fmt:requestEncoding

Like fmt:parseNumber and fmt:formatNumber, fmt:ParseDate and fmt:formatDate can store their result into a scoped variable or send it to the output. Also, fmt:formatDate is bodyless, while fmt:parseDate can be either bodyless or bodied. Not surprisingly, both actions support the timeZone attribute and the format attributes dateStyle (with possible values "full", "long", "medium", "short", or "default") and timeStyle (ditto). The Date Actions also support a pattern attribute. See Table 6-11 for a list of available symbols.
Table 6-11

Pattern Symbols for the Date Actions

Symbol

Meaning

G

Era designator (e.g., AD)

y

Year

M

Month

d

Day of the month

h

Hour (12-hour time)

H

Hour (24-hour time)

m

Minute

s

Second

S

Millisecond

E

Day of the week

D

Day of the year

F

Day of the week within the month (e.g., 2 means second Tue of the month)

w

Week of the year

W

Week of the month

a

AM/PM

k

Hour (12-hour time)

K

Hour (24-hour time)

z

Time zone

'

Escape for text

''

Quote

Additionally, fmt:parseDate supports the attribute parseLocale, and fmt:formatDate supports type (with possible values "date", "time", and "both").

With the remaining i18n action, fmt:requestEncoding, you specify what character encoding you expect for the text that the user types in forms, for example:
<fmt:requestEncoding value="UTF-8"/>

This action makes sense because the locale of the user might be different from the locale of the page. Note that if you develop a custom action that uses the method ServletResponse.setLocale() to set the locale of the response, it will take precedence over the character encoding set in fmt:requestEncoding.

Summary

In this chapter, you have learned everything about JSP standard actions and how to develop custom actions with JSP’s tag extension mechanism.

You saw detailed examples that explained how to develop and use custom actions with and without body, both implemented with tag handlers and with tag files.

After explaining the Expression Language, I described in general terms the JSP Standard Tag Library and explained in detail the core and the internationalization tags.

In the next chapter, I will introduce you to XML, an understanding of which is essential for developing professional web applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.247.31