WrappersS2C Home « Wrappers

At the end of the Using Filters lesson we saw how our response was committed using the writer.close(); statement and that by the time we got back to our custom filters and tried to add to the response it was too late. A scenario might also arise where we need to modify the request from a user, such as changing some header information using a filter, but we would still pick up the original request when our servlets run. Remember that our filters are generic and we may have several servlets using the filtered requests and responses unknowningly, so we certainly can't put code in each servlet to cater for our filters.

It seems the only alternative would be to create our own implemetation of the ServletRequest or ServletResponse interface, so we can pass a custom request or response from our filters to our servlets. In the vast majority of cases where we are using the HTTP protocol we would also have to create a custom implementation of the HttpServletRequest or HttpServletResponse interface as well. That's a lot of methods to implement from these interfaces when we may only want to modify a few of them for our custom request or response!

Luckily for us having to create custom requests and responses is such a common occurrence that the Servlet API provides custom implementations of the above interfaces that can be subclassed by developers wishing to modify the request or response object. The custom implementations are ServletRequestWrapper, ServletResponseWrapper, HttpServletRequestWrapper and HttpServletResponseWrapper and the tables below give more detail of each of these implementations.

All these classes implement the Decorator (Wrapper) design pattern which decorates (wraps) an object with an embellished implementation which adds functionality while still doing everything the decorated (wrapped) class did.

ServletRequestWrapper Overviewgo to top of page Top

This type provides a convenient implementation of the ServletRequest interface which can be subclassed to provide a custom request to a servlet. The methods in this implementation default to calling through to the wrapped request object.

The table below shows the declarations of some of the more common methods in the ServletRequestWrapper interface, split into their respective functional groups:

Method Declaration Description
Request Dispatching
RequestDispatcher getRequestDispatcher
  (java.lang.String path)
Default behavior is to return getRequestDispatcher(String path) on wrapped request object.
Request Parameters
java.lang.String getParameter(java.lang.String name)Default behavior is to return getParameter(String name) on wrapped request object.
java.util.Map getParameterMap()Default behavior is to return getParameterMap() on wrapped request object.
java.util.Enumeration getParameterNames()Default behavior is to return getParameterNames() on wrapped request object.
java.lang.String[] getParameterValues
  (java.lang.String name)
Default behavior is to return getParameterValues(String name) on wrapped request object.
Request Scoped Attributes
java.lang.Object getAttribute(java.lang.String name)Default behavior is to call getAttribute(String name) on wrapped request object.
java.util.Enumeration getAttributeNames()Default behavior is to return getAttributeNames() on wrapped request object.
void removeAttribute(java.lang.String name)Default behavior is to call removeAttribute(String name) on wrapped request object.
void setAttribute
  (java.lang.String name, java.lang.Object value)
Default behavior is to return setAttribute(String name, Object value) on wrapped request object.

For more information on these and the other methods in the ServletRequestWrapper interface follow the link to the official site at the end of the lesson.

ServletResponseWrapper Overviewgo to top of page Top

This type provides a convenient implementation of the ServletResponse interface which can be subclassed to provide a custom response from a servlet. The methods in this implementation default to calling through to the wrapped response object.

The table below shows the declarations of all the methods in the ServletResponseWrapper interface, split into their respective functional groups:

Method Declaration Description
Response Protocol & Transmission Data
java.lang.String getCharacterEncoding()Default behavior is to return getCharacterEncoding() on wrapped response object.
java.lang.String getContentType()Default behavior is to return getContentType() on wrapped response object.
java.util.Locale getLocale()Default behavior is to return getLocale() on wrapped response object.
void setCharacterEncoding(java.lang.String charset)Default behavior is to call setCharacterEncoding(String charset) on wrapped response object.
void setContentType(java.lang.String type)Default behavior is to call setContentType(String type) on wrapped response object.
void setLocale(java.util.Locale locale)Default behavior is to call setLocale(Locale locale) on wrapped response object.
void setContentLength(int length)Default behavior is to call setContentLength(int len) on wrapped response object.
Response Streams
void flushBuffer()Default behavior is to call flushBuffer() on wrapped response object.
int getBufferSize()Default behavior is to return getBufferSize() on wrapped response object.
ServletOutputStream getOutputStream()Default behavior is to return getOutputStream() on wrapped response object.
java.io.PrintWriter getWriter()Default behavior is to return getWriter() on wrapped response object.
boolean isCommitted()Default behavior is to return isCommitted() on wrapped response object.
void reset()Default behavior is to call reset() on wrapped response object.
void resetBuffer()Default behavior is to call resetBuffer() on wrapped response object.
void setBufferSize(int size)Default behavior is to call setBufferSize(int size) on wrapped response object.

For more information on the methods in the ServletResponseWrapper interface follow the link to the official site at the end of the lesson.

HttpServletRequestWrapper Overviewgo to top of page Top

This type provides a convenient implementation of the HttpServletRequestWrapper interface which can be subclassed to provide a custom request to a servlet. The methods in this implementation default to calling through to the wrapped request object.

The table below shows the declarations of some of the more common methods in the HttpServletRequestWrapper interface, split into their respective functional groups:

Method Declaration Description
Request Headers
java.lang.String getHeader(java.lang.String name)Default behavior is to return getHeader(String name) on wrapped request object.
java.util.Enumeration getHeaderNames()Default behavior is to return getHeaderNames() on wrapped request object.
java.util.Enumeration getHeaders
  (java.lang.String name)
Default behavior is to return getHeaders(String name) on wrapped request object.
Request Protocol Data
java.lang.String getMethod()Default behavior is to return getMethod() on wrapped request object.
Request Path
java.lang.String getQueryString()Default behavior is to return getQueryString() on wrapped request object.
java.lang.String getRequestURI()Default behavior is to return getRequestURI() on wrapped request object.
Security Related
Cookie[] getCookies()Default behavior is to return getCookies() on wrapped request object.
Session Management
HttpSession getSession()Default behavior is to return getSession() on wrapped request object.
HttpSession getSession(boolean create)Default behavior is to return getSession(boolean create) on wrapped request object.

For more information on these and the other methods in the HttpServletRequestWrapper interface follow the link to the official site at the end of the lesson.

HttpServletResponseWrapper Overviewgo to top of page Top

This type provides a convenient implementation of the HttpServletResponse interface which can be subclassed to provide a custom response from a servlet. The methods in this implementation default to calling through to the wrapped response object.

The table below shows the declarations of all the methods in the HttpServletResponseWrapper interface whose superclass methods are not deprecated, split into their respective functional groups:

Method Declaration Description
Cookies
void addCookie(Cookie cookie)Default behavior is to call addCookie(Cookie cookie) on wrapped response object.
HTTP Status Codes and Redirection
void sendError(int sc)Default behavior is to call sendError(int sc) on wrapped response object.
void sendError(int sc, java.lang.String msg)Default behavior is to call sendError(int sc, String msg) on wrapped response object.
void sendRedirect(java.lang.String location) Default behavior is to return sendRedirect(String location) on wrapped response object.
void setStatus(int sc)Default behavior is to call setStatus(int sc) on wrapped response object.
Response Headers
void addDateHeader(java.lang.String name, long date)Default behavior is to call addDateHeader(String name, long date) on wrapped response object.
void addHeader
  (java.lang.String name, java.lang.String value)
Default behavior is to return addHeader(String name, String value) on wrapped response object.
void addIntHeader(java.lang.String name, int value)Default behavior is to call addIntHeader(String name, int value) on wrapped response object.
boolean containsHeader(java.lang.String name)Default behavior is to call containsHeader(String name) on wrapped response object.
void setDateHeader(java.lang.String name, long date)Default behavior is to call setDateHeader(String name, long date) on wrapped response object.
void setHeader
  (java.lang.String name, java.lang.String value)
Default behavior is to return setHeader(String name, String value) on wrapped response object.
void setIntHeader(java.lang.String name, int value)Default behavior is to return setIntHeader(String name, int value) on wrapped response object.
URL Rewriting
java.lang.String
  encodeRedirectURL(java.lang.String url)
Default behavior is to return encodeRedirectURL(String url) on wrapped response object.
java.lang.String encodeURL(java.lang.String url)Default behavior is to call encodeURL(String url) on wrapped response object.

For more information on the methods in the HttpServletResponseWrapper interface follow the link to the official site at the end of the lesson.

Example Of Using Wrappersgo to top of page Top

We will use similar filters and the same servlet class from the Using Filters lesson for our wrappers example and add two new classes for our response so that all our HTML gets rendered, regardless of a serlvet closing the PrintWriter. In all programs we will also write some lines to the Tomcat 6 log so you can see each filter, the wrapper, the writer and servlet getting invoked.

Within the _ServletsAdv folder create a new folder for this lesson called wrappers

Within the wrappers folder we will create separate folders to hold our DD, source files and our compiled byte code and these will be called dd, src and classes.

Within the src folder create a subfolders called controller.

So after creating these folders your directory structure should look something like the following screenshot:

wrappers directory structure

Coding SubPrintWritergo to top of page Top

The SubPrintWriter class extends the PrintWriter class so we can override the close method.

Cut and paste the following code into your text editor and save in the   c:\_ServletsAdv\wrappers\src\controller directory as SubPrintWriter.java.


package controller;

import java.io.PrintWriter;
import java.io.Writer;

public class SubPrintWriter extends PrintWriter { 

    // Call super constructor
    public SubPrintWriter(Writer writer) {
        super(writer);
        System.out.println("Called super in SubPrintWriter");
    }

    public void close() { 
        // Just write to console
        System.out.println("Override in SubPrintWriter close() method");
    }
}

Compiling SubPrintWriter

Open your command line editor:

Change to directory  c:\_ServletsAdv\wrappers\src\controller

Compile SubPrintWriter.java using the java compiler with the -cp and -d options as below, making sure you change apache-tomcat-6.0.37 to wherever you downloaded Tomcat to.

javac -cp c:\apache-tomcat-6.0.37\lib\servlet-api.jar -d ..\..\classes SubPrintWriter.java

The following screenshot shows that we get a clean compile and also the SubPrintWriter class now compiled into the classes\controller directory.

compile SubPrintWriter class

Coding SubHttpServletResponseWrappergo to top of page Top

The SubHttpServletResponseWrapper class extends the HttpServletResponseWrapper class so we can wrap the response we pass to the filter and also wrap the PrintWriter we will create within the AServlet class with our SubPrintWriter class which we hold within the wrapper as an instance variable. This ensures that after we have customized the response in the ImplFilter1 classes doFilter method that any calls to PrintWriter are wrappered by the SubPrintWriter class.

Cut and paste the following code into your text editor and save in the   c:\_ServletsAdv\wrappers\src\controller directory as SubHttpServletResponseWrapper.java.


package controller;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.*;

public class SubHttpServletResponseWrapper extends HttpServletResponseWrapper {
    private SubPrintWriter writer; 

    // Call super constructor
    public SubHttpServletResponseWrapper(HttpServletResponse resp) {
        super(resp);
        System.out.println("Called super in SubHttpServletResponseWrapper"); 
        // Wrapping the PrintWriter class
        try {
            System.out.println("Creating wrapped SubPrintWriter instance");
            writer = new SubPrintWriter(resp.getWriter());
        } catch (IOException ex) {    
            System.out.println("Exception creating wrapped SubPrintWriter instance:" + ex);
        }    
    } 

    // Get PrintWriter from response
    public PrintWriter getWriter() throws IOException{
        System.out.println("Returning PrintWriter");
        return writer;
    }
}

Compiling SubHttpServletResponseWrapper

Open your command line editor:

Change to directory  c:\_ServletsAdv\wrappers\src\controller

Compile SubHttpServletResponseWrapper.java using the java compiler with the -cp and -d options as below, making sure you change apache-tomcat-6.0.37 to wherever you downloaded Tomcat to.

javac -cp c:\apache-tomcat-6.0.37\lib\servlet-api.jar;..\..\classes -d ..\..\classes SubHttpServletResponseWrapper.java

The following screenshot shows that we get a clean compile and also the SubHttpServletResponseWrapper class now compiled into the classes\controller directory.

compile SubHttpServletResponseWrapper class

Coding The Filtersgo to top of page Top

We are now ready to code our filters which will consist of implementations of the Filter interface.

Coding ImplFilter1

The ImplFilter1 class implements the int(), doFilter() and destroy() methods of the Filter interface. We output some messages to the console so you can see the lifecycle and invocation flow through the filter and how we get initialisation parameters from the DD using the FilterConfig object. The difference in the class from the last lesson is that we are wrapping the response before sending it to the next filter/resource in the chain via the doFilter() method.

Cut and paste the following code into your text editor and save in the   c:\_ServletsAdv\wrappers\src\controller directory as ImplFilter1.java.


package controller;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;
import javax.servlet.http.*;

public class ImplFilter1 implements Filter {
    private FilterConfig fc;

    @Override
    public void init(FilterConfig fc) throws ServletException { 
        // Write to console
        System.out.println("Within init() method of Filter1"); 
        // Save FilterConfig 
        this.fc = fc;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, 
             FilterChain chain) throws ServletException, IOException { 
        // Write to console
        System.out.println("Within doFilter() method of Filter1"); 
        // Get init parameter and write to console
        String initParam = fc.getInitParameter("f1param");
        System.out.println("Filter1 init param: f1param, value: " + initParam); 
        // Cast and wrap response before chaining to next resource
        HttpServletResponse httpResp = (HttpServletResponse)resp;
        SubHttpServletResponseWrapper wrappedHttpResp = new SubHttpServletResponseWrapper(httpResp); 
        // Invoke next filter or resource (Filter2)
        System.out.println("Leaving Filter1 with custom response");
        chain.doFilter(req, wrappedHttpResp); 
        System.out.println("Back in Filter1"); 
        // Create response
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        writer.print("<html><head></head><body><p>Filter1 Response</p></body></html>");
        writer.close();
    }

    @Override
    public void destroy() { 
        // Write to console
        System.out.println("Within the destroy() method of Filter1");
    }
}

Compiling ImplFilter1

Open your command line editor:

Change to directory  c:\_ServletsAdv\wrappers\src\controller

Compile ImplFilter1.java using the java compiler with the -cp and -d options as below, making sure you change apache-tomcat-6.0.37 to wherever you downloaded Tomcat to.

javac -cp c:\apache-tomcat-6.0.37\lib\servlet-api.jar;..\..\classes -d ..\..\classes ImplFilter1.java

The following screenshot shows that we get a clean compile and also the ImplFilter1 class now compiled into the classes\controller directory.

compile ImplFilter1 class
Coding ImplFilter2

The ImplFilter2 class implements the int(), doFilter() and destroy() methods of the Filter interface. We output some messages to the console so you can see the lifecycle and invocation flow through the filter.

Cut and paste the following code into your text editor and save in the   c:\_ServletsAdv\wrappers\src\controller directory as ImplFilter2.java.


package controller;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;

public class ImplFilter2 implements Filter {
    private FilterConfig fc;

    @Override
    public void init(FilterConfig fc) throws ServletException { 
        // Write to console
        System.out.println("Within init() method of Filter2"); 
        // Save FilterConfig 
        this.fc = fc;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, 
             FilterChain chain) throws ServletException, IOException { 
        // Write to console
        System.out.println("Within doFilter() method of Filter2"); 
        // Invoke next filter or resource (AServlet)
        System.out.println("Leaving Filter2");
        chain.doFilter(req, resp); 
         // response code 
        System.out.println("Back in Filter2"); 
        // Create response
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        writer.print("<html><head></head><body><p>Filter2 Response</p></body></html>");
    }

    @Override
    public void destroy() { 
        // Write to console
        System.out.println("Within the destroy() method of Filter2");
    }
}

Compiling ImplFilter2

Open your command line editor:

Change to directory  c:\_ServletsAdv\wrappers\src\controller

Compile ImplFilter2.java using the java compiler with the -cp and -d options as below, making sure you change apache-tomcat-6.0.37 to wherever you downloaded Tomcat to.

javac -cp c:\apache-tomcat-6.0.37\lib\servlet-api.jar -d ..\..\classes ImplFilter2.java

The following screenshot shows that we get a clean compile and also the ImplFilter2 class now compiled into the classes\controller directory.

compile ImplFilter2 class

Coding The AServlet Classgo to top of page Top

This simple servlet just creates a paragraph for HTML output and writes to the Tomat 6 logs.

Cut and paste the following code into your text editor and save it in the   c:\_ServletsAdv\wrappers\src\controller directory as AServlet.java.


package controller;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;
import javax.servlet.http.*;

public class AServlet extends HttpServlet {

    private static final long serialVersionUID = 871964L;

    public void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        // Write to console
        System.out.println("Within doGet() method of AServlet"); 
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        writer.print("<html><head></head><body><p>AServlet Response</p></body></html>");
        writer.flush(); 
        // Next statement goes to override
        writer.close();
    }
}

Compiling The AServlet Class

Open your command line editor:

Change to directory  c:\_ServletsAdv\wrappers\src\controller

Compile AServlet.java using the java compiler with the -cp and -d options as below, making sure you change apache-tomcat-6.0.37 to wherever you downloaded Tomcat to.

  javac -cp c:\apache-tomcat-6.0.37\lib\servlet-api.jar -d ..\..\classes AServlet.java

The following screenshot shows that we get a clean compile and also the AServlet class now compiled into the classes\controller directory.

compile AServlet class

Coding The DDgo to top of page Top

There are no DD entries for this application that we haven't seen before.


<?xml version="1.0" encoding="UTF-8"?>
<web-app xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
   <filter>
      <filter-name>FirstFilter</filter-name>
      <filter-class>controller.ImplFilter1</filter-class>
      <init-param>
         <param-name>f1param</param-name>
         <param-value>f1paramvalue</param-value>
      </init-param>
   </filter>
   <filter>
      <filter-name>SecondFilter</filter-name>
      <filter-class>controller.ImplFilter2</filter-class>
   </filter>
   <filter-mapping>
      <filter-name>FirstFilter</filter-name>
      <url-pattern>/example</url-pattern>
   </filter-mapping>
   <filter-mapping>
      <filter-name>SecondFilter</filter-name>
      <url-pattern>/example</url-pattern>
   </filter-mapping>
   <servlet>
      <servlet-name>UsingFilters</servlet-name>
      <servlet-class>controller.AServlet</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>UsingFilters</servlet-name>
      <url-pattern>/example</url-pattern>
   </servlet-mapping>
</web-app>

Save the web.xml file in the DD folder.

Tomcat Deploymentgo to top of page Top

Go to your Tomcat installation which in my case is:

C:\apache-tomcat-6.0.37\webapps\

Within the webapps folder create a folder for our web application called wrappers

Within the wrappers folder create the WEB-INF folder.

Copy the web.xml file and the classes directory and contents from our development environment into the WEB-INF folder.

After creating these folders and copying the files from development your Tomcat directory structure within the webapps\wrappers folder should look something like the following screenshot:

Tomcat directory structure
Testing Our Servletgo to top of page Top

Open a command prompt and change the directory to the location of our Tomcat 6 bin directory and then type in startup (Windows 7) or startup.sh (Linux/Unix/OSX). Press Enter and the Tomcat 6 server should open up in a new window.

You can also start up Tomcat by double-clicking the startup batch file within your Tomcat /bin folder.

With Tomcat up and running type the following into your web browser address bar and press enter:

  http://localhost:8080/wrappers/example

The following screenshot shows the results of typing the above into your web browser address bar and pressing enter.

Run AServlet

As you can see, unlike the example in the Using Filters lesson, the two paragraphs of HTML from the ImplFilter1 and ImplFilter2 classes now get rendered on the screen. The writer.out statement in the AServlet class is now wrapped to do nothing in our custom response and hence these two lines get printed.

We should also see some new entries in the Tomcat 6 logs (at the bottom) and the following screenshot shows the System.out.println messages we sent to the console from the ImplFilter1, ImplFilter2, SubHttpServletResponseWrapper, SubPrintWriter and AServlet classes. These appear in the Tomcat 6 server window and I have highlighted the relevant lines in yellow so you can see them easier and follow the flow.

Run AServlet 2

Java Documentationgo to top of page Top

The following link will take you to the online version of documentation for the Servlet API Documentation . Take a look at the documentation for the interfaces we have discussed, which you can find by scrolling down the lower left pane and clicking on a package and then the interface.

Lesson 5 Complete

In this lesson we looked at wrapping our requests and responses.

What's Next?

In the next lesson we learn how to secure our web applications.

go to home page Homepage go to top of page Top