9.10. Example: A Replacement Filter

This section presents one common application of the CharArrayWrapper shown in the previous section: a filter that changes all occurrences of a target string to some replacement string.

A Generic Replacement Filter

Listing 9.15 presents a filter that wraps the response in a CharArrayWrapper, passes that wrapper to the doFilter method of the FilterChain object, extracts a String that represents all of the resource’s output, replaces all occurrences of a target string with a replacement string, and sends that modified result to the client.

There are two things to note about this filter. First, it is an abstract class. To use it, you must create a subclass that provides implementations of the getTargetString and getReplacementString methods. The next subsection has an example of this process. Second, it uses a small utility class (Listing 9.16) to do the actual string substitution. If you are fortunate enough to be using JDK 1.4, you can use the new regular expression package instead of the low-level and cumbersome methods in the String and StringTokenizer classes. For details, see http://java.sun.com/j2se/1.4/docs/api/java/util/regex/Matcher.html and http://java.sun.com/j2se/1.4/docs/api/java/util/regex/Pattern.html. Just remember that use of this package limits portability; the servlet 2.3 specification mandates the Java 2 Platform but does not specify any particular JDK version within that general umbrella.

Listing 9.15. ReplaceFilter.java
package moreservlets.filters; 

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 
import java.util.*; 

/** Filter that replaces all occurrences of a given 
 *  string with a replacement. This is an abstract class: 
 *  you <I>must</I> override the getTargetString and 
 *  getReplacementString methods in a subclass. The 
 *  first of these methods specifies the string in 
 *  the response that should be replaced. The second 
 *  of these specifies the string that should replace 
 *  each occurrence of the target string. 
 */ 

public abstract class ReplaceFilter implements Filter {
  private FilterConfig config; 

  public void doFilter(ServletRequest request, 
                       ServletResponse response, 
                       FilterChain chain) 
      throws ServletException, IOException {
    CharArrayWrapper responseWrapper =
							new CharArrayWrapper((HttpServletResponse)response); 
    // Invoke resource, accumulating output in the wrapper. 
    chain.doFilter(request,responseWrapper); 
    // Turn entire output into one big String. 
    String responseString = responseWrapper.toString(); 
    // In output, replace all occurrences of target string 
    // with replacement string. 
    responseString =
							FilterUtils.replace(responseString,
							getTargetString(),
							getReplacementString()); 
    // Update the Content-Length header. 
    updateHeaders(response, responseString); 
    PrintWriter out = response.getWriter();
							out.write(responseString); 
  } 

  /** Store the FilterConfig object in case subclasses 
   *  want it. 
   */ 

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

  protected FilterConfig getFilterConfig() {
    return(config); 
  } 

  public void destroy() {} 

  /** The string that needs replacement. 
   *  Override this method in your subclass. 
   */ 

  public abstract String getTargetString(); 

  /** The string that replaces the target. 
   *  Override this method in your subclass. 
   */ 

  public abstract String getReplacementString(); 
  /** Updates the response headers. This simple version just sets 
   *  the Content-Length header, assuming that we are using a 
   *  character set that uses 1 byte per character. For other 
   *  character sets, override this method to use different logic 
   *  or to give up on persistent HTTP connections. In this latter 
   *  case, have this method set the Connection header to "close". 
   */ 

  public void updateHeaders(ServletResponse response, 
                            String responseString) {
    response.setContentLength(responseString.length()); 
  } 
} 

Listing 9.16. FilterUtils.java
package moreservlets.filters; 

/** Small utility to assist with response wrappers that 
 *  return strings. 
 */ 

public class FilterUtils {

  /** Change all occurrences of orig in mainString to 
   *  replacement. 
   */ 

  public static String replace(String mainString, 
                               String orig, 
                               String replacement) {
    String result = ""; 
    int oldIndex = 0; 
    int index = 0; 
    int origLength = orig.length(); 
    while((index = mainString.indexOf(orig, oldIndex)) 
          != -1) {
      result = result + 
               mainString.substring(oldIndex, index) + 
               replacement; 
      oldIndex = index + origLength; 
    } 
    result = result + mainString.substring(oldIndex); 
    return(result); 
  } 
} 

A Specific Replacement Filter

Oh no! A competitor bought out filtersRus.com. All the Web pages that refer to the company name are now obsolete. But, the developers hate to change all their Web pages since another takeover could occur anytime (this company is a hot commodity, after all). No problem— Listing 9.17 presents a filter that replaces all occurrences of filtersRus.com with weBefilters.com. Figure 9-7 shows a page (Listing 9.19) that promotes the filtersRus.com site name. Figure 9-8 shows the page after the filter is applied.

Figure 9-7. A page that promotes the filtersRus.com site.


Figure 9-8. The page that promotes the filtersRus.com site after its output is modified by the ReplaceSiteNameFilter.


To implement this functionality, the filter has the following capabilities.

  1. A class that implements the Filter interface. This class is called ReplaceSiteNameFilter and is shown in Listing 9.17. It extends the generic ReplaceFilter of Listing 9.15. The inherited init method stores the FilterConfig object in a field in case subclasses need access to the servlet context or filter name. The parent class also provides an empty body for the destroy method.

  2. A wrapped response object. The doFilter method, inherited from ReplaceFilter, wraps the ServletResponse object in a CharArrayWrapper and passes that wrapper to the doFilter method of the FilterChain object. After this call completes, all other filters and the final resource have executed and the output is inside the wrapper. So, the original doFilter extracts a String that represents all of the resource’s output and replaces all occurrences of the target string with the replacement string. Finally, doFilter sends that modified result to the client by supplying the entire String to the write method of the PrintWriter that is associated with the original response.

  3. Registration with the JSP page that promotes filtersRus.com. First, the filter element of web.xml (Listing 9.18) associates the name ReplaceSiteNameFilter with the class moreservlets.filters.ReplaceSiteNameFilter. Next, the filter-mapping element uses a url-pattern of /plugSite/page2.jsp (see Listing 9.19) so that the filter fires each time that JSP page is requested.

  4. Disablement of the invoker servlet. This operation is shown in Section 9.2 and is not repeated here.

Listing 9.17. ReplaceSiteNameFilter.java
package moreservlets.filters; 

public class ReplaceSiteNameFilter extends ReplaceFilter {
  public String getTargetString() {
    return("filtersRus.com"); 
  } 

  public String getReplacementString() {
    return("weBefilters.com"); 
  } 
} 

Listing 9.18. web.xml (Excerpt for site name replacement filter)
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app PUBLIC 
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
    "http://java.sun.com/dtd/web-app_2_3.dtd"> 
<web-app> 
  <!-- ... --> 

  <!-- Register the name "ReplaceSiteNameFilter" for 
       moreservlets.filters.ReplaceSiteNameFilter. 
  --> 
  <filter> 
    <filter-name>ReplaceSiteNameFilter</filter-name> 
    <filter-class> 
      moreservlets.filters.ReplaceSiteNameFilter 
    </filter-class> 
  </filter> 
  <!-- ... --> 


  <!-- Apply ReplaceSiteNameFilter to page2.jsp page 
       in the plugSite directory 
  --> 
  <filter-mapping> 
    <filter-name>ReplaceSiteNameFilter</filter-name> 
    <url-pattern>/plugSite/page2.jsp</url-pattern> 
  </filter-mapping> 

  <!-- ... --> 
</web-app> 

Listing 9.19. page1.jsp (Identical to page2.jsp)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<HTML> 
<HEAD> 
<TITLE>filtersRus.com</TITLE> 
<LINK REL=STYLESHEET 
      HREF="../filter-styles.css" 
      TYPE="text/css"> 
</HEAD> 
<BODY> 
<CENTER> 
<TABLE BORDER=5> 
  <TR><TH CLASS="TITLE">filtersRus.com</TABLE> 
<P> 
<TABLE> 
  <TR> 
    <TH><IMG SRC="../images/air-filter.jpg" 
             ALT="Air Filter"> 
    <TH><IMG SRC="../images/coffee-filter.gif" 
             ALT="Coffee Filter"> 
    <TH><IMG SRC="../images/pump-filter.jpg" 
             ALT="Pump Filter"> 
</TABLE> 

<H3>filtersRus.com specializes in the following:</H3> 
<UL> 
  <LI>Air filters 
  <LI>Coffee filters 
  <LI>Pump filters 
  <LI>Camera lens filters 
  <LI>Image filters for Adobe Photoshop 
  <LI>Web content filters 
  <LI>Kalman filters 
  <LI>Servlet and JSP filters 
</UL> 
Check out <A HREF="../TodaysSpecial">Today's Special</A>. 
</CENTER> 
</BODY> 
</HTML> 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.230.81