|[ Team LiB ]|
The Filter Interface
The Filter interface defines the methods that any servlet filter must implement, just as the Servlet interface defines methods that any servlet must implement. The interface defines three methods:
public void init(FilterConfig config) public void destroy() public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException
The init Method
Whenever the servlet container activates a filter, the container invokes the filter's init method, similar to the way the container invokes a servlet's init method. The FilterConfig object allows the filter to access its configuration items (configured by <init-param> tags in the web.xml file) as well as the ServletContext object.
The destroy Method
When the servlet container deactivates a filter, the container invokes the filter's destroy method, allowing the filter to perform any necessary cleanup. If a filter doesn't need to perform any cleanup, this method can be empty.
The doFilter Method
The doFilter method is the heart of the Filter interface. If a servlet or JSP is filtered, the servlet container invokes the filter's doFilter method rather than the servlet's service method. When the filter is ready for the servlet's service method to execute, the filter calls the doFilter method in the FilterChain object. The FilterChain object may refer to another filter (filters may be chained together) or it may refer to the actual servlet.
After the FilterChain's doFilter method returns, the filter may perform any additional processing on the response object.
The filter lifecycle is very similar to the servlet lifecycle. The servlet container creates an instance of a filter (usually one instance of a particular filter per container, just as with servlets). Before invoking the filter's doFilter method for the first time, the servlet container initializes the filter by calling the init method. Because usually only one instance of a particular filter is in the servlet container, the servlet container may invoke the doFilter method many times simultaneously, so you must be careful to ensure that the doFilter method is thread-safe. If the servlet container needs to remove the filter from service for some reason, it invokes the filter's destroy method first, allowing the filter to perform any necessary cleanup.
Like servlets, you must configure filters in the Web application's web.xml file. The configuration of a filter looks almost identical to that of a servlet. You first define a filter, giving it a name and specifying the name of the class that implements the filter. For example,
<filter> <filter-name>Example Filter</filter-name> <filter-class>examples.ExampleFilter</filter-class> </filter>
Next, you specify the various URL mappings that define when the filter is invoked. You can make a filter apply to all resources in the application with a URL of /* or you can apply it to only specific resources. For example,
<filter-mapping> <filter-name>Example Filter</filter-name> <servlet-name>FilterMe.jsp</servlet-name> </filter-mapping>
In this case the filter applies only to a JSP named FilterMe.jsp.
Naming JSPs as Servlets
When you want to apply a filter to several resources, you use the url-pattern element instead of a servlet-name element, as shown:
<filter-mapping> <filter-name>Example Filter</filter-name> <url-pattern>/myContext/*</url-pattern> </filter-mapping>
In this case the filter is applied to all resources available within the myContext.
By defining more than one filter in the deployment descriptor, filters can be chained to each other. In other words, when the first filter calls FilterChain's doFilter method, control will be passed to the next filter.
To determine which filter is next, a container will first test the request URI against filter URL patterns to determine which filter belongs to the set that will be applied to a resource. Once the set is determined, filters are applied in the order they appear in the deployment descriptor. Then, any resource specific filters defined by servlet-name elements will follow.
In version 2.3 of the Java Servlet specification, a filter could only apply to a resource requested by a client. The filter wouldn't apply to servlets invoked via the request dispatcher (that is, by forwarding or including). Version 2.4 of the specification allows you to specify that a filter can apply to forwards, includes, requests, or error pages via the error page mechanism. You simply add one or more <dispatcher> tags to the filter-mapping. The values of the <dispatcher> tags may be FORWARD, INCLUDE, REQUEST, or ERROR. For example, to configure a filter to be invoked via a request from a client or an include using a RequestDispatcher, but not a forward, use the following declaration:
<filter-mapping> <filter-name>Example Filter</filter-name> <url-pattern>/FilterMe.jsp</url-mapping> <dispatcher>REQUEST</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping>
Using Filters to Program Without Linking Binaries
The <filter> and <filter-mapping> elements must appear before any <servlet> and <servlet-mapping> elements.
A FilterConfig object is passed as a parameter in the init method of a Filter. FilterConfig provides methods to discover a filter's name, retrieve initialization parameters, and access the servlet context:
public java.lang.String getFilterName() public java.lang.String getInitParameter(java.lang.String name) public java.util.Enumeration getInitParameterNames() public ServletContext getServletContext()
Initialization parameters are added to the deployment descriptor by adding init-params elements as children to a filter element.
Request and Response Wrappers
When a filter invokes the doFilter method in the FilterChain object, it must pass in a request and response. The request and response don't necessarily need to be the same request and response that were originally passed to the filter. For example, if you want to supply an alternate output stream to a servlet, you need to supply a response object whose getOutputStream method returns the alternate output stream.
The problem with supplying an alternate request or response object is that there are so many methods in each of these objects that it becomes cumbersome to implement your own. One of the common design patterns (the Decorator pattern) for a situation like this is to create a wrapper class. The wrapper keeps a reference to the real object (the original request or response, in this case) and implements the same methods as the real object. In most cases, the wrapper's methods just invoke the methods in the real object. In a few cases, however, the wrapper has its own implementation (its own getOutputStream, for example), or may even supplement functionality with additional methods.
Creating wrapper classes is a little less cumbersome than writing your own classes from scratch, but it still involves creating a large number of methods yourself. Fortunately, the servlet API provides prebuilt wrappers for the request and response objects. You simply subclass these classes and override the particular methods in which you are interested.
The ServletRequestWrapper class wraps a ServletRequest object, just as the HttpServletRequestWrapper wraps an HttpServletRequest object. In both cases, the constructor for the wrapper class takes the real request object as a parameter. Similarly, the ServletResponseWrapper class wraps a ServletResponse, and the HttpServletResponseWrapper wraps an HttpServletResponse.
|[ Team LiB ]|