9.9. Modifying the Response

OK, so filters can block access to resources or invoke them normally. But what if filters want to change the response that a resource generates? There don’t appear to be any methods that provide access to the response that a resource generates. The second argument to doFilter (the ServletResponse) gives the filter a way to send new output to a client, but it doesn’t give the filter access to the output of the servlet or JSP page. How could it? When the doFilter method is first invoked, the servlet or JSP page hasn’t even executed yet. Once you call the doFilter method of the FilterChain object, it appears to be too late to modify the response—data has already been sent to the client. Hmm, a quandary.

The solution is to change the response object that is passed to the doFilter method of the FilterChain object. You typically create a version that buffers up all the output that the servlet or JSP page generates. The servlet 2.3 API provides a useful resource for this purpose: the HttpServletResponseWrapper class. Use of this class involves five steps:

1.
Create a response wrapper. Extend javax.servlet.http.HttpServletResponseWrapper.

2.
Provide a PrintWriter that buffers output. Override the getWriter method to return a PrintWriter that saves everything sent to it and stores that result in a field that can be accessed later.

3.
Pass that wrapper to doFilter. This call is legal because HttpServletResponseWrapper implements HttpServletResponse.

4.
Extract and modify the output. After the call to the doFilter method of the FilterChain, the output of the original resource is available to you through whatever mechanism you provided in Step 2. You can modify or replace it as appropriate for your application.

5.
Send the modified output to the client. Since the original resource no longer sends output to the client (the output is stored in your response wrapper instead), you have to send the output. So, your filter needs to obtain the PrintWriter or OutputStream from the original response object and pass the modified output to that stream.

A Reusable Response Wrapper

Listing 9.14 presents a wrapper that can be used in most applications where you want filters to modify a resource’s output. The CharArrayWrapper class overrides the getWriter method to return a PrintWriter that accumulates everything in a big char array. This result is available to the developer through the toCharArray (the raw char[]) or toString (a String derived from the char[]) method.

Sections 9.10 and 9.11 give two examples of use of this class.

Listing 9.14. CharArrayWrapper.java
package moreservlets.filters; 

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


/** A response wrapper that takes everything the client 
 *  would normally output and saves it in one big 
 *  character array. 
 */ 

public class CharArrayWrapper 
             extends HttpServletResponseWrapper {
  private CharArrayWriter charWriter; 

  /** Initializes wrapper. 
   *  <P> 
   *  First, this constructor calls the parent 
   *  constructor. That call is crucial so that the response 
   *  is stored and thus setHeader, setStatus, addCookie, 
   *  and so forth work normally. 
   *  <P> 
   *  Second, this constructor creates a CharArrayWriter 
   *  that will be used to accumulate the response. 
   */ 
  public CharArrayWrapper(HttpServletResponse response) {
							super(response);
							charWriter = new CharArrayWriter();
							} 

  /** When servlets or JSP pages ask for the Writer, 
   *  don't give them the real one. Instead, give them 
   *  a version that writes into the character array. 
   *  The filter needs to send the contents of the 
   *  array to the client (perhaps after modifying it). 
   */ 

  public PrintWriter getWriter() {
							return(new PrintWriter(charWriter));
							} 

  /** Get a String representation of the entire buffer. 
   *  <P> 
   *  Be sure <B>not</B> to call this method multiple times 
   *  on the same wrapper. The API for CharArrayWriter 
   *  does not guarantee that it "remembers" the previous 
   *  value, so the call is likely to make a new String 
   *  every time. 
   */ 

  public String toString() {
    return(charWriter.toString()); 
  } 

  /** Get the underlying character array. */ 

  public char[] toCharArray() {
    return(charWriter.toCharArray()); 
  } 
} 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.239.48