001 package org.rakeshv.filters;
002
003 import java.io.IOException;
004 import java.io.PrintWriter;
005
006 import javax.servlet.ServletOutputStream;
007 import javax.servlet.http.HttpServletResponse;
008 import javax.servlet.http.HttpServletResponseWrapper;
009
010 /**
011 * A <code>HttpServletResponseWrapper</code> class that is used to
012 * create a <code>compressed</code> output stream. This class
013 * over-rides appropriate methods in the parent class to create
014 * compressed OutputStreams and PrintWriters.
015 *
016 * <p><b>Note:</b> - It is <b>REQUIRED</b> that you set the value of
017 * the {@link #compressionType} instance variable using the mutator
018 * method {@link #setCompressionType( int )} if the compression is
019 * to work.</p>
020 *
021 * <p>© Copyright 2003, Rakesh Vidyadharan</p>
022 * @author Rakesh Vidyadharan 2<sup><small>nd</small></sup> September 2003
023 *
024 * @version $Id: CompressionResponseWrapper.java,v 1.5 2005/09/17 03:53:05 rakesh Exp $
025 */
026 public class CompressionResponseWrapper
027 extends HttpServletResponseWrapper
028 {
029 /**
030 * Original response
031 */
032 protected HttpServletResponse servletResponse = null;
033
034 /**
035 * The <code>ServletOutputStream</code> that has been returned by
036 * {@link #getOutputStream()}, if any.
037 */
038 protected ServletOutputStream stream = null;
039
040 /**
041 * The PrintWriter that has been returned by getWriter(), if any.
042 */
043 protected PrintWriter writer = null;
044
045 /**
046 * An integer that indicates the type of compression that is to
047 * be used. The different compression algorithms supported are
048 * the ones supported in the <code>java.util.zip</code> package.
049 */
050 protected int compressionType = -1;
051
052 /**
053 * Constructs a compressed response adaptor wrapping the given
054 * response. Calls the <code>super-class</code> constructor, and
055 * set the {@link #servletResponse} reference.
056 *
057 * @param response - The response that is to
058 * be compressed.
059 * @throws IllegalArgumentException - If the specified response is
060 * <code>null</code>.
061 */
062 public CompressionResponseWrapper( HttpServletResponse response )
063 throws IllegalArgumentException
064 {
065 super( response );
066 servletResponse = response;
067 }
068
069 /**
070 * Create a new instance of the {@link CompressionResponseWrapper}
071 * class, that compresses the response.
072 *
073 * @return ServletOutputStream - The appropriate instance of the
074 * ServletOutputStream that wraps a <code>DeflaterOutputStream
075 * </code>.
076 * @throws IOException - If exceptions are encountered while
077 * creating the compressed response stream.
078 */
079 public ServletOutputStream createOutputStream() throws IOException
080 {
081 CompressionResponseStream crs =
082 new CompressionResponseStream( servletResponse );
083 crs.setCompressionType( compressionType );
084
085 return crs;
086 }
087
088 /**
089 * Forces any content in the buffer to be written to the client. A
090 * call to this method automatically commits the response, meaning
091 * the status code and headers will be written.
092 */
093 public void flushBuffer() throws IOException
094 {
095 ( (CompressionResponseStream) stream ).flush();
096 }
097
098 /**
099 * Returns a ServletOutputStream suitable for writing binary data in
100 * the response. If a <code>Writer</code> has not already been
101 * created for the response (through a call to {@link #getWriter()}
102 * method) a new instance of the {@link CompressionResponseStream}
103 * is created, and the instance variable {@link #stream} set to the
104 * new instance created. If the {@link #stream} has already been
105 * initialised, then the reference is returned.
106 *
107 * @throws IOException - If errors are encountered while creating
108 * the compressed response stream.
109 * @throws IllegalStateException - If {@link #getWriter()} has
110 * already been called on this instance.
111 */
112 public ServletOutputStream getOutputStream() throws IOException
113 {
114 if ( writer != null )
115 {
116 throw new IllegalStateException(
117 "getWriter() has already been called for this response" );
118 }
119
120 if (stream == null)
121 {
122 stream = createOutputStream();
123 }
124
125 return stream;
126 }
127
128 /**
129 * Returns a PrintWriter object that can send character text to the
130 * client. The PrintWriter is created on top of the appropriate
131 * {@link CompressionResponseStream} class. The character encoding
132 * used is the one specified in the charset= property of the
133 * <code>setContentType( java.lang.String )</code> method, which must
134 * be called before calling this method for the charset to take
135 * effect.
136 *
137 * <p>If necessary, the MIME type of the response is modified to
138 * reflect the character encoding used.</p>
139 *
140 * <p>Either this method or {@link #getOutputStream()} may be called
141 * to write the body, not both.
142 *
143 * @throws IOException - If errors are encountered while creating
144 * the compressed response stream.
145 * @throws IllegalStateException - If {@link #getWriter()} has
146 * already been called on this instance.
147 */
148 public PrintWriter getWriter() throws IOException
149 {
150 if ( writer != null )
151 {
152 return writer;
153 }
154
155 if ( stream != null )
156 {
157 throw new IllegalStateException(
158 "getOutputStream() has already been called for this response" );
159 }
160
161 stream = createOutputStream();
162 writer = new PrintWriter( stream );
163 return writer;
164 }
165
166 /**
167 * Finishes writing compressed data to the {@link
168 * CompressionResponseStream} output stream without
169 * closing the underlying stream.
170 *
171 * <p><b>Note:</b> This method must be invoked by to properly finish
172 * the output if multiple filters are added in succession to the
173 * same output stream. This is generally the case, and hence this
174 * method <b>must</b> be called in order for the response to be
175 * completely sent back to the client.</p>
176 *
177 * @throws IOException - If errors are encountered while writing
178 * to the stream. An exception will be thrown if this method is
179 * invoked after the stream has been closed.
180 */
181 public void finish() throws IOException
182 {
183 if ( stream != null )
184 {
185 ( (CompressionResponseStream) stream ).finish();
186 }
187 }
188
189 /**
190 * Returns {@link #compressionType}.
191 *
192 * @return int - The value/reference of/to compressionType.
193 */
194 public final int getCompressionType()
195 {
196 return compressionType;
197 }
198
199 /**
200 * Set {@link #compressionType}.
201 *
202 * @param compressionType - The value to set.
203 */
204 public final void setCompressionType( int compressionType )
205 {
206 this.compressionType = compressionType;
207 }
208 }