805 OCPJP 6 Questions 788 SCJP 5 questions 650 OCPJWCD 5 questions 600 OCAJP 7 questions 610 OCPJP 7 questions 510 Upgrade to OCPJP 7 questions 900 Java J2EE Qns

Tutorials

SCWCD : Servlet Filter

Describe the Web container request processing model; write and configure a filter; create a request or response wrapper; and given a design problem, describe how to apply a filter or a wrapper.

Request processing model.

The container, when receiving an incoming request, processes the request as follows:

  • Identifies the target Web resource according to the rules of mappings.

  • If there are filters matched by servlet name and the Web resource has a <servlet-name>, the container builds the chain of filters matching in the order declared in the deployment descriptor. The last filter in this chain corresponds to the last <servlet-name> matching filter and is the filter that invokes the target Web resource.

  • If there are filters using <url-pattern> matching and the <url-pattern> matches the request URI according to the rules of mappings, the container builds the chain of <url-pattern> matched filters in the same order as declared in the deployment descriptor. The last filter in this chain is the last <url-pattern> matching filter in the deployment descriptor for this request URI. The last filter in this chain is the filter that invokes the first filter in the <servlet-name> matching chain, or invokes the target Web resource if there are none.

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.

Writing and configuring a filter.

Filters are Java components that allow on the fly transformations of payload and header information in both the request into a resource and the response from a resource. Filters differ from Web components in that they usually do not themselves create a response. Instead, a filter provides functionality that can be "attached" to any kind of Web resource. As a consequence, a filter should not have any dependencies on a Web resource for which it is acting as a filter, so that it can be composable with more than one type of Web resource.

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.

The main tasks that a filter can perform are as follows:

  • Query the request and act accordingly.

  • Block the request-and-response pair from passing any further.

  • Modify the request headers and data. You do this by providing a customized version of the request.

  • Modify the response headers and data. You do this by providing a customized version of the response.

  • Interact with external resources.

You can configure a Web resource to be filtered by a chain of zero, one, or more filters in a specific order. This chain is specified when the Web application containing the component is deployed and is instantiated when a Web container loads the component.

The filtering API is defined by the Filter, FilterChain, and FilterConfig interfaces in the javax.servlet package.

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 mapping to a group of servlets and static content resources by mapping a filter to a URL pattern.

package javax.servlet;

public interface Filter {
	public void init(FilterConfig filterConfig) throws ServletException;
	public void doFilter(ServletRequest request, ServletResponse response,
		FilterChain chain) throws java.io.IOException, ServletException;
	public void destroy();

}
					

The most important method in this interface is the doFilter method, which is passed request, response, and filter chain objects. This method can perform the following actions:

  • Examine the request headers.

  • Customize the request object if it wishes to modify request headers or data.

  • Customize the response object if it wishes to modify response headers or data.

  • Invoke the next entity in the filter chain. If the current filter is the last filter in the chain that ends with the target Web component or static resource, the next entity is the resource at the end of the chain; otherwise, it is the next filter that was configured in the WAR. It invokes the next entity by calling the doFilter method on the chain object (passing in the request and response it was called with, or the wrapped versions it may have created). Alternatively, it can choose to block the request by not making the call to invoke the next entity. In the latter case, the filter is responsible for filling out the response.

  • Examine response headers after it has invoked the next filter in the chain.

  • Throw an exception to indicate an error in processing.

In addition to doFilter, you must implement the init and destroy methods. The init method is called by the container when the filter is instantiated. If you wish to pass initialization parameters to the filter, you retrieve them from the FilterConfig object passed to init.

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 per Java Virtual Machine (JVM) of 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.

public final class ExampleFilter implements Filter {
	private String attribute = null;
	private FilterConfig filterConfig = null;

	public void init(FilterConfig filterConfig) throws ServletException {
		this.filterConfig = filterConfig;
		this.attribute = filterConfig.getInitParameter("attribute");
	}

	public void doFilter(ServletRequest request, ServletResponse response,
		FilterChain chain) throws IOException, ServletException {

		// Store ourselves as a request attribute (if requested)
		if (attribute != null) {
			request.setAttribute(attribute, this);
		}

		// Time and log the subsequent processing
		long startTime = System.currentTimeMillis();
		chain.doFilter(request, response);
		long stopTime = System.currentTimeMillis();
		filterConfig.getServletContext().log
			(this.toString() + ": " + (stopTime - startTime) +
			" milliseconds");
	}

	public void destroy() {
		this.attribute = null;
		this.filterConfig = null;
	}

}
					

<web-app>
	...
	<!-- Define servlet-mapped and path-mapped example filters -->
	<filter>
		<filter-name>Servlet Mapped Filter</filter-name>
		<filter-class>filters.ExampleFilter</filter-class>
		<init-param>
			<param-name>attribute</param-name>
			<param-value>filters.ExampleFilter.SERVLET_MAPPED</param-value>
		</init-param>
	</filter>

	<filter>
		<filter-name>Path Mapped Filter</filter-name>
		<filter-class>filters.ExampleFilter</filter-class>
		<init-param>
			<param-name>attribute</param-name>
			<param-value>filters.ExampleFilter.PATH_MAPPED</param-value>
		</init-param>
	</filter>

	<!-- Define filter mappings for the defined filters -->
	<filter-mapping>
		<filter-name>Servlet Mapped Filter</filter-name>
		<servlet-name>invoker</servlet-name>
	</filter-mapping>

	<filter-mapping>
		<filter-name>Path Mapped Filter</filter-name>
		<url-pattern>/servlet/*</url-pattern>
	</filter-mapping>
	...
</web-app>

					

Here is another 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 and static resources 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 groups of servlets and static content using the url-pattern style of filter mapping:


<filter-mapping>
	<filter-name>Logging Filter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

					
Here the Logging Filter is applied to all the servlets and static content pages in the Web application, because every request URI matches the '/*' URL pattern.

The url-pattern matching takes precedence (is applied first) over the servlet-name matching (is applied next).


<!--
Declares a filter in the web application. The filter is mapped to
either a servlet or a URL pattern in the filter-mapping element,
using the filter-name value to reference. Filters can access the
initialization parameters declared in the deployment descriptor at
runtime via the FilterConfig interface.

Used in: web-app
-->

<!ELEMENT filter (icon?, filter-name, display-name?, description?,
	filter-class, init-param*)>

					

<!--
Declaration of the filter mappings in this web application. The
container uses the filter-mapping declarations to decide which
filters to apply to a request, and in what order. The container
matches the request URI to a Servlet in the normal way. To determine
which filters to apply it matches filter-mapping declarations either
on servlet-name, or on url-pattern for each filter-mapping element,
depending on which style is used. The order in which filters are
invoked is the order in which filter-mapping declarations that match
a request URI for a servlet appear in the list of filter-mapping
elements.The filter-name value must be the value of the <filter-name>
sub-elements of one of the <filter> declarations in the deployment
descriptor.

Used in: web-app
-->

<!ELEMENT filter-mapping (filter-name, (url-pattern | servlet-name), dispatcher*)>

					
The dispatcher has four legal values: FORWARD, REQUEST, INCLUDE, and ERROR. A value of FORWARD means the Filter will be applied under RequestDispatcher.forward() calls. A value of REQUEST means the Filter will be applied under ordinary client calls to the PATH or SERVLET. A value of INCLUDE means the Filter will be applied under RequestDispatcher.include() calls. A value of ERROR means the Filter will be applied under the error page mechanism. The absence of any dispatcher elements in a filter-mapping indicates a default of applying filters only under ordinary client calls to the PATH or SERVLET (REQUEST).

<filter-mapping>
	<filter-name>Logging Filter</filter-name>
	<url-pattern>/products/*</url-pattern>
	<dispatcher>FORWARD</dispatcher>
	<dispatcher>REQUEST</dispatcher>
</filter-mapping>

					
This example would result in the Logging Filter being invoked by client requests starting /products/... and underneath a request dispatcher forward() call where the request dispatcher has path commencing /products/....

Wrapping request and response objects.

As well as performing basic pre and post processing operations a filter can also wrap up the request or response objects in a custom wrapper. Such custom wrappers can then modify the information provided to the servlet via a request object or process information generated by the servlet via the response object. There are four classes that make up the Wrapping API. These are the javax.servlet.ServletRequestWrapper, javax.servlet.ServletResponseWrapper, javax.servlet.http.HttpServletRequestWrapper and javax.servlet.http.HttpServletResponseWrapper. These classes implement the respective interfaces (e.g. ServletRequest, ServletResponse, HttpServletRequest and HttpServletResponse) and can thus be used anywhere that these interfaces are specified. Most notably they can therefore be used inside a Filter to wrap the actual request or response object up so that the filter can control either the data accessed by the Servlet (or JSP) or generated by the Servlet or JSP. A particular use of these wrappers is to perform some pre or post processing of the data being used or generated by the Servlet so that the Servlet does not need to know about this processing.

A filter that modifies a response must usually capture the response before it is returned to the client. The way to do this is to pass a stand-in stream to the servlet that generates the response. The stand-in stream prevents the servlet from closing the original response stream when it completes and allows the filter to modify the servlet's response.

To pass this stand-in stream to the servlet, the filter creates a response wrapper that overrides the getWriter or getOutputStream method to return this stand-in stream. The wrapper is passed to the doFilter method of the filter chain. Wrapper methods default to calling through to the wrapped request or response object. This approach follows the well-known Wrapper or Decorator pattern described in 'Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1995)'.

To override request methods, you wrap the request in an object that extends ServletRequestWrapper or HttpServletRequestWrapper. To override response methods, you wrap the response in an object that extends ServletResponseWrapper or HttpServletResponseWrapper.

Example of filter with wrapper (post processing of servlet's output):


public final class HitCounterFilter implements Filter {
	private FilterConfig filterConfig = null;

	public void init(FilterConfig filterConfig) 
			throws ServletException {
		this.filterConfig = filterConfig;
	}

	public void doFilter(ServletRequest request, ServletResponse response, 
			FilterChain chain) throws IOException, ServletException {
		StringWriter sw = new StringWriter();
		PrintWriter writer = new PrintWriter(sw);
		Counter counter = (Counter)filterConfig.getServletContext().
			getAttribute("hitCounter");
		writer.println();
		writer.println("===============");
		writer.println("The number of hits is: " + counter.incCounter());
		writer.println("===============");
		// Log the resulting string
		writer.flush();
		filterConfig.getServletContext().log(sw.getBuffer().toString());

		PrintWriter out = response.getWriter();
		CharResponseWrapper wrapper = 
			new CharResponseWrapper((HttpServletResponse)response); 
		chain.doFilter(request, wrapper);
		CharArrayWriter caw = new CharArrayWriter();
		caw.write(wrapper.toString().
			substring(0, wrapper.toString().indexOf("</body>")-1));
		caw.write("<p>\n<center><center>" + 
			messages.getString("Visitor") + 
			"<font color='red'>" + counter.getCounter() + 
			"</font><center>");
		caw.write("\n</body></html>");
		response.setContentLength(caw.toString().length());
		out.write(caw.toString());        
		out.close();
	}

	public void destroy() {
		this.filterConfig = null;
	}
}

					
public class CharResponseWrapper extends HttpServletResponseWrapper {
    private CharArrayWriter output;

    public String toString() {
        return output.toString();
    }
      
    public CharResponseWrapper(HttpServletResponse response) {
        super(response);
        output = new CharArrayWriter();
    }

    public PrintWriter getWriter() {
        return new PrintWriter(output);
    }
}
					
HitCounterFilter wraps the response in a CharResponseWrapper. The wrapped response is passed to the next object in the filter chain. Next servlet writes (buffers) its response into the stream created by CharResponseWrapper. When chain.doFilter returns, HitCounterFilter retrieves the servlet's response from PrintWriter and writes it to a buffer (CharArrayWriter). The filter inserts the value of the counter into the buffer, resets the content length header of the response, and finally writes the contents of the buffer to the response stream.

scjp 1.5 | scjp 1.6 | scwcd 1.5
Java Certifications
www.javacertifications.net