Skip Headers

Oracle9iAS Containers for J2EE Servlet Developerís Guide
Release 2 (9.0.2)

Part Number A95878-01
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

4
Servlet Filters

This chapter describes servlet filters, which can be a useful part of Web-tier applications. Filters are new in the Servlet 2.3 specification, although many earlier Web servers have supported similar constructs.

This chapter covers the following topics:

Overview of Servlet Filters

When the servlet container calls a method in a servlet on behalf of the client, the HTTP request that the client sent is, by default, passed directly to the servlet. The response that the servlet generates is, by default, passed directly back to the client, with its content unmodified by the container. So, normally, the servlet must process the request and generate as much of the response as the application requires.

But there are many cases where some preprocessing of the request for servlets would be useful. In addition, it is sometimes useful to modify the response from a class of servlets. One example is encryption. A servlet, or a group of servlets in an application, might generate response data that is sensitive and should not go out over the network in clear-text form, especially when the connection has been made using a non-secure protocol such as HTTP. A filter can encrypt the responses. Of course, in this case the client must be able to decrypt the responses.

A common case for a filter is where you want to apply pre-processing or post-processing to requests and responses for a group of servlets, not just a single servlet. If you need to modify the request or response for just one servlet, there is no need to create a filter--just do what is required directly in the servlet itself.

Note that filters are not servlets. They do not implement and override HttpServlet methods such as doGet() or doPost(). Rather, a filter implements the methods of the javax.servlet.Filter interface. The methods are:

How the Servlet Container Invokes Filters

Figure 4-1 shows how the servlet container invokes filters. On the left is a scenario where no filters are configured for the servlet being called. On the right, several filters (1, 2, ..., N) have been configured in a chain to be invoked by the container before the servlet is called. Specify in the web.xml file which servlets or JSP pages cause the container to invoke the filters.

Figure 4-1 Servlet Invocation with and without Filters

Text description of invfilt.gif follows.

Text description of the illustration invfilt.gif

The order in which filters are invoked depends on the order in which they are configured in the web.xml file. The first filter web.xml is the first one invoked during the request, and the last filter in web.xml is the first one invoked during the response (note the reverse order during the response).

Filter Examples

This section lists and describes three servlet filter examples.

Filter Example #1

This section provides a simple filter example. Any filter must implement the three methods in the javax.servlet.Filter interface or must extend a class that implements them. So the first step is to write a class that implements these methods. This class, which we will call GenericFilter, can be extended by other filters.

Generic Filter

Here is the generic filter code. Assume this generic filter is part of the com.acme.filter package, so you should set up a corresponding directory structure somewhere.

The numbers in comments at the right of the code match numbers in the "Code Notes" below.

package com.acme.filter;                                                   //1.
import javax.servlet.*;

public
class GenericFilter implements javax.servlet.Filter {
  public FilterConfig filterConfig;                                        //2. 

  public void doFilter(final ServletRequest request,                       //3.
                       final ServletResponse response,
                       FilterChain chain)
      throws java.io.IOException, javax.servlet.ServletException { 
    chain.doFilter(request,response);                                      //4. 
  } 

  public void init(final FilterConfig filterConfig) {              //5.
    this.filterConfig = filterConfig;
  } 

  public void destroy() {                                                  //6.
  }
}

Save this code in a file called GenericFilter.java in the package directory.

Code Notes

  1. The filter examples in this chapter are kept in this package.

  2. This declares a variable to save the filter configuration object.

  3. The doFilter() method contains the code that implements the filter.

  4. In the generic case, just call the filter chain.

  5. The init() method saves the filter configuration in a variable.

  6. The destroy() method can be overridden to accomplish any required finalization.

Filter Code: HelloWorldFilter.java

This filter overrides the doFilter() method of the GenericFilter class above. It prints a message on the console when it is called on entrance, next adds a new attribute to the servlet request, then calls the filter chain. In this example there is no other filter in the chain, so the container passes the request directly to the servlet. Enter the following code in a file called HelloWorldFilter.java:

package com.acme.filter;

import javax.servlet.*;

public class HelloWorldFilter extends GenericFilter {
  private FilterConfig filterConfig; 

  public void doFilter(final ServletRequest request,
                       final ServletResponse response,
                       FilterChain chain)
       throws java.io.IOException, javax.servlet.ServletException  { 
    System.out.println("Entering Filter");
    request.setAttribute("hello","Hello World!");
    chain.doFilter(request,response);
    System.out.println("Exiting HelloWorldFilter"); 
  } 
} 

JSP Code: filter.jsp

To keep the example simple, the "servlet" to process the filter output is written as a JSP page. Here it is:

<HTML> 
<HEAD> 
<TITLE>Filter Example 1</TITLE> 
</HEAD>
<BODY> 
<HR>
<P><%=request.getAttribute("hello")%></P>
<P>Check your console output!</P>
<HR> 
</BODY> 
</HTML> 

The JSP page gets the new request attribute, hello, that the filter added, and prints its value on the console. Put the filter.jsp page in the document root of the application--in this case, in j2ee/home/default-web-app--and make sure your console window is visible when you invoke filter.jsp from your browser.

Setting Up Example #1

To test the filter examples in this chapter, we will use the OC4J default application. Configure the filter in the web.xml file of the default application by editing j2ee/home/default-web-app/WEB-INF/web.xml. Add the following lines to this file, in the <web-app> element:

  <!-- Filter Example #1 -->
  <filter> 
    <filter-name>helloWorld</filter-name>
    <filter-class>com.acme.filter.HelloWorldFilter</filter-class> 
  </filter> 
  <filter-mapping> 
    <filter-name>helloWorld</filter-name>
    <url-pattern>/filter.jsp</url-pattern> 
  </filter-mapping> 
  <!-- end Filter Example #1 -->

The <filter> element defines the name of the filter and the Java class that implements the filter. The <filter-mapping> element defines the URL pattern that specifies to which targets the <filter-name> should apply. In this simple example, the filter applies to only one target: the JSP code in filter.jsp.

Running Example #1

Invoke filter.jsp from your Web browser as follows, and watch the output on your console:

http://<hostname><:TTCport>/j2ee/filter.jsp

The console output should look something like this:

<hostname>% Entering Filter
Exiting HelloWorldFilter

The output to the Web browser is something like what is shown in Figure 4-2.

Figure 4-2 Example #1 Output

Text description of filters0.gif follows.

Text description of the illustration filters0.gif

Filter Example #2

You can configure a filter with initialization parameters in the web.xml file. This section provides a filter example that uses the following web.xml entry, which demonstrates a parameterized filter:

  <!-- Filter Example #2 -->
  <filter> 
    <filter-name>message</filter-name>
    <filter-class>com.acme.filter.MessageFilter</filter-class>
    <init-param> 
      <param-name>message</param-name>
      <param-value>A message for you!</param-value> 
    </init-param> 
  </filter> 
  <filter-mapping> 
    <filter-name>message</filter-name>
    <url-pattern>/filter2.jsp</url-pattern> 
  </filter-mapping> 
  <!-- end Filter Example #2 -->

Here, the filter named message has been configured with an initialization parameter, also called message. The value of the message parameter is "A message for you!"

Filter Code: MessageFilter.java

The code to implement the message filter example is shown below. Note that it uses the GenericFilter class from "Filter Example #1".

package com.acme.filter;
import javax.servlet.*;

public class MessageFilter extends GenericFilter { 
  public void doFilter(final ServletRequest request,
                       final ServletResponse response,
                       FilterChain chain)
       throws java.io.IOException, javax.servlet.ServletException { 
    System.out.println("Entering MessageFilter");
    String message = filterConfig.getInitParameter("message");
    request.setAttribute("message",message);
    chain.doFilter(request,response);
    System.out.println("Exiting MessageFilter"); 
  } 
} 

This filter uses the filterConfig object that was saved in the generic filter. The filterConfig.getInitParameter() method returns the value of the initialization parameter.

JSP Code: filter2.jsp

As in the first example, this example uses a JSP page to implement the "servlet" that tests the filter. The filter named in the <url-pattern> tag above is filter2.jsp. Here is the code, which you can enter into a file j2ee/home/default-web-app/filter2.jsp:

<HTML> 
<HEAD> 
<TITLE>Lesson 2</TITLE> 
</HEAD>
<BODY> 
<HR>
<P><%=request.getAttribute("message")%></P>
<P>Check your console output!</P>
<HR> 
</BODY> 
</HTML> 

Running Example #2

Make sure that you have entered the filter configuration in the web.xml file, as shown above. Then access the JSP page with your browser:

http://<hostname>:<port>/j2ee/filter2.jsp

The console output should show something like the following:

Auto-deploying file:/private/tssmith/appserver/default-web-app/ (Assembly had 
been updated)...
Entering MessageFilter
Exiting MessageFilter

Note the message from the server showing that it redeployed the default application after the web.xml file was edited, and note the messages from the filter as it was entered and exited. The Web browser screen should show something like what is shown in Figure 4-3.

Figure 4-3 Example #2 Output

Text description of filtersa.gif follows.

Text description of the illustration filtersa.gif

Filter Example #3

A particularly useful function for a filter is to manipulate the response to a request. To accomplish this, use the standard javax.servlet.http.HttpServletResponseWrapper class, a custom javax.servlet.ServletOutputStream object, and a filter. To test the filter, you also need a target to be processed by the filter. In this example, the target that is filtered is a JSP page.

There are three new classes to write to implement this example:

This example uses the HttpServletResponseWrapper class to wrap the response before it is sent to the target. This class is an object that acts as a wrapper for the ServletResponse object (using a Decorator design pattern, as described in Design Patterns: Elements of Reusable Object-Oriented Software, by Gamma, Helm, Johnson, and Vlissides; Addison-Wesley Press). It is used to wrap the real response so that it can be modified after the target of the request has delivered its response.

The HTTP servlet response wrapper developed in this example uses a custom servlet output stream that lets the wrapper manipulate the response data after the servlet (or JSP page, in this example) is finished writing it out. Normally, this cannot be done after the servlet output stream has been closed (essentially, after the servlet has committed it). That is the reason for implementing a filter-specific extension to the ServletOutputStream class in this example.

Output Stream: FilterServletOutputStream.java

The FilterServletOutputStream class is used to manipulate the response of another resource. This class overrides the three write() methods of the standard java.io.OutputStream class.

Here is the code for the new output stream:

package com.acme.filter;

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

public
class FilterServletOutputStream extends ServletOutputStream {

  private DataOutputStream stream; 

  public FilterServletOutputStream(OutputStream output) { 
    stream = new DataOutputStream(output); 
  }

  public void write(int b) throws IOException  { 
    stream.write(b); 
  }

  public void write(byte[] b) throws IOException  { 
    stream.write(b); 
  }

  public void write(byte[] b, int off, int len) throws IOException  { 
    stream.write(b,off,len); 
  } 

}

Save this code in the following directory and compile it:

j2ee/home/default-web-app/WEB-INF/classes/com/acme/filter

Servlet Response Wrapper: GenericResponseWrapper.java

To use the custom ServletOutputStream class, implement a class that can act as a response object. This wrapper object is sent back to the client in place of the original response generated by the servlet (or JSP page).

The wrapper must implement some utility methods, such as to retrieve the content type and content length of its content. The GenericResponseWrapper class accomplishes this:

package com.acme.filter;

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

public class GenericResponseWrapper extends HttpServletResponseWrapper { 
  private ByteArrayOutputStream output;
  private int contentLength;
  private String contentType;

  public GenericResponseWrapper(HttpServletResponse response) { 
    super(response);
    output=new ByteArrayOutputStream();
  } 

  public byte[] getData() { 
    return output.toByteArray(); 
  } 

  public ServletOutputStream getOutputStream() { 
    return new FilterServletOutputStream(output); 
  } 
  
  public PrintWriter getWriter() { 
    return new PrintWriter(getOutputStream(),true); 
  } 

  public void setContentLength(int length) { 
    this.contentLength = length;
    super.setContentLength(length); 
  } 

  public int getContentLength() { 
    return contentLength; 
  } 

  public void setContentType(String type) { 
    this.contentType = type;
    super.setContentType(type); 
  } 


  public String getContentType() { 
    return contentType; 
  } 
} 

Save this code in the following directory and compile it:

j2ee/home/default-web-app/WEB-INF/classes/com/acme/filter

Writing the Filter

This filter adds content to the response of the servlet (or JSP page) after that target is invoked. This filter extends the filter from "Generic Filter".

Filter Code: PrePostFilter.java

package com.acme.filter;

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

public class PrePostFilter extends GenericFilter { 

  public void doFilter(final ServletRequest request,
                       final ServletResponse response,
                       FilterChain chain)
       throws IOException, ServletException { 
  OutputStream out = response.getOutputStream();
  out.write("<HR>PRE<HR>".getBytes());
  GenericResponseWrapper wrapper = new 
GenericResponseWrapper((HttpServletResponse) response); chain.doFilter(request,wrapper); out.write(wrapper.getData()); out.write("<HR>POST<HR>".getBytes()); out.close(); } }

Save this code in the following directory and compile it:

j2ee/home/default-web-app/WEB-INF/classes/com/acme/filter

JSP code: filter3.jsp

As in the previous examples, create a simple JSP page and place it in the root of default-web-app:

<HTML> 
<HEAD> 
<TITLE>Filter Example 3</TITLE> 
</HEAD>
<BODY> 
This is a testpage. You should see<br>
this text when you invoke filter3.jsp, <br>
as well as the additional material added<br>
by the PrePostFilter. 
<br>
</BODY> 
</HTML

Save this JSP code as j2ee/home/default-web-app/filter3.jsp.

Configuring the Filter

Add the following <filter> element to web.xml, after the configuration of the message filter:

  <!-- Filter Example #3 -->
  <filter> 
    <filter-name>prePost</filter-name>
    <display-name>prePost</display-name>
    <filter-class>com.acme.filter.PrePostFilter</filter-class> 
  </filter> 
  <filter-mapping> 
    <filter-name>prePost</filter-name>
    <url-pattern>/filter3.jsp</url-pattern> 
  </filter-mapping> 
  <!-- end Filter Example #3 -->

Running Example #3

In your Web browser, enter a URL such as the following:

http://<hostname>:<port>/j2ee/filter3.jsp

You should see a page that looks something like what is shown in Figure 4-4.

Figure 4-4 Example3 Output

Text description of filtersb.gif follows.

Text description of the illustration filtersb.gif


Go to previous page Go to next page
Oracle
Copyright © 2002 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index