| C H A P T E R 6 |
|
Filtering |
Filters are Java programming language components that, during runtime, allow transformations of payload and header information in both the request into a resource and the response from a resource.
This chapter describes the Java Servlet API classes and methods that provide a lightweight framework for filtering active and static content. It describes how filters are configured in a web application, and conventions and semantics for their implementation.
API documentation for servlet filters is provided separately in Javadoc tool format. The configuration syntax for filters is given by the deployment descriptor schema in Chapter 13. The reader should use these sources as references when reading this chapter.
This Java Card Platform version of the specification imposes that filters be mapped only to URL patterns to which servlets have been mapped. Therefore, filters cannot directly apply to static content. Filters can only apply indirectly to static content through a servlet such as an explicitly declared “default” servlet that is used to serve static content in response to requests from web clients when no other servlet applies. This indirect mapping is assumed for applying filters to static content.
A filter is a reusable piece of code that can transform the content of HTTP requests, responses, and header information. Filters do not generally create a response or respond to a request as servlets do, rather they modify or adapt the requests for a resource, and modify or adapt responses from a resource.
Filters can act on dynamic or static content. For the purposes of this chapter, dynamic and static content are referred to as web resources.
Some of the types of filtering functionality available are the following:
The main concepts of this filtering model are described in this section.
The application developer creates a filter by implementing the javax.servlet.Filter interface and providing a public constructor taking no arguments. The class is packaged in the Web Archive along with the static content and servlets that make up the web application. A filter is declared using the <filter> element in the deployment descriptor. A filter or collection of filters can be configured for invocation by defining <filter-mapping> elements in the deployment descriptor. This is done by mapping filters to a particular servlet by the servlet’s logical name or by the URL pattern the servlet is mapped to.
After deployment of the web application, and before a request causes the container to access a web resource, the container must locate the list of filters that must be applied to the web resource as described below. The container must ensure that it has instantiated a filter of the appropriate class for each filter in the list and called its init(FilterConfig config) method. The filter may throw an exception to indicate that it cannot function properly. If the exception is of type UnavailableException, the container may examine the isPermanent attribute of the exception and may choose to retry the filter at some later time.
Only one instance per <filter> declaration in the deployment descriptor is instantiated by the container. The container provides the filter config as declared in the filter’s deployment descriptor, the reference to the ServletContext for the web application, and the set of initialization parameters.
When the container receives an incoming request, it takes the first filter instance in the list and calls its doFilter method, passing in the ServletRequest and ServletResponse, and a reference to the FilterChain object it will use.
The doFilter method of a filter will typically be implemented following this or some subset of the following pattern:
1. The method examines the request’s headers.
2. The method may wrap the request object with a customized implementation of ServletRequest or HttpServletRequest in order to modify request headers or data.
3. The method may wrap the response object passed in to its doFilter method with a customized implementation of ServletResponse or HttpServletResponse to modify response headers or data.
4. The filter may invoke the next entity in the filter chain. The next entity may be another filter, or if the filter making the invocation is the last filter configured in the deployment descriptor for this chain, the next entity is the target web resource. The invocation of the next entity is effected by calling the doFilter method on the FilterChain object, and passing in the request and response with which it was called or passing in wrapped versions it may have created.
The filter chain’s implementation of the doFilter method, provided by the container, must locate the next entity in the filter chain and invoke its doFilter method, passing in the appropriate request and response objects.
Alternatively, the filter chain can block the request by not making the call to invoke the next entity, leaving the filter responsible for filling out the response object.
5. After invocation of the next filter in the chain, the filter may examine response headers.
6. Alternatively, the filter may have thrown an exception to indicate an error in processing. If the filter throws an UnavailableException during its doFilter processing, the container must not attempt continued processing down the filter chain. It may choose to retry the whole chain at a later time if the exception is not marked permanent.
7. When the last filter in the chain has been invoked, the next entity accessed is the target servlet or resource at the end of the chain.
8. Before a filter instance can be removed from service by the container, the container must first call the destroy method on the filter to enable the filter to release any resources and perform other cleanup operations.
Refer to the Runtime Environment Specification, Java Card Platform, Version 3.0.1, Connected Edition for more details on the lifetime of filter objects specific to the Java Card Platform.
Central to the notion of filtering is the concept of wrapping a request or response so it can override behavior to perform a filtering task. In this model, the developer not only has the ability to override existing methods on the request and response objects, but to provide new APIs suited to a particular filtering task to a filter or target web resource down the chain. For example, the developer may wish to extend the response object with higher level output objects than the output stream or the writer.
To support this style of filter, the container must support the following requirement: When a filter invokes the doFilter method on the container’s filter chain implementation, the container must ensure that the request and response object that it passes to the next entity in the filter chain, or to the target web resource if the filter was the last in the chain, is the same object that was passed into the doFilter method by the calling filter.
The same requirement of wrapper object identity applies to the calls from a servlet or a filter to RequestDispatcher.forward or RequestDispatcher.include, when the caller wraps the request or response objects. In this case, the request and response objects seen by the called servlet must be the same wrapper objects that were passed in by the calling servlet or filter.
A set of initialization parameters can be associated with a filter using the <init-params> element in the deployment descriptor. The names and values of these parameters are available to the filter at runtime via the getInitParameter and getInitParameterNames methods on the filter’s FilterConfig object. Additionally, the FilterConfig affords access to the ServletContext of the web application for the loading of resources, for logging functionality, and for storage of state in the ServletContext’s attribute list.
A filter is defined in the deployment descriptor using the <filter> element. In this element, the programmer declares the following:
Optionally, the programmer can specify icons, a textual description, and a display name for tool manipulation. The container must instantiate exactly one instance of the Java class defining the filter per filter declaration in the deployment descriptor. Hence, two instances of the same filter class will be instantiated by the container if the developer makes two filter declarations for the same filter class.
Here is an example of a filter declaration:
<filter> <filter-name>Image Filter</filter-name> <filter-class>com.acme.ImageServlet</filter-class> </filter> |
Once a filter has been declared in the deployment descriptor, the assembler uses the <filter-mapping> element to define servlets in the web application to which the filter is to be applied. Filters can be associated with a servlet using the <servlet-name> element. For example, the following code example maps the Image Filter filter to the ImageServlet servlet:
<filter-mapping> <filter-name>Image Filter</filter-name> <servlet-name>ImageServlet</servlet-name> </filter-mapping> |
Filters can be associated with a servlet using the <url-pattern> style of filter mapping:
<filter-mapping> <filter-name>Logging Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
When processing a <filter-mapping> element using the <url-pattern> style, the container must determine whether the <url-pattern> matches the request URI using the path mapping rules defined in Chapter 11.
The order the container uses in building the chain of filters to be applied for a particular request URI is as follows:
1. First, the <url-pattern> matching filter mappings in the same order that these elements appear in the deployment descriptor.
2. Next, the <servlet-name> matching filter mappings in the same order that these elements appear in the deployment descriptor.
This requirement means that the container, when receiving an incoming request, processes the request as follows:
It is expected that high performance web containers will cache filter chains so that they do not need to compute them on a per-request basis.
Filters are only applied to a request when they come directly from the client.
Copyright © 2009 Sun Microsystems, Inc. All rights reserved.