Servlet Filtering

Filters are a feature that was introduced in version 2.3 of the servlet specification. A filter is a special type of servlet that dynamically intercepts requests and responses and transforms the information contained in them. The main advantage of filters is that they can be added to existing applications without any need for recompilation.

Filters can have several important uses:

  • To encapsulate recurring tasks in reusable units

  • To format the data sent back to the client

  • To provide authorization and blocking of requests

  • To provide logging and auditing

A filter can perform filtering tasks on the request, the response, or both.

Programming Filters

A filter is a servlet that also implements the javax.servlet.Filter interface.

Instead of doGet() or doPost(), filter tasks are done in a doFilter() method.

So that a filter can access initialization parameters, it is passed a FilterConfig object in its init() method. A filter can access the ServletContext through the FilterConfig object and thereby load any resources needed for the filtering tasks.

Filters can be connected together in a FilterChain. The servlet container constructs the filter chain in the order the filters appear in the deployment descriptor.

Because filters are added to an application at deploy time, it is possible to map a filter to one or more servlets. This is illustrated in Figure 12.17, where the AuthenticateUser filter is applied to all servlets. The PageCounter is mapped to VerifyData and HTMLPage, and the EncodeResponse filter only affects requests to the AgencyTable servlet.

Figure 12.17. Servlet filter chain.


After a filter successfully completes its task, it must then call the doFilter() method on the next filter in the chain. The filter chain object is passed to the filter by the server as a parameter to the doFilter() method.

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws
 IOException, ServletException {
    ...  // filter code
    chain.doFilter(req, res);  // call the next filter in the chain
}

If it is the last filter in the chain, instead of invoking another filter, the container will invoke the resource at the end of the chain (a normal servlet). If for some reason the filter processing fails, and if it is no longer appropriate to continue servicing the request, there is no need to call doFilter() on the next filter in the chain.

In a filter, you must provide an init(FilterConfig) method.

This init(FilterConfig) method is called by the Web server when a filter is being placed into service, and it must complete successfully before the filter can do any filtering work.

The destroy() method is called when a filter is being taken out of service, and gives the filter an opportunity to clean up any resources.

The use of these methods will be shown in the following example.

Example Auditing Filter

The filter in Listing 12.9 logs the number of times the application is accessed. A similar technique could be used to intercept requests and authorize the user before calling the servlet to service the request.

Listing 12.9. Servlet Filter
 1: import java.io.*;
 2: import javax.servlet.*;
 3: import javax.servlet.http.*;
 4:
 5: public class AuditFilter extends HttpServlet implements Filter {
 6:     private FilterConfig filterConfig = null;
 7:
 8:     public void init(FilterConfig filterConfig)
 9:        throws ServletException {
10:        this.filterConfig = filterConfig;
11:     }
12:
13:     public void destroy() {
14:        this.filterConfig = null;
15:     }
16:
17:     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
 throws IOException, ServletException {
18:         if (filterConfig == null)
19:             return;
20:         StringBuffer buf = new StringBuffer();
21:         buf.append ("The number of hits is: ");
22:         synchronized (this) {
23:             Integer counter = (Integer)filterConfig.getServletContext().getAttribute
("Counter");
24:             if (counter == null)
25:                 counter = new Integer(1);
26:             else
27:                 counter = new Integer(counter.intValue() + 1);
28:             buf.append (counter.toString());
29:             filterConfig.getServletContext().log(buf.toString());
30:             filterConfig.getServletContext().setAttribute("Counter", counter);
31:         }
32:         chain.doFilter(req, res);  // call the next filter in the chain
33:     }
34: }
						

Deploying Filters

Programming the filter is (as always) only half the task. Now it has to be configured into the application. In J2EE RI, this is achieved with the following steps:

1.
Add a new Web component to your Servlets application containing the filter class. On the component page, check the Servlets Filters box to indicate that this is a filter class (see Figure 12.18). There is no need to give this servlet a component alias because it is not referenced directly.

Figure 12.18. deploytool Choose Component Type—Servlet Filters.


2.
With the Servlets application highlighted in the left window, select the Filter Mapping tab (see Figure 12.19).

Figure 12.19. Deploytool Filter Mapping tab.


3.
Click the Edit Filter List button and add the AuditFilter to the Servlet Filters box (see Figure 12.20).

Figure 12.20. deploytool Servlet filters.


If you view the servlet's deployment descriptor, you will see the following lines have been added:

<filter>
    <filter-name>AuditFilter</filter-name>
    <display-name>AuditFilter</display-name>
    <description></description>
    <filter-class>AuditFilter</filter-class>
  </filter>

4.
Now map the filter to the page whose access you want to be logged. In this case, HTMLPage (see Figure 12.21).

Figure 12.21. deploytool Filter Mapping.


The following deployment descriptor entry shows the AuditFilter mapped to the HTMLPage:

<filter-mapping>
  <filter-name>AuditFilter</filter-name>
  <servlet-name>HTMLPage</servlet-name>
</filter-mapping>

5.
Deploy the application.

Now, every time the HTMLPage is accessed, the counter will be incremented and logged. The log file will be found in your J2EE installation directory under logs<machine name>web.

Note

There will probably be a number of log files in this directory; look for the one with the latest date on it.


At the end of the log file you should see something like the following:

HTMLPage: init
The number of hits is: 1
The number of hits is: 2
The number of ....

Another way to see if the filter is working is to amend the HTMLPage code to output the counter, as shown in Listing 12.10.

Listing 12.10. HTMLPage with Counter Added
 1: import java.io.*;
 2: import javax.servlet.*;
 3: import javax.servlet.http.*;
 4:
 5: public class HTMLPage extends HttpServlet {
 6:
 7:     public void doGet(HttpServletRequest req, HttpServletResponse res)
 8:                  throws ServletException, IOException {
 9:         res.setContentType ("image/gif");
10:         PrintWriter out = res.getWriter();
11:         out.println ("<HTML>");
12:         out.println ("<HEAD><TITLE>Filtered Servlet</TITLE></HEAD>");
13:         out.println ("<BODY>");
14:         out.println ("<H1>A Generated HTML Page with a Filter attached</H1>");
15:         Integer counter = (Integer)getServletContext().getAttribute("Counter");
							16:         out.println ("<P>This page has been accessed " + counter + " times</P>");
17:         out.println ("</BODY>");
18:         out.println ("</HTML>");
19:     }
20: }
						

This was a very simple example, more sophisticated filters can be used to modify the request or the response. To do this, you must override the request or response methods by wrapping the request or response in an object that extends HttpServletRequestWrapper or HttpServletResponseWrapper. This approach follows the well-known Wrapper or Decorator pattern technique. Patters will be described in detail on Day 18, Patterns.”

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

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