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: 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: 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.
Messenger interface
public interface Messenger {
public String getMessage();
}
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.
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.
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.
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: 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: 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.MultipartRequestWrapperclass that functions as aServletRequestwrapper. Designed to handle file upload,MultipartRequestWrapperoverrides thegetParameter(),getParameterNames(), andgetParameterValues()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
PageFlowRequestWrapperclass in theorg.apache.beehive.netui.pageflow.internalpackage functions as aServletRequestwrapper 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.
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.
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.