ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button
Java Servlet & JSP Cookbook

Six Cool New JSP and Servlet Features

by Bruce W. Perry, author of Java Servlet & JSP Cookbook
02/11/2004

If you use a web container such as Tomcat 5.x, which supports Servlet API 2.4 and JSP 2.0, then you can use a number of useful new features. These include:

  1. Using a servlet as a welcome file.
  2. Mapping filters to RequestDispatchers.
  3. The new ServletRequestListener and ServletRequestAttributeListener interfaces.
  4. Using Expression Language (EL) code within template text, not just as tag attribute values.
  5. Writing tag files.
  6. Writing Expression Language qualified functions.

In this article, we'll delve into how you can use each of these features in your projects, using working code examples. Let's take a look at the first one on the list.

1. Servlets as Welcome Files

Welcome files are automatic web server responses to requests that specify only directories, not specific web components or files. When a visitor wants to request a home page, for example, they normally will just type in the name of the protocol (HTTP) and the host name, as in: http://www.google.com. Using Java web components, you can configure the response that is automatically sent to requests of this type by using a welcome-file element in WEB-INF/web.xml. The element looks like this, with index.html as the welcome file, followed by its alternative, default.jsp (if index.html does not exist in the web application, which would be admittedly odd, considering that it is configured as a welcome file).

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
</welcome-file-list>

With Servlet 2.4, now you can have a servlet as a welcome file, which is useful for applications that use servlets as "Front Controllers." This is a design pattern representing the web components that grab the request and figure out the best place to which it should be routed among several alternatives. Here's how to configure a servlet as a welcome file.

First, register the servlet in web.xml.

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi=
  "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=
    "http://java.sun.com/xml/ns/j2ee 
      http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">

    <servlet>
        <servlet-name>MyServlet</servlet-name.
        <servlet-class>com.jspservletcookbook.MyServlet</servlet-class>
    </servlet>
    <!-- optionally map the 'MyServlet' servlet to a URL pattern -->
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/myservlet</url-pattern>
    </servlet-mapping>
    <!-- rest of web.xml ... -->

Then create a welcome-file element in web.xml that specifies the registered servlet name.

<welcome-file-list>
    <welcome-file>MyServlet</welcome-file>
    <welcome-file>default.jsp</welcome-file>
</welcome-file-list>

Make sure to use the servlet name in the welcome-file element without a forward slash (/) preceding it. With the prior configuration, the servlet is the primary welcome file; however, default.jsp will be the welcome file, if a servlet of that registered name does not exist in the web application.

2. Mapping Filters to RequestDispatchers

Filters are great servlet API features that can intercept specified requests and initiate logging, security measures, data compression, form-parameter validation, or whatever task you need them to accomplish before the filter sends the request back on its way. Servlet 2.4 now allows filters to intervene with javax.servlet.RequestDispatcher objects that are including the output of a web component or forwarding a request to another web component. This feature is once again configured in WEB-INF/web.xml.

<?xml version="1.0"encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation=
  "http://java.sun.com/xml/ns/j2ee
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"version="2.4">

<filter>
    <filter-name>LogFilter</filter-name>
    <filter-class>com.jspservletcookbook.LogFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>LogFilter</filter-name>
    <url-pattern>/requestheaders</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
</filter-mapping>

The dispatcher elements in the example configuration specify that the LogFilter applies to requests for the servlet path /requestheaders, as well as to any RequestDispatchers that include the output of the servlet path /requestheaders.

Similarly, if you want to initiate a filter when you are using a RequestDispatcher to forward a request to another component, use the FORWARD value with the dispatcher element:

<filter-mapping>
    <filter-name>LogFilter</filter-name>
    <url-pattern>/requestheaders</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

3. Using Listeners with Servlet Requests

Servlet 2.4 provides two interfaces that you can use as application event listeners for HTTP requests: javax.servlet.ServletRequestListener and javax.servlet.ServletRequestAttributeListener. An application event listener is an object that is notified when certain events occur, so you can include objects that initiate tasks when a new request comes into your application. For example, this code counts the number of web application requests by incrementing a static variable inside of a ServletRequestListener.

/* package and import statements */

public class ReqListener implements ServletRequestListener {

    private static long reqCount;
    //no args constructor made explicit here
    public ReqListener(){}

  public void requestInitialized(ServletRequestEvent sre){

      //used for logging purposes
      ServletContext context =sre.getServletContext();
      //Used to get information about a new request
      ServletRequest request =sre.getServletRequest();
      //The static class variable reqCount is incremented in this block;
      synchronized (context){
          context.log(
            "Request for "+
            (request instanceof HttpServletRequest ?
            ((HttpServletRequest)request).getRequestURI():
             "Unknown")+";Count="+ ++reqCount);
      }//synchronized
}

  public void requestDestroyed(ServletRequestEvent sre){
      //Called when the servlet request is going out of scope.
  }//requestDestroyed
}// ReqListener

Each time the web application receives a new request, the listener is notified and its requestInitialized() method is called. This method's parameter is a javax.servlet.ServletRequestEvent type. Calling this object's getServletRequest() method gives the developer access to the new request, a javax.servlet.ServletRequest type (to do whatever they want with the new request).

The listener must have a constructor with no arguments. You have to register the ServletRequestListener in web.xml:

<listener>
    <listener-class>com.jspservletcookbook.ReqListener</listener-class>
</listener>

The web container then creates an instance of the listener when it deploys your web application.

Note: Servlet 2.4 also includes a ServletRequestAttributeListener interface. An object that implements this interface can receive notifications of when object attributes are added to or removed from a ServletRequest. You also have to register these listener types in web.xml.

4. Using EL Code Within Template Text

The Expression Language (EL) is a powerful tool that you can use with JSPs. What's different with JSP 2.0 is that the JSP container is now responsible for the EL, and you can use EL code embedded inside of template text. For example, imagine that you had an object attribute named user stored in a session. The user object has a getName() method that returns the user's name. With a JSP 2.0 container, you can display the user's name in a JSP in the following manner:

<html>
<head><title>The User's Name</title></head>
<body>
<%-- you could also use the syntax ${sessionScope.user.name} --%>
<strong>User name:</strong> ${user.name}
</body>
</html>

Notice that the code did not use the former JSTL-related syntax of:

<c:out value="${user.name}"/>

Related Reading

Java Servlet & JSP Cookbook
By Bruce W. Perry

One caveat is that if your web application is still using the Servlet 2.3 format of web.xml, then the JSP container will automatically deactivate the evaluation of EL expressions in template text, and usages such as in the example will not work as expected. Therefore, in most cases, you should upgrade your application to the Servlet 2.4 format of web.xml.

5. Writing Tag Files

JSP 2.0 has added the tag file feature, which is designed to make it much easier for developers that are not Java specialists to create a custom tag. Tag files can be written in either JSP syntax or XML. Therefore, you can skip the stage of writing the Java source file and compiling it.

The required extensions for a tag file are .tag if you write the file in JSP syntax, and .tagx if the file is only composed of XML elements. The JSP 2.0 specification requires you to place the tag file in the WEB-INF/tags directory, or a subdirectory thereof. If you want to package the tag file in a Java Archive .jar file as part of a custom tag library, then you can store it in META-INF/tags (or a subdirectory of META-INF/tags), and then describe the tag file in a Tag Library Descriptor (TLD), a type of configuration file. You do not have to describe the tag files that are placed beneath WEB-INF/tags in a TLD, but you can, if you want to consolidate a library of traditional custom tags and tag files in one TLD.

The following tag file generates the HTML text for inserting a logo image inside of the page.

<%@ tag body-content="scriptless" description="Writes 
the HTML code for inserting a logo." %>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ attribute name="heading" required="true" rtexprvalue=
  "true" description="The heading level for the logo."%>

<%@ attribute name="image" required="true" rtexprvalue=
  "true" description="The image name for the logo."%>

<%@ attribute name="width" required="true" rtexprvalue=
  "true" description="The image width for the logo."%>

<%@ attribute name="height" required="true" rtexprvalue=
  "true" description="The image height for the logo."%>
 
<img src="${imgDir}${image}" width=
  "${width}" height="${height}" align="left">

<H${heading}>
  <jsp:doBody/></H${heading}>

In the example above, imgDir is a servlet context attribute representing the image directory, so the Expression Language may access the attribute value with the syntax ${imgDir}.

Inside of the JSPs that use the custom tag, you specify the location of the tag file for the JSP container by using the taglib directive's tagDir attribute. In other words, the tagDir attribute provides the path to the web application directory where you stored the tag file. Here's an example:

<%@ taglib prefix="cbck" tagdir="/WEB-INF/tags" %>

As long as you place the tag file, which has a .tag extension (or .tagx extension if the tag file is in XML syntax), in /WEB-INF/tags, then JSPs will be able to use the tag associated with the example tag file. Here is an example of how the tag would be used inside of a JSP:

<cbck:logo heading="1" image="stamp.gif" width="42" height="54">Thanks for
visiting</cbck:logo>

The text returned to the user agent that requests the JSP looks like this:

<img src="/home/images/stamp.gif" width="42" height="54" 
align="left"><H1> Thanks for visiting</H1>

6. Writing EL-Qualified Functions

You can embed your own Java functions within Expression Language (EL) code with JSP 2.0. This allows developers to expand the capabilities of the EL's built-in functions and objects. Java Servlet & JSP Cookbook uses the example of an EL function inside of a JSP that calls an Oracle stored procedure (Recipe 21.8). The JSP 2.0 specification calls them "qualified" functions because the function call is qualified by a particular namespace, the namespace represented by your custom tag library.

First, you write the Java source file and include a public static method. Here's an example:

//...import statements, class declaration, and constructor
public static void addRaceEvent(String name,String location,String date) {
      Connection conn = null;
        
      try{
        
          conn = pool.getConnection();
        
          if (conn == null )
          throw new SQLException(
          "Invalid Connection in addRaceEvent method");
        
      CallableStatement cs = null;
        
      //Create an instance of the CallableStatement
      cs = conn.prepareCall( "{call addEvent (?,?,?)}" );
        
      cs.setString(1,name); 
      cs.setString(2,location); 
      cs.setString(3,date); 
        
      //Call the inherited PreparedStatement.executeUpdate() method
      cs.executeUpdate();
        
      // return the connection to the pool
      conn.close();
       
      } catch (SQLException sqle) { }
       

  }//addRaceEvent  

In JSP 2.0, you then describe the function in a Tag Library Descriptor:

<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi=
  "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=
  "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/
   web-jsptaglibrary_2_0.xsd"
   version="2.0"
>
<!-- other taglib nested elements... -->
    
    <function>

        <name>addRaceEvent</name>

        <function-class>
            com.jspservletcookbook.StoredProcUtil
        </function-class>

        <function-signature>
            void addRaceEvent(java.lang.String,
            java.lang.String,java.lang.String)
        </function-signature>

    </function>

    <tag>
        <!-- define a custom tag here if you have to -->
    </tag>

</taglib>

Use the taglib directive in the JSP to declare the tag library that includes the defined function, then call the function.

<%@ taglib uri="jspservletcookbook.com.tags" prefix="cbck" %>

<html>
<head><title>Calling a Stored procedure</title></head>
<body>
<h2>This JSP calls a stored procedure with a JSP 2.0 function</h2>

${cbck:addRaceEvent("Falmouth Triathlon","Falmouth MA","26-Jul-2003")}

</body>
</html>

This is a pretty good way to use JSPs as the presentation component for an application that is based on stored procedures. In general, creating your own functions is a great way to extend the features of the EL for the benefit of your project.

Bruce W. Perry is an independent software developer and writer, and the author of Java Servlet & JSP Cookbook and just-published Ajax Hacks.


O'Reilly & Associates published Java Servlet & JSP Cookbook in January 2004.


Return to ONJava.com.