Decorating Servlet Request Objects

by Budi Kurniawan

Originally published on BEA Dev2Dev May 2005

Abstract

The Decorator pattern is one of the original design patterns presented in the book "Design Patterns: Elements of Reusable Object-Oriented Software," by Erich Gamma et al. Traditionally, this pattern was popular among Swing programmers who applied it to improve their software. Today, even though many applications are web-based, the Decorator pattern is still applicable and can be used rewardingly in a J2EE setting.

This article shows how to apply the Decorator pattern to servlet request objects. It begins with an introduction to a problem involving servlet filters and explains the Decorator pattern for the uninitiated. It then discusses how to use the pattern in servlets and lists popular servlet-related projects that use it. Finally, this article concludes with a trimming filter that showcases the use of the Decorator pattern in servlets.

Introduction

The introduction of filters in the servlet specification was very exciting as it introduced a powerful intercept model. A filter is a Java object that can intercept the HttpServletRequest object before the request reaches the servlet's service method and the HttpServletResponse object after the control leaves the service method. You can do useful things with filters, such as verifying user input and compressing web content. But the creative use of filters is hindered by the fact that you cannot change the request parameters of an HttpServletRequest object, because the java.util.Map that contains the parameters in an HttpServletRequest object is immutable. This greatly reduces the usefulness of filters. At least half the time, you wish you could change the object you are applying your filter to. Wouldn't it be great if you could, for example, write a filter that trims users' input before the HttpServletRequest object reaches the Struts action servlet? Then you would not need to trim them in your Struts action form's validate methods.

Fortunately, you can use the Decorator design pattern to change the behavior of immutable objects even though you cannot change the objects themselves.

The Decorator Pattern

With inheritance, you can change the behavior of an object by extending the object's class and therefore override the methods whose behaviors you want to modify. However, inheritance is powerless if the object in question is constructed by another subsystem in your application, such as an object factory or a servlet container.

The Decorator pattern can also be used to add functionality to an existing object or to change the behavior of an object. Rather than extending the class using inheritance, this pattern wraps an object in another object. Figure 1 shows the UML class diagram of the Decorator pattern.

Figure 1
Figure 1: The Decorator pattern

In Figure 1, the Component interface defines a component whose implementation is ConcreteComponent. To change the behavior of Component, you can modify ConcreteComponent or extend it. However, if ConcreteComponent comes from a factory, you cannot do this. What you can do is create a decorator that also implements Component. In Figure 1, the decorator is represented by Decorator, which is usually coded as an interface or abstract class. One of the features of the Decorator type is a constructor that accepts a Component object. You pass the object to be decorated to this constructor; in this case, this object is the ConcreteComponent object you obtain from the factory. By assigning the decorated object to a class variable in Decorator, you have access to it from any method in Decorator. This will then enable you to add behavior to the object.

The Decorator type in Figure 1 does not have to be an interface or an abstract class. If your application is not very complex, you can write the implementation as a concrete Decorator class.

As an example, consider a simple messaging application that centers on the Messenger interface and its implementation MessengerImpl. Let's assume that MessengerImpl objects come from a factory, so you cannot modify their behavior. If you need to add or change the functionality of Messenger objects, you can create a MessengerDecorator class. Figure 2 shows the class diagram for this example.

Figure 2
Figure 2: The Messenger Decorator

Let's look at the implementation of this application. The Messenger interface is given in Listing 1 and MessengerImpl is given in Listing 2.

Listing 1: The Messenger interface
public interface Messenger {

  public String getMessage();

}

Listing 2: The MessengerImpl class
public class MessengerImpl implements Messenger {

  private String message;

  public MessengerImpl(String message) {

    this.message = message;

  }

  public String getMessage() {

    return message;

  }

}

Messenger objects are created by a factory called MessengerFactory, presented in Listing 3.

Listing 3: The MessengerFactory class
public class MessengerFactory {

  public static Messenger getMessenger() {

    return new MessengerImpl("secrets");

  }

}

This factory sets the initial state, that is, the String returned by getMessage(), of every Messenger object it creates based on some unknown formula. In other words, you cannot create the Messenger object yourself.

In your application, the purpose of having a Messenger object is to pass it to the broadcast() static method of a utility class called Util. Listing 4 presents the Util class.

Listing 4: The Util class
public class Util {

  public static void broadcast(Messenger messenger) {

    System.out.print(messenger.getMessage());

  }



  // other methods here

}

In your own class, you may have the following code:

Messenger messenger = MessengerFactory.getMessenger();

Util.broadcast(messenger);

Suppose, you want to modify slightly the message printed by the broadcast() method. You want it to be printed in upper case letters. What can you do? Technically, you could subclass Messenger, instantiate the subclass, and feed the returned object to Util.broadcast(). However, that would be pointless because only the factory object knows how to initialize a Messenger object so that its getMessage() method returns the correct value.

Using the Decorator pattern, you can create a MessengerDecorator class, given in Listing 5.

Listing 5: The MessengerDecorator class
public class MessengerDecorator implements Messenger {

  private Messenger messenger;

  public MessengerDecorator(Messenger messenger) {

    this.messenger = messenger;

  }

  public String getMessage() {

    return messenger.getMessage().toUpperCase();

  }

}

Because MessengerDecorator implements Messenger, Util.broadcast() will accept an instance of MessengerDecorator. However, MessengerDecorator is not just an implementation; it is a decorator of a MessengerImpl object. For this, there must be a constructor in MessengerDecorator that accepts the Messenger object to be decorated.

As Listing 5 shows, this constructor assigns the argument to a variable. You can now override the getMessage() method in MessengerDecorator so that it prints the message in upper case letters. Because you have the reference to the original Messenger object, you can write your getMessage() method like this:

public String getMessage() {

  return this.messenger.getMessage().toUpperCase();

}

The getMessage() method in MessengerDecorator returns the upper case version of the original message.

In your class, you can get a Messenger object as usual and pass the Decorator to Util.broadcast.

Messenger messenger = factory.getMessenger();

Util.broadcast(new MessengerDecorator(messenger));

Instead of passing the original object to the intended destination, you pass to it a decorator of the object.

Applying the Decorator Pattern to Servlets

The example with the Messenger class above parallels the ServletRequest objects constructed by servlet containers. Upon receiving an HTTP request, a servlet container creates ServletRequest and ServletResponse objects (an instance of ServletRequestImpl and an instance of ServletResponseImpl, respectively) and passes the two objects to the specified servlet's service method. Now if you can create a decorator for ServletRequest and pass it to the servlet's service method , you will have implemented the Decorator pattern.

It is really easy to implement this pattern with ServletRequest, because the servlet API provides a wrapper class for ServletRequest: ServletRequestWrapper. Figure 3 represents the UML class diagram of a servlet decorator.

Figure 3
Figure 3: The Decorator pattern in the Servlet API

The HTTP version of the class diagram in Figure 3 is shown in Figure 4. Don't get confused by the extra classes. Just focus on the three types ( HttpServletRequest, HttpServletRequestImpl, HttpServletRequestWrapper) in the box.

Figure 4
Figure 4: The Decorator pattern for the Servlet API (HTTP)

This is a similar situation. You have an implementation of ServletRequest, but it is created by the servlet container. You can decorate these ServletRequest objects using the supplied ServletRequestWrapper.

This pattern is easy and applicable in real-world applications. In fact, it has been applied to a number of high-profile applications, including the following.

  • Struts - Struts is currently the most popular framework for developing Java web applications based on the Model-View-Controllers pattern. Struts provides the org.apache.struts.upload.MultipartRequestWrapper class that functions as a ServletRequest wrapper. Designed to handle file upload, MultipartRequestWrapper overrides the getParameter(), getParameterNames(), and getParameterValues() methods.
  • Apache Beehive - This open source project, originally part of BEA's WebLogic Workshop, runs on top of Struts and eases the development of web applications and web services. The PageFlowRequestWrapper class in the org.apache.beehive.netui.pageflow.internal package functions as a ServletRequest wrapper that helps in the page flow processing of any Apache Beehive applications.

Let's now study how you can write your own HttpServletRequest decorator.

A Trimming Filter

This section puts the theory into practice by showing an example trimmer servlet filter that illustrates the use of the javax.servlet.http.HttpServletRequestWrapper class as a decorator template for HttpServletRequest objects. In this example, the trimmer filter will trim superfluous whitespace from incoming parameters.

This can be useful in many servlet/JSP applications, including Struts and JavaServer Faces applications. For example, Struts populates an action form by calling the getParameterValues() method on the HttpServletRequest object. By overriding this method in a decorator class, you change the behavior of the current HttpServletRequest object.

To create a decorator for HttpServletRequest, you need to extend HttpServletRequestWrapper and override the methods you want to change. Listing 5 presents the MyRequestWrapper class that trims the return value of the getParameterValues() method.

Listing 5: A HttpServletRequest decorator
package trimmer.filter;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletRequestWrapper;



public final class MyRequestWrapper extends

  HttpServletRequestWrapper {

  public MyRequestWrapper(HttpServletRequest servletRequest) {

    super(servletRequest);

  }



  public String[] getParameterValues(String parameter) {

    String[] results = super.getParameterValues(parameter);

    if (results==null)

      return null;

    int count = results.length;



    String[] trimResults = new String[count];

    for (int i=0; i<count; i++) {

      trimResults[i] = results[i].trim();

    }

    return trimResults;

  }

}

The trimmer filter that intercepts HTTP requests and decorates the HttpServletRequest objects is presented in Listing 6.

Listing 6: The trimming filter
package trimmer.filter;

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;



public class MyFilter implements Filter {

  private FilterConfig filterConfig;



  public void init(FilterConfig filterConfig) throws

    ServletException {

    System.out.println("Filter initialized");

    this.filterConfig = filterConfig;

  }



  public void destroy() {

    System.out.println("Filter destroyed");

    this.filterConfig = null;

  }



  public void doFilter(ServletRequest request, ServletResponse response,

    FilterChain chain)

    throws IOException, ServletException {

    chain.doFilter( new MyRequestWrapper((HttpServletRequest) request), response);

  }

}

The trimmer application uses the trimmer filter in Listing 6 to trim user input. To apply the filter you need the following filter and filter-mapping elements in the web.xml file:

  <filter>

    <filter-name>TrimmerFilter</filter-name>

    <filter-class>trimmer.filter.MyFilter</filter-class>

  </filter>

  <filter-mapping>

    <filter-name>TrimmerFilter</filter-name>

    <url-pattern>*.do</url-pattern>

  </filter-mapping>

To test the filter, invoke the trimmer application and type some values into the form, submit the form, and see how the filter trims the input values. This is a practical, and useful, application of the Decorator pattern.

Summary

Servlet filters can be used to pre-process and post-process HTTP requests after the invocation of a servlet's service method. This is very promising but the potential uses for filters are limited because you cannot change HttpServletRequest objects.

The Decorator pattern can help. This article demonstrated how to apply the Decorator pattern to "modify" HttpServletRequest objects, thereby making your servlet filters much more useful. In the example trimmer filter, the filter changes user input in the request parameters, something you would not be able to do without decorating the request objects.


Budi Kurniawan is a consultant at Brainy Software Corp. He has architected and developed large scale applications for organizations around the world, and has written several programming books, including Struts 2 Design and Programming: A Tutorial, How Tomcat Works, Java 6 New Features, and Java for the Web with Servlets, JSP, and EJB.