Using FiltersS2C Home « Using Filters

In this lesson we look at filters which are Java components that allow us to receive requests and responses and manipulate them through the filtering mechanism. In many ways filters are like servlets, they have a lifecycle, access to the servlet context and can pass control to another filter or target resource, in much the same way as request dispatchers work with servlets.

The main purpose of filters is to intercept a client request before it reaches a web resource such as a servlet or JSP page and then to interpose itself after the response has been sent from the web resource and before it reaches the client. There are many reasons why you may want to use filters before a web resource gets the request or after it sends the response and some of these are listed below:

  • Filtration Before Request:
    1. Authentication filters which can deny acesss to the requested resource.
    2. Caching filters that store uploaded resources.
    3. Logging and auditing filters that write traffic details and volumes to reports.
    4. MIME-type chain filters that reformat the request accordingly.
    5. Tokenizing filters that reformat the request from an input form.
    6. XSL/T filters that transform XML content
  • Filtration After Response:
    1. Data compression filters that zip up responses before sending them back to the client.
    2. Encryption filters that encode the response for security purposes.
    3. Image conversion filters that deflate or change images before sending them back to the client.
    4. Reformat filters that transorm the response tailored to a particular client.

Filters are modular in nature and because of this modularity it's common practice to have several filters chained together each with a specific purpose in modifying the request or response. The sequence of filter invocation is configured via URL mappings within the DD and we will look at this in more detail when we code a filter later in the lesson. This also means that filters aren't tied to any particular servlet and in fact a servlet has no idea that the request or response is being filtered.

The following slideshow shows a filter intercepting the request and response from the client so you can see the sequence of events.

filt 1 filt 2 filt 3 filt 4 filt 5 filt 6 filt 7 filt 8

In this slide our client has clicked on a link that points to a resource that is a servlet or a static resource that is declared as requiring filtration in the DD, so the web server directs the HTTP request to our web container.

The container processes the HTTP request and creates a HttpServletRequest object and a HttpServletResponse object.

The container resolves the mapping to the servlet required via the deployment descriptor and this is intercepted by Filter1.

Filter1 ends and passes control to Filter2.

Filter2 ends and passes control to the servlet.

The servlet ends and the HttpServletResponse object is intercepted by Filter3.

Filter3 ends and passes the HttpServletResponse object back to the container.

In this final slide the container passes the filtered HTTP response back to the client.

Press the button below to cycle through our Filtering A Servlet Request slideshow.


The Filter APITop

The Filter API consists of three interfaces these being, the javax.servlet.Filter interface which is analagous to the javax.servlet.Servlet interface and supplies the framework with which we build our filters. The javax.servlet.FilterConfig interface which is comparable to the javax.servlet.ServletConfig interface in that it provides a mechanism for configuring a filter from initialisation parameters we declare in the DD. Lastly the javax.servlet.FilterChain interface which allows us to chain filters together by passing the request and response from one filter to the next. The tables below summarize the methods within each of the interfaces.

The Filter InterfaceTop

Every Filter object can access a FilterConfig object, but to be of any use this object must be saved, generally as an instance variable from within the overidden init() method. The FilterConfig object can then be used to obtain initialization parameters, as well as a reference to the ServletContext object which can be useful for things such as loading the resources required for filtering tasks. The doFilter() method is where we perform the filtering tasks and the destroy() can be useful for tidying up resources. These three methods are shown in the table below, use the links in the table to go to example code of the method in question.

Method Declaration Description
void init( FilterConfig filterConfig)Invoked by the web container to advise a filter that it is being placed into service.
void doFilter( ServletRequest request,
  ServletResponse response, FilterChain chain)
Invoked by the web container each time a request/response pair is applied to the current client request for a resource.
void destroy()Invoked by the web container to advise a filter that it is being taken out of service.

The FilterConfig InterfaceTop

The FilterConfig interface allows us to pass information to a filter during initialisation. The container provides an instance of a FilterConfig implementation which can be saved to an instance variable during the initialisation of a filter within the init() method. The four methods of the FilterConfig Interface are shown in the table below, use the links in the table to go to example code of the method in question.

Method Declaration Description
java.lang.String getServletName()Returns name of this filter as defined in the DD.
java.lang.String
   getInitParameter( java.lang.String name)
Returns a String containing value of specified name initialization parameter, or null if the parameter does not exist.
java.util.Enumeration getInitParameterNames()Returns a java.util.Enumeration of String objects containing the filter's initialization parameter names, or an empty java.util.Enumeration if filter has none.
ServletContext getServletContext()Returns a reference to the ServletContext in which the caller is executing.

The FilterChain InterfaceTop

The FilterChain interface allows a filter to invoke the next filter in the chain, or if the calling filter is the last filter in the chain, to invoke the resource at the end of the chain. The container provides instances of FilterChain implementation when required so there is no need to instantiate this type. The table below shows the single method in the FilterChain interface, use the links in the table to go to example code of the method.

Method Declaration Description
void doFilter(ServletRequest request,
   ServletResponse response)
Causes the next filter in the chain to be invoked, or if the calling filter is the last filter in the chain, causes the resource at the end of the chain to be invoked.

Filter LifecycleTop

We can think of an object's lifecycle as the various stages that said object goes through during its existence. Because a filter has to run within the boundaries of whatever web container we are using, there are additional factors involved with the lifecycle of a filter object.

The following slideshow shows the various stages in the filter lifecycle. Press the button below to step through the slideshow:

fl 1 fl 2 fl 3 fl 4 fl 5 fl 6 fl 7

Our client has clicked on a link that points to a resource that is a servlet or a static resource that is declared as requiring filtration in the DD, so the web server directs the HTTP request to our web container.

This filter has not been called by the container before so will have to be loaded by the application's class loader.


Just like any other object our filter has to be instantiated so it can be called by the container. The container calls the default no-args constructor which is best left to the compiler to generate.

Now we have a filter object the first of the three lifecycle methods, the init() method is called for the first and only time, and is where the initialisation of the servlet takes place.

The second of the three lifecycle methods, the doFilter() method is called on our initialized filter and is where we do our filtering tasks.

The filter sits there in its initialized state happily filtering requests and/or responses.


The third and final lifecycle method, the destroy() method is called on our filter. This can happen for a number of reasons including server shutdown and an application being undeployed.

Press the button below to cycle through our Filter Lifecycle slideshow.


We will go into the different stages of the filter lifecycle shown in the slideshow in much more detail and answer some other questions raised by it below.

Class LoadingTop

A container can contain many web applications and each of these has a class loader that is used to search for and load classes from the /WEB-INF/classes/ directory and JAR files from the /WEB-INF/lib/ directory. Having separate class loaders for each application allows filters in different applications to have the same name.

Because the container finds a class it doesn't necessarily load it; the filter could be lazily initialised on first use or when the container deems it necessary.

InstantiationTop

Just like any other object our filter has to be instantiated so it can be called by the container. This is achieved using the default no-args constructor which is best left to the compiler to generate. If you absolutely must have a custom constructor for your filter then you also need to explicitly code a no-args constructor so the container can instantiate your filter.

You cannot do any initialisation at this stage as our filter doesn't exist in what we can think of as a filter state until the no-args constructor has completed and the container makes it into a filter object. Any attempts to initialise the filter using other parts of the application will fail and is the reason why we have separate instantiation and intialisation steps.

InitialisationTop

We now have a fully fledged filter object waiting to be initialized to its default state. Here is a good time to talk about what value we get from a normal object being transformed into a filter object. Well apart from the benefits we get from the container every filter also gets access to three other objects, these being FilterConfig, FilterChain and ServletContext.

Each filter gets one FilterConfig object and this is where we can put configuration information for deployment rather than in a constructor. We configure initialisation parameters for the FilterConfig object via the DD. This is achieved using the <init-param> sub-level element of the top-level <filter> element, an example of which is shown below.


<filter>
   <filter-name>compressionFiltre</servlet-name>
   <filter-class>test.Filter</servlet-class>
   <init-param>
      <param-name>datasource</param-name>
      <param-value>somefile.txt</param-value>
   </init-param>
</filter>

Don't worry too much about the DD elements shown above for now but a point of note is that we can have multiple entries of the <init-param> sub-element.

The FilterConfig object also allows us to access the ServletContext object which we spoke about in detail in the ServletConfig & ServletContext lesson.

The init() Lifecycle MethodTop

The init() lifecycle method is the first of the three lifecycle methods associated with a filter and is run only once during the life of a servlet. You can put initialisation code required by your filter that cannot be placed declaratively within the DD in this method, such as Java code for referencing and database connections.

The FilterConfig object created by the container is passes as a parameter to this method and this is your one and only chance to save this object, generally to an instance variable, for later use. We can also use methods of the FilterConfig object to access any initialisation parameters we declared within the DD.

The init() method can throw a ServletException or a subclass thereof and if this happens the container bypasses the other lifecycle methods and makes the servlet available for garbage collection.

Request ServicingTop

So our one time initialisation has completed and our filter is now ready to service requests. When a request from a client comes in that points to a resource that is a servlet or a static resource that is declared as requiring filtration in the DD, the doFilter() method is invoked.

The doFilter() Lifecycle MethodTop

The doFilter() lifecycle method is the second of the three lifecycle methods associated with a servlet and is run every time a client requests a resource that is a servlet or a static resource that is declared as requiring filtration in the DD. As you can see from the signature doFilter(ServletRequest request, ServletResponse response, FilterChain chain) method uses the ServletRequest and ServletResponse objects and is where all our filtration takes place. It also allows us to chain to the next filter, or if the calling filter is the last filter in the chain, to invoke the resource at the end of the chain using the chain method parameter, an example of which we will see shortly when we write some code.

The doFilter() method can throw a ServletException or a subclass thereof and if this happens and the exception is permanent the container returns a 404('Not Found') HTTP status code and removes the filter from service. If the exception is temporary the container returns a 503('Service Unavailable') HTTP status code and makes the filter temporarily unavailable. After a period of time the container will put the filter back into service, making it available to filter more requests. The doFilter() method can also throw an IOException as we are accessing writers which can cause exceptions.

DestructionTop

The final phase of a filters lifecycle is its destruction and can happen for a number of reasons including server shutdown and an application being undeployed. When such an event happens the container will call the filters destroy() method which gives us an opportunity to free resources and tidy up before the filter is garbage collected.

The destroy() Lifecycle MethodTop

The destroy() lifecycle method is the last of the three lifecycle methods associated with a filter and is run only once during the life of a filter. This method is invoked by the container when a filter is going to be destroyed and gives us a chance to clean up and housekeep before the filter is garbage collected.

Filter StackingTop

We have spoken about chaining filters within the DD but what does this mean in terms of Java and the stack? The following slideshow illustrates two filters that are declared in the DD and a final chain to a servlet which shows what happens with the stack.

filterstack 1 filterstack 2 filterstack 3 filterstack 4 filterstack 5

Press the button below to cycle through our filter stacking explanation.

Example Of Using FiltersTop

We will enhance the code from the slideshow above for our filtering example and just write some lines to the Tomcat log so you can see each filter and then the servlet getting invoked.

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

Within the filtering 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:

filtering directory structure

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.

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


package controller;

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

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); 
        // Invoke next filter or resource (Filter2)
        System.out.println("Leaving Filter1");
        chain.doFilter(req, resp);
        System.out.println("Back in Filter1"); 
        // Create response
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        writer.print("<p>Filter1 Response</p>");
    }

    @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\filtering\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 -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\filtering\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("<p>Filter2 Response</p>");
    }

    @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\filtering\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 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\filtering\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();
        writer.close();
    }
}

Compiling The AServlet Class

Open your command line editor:

Change to directory  c:\_ServletsAdv\filtering\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 DDTop


<?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.

The <filter> ElementTop

Ok lets look at the new DD elements we have entered starting with the top-level <filter> element which is used to describe and point to our filter class. The <filter> element contains several sub-level elements which themselves can contain sub-level elements. All of which are explained in detail in the DD Elements At A Glance quick reference so we won't go into them here. What we will explain are the sub-level elements within our DD above. The sub-level <filter-name> and <filter-class> elements are mandatory and can only appear once within the top-level <filter> element.

The <filter-name> sub-level element must come before the <filter-class> sub-level element. The value of the filter name you give this element must be unique within the web application and be at least one character long. The <filter> top-level element is used in conjunction with the <filter-mapping> top-level element, which we look at below.

The <filter-class> sub-level element defines the fully qualifed name of a Java Servlet class, delimited by dots for the packages our servlet is within. The value you give this class doesn't have to be unique within a web application.

The <init-param> sub-level element is optional and can appear many times within the top-level <filter> element. Within <init-param> the <description> sub-level element is optional and the <param-name> and <param-value> sub-level elements are both mandatory, must appear only once and represent a key/value pair. The values within these elements can be retrieved using methods of the FilterConfig interface.

The <filter-mapping> ElementTop

The <filter-mapping> element is used to map an incoming resource to a filter and is used in conjunction with the <filter> top-level element to allow controlled access to resources. The <filter-mapping> element has three sub-level elements described below.

The <url-pattern> and <servlet-name> sub-level elements can be placed in any order and there must be at least one of either present. The value of the servlet names must be unique within the web application and be at least one character long.

When a request comes in for a servlet or a static resource that is declared as requiring filtration in the DD the part of the address supplied by the client after the web application name, is used to match against the <url-pattern> and <servlet-name> sub-level elements within the DD. When one is found the <filter-name> sub-level element of the <filter-mapping> top-level element is used to find the <filter-name> sub-level element within the top-level <filter> element. From here we can get the location of the filter via the <filter-class> sub-level element. This is how the mapping from the request to the filter, which is hidden from public view in the WEB-INF directory is achieved.

A filter chain is based on the order of the <url-pattern> and <servlet-name> sub-level elements declared in the DD. When more than one resource is mapped to a given resource all filters with matching URL patterns are located and are applied to the chain in the order they were declared in the DD. Once this is completed the same process is repeated for filters that have a matching <servlet-name>.

The <dispatcher> sub-level element is optional and can appear up to four times; the values are listed below:

  • REQUEST - This is the default and is a direct client request for a resource.
  • FORWARD - Internal request on the web server for a resource via the forward() method of a Request Dispatcher.
  • INCLUDE - Internal request on the web server for a resource via the include() method of a Request Dispatcher.
  • ERROR - Internal request on the web server for a resource that has been created as an error-page.

A discussion on URL mapping takes place in the Servlets Glossary - URL Mapping section.

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 filtering

Within the filtering 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\filtering folder should look something like the following screenshot:

Tomcat directory structure
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/filtering/example

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

Run AServlet

So the AServlet servlet seemed to run fine and render some HTML to our browser window, but what happened to the HTML paragraphs we sent from the ImplFilter1 and ImplFilter2 classes?. Lets check the entries in the Tomcat logs (at the bottom) to make sure everything worked ok.

The following screenshot shows the System.out.println messages we sent to the console from the ImplFilter1, ImplFilter2 and AServlet classes. The relevant lines are highlighted in yellow so you can see them easier.

Run AServlet 2

So from looking at the logs everything has run as expected but still doesn't answer where the paragraphs from the ImplFilter1 and ImplFilter2 classes has gone. Well the reason that we don't see these lines is that we closed the response in the AServlet servlet using the writer.close(); statement. This commits the response and so anything we do after that is like closing the stable door after the horse has bolted, it's too late. Admittedly we are adding the two paragraphs after we have closed the HTML so we are not coding well formed HTML. Of course in the real world this is not acceptable but makes no difference to the point we are making, in fact if you remove the writer.close(); statement from the AServlet servlet and recompile, redeploy and run the code the two paragraphs will then appear.

How we get around this problem with the response being committed is the discussion of the next lesson when we look at wrappers.

Lesson 4 Complete

In this lesson we looked at the three filter interfaces and how we can use filters to intercept our requests and responses.

What's Next?

In the next lesson we look at decorating our requests and responses using wrappers.

go to home page Homepage go to top of page Top