FileDocCategorySizeDatePackage
CacheFilter.javaAPI DocExample3238Sun Nov 23 17:43:06 GMT 2003cfexample.controller

CacheFilter.java

package cfexample.controller;

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

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * A filter that caches pages after they are generated.
 */
public class CacheFilter implements Filter {
    /** the filter configuration */
    private FilterConfig filterConfig = null;
    
    /** the cached data */
    private HashMap cache;
    
    /**
     * Constructor
     */
    public CacheFilter() {
    }
    
    /**
     * Perform the actual caching.  If a given key is available in the
     * cache, return it immediately.  If not, cache the result using a 
     * CacheResponseWrapper
     */
    public void doFilter(ServletRequest request, 
                         ServletResponse response,
                         FilterChain chain)
        throws IOException, ServletException
    {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
       
        // the cache key is the URI + query string
        String key = req.getRequestURI() + "?" + req.getQueryString();
        
        // only cache GET requests that contain cacheable data
        if (req.getMethod().equalsIgnoreCase("get") && isCacheable(key)) {
            // try to retrieve the data from the cache
            byte[] data = (byte[]) cache.get(key);
            
            // on a cache miss, generate the result normally and add it to the
            // cache
            if (data == null) {
                CacheResponseWrapper crw = new CacheResponseWrapper(res);
                chain.doFilter(request, crw);
                data = crw.getBytes();
                cache.put(key, data);
            } 
            
            // if the data was found, use it to generate the result
            if (data != null) {
                res.setContentType("text/html");
                res.setContentLength(data.length);
                
                try {
                    OutputStream os = res.getOutputStream();
                    os.write(data);
                    os.flush();
                    os.close();
                } catch(Exception ex) {
                    ex.printStackTrace();
                }
            }
        } else {
            // generate the data normally if it was not cacheable
            chain.doFilter(request, response);
        }
    }
    
    /**
     * Return whether the given URI + query string is cacheable.  A real
     * implementation should use some kind of policy here.
     */
    private boolean isCacheable(String key) {
        return true;
    }
    
    /**
     * Initialize the cache
     */
    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
        
        cache = new HashMap();
    }
    /**
     * Destroy the cache
     */
    public void destroy() {
        cache.clear();
        
        cache = null;
        filterConfig = null;
    }
}