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
OverviewTop
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 | 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
OverviewTop
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
OverviewTop
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
OverviewTop
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 | 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 | 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 WrappersTop
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 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:
Coding SubPrintWriter
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.
Coding SubHttpServletResponseWrapper
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.
Coding The FiltersTop
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.
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.
Coding The AServlet
ClassTop
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.
Coding The DDTop
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 DeploymentTop
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:
Testing Our ServletTop
Open a command prompt and change the directory to the location of our Tomcat bin directory and then type in startup
(Windows 7) or startup.sh
(Linux/Unix/OSX).
Press Enter and the Tomcat 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.
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 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 server window and I have highlighted the
relevant lines in yellow so you can see them easier and follow the flow.
Java DocumentationTop
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.