001 package org.rakeshv.filters;
002
003 import java.io.File;
004 import java.io.IOException;
005 import java.io.PrintWriter;
006 import java.util.Locale;
007
008 import javax.servlet.ServletOutputStream;
009 import javax.servlet.http.HttpServletResponse;
010 import javax.servlet.http.HttpServletResponseWrapper;
011
012 /**
013 * A <code>HttpServletResponseWrapper</code> class that is used to
014 * create a <code>cached</code> output stream. This class
015 * over-rides appropriate methods in the parent class to create
016 * cached OutputStreams and PrintWriters.
017 *
018 * <p>© Copyright 2005, Rakesh Vidyadharan</p>
019 * @author Rakesh Vidyadharan 15<sup><small>th</small></sup> September 2005
020 *
021 * @version $Id: CachingResponseWrapper.java,v 1.4 2005/10/16 02:19:57 rakesh Exp $
022 */
023 public class CachingResponseWrapper
024 extends HttpServletResponseWrapper
025 {
026 /**
027 * Original response
028 */
029 protected HttpServletResponse servletResponse = null;
030
031 /**
032 * The <code>ServletOutputStream</code> that has been returned by
033 * {@link #getOutputStream()}, if any.
034 */
035 protected ServletOutputStream stream = null;
036
037 /**
038 * The PrintWriter that has been returned by getWriter(), if any.
039 */
040 protected PrintWriter writer = null;
041
042 /**
043 * The file to which the cached contents are to be written.
044 */
045 protected File cacheFile = null;
046
047 /**
048 * The {@link CachingFilter.FileProperties} that is to be
049 * modified if the content properties for the response are
050 * modified by objects down the filter chain.
051 */
052 private CachingFilter.FileProperties fileProperties;
053
054 /**
055 * Constructs a cached response adaptor wrapping the given
056 * response. Calls the <code>super-class</code> constructor, and
057 * set the {@link #servletResponse} reference.
058 *
059 * @param response The response that is to be cached.
060 * @param file The file to which the contents are to be cached.
061 * @param fileProperties The <code>FileProperties</code> that will
062 * be passed along to the {@link CachingResponseStream}.
063 * @throws IllegalArgumentException If the specified response is
064 * <code>null</code>.
065 */
066 public CachingResponseWrapper( HttpServletResponse response,
067 File file, CachingFilter.FileProperties fileProperties )
068 throws IllegalArgumentException
069 {
070 super( response );
071 servletResponse = response;
072 cacheFile = file;
073 this.fileProperties = fileProperties;
074 }
075
076 /**
077 * Create a new instance of the {@link CachingResponseWrapper}
078 * class, that compresses the response.
079 *
080 * @return ServletOutputStream - The appropriate instance of the
081 * ServletOutputStream that wraps a <code>DeflaterOutputStream
082 * </code>.
083 * @throws IOException If exceptions are encountered while
084 * creating the cached response stream.
085 */
086 public ServletOutputStream createOutputStream() throws IOException
087 {
088 CachingResponseStream crs = new CachingResponseStream(
089 servletResponse, cacheFile );
090
091 return crs;
092 }
093
094 /**
095 * Forces any content in the buffer to be written to the client. A
096 * call to this method automatically commits the response, meaning
097 * the status code and headers will be written.
098 */
099 public void flushBuffer() throws IOException
100 {
101 ( (CachingResponseStream) stream ).flush();
102 }
103
104 /**
105 * Returns a ServletOutputStream suitable for writing binary data in
106 * the response. If a <code>Writer</code> has not already been
107 * created for the response (through a call to {@link #getWriter()}
108 * method) a new instance of the {@link CachingResponseStream}
109 * is created, and the instance variable {@link #stream} set to the
110 * new instance created. If the {@link #stream} has already been
111 * initialised, then the reference is returned.
112 *
113 * @throws IOException If errors are encountered while creating
114 * the cached response stream.
115 * @throws IllegalStateException If {@link #getWriter()} has
116 * already been called on this instance.
117 */
118 public ServletOutputStream getOutputStream() throws IOException
119 {
120 if ( writer != null )
121 {
122 throw new IllegalStateException(
123 "getWriter() has already been called for this response" );
124 }
125
126 if (stream == null)
127 {
128 stream = createOutputStream();
129 }
130
131 return stream;
132 }
133
134 /**
135 * Returns a PrintWriter object that can send character text to the
136 * client. The PrintWriter is created on top of the appropriate
137 * {@link CachingResponseStream} class. The character encoding
138 * used is the one specified in the charset= property of the
139 * <code>setContentType( java.lang.String )</code> method, which must
140 * be called before calling this method for the charset to take
141 * effect.
142 *
143 * <p>If necessary, the MIME type of the response is modified to
144 * reflect the character encoding used.</p>
145 *
146 * <p>Either this method or {@link #getOutputStream()} may be called
147 * to write the body, not both.
148 *
149 * @throws IOException If errors are encountered while creating
150 * the cached response stream.
151 * @throws IllegalStateException If {@link #getWriter()} has
152 * already been called on this instance.
153 */
154 public PrintWriter getWriter() throws IOException
155 {
156 if ( writer != null )
157 {
158 return writer;
159 }
160
161 if ( stream != null )
162 {
163 throw new IllegalStateException(
164 "getOutputStream() has already been called for this response" );
165 }
166
167 stream = createOutputStream();
168 writer = new PrintWriter( stream );
169 return writer;
170 }
171
172 /**
173 * Closes the cached file in the {@link CachingResponseStream} without
174 * closing the underlying stream.
175 *
176 * <p><b>Note:</b> This method must be invoked by to ensure that the
177 * cache file that was generated is properly closed after the actual
178 * response was generated.</p>
179 *
180 * @throws IOException - If errors are encountered while closing
181 * the file.
182 */
183 public void closeCacheFile() throws IOException
184 {
185 if ( stream != null )
186 {
187 ( (CachingResponseStream) stream ).closeCacheFile();
188 }
189 }
190
191 /**
192 * Add the specified header to the {@link #fileProperties}
193 *
194 * @param name The name of the header
195 * @param value The value of the header
196 */
197 public void addHeader( String name, String value )
198 {
199 super.addHeader( name, value );
200 fileProperties.setHeader( name, value );
201 }
202
203 /**
204 * Add the specified header to the {@link #fileProperties}
205 *
206 * @param name The name of the header
207 * @param value The value of the header
208 */
209 public void setHeader( String name, String value )
210 {
211 super.setHeader( name, value );
212 fileProperties.setHeader( name, value );
213 }
214
215 /**
216 * Update the property in the {@link #fileProperties} and then pass
217 * along to the super class implementation.
218 *
219 * @param charset A String specifying only the character set defined
220 * by IANA Character Sets (http://www.iana.org/assignments/character-sets)
221 */
222 public void setCharacterEncoding( String charset )
223 {
224 super.setCharacterEncoding( charset );
225 fileProperties.setCharacterEncoding( charset );
226 }
227
228 /**
229 * Update the property in the {@link #fileProperties} and then pass
230 * along to the super class implementation.
231 *
232 * @param type A String specifying the MIME type of the content
233 */
234 public void setContentType( String type )
235 {
236 super.setContentType( type );
237 fileProperties.setContentType( type );
238 }
239
240 /**
241 * Update the property in the {@link #fileProperties} and then pass
242 * along to the super class implementation.
243 *
244 * @param locale The locale of the response
245 */
246 public void setLocale( Locale locale )
247 {
248 super.setLocale( locale );
249 fileProperties.setLocale( locale );
250 }
251
252 /**
253 * If the status is not equal to <code>SC_OK</code>, indicate to the
254 * {@link #fileProperties} that the response should not be cached.
255 *
256 * @param status The status code to set for the response.
257 */
258 public void setStatus( int status )
259 {
260 super.setStatus( status );
261 if ( status != HttpServletResponse.SC_OK )
262 {
263 fileProperties.setValidResponse( false );
264 }
265 }
266 }