Filterによる本文圧縮


public class CompressionResponseStream extends ServletOutputStream {

    protected int compressionThreshold = 0;//           
    protected byte[] buffer = null;//              
    protected int bufferCount = 0; //            
    protected GZIPOutputStream gzipstream = null;
    protected boolean closed = false;//               
    protected int length = -1;
    protected HttpServletResponse response = null;
    protected ServletOutputStream output = null;

    public CompressionResponseStream(HttpServletResponse response)
            throws IOException {
        super();
        closed = false;
        this.response = response;
        this.output = response.getOutputStream();
    }

    protected void setBuffer(int threshold) {
        compressionThreshold = threshold;
        buffer = new byte[compressionThreshold];
    }

    public void close() throws IOException {
        if (closed) {
            throw new IOException("This output stream has already been closed");
        }
        /*
         *   gzipstream   null,              
         *         ,        ,write       gzipstream  
         */
        if (gzipstream != null) {
            flushToGZip();
            gzipstream.close();
            gzipstream = null;
        } else {
            if (bufferCount > 0) {
                output.write(buffer, 0, bufferCount);
                bufferCount = 0;
            }
        }

        output.close();
        closed = true;
    }

    public void flush() throws IOException {
        if (closed) {
            throw new IOException("Can't flush a closed output stream");
        }
        if (gzipstream != null) {
            gzipstream.flush();
        }
    }

    /**
     *  buffer          gzipstream 
     *
     * @throws IOException
     */
    public void flushToGZip() throws IOException {
        if (bufferCount > 0) {
            writeToGZip(buffer, 0, bufferCount);
            bufferCount = 0;
        }
    }

    @Override
    public void write(int b) throws IOException {
        if (closed) {
            throw new IOException("Can't write to a closed output stream");
        }

        /*
         *                  ,    buffer         gzipstream   
         */
        if (bufferCount >= buffer.length) {
            flushToGZip();
        }
        buffer[bufferCount++] = (byte) b;
    }

    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }

    public void write(byte[] b, int off, int len) throws IOException {
        if (closed) {
            throw new IOException("Can't write to a closed output stream");
        }
        if (len == 0) {
            return;
        }
        /*
         *   buffer                   ,           buffer    
         */
        if (len <= (buffer.length - bufferCount)) {
            System.arraycopy(b, off, buffer, bufferCount, len);
            bufferCount += len;
            return;
        }
        /*
         *   buffer                  ,    buffer           gzipstream   
         */
        flushToGZip();

        /*
         *   buffer      ,    buffer               ,            buffer    
         */
        if (len <= (buffer.length - bufferCount)) {
            System.arraycopy(b, off, buffer, bufferCount, len);
            bufferCount += len;
            return;
        }
        /*
         *     buffer                 ,           gzipstream 
         */
        writeToGZip(b, off, len);
    }

    /**
     *  gzipstream       ,             gzips    
     *
     * @param b
     * @param off
     * @param len
     * @throws IOException
     */
    public void writeToGZip(byte b[], int off, int len) throws IOException {
        if (gzipstream == null) {
            response.addHeader("Content-Encoding", "gzip");
            gzipstream = new GZIPOutputStream(output);
        }
        gzipstream.write(b, off, len);
    }
}
 
public class CompressionServletResponseWrapper extends
		HttpServletResponseWrapper {

	protected HttpServletResponse origResponse = null;
	protected static final String info = "CompressionServletResponseWrapper";
	protected ServletOutputStream stream = null;
	protected PrintWriter writer = null;
	protected int threshold = 0;
	protected String contentType = null;

	public CompressionServletResponseWrapper(HttpServletResponse response) {
		super(response);
		origResponse = response;
	}

	public void setContentType(String contentType) {
		this.contentType = contentType;
		origResponse.setContentType(contentType);
	}

	public void setCompressionThreshold(int threshold) {
		this.threshold = threshold;
	}

	/**
	 *      response         
	 * 
	 * @return
	 * @throws IOException
	 */
	public ServletOutputStream createOutputStream() throws IOException {
		CompressionResponseStream stream = new CompressionResponseStream(
				origResponse);
		stream.setBuffer(threshold);
		return stream;
	}

	/**
	 *       Servlet         ,Filter                 
	 */
	public void finishResponse() {
		try {
			if (writer != null) {
				writer.close();
			} else {
				if (stream != null) {
					stream.close();
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

	/**
	 *   flushBuffer  
	 */
	public void flushBuffer() throws IOException {
		((CompressionResponseStream) stream).flush();
	}

	/**
	 *   getOutputStream  
	 */
	public ServletOutputStream getOutputStream() throws IOException {
		if (writer != null) {
			throw new IllegalStateException(
					"getWriter() has already been called for this resposne");
		}
		if (stream == null) {
			stream = createOutputStream();
		}
		return stream;
	}

	public PrintWriter getWriter() throws IOException {
		if (writer != null) {
			return writer;
		}
		if (stream != null) {
			throw new IllegalStateException(
					"getOutputStream() has already been called for this resposne");
		}
		stream = createOutputStream();

		String charEnc = origResponse.getCharacterEncoding();
		if (charEnc != null) {
			writer = new PrintWriter(new OutputStreamWriter(stream, charEnc));
		} else {
			writer = new PrintWriter(stream);
		}
		return writer;
	}

}
 
public class CompressionFilter implements Filter {
	private FilterConfig config = null;
	private int minThreshold = 128;
	protected int compressionThreshold;

	public void init(FilterConfig filterConfig) throws ServletException {
		this.config = filterConfig;
		if (filterConfig != null) {
			String str = filterConfig.getInitParameter("compressionThreshold");
			if (compressionThreshold != 0 & compressionThreshold < minThreshold) {
				compressionThreshold = minThreshold;
			} else {
				//                
				compressionThreshold = 0;
			}
		} else {
			compressionThreshold = 0;
		}

	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		/*
		 *                
		 */
		if (compressionThreshold == 0) {
			chain.doFilter(request, response);
		}
		/*
		 *             gzip      
		 */
		boolean supportCompression = false;
		if (request instanceof HttpServletRequest) {
			Enumeration<String> e = ((HttpServletRequest) request)
					.getHeaders("Accept-Encoding");
			while (e.hasMoreElements()) {
				String name = e.nextElement();
				if (name.indexOf("gzip") != -1) {
					supportCompression = true;
				}
			}
		}
		if (!supportCompression) {
			chain.doFilter(request, response);
			return;
		} else {
			if (response instanceof HttpServletResponse) {
				/*
				 *       Response  
				 */
				CompressionServletResponseWrapper wrapperResponse = 
                         new CompressionServletResponseWrapper(
						(HttpServletResponse) response);
				wrapperResponse.setCompressionThreshold(compressionThreshold);
				try {
					chain.doFilter(request, wrapperResponse);
				} finally {
					wrapperResponse.finishResponse();
				}
			}
			return;
		}
	}

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

}