To add a new filter to a web application, you must define it and then map it to resources. You do this in the web application's deployment descriptor (the web.xml file). This section describes the options for defining filters and determining the order in which they are executed.
Because you define filters in the web.xml file, you can reorder the filters, define initialization parameters, and add and remove filters without recompiling your web applications. This loosely coupled architecture separates the task of configuring filters from the task of writing the applications. The applications and their underlying resources operate independently of the filters that process the requests and responses.
You can define other configuration information for filters in the web.xml file. For more information, see "Accessing initialization parameters".
In the web.xml file, you first define the filter by name and class within the web-app block. The following example shows a filter definition from the web.xml file:
<web-app>
... <filter> �<filter-name>filter_name</filter-name> �<filter-class>filter_class</filter-class> </filter> ... </web-app>
For example, to define the TimingFilter:
<filter>
�<filter-name>TimingFilter</filter-name> �<filter-class>jrunsamples.filters.TimingFilter</filter-class> </filter>
You can also define initialization parameters in the filter block. For more information, see "Accessing initialization parameters".
You define the resources to which a filter is mapped using the url-pattern or the servlet-name elements. You can declare the same filter multiple times using different filter names. Thus, you can map one filter to multiple resources, using a combination of URL mappings and servlet names.
You can define filters using URL patterns in the web.xml file, as the following syntax shows:
<web-app>
... <filter> �<filter-name>filter_name</filter-name> �<filter-class>filter_class</filter-class> </filter> ...
<filter-mapping>
�<filter-name>filter_name</filter-name> �<url-pattern>pattern_for_resource</url-pattern> </filter-mapping> ... </web-app>
For example, use the following code to map the TimingFilter to the welcome.jsp file:
<filter>
�<filter-name>TimingFilter</filter-name> �<filter-class>jrunsamples.filters.TimingFilter</filter-class> </filter>
<filter-mapping>
�<filter-name>TimingFilter</filter-name> �<url-pattern>/welcome.jsp</url-pattern> </filter-mapping>
You might recognize url-pattern as the same element used in mapping servlets to resources in the web.xml file.
You can map a filter to more than one resource using wild cards in the url-pattern element, just as you can when using any URL mapping in the web.xml file. For example, to map a filter to all JSPs in a web application's context, define the pattern as follows:
<url-pattern>/*.jsp</url-pattern>
To map a filter to all servlets, JSPs and static content, define the pattern as follows:
<url-pattern>/*</url-pattern>
You can also map filters to named servlets. The following syntax maps a filter to named servlets:
<web-app>
... <servlet> �<servlet-name>servlet_name</servlet-name> �<servlet-class>servlet_class</servlet-class> </servlet> ... <filter> �<filter-name>filter_name</filter-name> �<filter-class>filter_class</filter-class> </filter> ...
<filter-mapping>
�<filter-name>filter_name</filter-name> �<servlet-name>servlet_name</servlet-name> </filter-mapping> ... </web-app>
JRun orders the execution of filters for each request depending on the URL patterns and servlets that the request URI matches in the web.xml file. JRun considers url-pattern matches first, in the order that they appear in the web.xml file, followed by servlet-name matches in the order that they appear in the web.xml file.
In the following example, JRun invokes the servlets in the order Filter1, Filter3, Filter2 because Filter1 and Filter3 are mapped to resources using URL mappings, while Filter2 uses a servlet name mapping:
<web-app>
... <filter> �//Filter1 definition </filter>
<filter>
�//Filter2 definition </filter>
<filter>
�//Filter3 definition </filter>
<filter-mapping>
�//Filter1 mapping �<url-mapping>...</url-mapping> </filter-mapping>
<filter-mapping>
�//Filter2 mapping �<servlet-name>...</servlet-name> </filter-mapping>
<filter-mapping>
�//Filter3 mapping �<url-mapping>...</url-mapping> </filter-mapping> ... </web-app>
Filters can extract initialization parameters from the web application's web.xml file. This allows you to change settings on the fly without recompiling a web application. For example, you could set a data source or log file location in the initialization parameter rather than hard-coding it.
Initialization parameters in filter definitions work the same way that they do for servlets. The FilterConfig class uses methods that share the same name as the ServletConfig class to access these parameters:
getInitParamter()
getInitParameterNames()
Use the init-param elements to define the name and value of the initialization parameter in the web.xml file, as the following syntax shows:
...
<filter> <filter-name>filter_name</filter-name> <filter-class>filter_class</filter-class> <init-param> <param-name>parameter_name</param-name> <param-value>parameter_value</param-value> </init-param> </filter> ...
You can specify any number of initialization parameters per filter; for example:
<filter>
<filter-name>InitParamsFilter</filter-name> <filter-class>jrunsamples.filters.InitParamsFilter</filter-class> <init-param> <param-name>message</param-name> <param-value>Drink your Ovaltine.</param-value> </init-param> <init-param> <param-name>answer</param-name> <param-value>42</param-value> </init-param> </filter>
The following code sample from the filter's doFilter method gets a list of initialization parameters and prints them to the standard output:
...
Enumeration initParams = filterConfig.getInitParameterNames();
if (initParams == null) {
�System.out.println("No initialization parameters in filter definition");
�chain.doFilter(request, response);
} else {
�while (initParams.hasMoreElements()) {
�String name = (String) initParams.nextElement();
�String value = filterConfig.getInitParameter(name);
�System.out.println(name + ":" + value);
}
...
A simple example filter is the TimingFilter. This filter prints the time (in milliseconds) that JRun starts processing the request. When the request comes back from the chain, JRun again prints the time.
This filter extends the GenericFilter interface so that it does not override the doInit and doDestroy methods.
package jrunsamples.filters; import javax.servlet.*;
import javax.servlet.http.*;
public class TimingFilter extends GenericFilter {
�public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
��long bef = System.currentTimeMillis();
��System.out.println("Entering Filter: " + bef);
��chain.doFilter(request,response);
��long aft = System.currentTimeMillis();
��System.out.println("Exiting Filter: " + aft);
�}
}
In the web application's web.xml deployment descriptor, the filter and mapping are defined as follows:
<filter>
<filter-name>TimingFilter</filter-name> <filter-class>jrunsamples.filters.TimingFilter</filter-class> </filter>
<filter-mapping>
<filter-name>TimingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
When you invoke a resource in this application context, a message similar to the following example prints to your system console:
11/20 14:42:47 info JSPServlet: init
Entering filter: 1006285367836 Exiting filter: 1006285367956
Filters can view the headers of request and response objects through the ServletContext. They also can access attributes of this object. However, to modify the actual content of a request or response, they must be able to capture the content stream of the request or response before it is returned to the client. They do this with the following wrapper classes:
javax.servlet.http.ServletRequestWrapper(ServletRequest req)
javax.servlet.http.HttpServletRequestWrapper(HttpServletRequest req) javax.servlet.http.ServletResponseWrapper(ServletResponse resp) javax.servlet.http.HttpServletResponseWrapper(HttpServletResponse resp)
By default, these wrapper classes pass all method calls to the classes from which they are derived without modifying those calls. Using the wrappers, you can override any of the methods that the wrapped objects expose.
By default, the HttpServletRequestWrapper passes all method calls to the HttpServletRequest object that it wraps. To override the request methods (such as isUserInRole or getRemoteUser), you create a wrapper, implement those methods in the wrapper, and then call those overridden methods on the wrapper.
By default, the HttpServletResponseWrapper passes all method calls to the HttpServletResponse object that it wraps. To override the response methods (such as getWriter or getLocale), you call those overridden methods on the wrapper.
Regardless of whether a request or response has been wrapped, other filters in the chain treat the object as any other request or response. They cannot determine if it is wrapped or not.
To determine if an object is a wrapper, you can use the instanceOf operator.
Send me an e-mail when comments are added to this page | Comment Report
Current page: http://livedocs.adobe.com/jrun/4/Programmers_Guide/filters4.htm