UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

415 lines (387 loc) 51.4 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title>Servlet Filters</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Servlet Filters"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-15-SECT-4"/>Servlet Filters</h1></div></div></div><p><a id="idx10892" class="indexterm"/>The servlet Filter API generalizes the Java Servlet API to allow modular component “filters” to operate on the servlet request and responses in a sort of pipeline. Filters are <span class="emphasis"><em>chained</em></span>, meaning that when more than one filter is applied, the servlet request is passed through each filter in succession, with each having an opportunity to act upon or modify the request before passing it to the next filter. Similarly, upon completion, the servlet result is effectively passed back through the chain on its return trip to the browser. Servlet filters may operate on any requests to a web application, not just those handled by the servlets; they may filter static content, as well. You can also control whether filters are applied to error and welcome pages as well as pages forwarded or included using the request dispatcher (from servlet to servlet).</p><p>Filters can be declared and mapped to servlets in the <span class="emphasis"><em>web.xml</em></span> file or using annotations. There are two ways to map a filter: using a URL pattern like those used for servlets or by specifying a servlet by its servlet name as defined in its servlet config. Filters obey the same basic rules as servlets when it comes to URL matching, but when multiple filters match a path, they are each invoked.</p><p>When using <span class="emphasis"><em>web.xml</em></span>, the order of the chain is determined by the order in which matching filter mappings appear in the <span class="emphasis"><em>web.xml</em></span> file, with <a id="I_indexterm15_id782226" class="indexterm"/><code class="literal">&lt;url-pattern&gt;</code> matches taking precedence over <a id="I_indexterm15_id782240" class="indexterm"/><code class="literal">&lt;servlet-name&gt;</code> matches. This is contrary to the way in which servlet URL matching is done, with specific matches taking the highest priority. Filter chains are constructed as follows. First, each filter with a matching URL pattern is called in the order in which it appears in the <span class="emphasis"><em>web.xml</em></span> file; next, each filter with a matching servlet name is called, also in order of appearance. URL patterns take a higher priority than filters specifically associated with a servlet, so in this case, patterns such as <code class="literal">/*</code> have first crack at an incoming request.</p><p>Servlet filters may be declared and mapped using the <a id="I_indexterm15_id782270" class="indexterm"/><code class="literal">WebFilter</code> annotation. There is no corresponding way to control filter ordering using annotations; however, as always you can mix annotations and <span class="emphasis"><em>web.xml</em></span> to minimize the XML configuration by only declaring the filter mappings in the XML. (We’ll discuss configuration more later in this chapter.)</p><p>The Filter API is very simple and mimics the Servlet API. A servlet filter implements the <a id="I_indexterm15_id782293" class="indexterm"/><code class="literal">javax.servlet.Filter</code> interface and implements three methods: <code class="literal">init()</code>, <code class="literal">doFilter()</code>, and <code class="literal">destroy()</code>. The <code class="literal">doFilter()</code> method is where the work is performed. For each incoming request, the <code class="literal">ServletRequest</code> and <code class="literal">ServletResponse</code> objects are passed to <code class="literal">doFilter()</code>. Here, we have a chance to examine and modify these objects—or even substitute our own objects for them—before passing them to the next filter and, ultimately, the servlet (or user) on the other side. Our link to the rest of the filter chain is another parameter of <code class="literal">doFilter()</code>, the <code class="literal">FilterChain</code> object. With <code class="literal">FilterChain</code>, we can invoke the next element in the pipeline. The following section presents an example.</p><div class="sect2" title="A Simple Filter"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-4.1"/>A Simple Filter</h2></div></div></div><p><a id="idx10865" class="indexterm"/>For our first filter, we’ll do something easy but practical: create a filter that limits the number of concurrent connections to its URLs. We’ll simply have our filter keep a counter of the active connections passing through it and turn away new requests when they exceed a specified limit:</p><a id="I_15_tt953"/><pre class="programlisting"><code class="kn">import</code> <code class="nn">java.io.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.annotation.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.http.*</code><code class="o">;</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">ConLimitFilter</code> <code class="kd">implements</code> <code class="n">Filter</code> <code class="o">{</code> <code class="kt">int</code> <code class="n">limit</code><code class="o">;</code> <code class="kd">volatile</code> <code class="kt">int</code> <code class="n">count</code><code class="o">;</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">init</code><code class="o">(</code> <code class="n">FilterConfig</code> <code class="n">filterConfig</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">ServletException</code> <code class="o">{</code> <code class="n">String</code> <code class="n">s</code> <code class="o">=</code> <code class="n">filterConfig</code><code class="o">.</code><code class="na">getInitParameter</code><code class="o">(</code><code class="s">"limit"</code><code class="o">);</code> <code class="k">if</code> <code class="o">(</code> <code class="n">s</code> <code class="o">==</code> <code class="kc">null</code> <code class="o">)</code> <code class="k">throw</code> <code class="k">new</code> <code class="nf">ServletException</code><code class="o">(</code><code class="s">"Missing init parameter: "</code><code class="o">+</code><code class="n">limit</code><code class="o">);</code> <code class="n">limit</code> <code class="o">=</code> <code class="n">Integer</code><code class="o">.</code><code class="na">parseInt</code><code class="o">(</code> <code class="n">s</code> <code class="o">);</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">doFilter</code> <code class="o">(</code> <code class="n">ServletRequest</code> <code class="n">req</code><code class="o">,</code> <code class="n">ServletResponse</code> <code class="n">res</code><code class="o">,</code> <code class="n">FilterChain</code> <code class="n">chain</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">IOException</code><code class="o">,</code> <code class="n">ServletException</code> <code class="o">{</code> <code class="k">if</code> <code class="o">(</code> <code class="n">count</code> <code class="o">&gt;</code> <code class="n">limit</code> <code class="o">)</code> <code class="o">{</code> <code class="n">HttpServletResponse</code> <code class="n">httpRes</code> <code class="o">=</code> <code class="o">(</code><code class="n">HttpServletResponse</code><code class="o">)</code><code class="n">res</code><code class="o">;</code> <code class="n">httpRes</code><code class="o">.</code><code class="na">sendError</code><code class="o">(</code> <code class="n">httpRes</code><code class="o">.</code><code class="na">SC_SERVICE_UNAVAILABLE</code><code class="o">,</code> <code class="s">"Too Busy."</code><code class="o">);</code> <code class="o">}</code> <code class="k">else</code> <code class="o">{</code> <code class="o">++</code><code class="n">count</code><code class="o">;</code> <code class="n">chain</code><code class="o">.</code><code class="na">doFilter</code><code class="o">(</code> <code class="n">req</code><code class="o">,</code> <code class="n">res</code> <code class="o">);</code> <code class="o">--</code><code class="n">count</code><code class="o">;</code> <code class="o">}</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">destroy</code><code class="o">()</code> <code class="o">{</code> <code class="o">}</code> <code class="o">}</code></pre><p><code class="literal">ConLimitFilter</code> implements the three lifecycle methods of the <code class="literal">Filter</code> interface: <code class="literal">init()</code>, <code class="literal">doFilter()</code>, and <code class="literal">destroy()</code>. In our <code class="literal">init()</code> method, we use the <code class="literal">FilterConfig</code> object to look for an initialization parameter named “limit” and turn it into an integer. Users can set this value in the section of the <span class="emphasis"><em>web.xml</em></span> file where the instance of our filter is declared or in the annotation as shown. The <code class="literal">doFilter()</code> method implements all our logic. First, it receives <code class="literal">ServletRequest</code> and <code class="literal">ServletResponse</code> object pairs for incoming requests. Depending on the counter, it then either passes them down the chain by invoking the next <code class="literal">doFilter()</code> method on the <code class="literal">FilterChain</code> object, or rejects them by generating its own response. We use the standard HTTP message “504 Service Unavailable” when we deny new connections.</p><p>Calling <code class="literal">doFilter()</code> on the <code class="literal">FilterChain</code> object continues processing by invoking the next filter in the chain or by invoking the servlet if ours is the last filter. Alternatively, when we choose to reject the call, we use the <code class="literal">ServletResponse</code> to generate our own response and then simply allow <code class="literal">doFilter()</code> to exit. This stops the processing chain at our filter, although any filters called before us still have an opportunity to intervene as the request effectively traverses back to the client.</p><p>Notice that <code class="literal">ConLimitFilter</code> increments the count before calling <code class="literal">doFilter()</code> and decrements it after. Prior to calling <code class="literal">doFilter()</code>, we can work on the request before it reaches the rest of the chain and the servlet. After the call to <code class="literal">doFilter()</code>, the chain to the servlet has completed, and the request is sent back to the client. This is our opportunity to do any post-processing of the response.</p><p>Finally, we should mention that although we’ve been talking about the servlet request and response as if they were <code class="literal">HttpServletRequest</code> and <code class="literal">HttpServletResponse</code>, the <code class="literal">doFilter()</code> method actually takes the more generic <a id="I_indexterm15_id782561" class="indexterm"/><code class="literal">ServletRequest</code> and <a id="I_indexterm15_id782571" class="indexterm"/><code class="literal">ServletResponse</code> objects as parameters. As filter implementers, we are expected to determine when it is safe to treat them as HTTP traffic and perform the cast as necessary (which we do here in order to use the <code class="literal">sendError()</code> HTTP response method).<a id="I_indexterm15_id782589" class="indexterm"/></p></div><div class="sect2" title="A Test Servlet"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-4.2"/>A Test Servlet</h2></div></div></div><p><a id="idx10866" class="indexterm"/>Before we go on, here is a simple test servlet you can use to try out this filter and the other filters we’ll develop in this section. It’s called <code class="literal">WaitServlet</code> and, as its name implies, it simply waits. You can specify how long it waits as a number of seconds with the servlet parameter <code class="literal">time</code>. (This is the “dumb” version of the <code class="literal">BackgroundWaitServlet</code> that we created earlier in this chapter when discussing asynchronous servlets.)</p><a id="I_15_tt954"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.io.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.http.*</code><code class="o">;</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">WaitServlet</code> <code class="kd">extends</code> <code class="n">HttpServlet</code> <code class="o">{</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">doGet</code><code class="o">(</code> <code class="n">HttpServletRequest</code> <code class="n">request</code><code class="o">,</code> <code class="n">HttpServletResponse</code> <code class="n">response</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">ServletException</code><code class="o">,</code> <code class="n">IOException</code> <code class="o">{</code> <code class="n">String</code> <code class="n">waitStr</code> <code class="o">=</code> <code class="n">request</code><code class="o">.</code><code class="na">getParameter</code><code class="o">(</code><code class="s">"time"</code><code class="o">);</code> <code class="k">if</code> <code class="o">(</code> <code class="n">waitStr</code> <code class="o">==</code> <code class="kc">null</code> <code class="o">)</code> <code class="k">throw</code> <code class="k">new</code> <code class="nf">ServletException</code><code class="o">(</code><code class="s">"Missing parameter: time"</code><code class="o">);</code> <code class="kt">int</code> <code class="n">wait</code> <code class="o">=</code> <code class="n">Integer</code><code class="o">.</code><code class="na">parseInt</code><code class="o">(</code><code class="n">waitStr</code><code class="o">);</code> <code class="k">try</code> <code class="o">{</code> <code class="n">Thread</code><code class="o">.</code><code class="na">sleep</code><code class="o">(</code> <code class="n">wait</code> <code class="o">*</code> <code class="mi">1000</code> <code class="o">);</code> <code class="o">}</code> <code class="k">catch</code><code class="o">(</code> <code class="n">InterruptedException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="k">throw</code> <code class="k">new</code> <code class="nf">ServletException</code><code class="o">(</code><code class="n">e</code><code class="o">);</code> <code class="o">}</code> <code class="n">response</code><code class="o">.</code><code class="na">setContentType</code><code class="o">(</code><code class="s">"text/html"</code><code class="o">);</code> <code class="n">PrintWriter</code> <code class="n">out</code> <code class="o">=</code> <code class="n">response</code><code class="o">.</code><code class="na">getWriter</code><code class="o">();</code> <code class="n">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="s">"&lt;html&gt;&lt;body&gt;&lt;h1&gt;WaitServlet Response&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;"</code><code class="o">);</code> <code class="n">out</code><code class="o">.</code><code class="na">close</code><code class="o">();</code> <code class="o">}</code> <code class="o">}</code></pre><p>By making multiple simultaneous requests to the <code class="literal">WaitServlet</code>, you can try out the <code class="literal">ConLimitFilter</code>. Note that some web browsers won’t open multiple requests to the same URL or may delay opening multiple tabs. You may have to add extraneous parameters to trick the web browser. Alternately, you may wish to use the <a id="I_indexterm15_id782679" class="indexterm"/><span class="emphasis"><em>curl</em></span> command-line utility to make the requests if you have it.<a id="I_indexterm15_id782688" class="indexterm"/></p></div><div class="sect2" title="Declaring and Mapping Filters"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-4.3"/>Declaring and Mapping Filters</h2></div></div></div><p><a id="idx10853" class="indexterm"/> <a id="idx10862" class="indexterm"/>In the <span class="emphasis"><em>web.xml</em></span> file filters are declared and mapped much as servlets are. Like servlets, one instance of a filter class is created for each filter declaration in the <span class="emphasis"><em>web.xml</em></span> file. A filter declaration looks like this:</p><a id="I_15_tt955"/><pre class="programlisting"> <code class="o">&lt;</code><code class="n">filter</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code><code class="n">defaultsfilter1</code><code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">class</code><code class="o">&gt;</code><code class="n">RequestDefaultsFilter</code><code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">class</code><code class="o">&gt;</code> <code class="o">&lt;/</code><code class="n">filter</code><code class="o">&gt;</code></pre><p>It specifies a filter handle name to be used for reference within the <span class="emphasis"><em>web.xml</em></span> file and the filter’s Java class name. Filter declarations may also contain <a id="I_indexterm15_id782754" class="indexterm"/><code class="literal">&lt;init-param&gt;</code> parameter sections, just like servlet declarations.</p><p>Filters are mapped to resources with <a id="I_indexterm15_id782771" class="indexterm"/><code class="literal">&lt;filter-mapping&gt;</code> declarations that specify the filter handle name and either the specific servlet handle name or a URL pattern, as we discussed earlier:</p><a id="I_15_tt956"/><pre class="programlisting"> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">mapping</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code><code class="n">conlimitfilter1</code><code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">servlet</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code><code class="n">waitservlet1</code><code class="o">&lt;/</code><code class="n">servlet</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code> <code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">mapping</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">mapping</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code><code class="n">conlimitfilter1</code><code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">url</code><code class="o">-</code><code class="n">pattern</code><code class="o">&gt;/*&lt;/</code><code class="n">url</code><code class="o">-</code><code class="n">pattern</code><code class="o">&gt;</code> <code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">mapping</code><code class="o">&gt;</code></pre><p>The corresponding <code class="literal">WebFilter</code> annotation can declare and map filters as well as supply filter parameters. The annotation will accept either a <a id="I_indexterm15_id782806" class="indexterm"/><code class="literal">urlPatterns</code> or a <a id="I_indexterm15_id782816" class="indexterm"/><code class="literal">servletNames</code> attribute for the mapping.<a id="I_indexterm15_id782828" class="indexterm"/><a id="I_indexterm15_id782835" class="indexterm"/></p><a id="I_programlisting15_id782842"/><pre class="programlisting"><code class="nd">@WebFilter</code><code class="o">(</code> <code class="n">urlPatterns</code> <code class="o">=</code> <code class="s">"/*"</code><code class="o">,</code> <code class="n">initParams</code> <code class="o">=</code> <code class="o">{</code> <code class="nd">@WebInitParam</code><code class="o">(</code><code class="n">name</code><code class="o">=</code><code class="s">"limit"</code><code class="o">,</code> <code class="n">value</code><code class="o">=</code><code class="s">"3"</code><code class="o">)</code> <code class="o">}</code> <code class="o">)</code></pre></div><div class="sect2" title="Filtering the Servlet Request"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-4.4"/>Filtering the Servlet Request</h2></div></div></div><p><a id="idx10863" class="indexterm"/>Our first filter example was not very exciting because it did not actually modify any information going to or coming from the servlet. Next, let’s do some actual “filtering” by modifying the incoming request before it reaches a servlet. In this example, we’ll create a request “defaulting” filter that automatically supplies default values for specified servlet parameters when they are not provided in the incoming request. Here is the <code class="literal">RequestDefaultsFilter</code>:</p><a id="I_15_tt957"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.io.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.http.*</code><code class="o">;</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">RequestDefaultsFilter</code> <code class="kd">implements</code> <code class="n">Filter</code> <code class="o">{</code> <code class="n">FilterConfig</code> <code class="n">filterConfig</code><code class="o">;</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">init</code><code class="o">(</code> <code class="n">FilterConfig</code> <code class="n">filterConfig</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">ServletException</code> <code class="o">{</code> <code class="k">this</code><code class="o">.</code><code class="na">filterConfig</code> <code class="o">=</code> <code class="n">filterConfig</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">doFilter</code> <code class="o">(</code> <code class="n">ServletRequest</code> <code class="n">req</code><code class="o">,</code> <code class="n">ServletResponse</code> <code class="n">res</code><code class="o">,</code> <code class="n">FilterChain</code> <code class="n">chain</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">IOException</code><code class="o">,</code> <code class="n">ServletException</code> <code class="o">{</code> <code class="n">WrappedRequest</code> <code class="n">wrappedRequest</code> <code class="o">=</code> <code class="k">new</code> <code class="nf">WrappedRequest</code><code class="o">(</code> <code class="o">(</code><code class="n">HttpServletRequest</code><code class="o">)</code><code class="n">req</code> <code class="o">);</code> <code class="n">chain</code><code class="o">.</code><code class="na">doFilter</code><code class="o">(</code> <code class="n">wrappedRequest</code><code class="o">,</code> <code class="n">res</code> <code class="o">);</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">destroy</code><code class="o">()</code> <code class="o">{</code> <code class="o">}</code> <code class="kd">class</code> <code class="nc">WrappedRequest</code> <code class="kd">extends</code> <code class="n">HttpServletRequestWrapper</code> <code class="o">{</code> <code class="n">WrappedRequest</code><code class="o">(</code> <code class="n">HttpServletRequest</code> <code class="n">req</code> <code class="o">)</code> <code class="o">{</code> <code class="kd">super</code><code class="o">(</code> <code class="n">req</code> <code class="o">);</code> <code class="o">}</code> <code class="kd">public</code> <code class="n">String</code> <code class="nf">getParameter</code><code class="o">(</code> <code class="n">String</code> <code class="n">name</code> <code class="o">)</code> <code class="o">{</code> <code class="n">String</code> <code class="n">value</code> <code class="o">=</code> <code class="kd">super</code><code class="o">.</code><code class="na">getParameter</code><code class="o">(</code> <code class="n">name</code> <code class="o">);</code> <code class="k">if</code> <code class="o">(</code> <code class="n">value</code> <code class="o">==</code> <code class="kc">null</code> <code class="o">)</code> <code class="n">value</code> <code class="o">=</code> <code class="n">filterConfig</code><code class="o">.</code><code class="na">getInitParameter</code><code class="o">(</code> <code class="n">name</code> <code class="o">);</code> <code class="k">return</code> <code class="n">value</code><code class="o">;</code> <code class="o">}</code> <code class="o">}</code> <code class="o">}</code></pre><p>To interpose ourselves in the data flow, we must do something drastic. We kidnap the incoming <code class="literal">HttpServletRequest</code> object and replace it with an imposter that does our bidding. The technique, which we’ll use here for modifying the request object and later for modifying the response, is to wrap the real request with an adapter, allowing us to override some of its methods. Here, we will take control of the <code class="literal">HttpServletRequest</code>’s <code class="literal">getParameter()</code> method, modifying it to look for default values where it would otherwise return <code class="literal">null</code>.</p><p>Again, we implement the three lifecycle methods of <code class="literal">Filter</code>, but this time, before invoking <code class="literal">doFilter()</code> on the filter chain to continue processing, we wrap the incoming <a id="I_indexterm15_id782947" class="indexterm"/><code class="literal">HttpServletRequest</code> in our own class, <code class="literal">WrappedRequest</code>. <code class="literal">WrappedRequest</code> extends a special adapter called <code class="literal">HttpServletRequestWrapper</code>. This wrapper class is a convenience utility that extends <code class="literal">HttpServletRequest</code>. It accepts a reference to a target <code class="literal">HttpServletRequest</code> object and, by default, delegates all of its methods to that target. This makes it very convenient for us to simply override one or more methods of interest to us. All we have to do is override <code class="literal">getParameter()</code> in our <code class="literal">WrappedRequest</code> class and add our functionality. Here, we simply call our parent’s <code class="literal">getParameter()</code>, and in the case where the value is <code class="literal">null</code>, we try to substitute a filter initialization parameter of the same name.</p><p>Try this example using the <code class="literal">WaitServlet</code> with a filter declaration and mapping or annotation as follows:</p><a id="I_15_tt958"/><pre class="programlisting"><code class="o">&lt;</code><code class="n">filter</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code><code class="n">defaultsfilter1</code><code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">class</code><code class="o">&gt;</code><code class="n">RequestDefaultsFilter</code><code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">class</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">init</code><code class="o">-</code><code class="n">param</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">param</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code><code class="n">time</code><code class="o">&lt;/</code><code class="n">param</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">param</code><code class="o">-</code><code class="n">value</code><code class="o">&gt;</code><code class="mi">3</code><code class="o">&lt;/</code><code class="n">param</code><code class="o">-</code><code class="n">value</code><code class="o">&gt;</code> <code class="o">&lt;/</code><code class="n">init</code><code class="o">-</code><code class="n">param</code><code class="o">&gt;</code> <code class="o">&lt;/</code><code class="n">filter</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">mapping</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code><code class="n">defaultsfilter1</code><code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code> <code class="o">&lt;</code><code class="n">servlet</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code><code class="n">waitservlet1</code><code class="o">&lt;/</code><code class="n">servlet</code><code class="o">-</code><code class="n">name</code><code class="o">&gt;</code> <code class="o">&lt;/</code><code class="n">filter</code><code class="o">-</code><code class="n">mapping</code><code class="o">&gt;</code> <code class="nd">@WebFilter</code><code class="o">(</code> <code class="n">servletNames</code> <code class="o">=</code> <code class="s">"waitservlet1"</code><code class="o">,</code> <code class="n">initParams</code> <code class="o">=</code> <code class="o">{</code> <code class="nd">@WebInitParam</code><code class="o">(</code><code class="n">name</code><code class="o">=</code><code class="s">"time"</code><code class="o">,</code> <code class="n">value</code><code class="o">=</code><code class="s">"3"</code><code class="o">)</code> <code class="o">}</code> <code class="o">)</code></pre><p>Now the <code class="literal">WaitServlet</code> receives a default time value of three seconds even when you don’t specify one.<a id="I_indexterm15_id783043" class="indexterm"/></p></div><div class="sect2" title="Filtering the Servlet Response"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-15-SECT-4.5"/>Filtering the Servlet Response</h2></div></div></div><p><a id="idx10864" class="indexterm"/>Filtering the request was fairly easy, and we can do something similar with the response object using exactly the same technique. There is a corresponding <a id="I_indexterm15_id783073" class="indexterm"/><code class="literal">HttpServletResponseWrapper</code> that we can use to wrap the response before the servlet uses it to communicate back to the client. By wrapping the response, we can intercept methods that the servlet uses to write the response, just as we intercepted the <code class="literal">getParameter()</code> method that the servlet used in reading the incoming data. For example, we could override the <code class="literal">sendError()</code> method of the <code class="literal">HttpServletResponse</code> object and modify it to redirect to a specified page. In this way, we could create a servlet filter that emulates the programmable error page control offered in the <span class="emphasis"><em>web.xml</em></span> file. But the most interesting technique available to us, and the one we’ll show here, involves actually modifying the data written by the servlet before it reaches the client. In order to do this, we have to pull a double “switcheroo.” We wrap the servlet response to override the <code class="literal">getWriter()</code> method and then create our own wrapper for the client’s <code class="literal">PrintWriter</code> object supplied by this method, one that buffers the data written and allows us to modify it. This is a useful and powerful technique, but it can be tricky.</p><p>Our example, <code class="literal">LinkResponseFilter</code>, is an automatic hyperlink-generating filter that reads HTML responses and searches them for patterns supplied as regular expressions. When it matches a pattern, it turns it into an HTML link. The pattern and links are specified in the filter initialization parameters. You could extend this example with access to a database or XML file and add more rules to make it into a useful site-management helper. Here it is:</p><a id="I_15_tt959"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.io.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">java.util.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.*</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.servlet.http.*</code><code class="o">;</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">LinkResponseFilter</code> <code class="kd">implements</code> <code class="n">Filter</code> <code class="o">{</code> <code class="n">FilterConfig</code> <code class="n">filterConfig</code><code class="o">;</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">init</code><code class="o">(</code> <code class="n">FilterConfig</code> <code class="n">filterConfig</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">ServletException</code> <code class="o">{</code> <code class="k">this</code><code class="o">.</code><code class="na">filterConfig</code> <code class="o">=</code> <code class="n">filterConfig</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">doFilter</code> <code class="o">(</code> <code class="n">ServletRequest</code> <code class="n">req</code><code class="o">,</code> <code class="n">ServletResponse</code> <code class="n">res</code><code class="o">,</code> <code class="n">FilterChain</code> <code class="n">chain</code> <code class="o">)</code> <code class="kd">throws</code> <code class="n">IOException</code><code class="o">,</code> <code class="n">ServletException</code> <code class="o">{</code> <code class="n">WrappedResponse</code> <code class="n">wrappedResponse</code> <code class="o">=</code> <code class="k">new</code> <code class="nf">WrappedResponse</code><code class="o">(</code> <code class="o">(</code><code class="n">HttpServletResponse</code><code class="o">)</code><code class="n">res</code> <code class="o">);</code> <code class="n">chain</code><code class="o">.</code><code class="na">doFilter</code><code class="o">(</code> <code class="n">req</code><code class="o">,</code> <code class="n">wrappedResponse</code> <code class="o">);</code> <code class="n">wrappedResponse</code><code class="o">.</code><code class="na">close</code><code class="o">();</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">destroy</code><code class="o">()</code> <code class="o">{</code> <code class="o">}</code> <code class="kd">class</code> <code class="nc">WrappedResponse</code> <code class="kd">extends</code> <code class="n">HttpServletResponseWrapper</code> <code class="o">{</code> <code class="kt">boolean</code> <code class="n">linkText</code><code class="o">;</code> <code class="n">PrintWriter</code> <code class="n">client</code><code class="o">;</code> <code class="n">WrappedResponse</code><code class="o">(</code> <code class="n">HttpServletResponse</code> <code class="n">res</code> <code class="o">)</code> <code class="o">{</code> <code class="kd">super</code><code class="o">(</code> <code class="n">res</code> <code class="o">);</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">setContentType</code><code class="o">(</code> <code class="n">String</code> <code class="n">mime</code> <code class="o">)</code> <code class="o">{</code> <code class="kd">super</code><code class="o">.</code><code class="na">setContentType</code><code class="o">(</code> <code class="n">mime</code> <code class="o">);</code> <code class="k">if</code> <code class="o">(</code> <code class="n">mime</code><code class="o">.</code><code class="na">startsWith</code><code class="o">(</code><code class="s">"text/html"</code><code class="o">)</code> <code class="o">)</code> <code class="n">linkText</code> <code class="o">=</code> <code class="kc">true</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="n">PrintWriter</code> <code class="nf">getWriter</code><code class="o">()</code> <code class="kd">throws</code> <code class="n">IOException</code> <code class="o">{</code> <code class="k">if</code> <code class="o">(</code> <code class="n">client</code> <code class="o">==</code> <code class="kc">null</code> <code class="o">)</code> <code class="k">if</code> <code class="o">(</code> <code class="n">linkText</code> <code class="o">)</code> <code class="n">client</code> <code class="o">=</code> <code class="k">new</code> <code class="n">LinkWriter</code><code class="o">(</code> <code class="kd">super</code><code class="o">.</code><code class="na">getWriter</code><code class="o">(),</code> <code class="k">new</code> <code class="n">ByteArrayOutputStream</code><code class="o">()</code> <code class="o">);</code> <code class="k">else</code> <code class="n">client</code> <code class="o">=</code> <code class="kd">super</code><code class="o">.</code><code class="na">getWriter</code><code class="o">();</code> <code class="k">return</code> <code class="n">client</code><code class="o">;</code> <code class="o">}</code> <code class="kt">void</code> <code class="nf">close</code><code class="o">()</code> <code class="o">{</code> <code class="k">if</code> <code class="o">(</code> <code class="n">client</code> <code class="o">!=</code> <code class="kc">null</code> <code class="o">)</code> <code class="n">client</code><code class="o">.</code><code class="na">close</code><code class="o">();</code> <code class="o">}</code> <code class="o">}</code> <code class="kd">class</code> <code class="nc">LinkWriter</code> <code class="kd">extends</code> <code class="n">PrintWriter</code> <code class="o">{</code> <code class="n">ByteArrayOutputStream</code> <code class="n">buffer</code><code class="o">;</code> <code class="n">Writer</code> <code class="n">client</code><code class="o">;</code> <code class="n">LinkWriter</code><code class="o">(</code> <code class="n">Writer</code> <code class="n">client</code><code class="o">,</code> <code class="n">ByteArrayOutputStream</code> <code class="n">buffer</code> <code class="o">)</code> <code class="o">{</code> <code class="kd">super</code><code class="o">(</code> <code class="n">buffer</code> <code class="o">);</code> <code class="k">this</code><code class="o">.</code><code class="na">buffer</code> <code class="o">=</code> <code class="n">buffer</code><code class="o">;</code> <code class="k">this</code><code class="o">.</code><code class="na">client</code> <code class="o">=</code> <code class="n">client</code><code class="o">;</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">close</code><code class="o">()</code> <code class="o">{</code> <code class="k">try</code> <code class="o">{</code> <code class="n">flush</code><code class="o">();</code> <code class="n">client</code><code class="o">.</code><code class="na">write</code><code class="o">(</code> <code class="n">linkText</code><code class="o">(</code> <code class="n">buffer</code><code class="o">.</code><code class="na">toString</code><code class="o">()</code> <code class="o">)</code> <code class="o">);</code> <code class="n">client</code><code class="o">.</code><code class="na">close</code><code class="o">();</code> <code class="o">}</code> <code class="k">catch</code> <code class="o">(</code> <code class="n">IOException</code> <code class="n">e</code> <code class="o">)</code> <code class="o">{</code> <code class="n">setError</code><code class="o">();</code> <code class="o">}</code> <code class="o">}</code> <code class="n">String</code> <code class="nf">linkText</code><code class="o">(</code> <code class="n">String</code> <code class="n">text</code> <code class="o">)</code> <code class="o">{</code> <code class="n">Enumeration</code> <code class="n">en</code> <code class="o">=</code> <code class="n">filterConfig</code><code class="o">.</code><code class="na">getInitParameterNames</code><code class="o">();</code> <code class="k">while</code> <code class="o">(</code> <code class="n">en</code><code class="o">.</code><code class="na">hasMoreElements</code><code class="o">()</code> <code class="o">)</code> <code class="o">{</code> <code class="n">String</code> <code class="n">pattern</code> <code class="o">=</code> <code class="o">(</code><code class="n">String</code><code class="o">)</code><code class="n">en</code><code class="o">.</code><code class="na">nextElement</code><code class="o">();</code> <code class="n">String</code> <code class="n">value</code> <code class="o">=</code> <code class="n">filterConfig</code><code class="o">.</code><code class="na">getInitParameter</code><code class="o">(</code> <code class="n">pattern</code> <code class="o">);</code> <code class="n">text</code> <code class="o">=</code> <code class="n">text</code><code class="o">.</code><code class="na">replaceAll</code><code class="o">(</code> <code class="n">pattern</code><code class="o">,</code> <code class="s">"&lt;a href="</code><code class="o">+</code><code class="n">value</code><code class="o">+</code><code class="s">"&gt;$0&lt;/a&gt;"</code> <code class="o">);</code> <code class="o">}</code> <code class="k">return</code> <code class="n">text</code><code class="o">;</code> <code class="o">}</code> <code class="o">}</code> <code class="o">}</code></pre><p>That was a bit longer than our previous examples, but the basics are the same. We wrapped the <code class="literal">HttpServletResponse</code> object with our own <code class="literal">WrappedResponse</code> class using the <code class="literal">HttpServletResponseWrapper</code> helper class. Our <code class="literal">WrappedResponse</code> overrides two methods: <code class="literal">getWriter()</code> and <code class="literal">setContentType()</code>. We override <code class="literal">setContentType()</code> in order to set a flag that indicates whether the output is of type “text/html” (an HTML document). We don’t want to be performing regular-expression replacements on binary data such as images, for example, should they happen to match our filter. We also override <code class="literal">getWriter()</code> to provide our substitute writer stream, <code class="literal">LinkWriter</code>. Our <code class="literal">LinkWriter</code> class is a <code class="literal">PrintStream</code> that takes as arguments the client <code class="literal">PrintWriter</code> and a <code class="literal">ByteArrayOutputStream</code> that serves as a buffer for storing output data before it is written. We are careful to substitute our <code class="literal">LinkWriter</code> only if the <code class="literal">linkText</code> Boolean set by <code class="literal">setContent()</code> is <code class="literal">true</code>. When we do use our <code class="literal">LinkWriter</code>, we cache the stream so that any subsequent calls to <code class="literal">getWriter()</code> return the same object. Finally, we have added one method to the response object: <code class="literal">close()</code>. A normal <a id="I_indexterm15_id783312" class="indexterm"/><code class="literal">HttpServletResponse</code> does not have a <code class="literal">close()</code> method. We use ours on the return trip to the client to indicate that the <code class="literal">LinkWriter</code> should complete its processing and write the actual data to the client. We do this in case the client does not explicitly close the output stream before exiting the servlet service methods.</p><p>This explains the important parts of our filter-writing example. Let’s wrap up by looking at the <code class="literal">LinkWriter</code>, which does the magic in this example. <code class="literal">LinkWriter</code> is a <code class="literal">PrintStream</code> that holds references to two other <code class="literal">Writers</code>: the true client <code class="literal">PrintWriter</code> and a <a id="I_indexterm15_id783368" class="indexterm"/><code class="literal">ByteArrayOutputStream</code>. The <code class="literal">LinkWriter</code> calls its superclass constructor, passing the <code class="literal">ByteArrayOutputStream</code> as the target stream, so all of its default functionality (its <code class="literal">print()</code> methods) writes to the byte array. Our only real job is to intercept the <code class="literal">close()</code> method of the <code class="literal">PrintStream</code> and add our text linking before sending the data. When <code class="literal">LinkWriter</code> is closed, it flushes itself to force any data buffered in its superclass out to the <code class="literal">ByteArrayOutputStream</code>. It then retrieves the buffered data (with the <code class="literal">ByteArrayOutputStream toString()</code> metho