Clover coverage report - Coverage timestamp: Sa Jul 7 2007 09:11:40 CEST FRAMES NO FRAMES |
file stats: | LOC: | 411 |  | Methods: | 23
| NCLOC: | 199 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
CacheHttpServletResponseWrapper.java | 0% | 0% | 0% | 0% |

1 |  | /*
2 |  | * Copyright (c) 2002-2003 by OpenSymphony
3 |  | * All rights reserved.
4 |  | */
5 |  | package com.opensymphony.oscache.web.filter;
6 |  |
7 |  | import org.apache.commons.logging.Log;
8 |  | import org.apache.commons.logging.LogFactory;
9 |  |
10 |  | import java.io.IOException;
11 |  | import java.io.OutputStreamWriter;
12 |  | import java.io.PrintWriter;
13 |  |
14 |  | import java.util.Locale;
15 |  |
16 |  | import javax.servlet.ServletOutputStream;
17 |  | import javax.servlet.http.HttpServletResponse;
18 |  | import javax.servlet.http.HttpServletResponseWrapper;
19 |  |
20 |  | /**
21 |  | * CacheServletResponse is a serialized representation of a response
22 |  | *
23 |  | * @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
24 |  | * @version $Revision: 469 $
25 |  | */
26 |  | public class CacheHttpServletResponseWrapper extends HttpServletResponseWrapper {
27 |  |
28 |  | private final Log log = LogFactory.getLog(this.getClass());
29 |  |
30 |  | /**
31 |  | * We cache the printWriter so we can maintain a single instance
32 |  | * of it no matter how many times it is requested.
33 |  | */
34 |  | private PrintWriter cachedWriter = null;
35 |  | private ResponseContent result = null;
36 |  | private SplitServletOutputStream cacheOut = null;
37 |  | private boolean fragment = false;
38 |  | private int status = SC_OK;
39 |  | private long expires = CacheFilter.EXPIRES_ON;
40 |  | private long lastModified = CacheFilter.LAST_MODIFIED_INITIAL;
41 |  | private long cacheControl = -60;
42 |  |
43 |  | /**
44 |  | * Constructor
45 |  | *
46 |  | * @param response The servlet response
47 |  | */
48 | 0 | public CacheHttpServletResponseWrapper(HttpServletResponse response) {
49 | 0 | this(response, false, Long.MAX_VALUE, CacheFilter.EXPIRES_ON, CacheFilter.LAST_MODIFIED_INITIAL, -60);
50 |  | }
51 |  |
52 |  | /**
53 |  | * Constructor
54 |  | *
55 |  | * @param response The servlet response
56 |  | * @param fragment true if the repsonse indicates that it is a fragement of a page
57 |  | * @param time the refresh time in millis
58 |  | * @param lastModified defines if last modified header will be send, @see CacheFilter
59 |  | * @param expires defines if expires header will be send, @see CacheFilter
60 |  | * @param cacheControl defines if cache control header will be send, @see CacheFilter
61 |  | */
62 | 0 | public CacheHttpServletResponseWrapper(HttpServletResponse response, boolean fragment, long time, long lastModified, long expires, long cacheControl) {
63 | 0 | super(response);
64 | 0 | result = new ResponseContent();
65 | 0 | this.fragment = fragment;
66 | 0 | this.expires = expires;
67 | 0 | this.lastModified = lastModified;
68 | 0 | this.cacheControl = cacheControl;
69 |  |
70 |  | // only set inital values for last modified and expires, when a complete page is cached
71 | 0 | if (!fragment) {
72 |  | // setting a default last modified value based on object creation and remove the millis
73 | 0 | if (lastModified == CacheFilter.LAST_MODIFIED_INITIAL) {
74 | 0 | long current = System.currentTimeMillis();
75 | 0 | current = current - (current % 1000);
76 | 0 | result.setLastModified(current);
77 | 0 | super.setDateHeader(CacheFilter.HEADER_LAST_MODIFIED, result.getLastModified());
78 |  | }
79 |  | // setting the expires value
80 | 0 | if (expires == CacheFilter.EXPIRES_TIME) {
81 | 0 | result.setExpires(result.getLastModified() + time);
82 | 0 | super.setDateHeader(CacheFilter.HEADER_EXPIRES, result.getExpires());
83 |  | }
84 |  | // setting the cache control with max-age
85 | 0 | if (this.cacheControl == CacheFilter.MAX_AGE_TIME) {
86 |  | // set the count down
87 | 0 | long maxAge = System.currentTimeMillis();
88 | 0 | maxAge = maxAge - (maxAge % 1000) + time;
89 | 0 | result.setMaxAge(maxAge);
90 | 0 | super.addHeader(CacheFilter.HEADER_CACHE_CONTROL, "max-age=" + time / 1000);
91 | 0 | } else if (this.cacheControl != CacheFilter.MAX_AGE_NO_INIT) {
92 | 0 | result.setMaxAge(this.cacheControl);
93 | 0 | super.addHeader(CacheFilter.HEADER_CACHE_CONTROL, "max-age=" + (-this.cacheControl));
94 | 0 | } else if (this.cacheControl == CacheFilter.MAX_AGE_NO_INIT ) {
95 | 0 | result.setMaxAge(this.cacheControl);
96 |  | }
97 |  | }
98 |  | }
99 |  |
100 |  | /**
101 |  | * Get a response content
102 |  | *
103 |  | * @return The content
104 |  | */
105 | 0 | public ResponseContent getContent() {
106 |  | // Flush the buffer
107 | 0 | try {
108 | 0 | flush();
109 |  | } catch (IOException ignore) {
110 |  | }
111 |  |
112 |  | // Create the byte array
113 | 0 | result.commit();
114 |  |
115 |  | // Return the result from this response
116 | 0 | return result;
117 |  | }
118 |  |
119 |  | /**
120 |  | * Set the content type
121 |  | *
122 |  | * @param value The content type
123 |  | */
124 | 0 | public void setContentType(String value) {
125 | 0 | if (log.isDebugEnabled()) {
126 | 0 | log.debug("ContentType: " + value);
127 |  | }
128 |  |
129 | 0 | super.setContentType(value);
130 | 0 | result.setContentType(value);
131 |  | }
132 |  |
133 |  | /**
134 |  | * Set the date of a header
135 |  | *
136 |  | * @param name The header name
137 |  | * @param value The date
138 |  | */
139 | 0 | public void setDateHeader(String name, long value) {
140 | 0 | if (log.isDebugEnabled()) {
141 | 0 | log.debug("dateheader: " + name + ": " + value);
142 |  | }
143 |  |
144 |  | // only set the last modified value, if a complete page is cached
145 | 0 | if ((lastModified != CacheFilter.LAST_MODIFIED_OFF) && (CacheFilter.HEADER_LAST_MODIFIED.equalsIgnoreCase(name))) {
146 | 0 | if (!fragment) {
147 | 0 | result.setLastModified(value);
148 |  | } // TODO should we return now by fragments to avoid putting the header to the response?
149 |  | }
150 |  |
151 |  | // implement RFC 2616 14.21 Expires (without max-age)
152 | 0 | if ((expires != CacheFilter.EXPIRES_OFF) && (CacheFilter.HEADER_EXPIRES.equalsIgnoreCase(name))) {
153 | 0 | if (!fragment) {
154 | 0 | result.setExpires(value);
155 |  | } // TODO should we return now by fragments to avoid putting the header to the response?
156 |  | }
157 |  |
158 | 0 | super.setDateHeader(name, value);
159 |  | }
160 |  |
161 |  | /**
162 |  | * Add the date of a header
163 |  | *
164 |  | * @param name The header name
165 |  | * @param value The date
166 |  | */
167 | 0 | public void addDateHeader(String name, long value) {
168 | 0 | if (log.isDebugEnabled()) {
169 | 0 | log.debug("dateheader: " + name + ": " + value);
170 |  | }
171 |  |
172 |  | // only set the last modified value, if a complete page is cached
173 | 0 | if ((lastModified != CacheFilter.LAST_MODIFIED_OFF) && (CacheFilter.HEADER_LAST_MODIFIED.equalsIgnoreCase(name))) {
174 | 0 | if (!fragment) {
175 | 0 | result.setLastModified(value);
176 |  | } // TODO should we return now by fragments to avoid putting the header to the response?
177 |  | }
178 |  |
179 |  | // implement RFC 2616 14.21 Expires (without max-age)
180 | 0 | if ((expires != CacheFilter.EXPIRES_OFF) && (CacheFilter.HEADER_EXPIRES.equalsIgnoreCase(name))) {
181 | 0 | if (!fragment) {
182 | 0 | result.setExpires(value);
183 |  | } // TODO should we return now by fragments to avoid putting the header to the response?
184 |  | }
185 |  |
186 | 0 | super.addDateHeader(name, value);
187 |  | }
188 |  |
189 |  | /**
190 |  | * Set a header field
191 |  | *
192 |  | * @param name The header name
193 |  | * @param value The header value
194 |  | */
195 | 0 | public void setHeader(String name, String value) {
196 | 0 | if (log.isDebugEnabled()) {
197 | 0 | log.debug("header: " + name + ": " + value);
198 |  | }
199 |  |
200 | 0 | if (CacheFilter.HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) {
201 | 0 | result.setContentType(value);
202 |  | }
203 |  |
204 | 0 | if (CacheFilter.HEADER_CONTENT_ENCODING.equalsIgnoreCase(name)) {
205 | 0 | result.setContentEncoding(value);
206 |  | }
207 |  |
208 | 0 | super.setHeader(name, value);
209 |  | }
210 |  |
211 |  | /**
212 |  | * Add a header field
213 |  | *
214 |  | * @param name The header name
215 |  | * @param value The header value
216 |  | */
217 | 0 | public void addHeader(String name, String value) {
218 | 0 | if (log.isDebugEnabled()) {
219 | 0 | log.debug("header: " + name + ": " + value);
220 |  | }
221 |  |
222 | 0 | if (CacheFilter.HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) {
223 | 0 | result.setContentType(value);
224 |  | }
225 |  |
226 | 0 | if (CacheFilter.HEADER_CONTENT_ENCODING.equalsIgnoreCase(name)) {
227 | 0 | result.setContentEncoding(value);
228 |  | }
229 |  |
230 | 0 | super.addHeader(name, value);
231 |  | }
232 |  |
233 |  | /**
234 |  | * Set the int value of the header
235 |  | *
236 |  | * @param name The header name
237 |  | * @param value The int value
238 |  | */
239 | 0 | public void setIntHeader(String name, int value) {
240 | 0 | if (log.isDebugEnabled()) {
241 | 0 | log.debug("intheader: " + name + ": " + value);
242 |  | }
243 |  |
244 | 0 | super.setIntHeader(name, value);
245 |  | }
246 |  |
247 |  | /**
248 |  | * We override this so we can catch the response status. Only
249 |  | * responses with a status of 200 (<code>SC_OK</code>) will
250 |  | * be cached.
251 |  | */
252 | 0 | public void setStatus(int status) {
253 | 0 | super.setStatus(status);
254 | 0 | this.status = status;
255 |  | }
256 |  |
257 |  | /**
258 |  | * We override this so we can catch the response status. Only
259 |  | * responses with a status of 200 (<code>SC_OK</code>) will
260 |  | * be cached.
261 |  | */
262 | 0 | public void sendError(int status, String string) throws IOException {
263 | 0 | super.sendError(status, string);
264 | 0 | this.status = status;
265 |  | }
266 |  |
267 |  | /**
268 |  | * We override this so we can catch the response status. Only
269 |  | * responses with a status of 200 (<code>SC_OK</code>) will
270 |  | * be cached.
271 |  | */
272 | 0 | public void sendError(int status) throws IOException {
273 | 0 | super.sendError(status);
274 | 0 | this.status = status;
275 |  | }
276 |  |
277 |  | /**
278 |  | * We override this so we can catch the response status. Only
279 |  | * responses with a status of 200 (<code>SC_OK</code>) will
280 |  | * be cached.
281 |  | */
282 | 0 | public void setStatus(int status, String string) {
283 | 0 | super.setStatus(status, string);
284 | 0 | this.status = status;
285 |  | }
286 |  |
287 |  | /**
288 |  | * We override this so we can catch the response status. Only
289 |  | * responses with a status of 200 (<code>SC_OK</code>) will
290 |  | * be cached.
291 |  | */
292 | 0 | public void sendRedirect(String location) throws IOException {
293 | 0 | this.status = SC_MOVED_TEMPORARILY;
294 | 0 | super.sendRedirect(location);
295 |  | }
296 |  |
297 |  | /**
298 |  | * Retrieves the captured HttpResponse status.
299 |  | */
300 | 0 | public int getStatus() {
301 | 0 | return status;
302 |  | }
303 |  |
304 |  | /**
305 |  | * Set the locale
306 |  | *
307 |  | * @param value The locale
308 |  | */
309 | 0 | public void setLocale(Locale value) {
310 | 0 | super.setLocale(value);
311 | 0 | result.setLocale(value);
312 |  | }
313 |  |
314 |  | /**
315 |  | * Get an output stream
316 |  | *
317 |  | * @throws IOException
318 |  | */
319 | 0 | public ServletOutputStream getOutputStream() throws IOException {
320 |  | // Pass this faked servlet output stream that captures what is sent
321 | 0 | if (cacheOut == null) {
322 | 0 | cacheOut = new SplitServletOutputStream(result.getOutputStream(), super.getOutputStream());
323 |  | }
324 |  |
325 | 0 | return cacheOut;
326 |  | }
327 |  |
328 |  | /**
329 |  | * Get a print writer
330 |  | *
331 |  | * @throws IOException
332 |  | */
333 | 0 | public PrintWriter getWriter() throws IOException {
334 | 0 | if (cachedWriter == null) {
335 | 0 | String encoding = getCharacterEncoding();
336 | 0 | if (encoding != null) {
337 | 0 | cachedWriter = new PrintWriter(new OutputStreamWriter(getOutputStream(), encoding));
338 |  | } else { // using the default character encoding
339 | 0 | cachedWriter = new PrintWriter(new OutputStreamWriter(getOutputStream()));
340 |  | }
341 |  | }
342 |  |
343 | 0 | return cachedWriter;
344 |  | }
345 |  |
346 |  | /**
347 |  | * Flushes all streams.
348 |  | * @throws IOException
349 |  | */
350 | 0 | private void flush() throws IOException {
351 | 0 | if (cacheOut != null) {
352 | 0 | cacheOut.flush();
353 |  | }
354 |  |
355 | 0 | if (cachedWriter != null) {
356 | 0 | cachedWriter.flush();
357 |  | }
358 |  | }
359 |  |
360 | 0 | public void flushBuffer() throws IOException {
361 | 0 | super.flushBuffer();
362 | 0 | flush();
363 |  | }
364 |  |
365 |  | /**
366 |  | * Returns a boolean indicating if the response has been committed.
367 |  | * A commited response has already had its status code and headers written.
368 |  | *
369 |  | * @see javax.servlet.ServletResponseWrapper#isCommitted()
370 |  | */
371 | 0 | public boolean isCommitted() {
372 | 0 | return super.isCommitted(); // || (result.getOutputStream() == null);
373 |  | }
374 |  |
375 |  | /**
376 |  | * Clears any data that exists in the buffer as well as the status code and headers.
377 |  | * If the response has been committed, this method throws an IllegalStateException.
378 |  | * @see javax.servlet.ServletResponseWrapper#reset()
379 |  | */
380 | 0 | public void reset() {
381 | 0 | log.info("CacheHttpServletResponseWrapper:reset()");
382 | 0 | super.reset();
383 |  | /*
384 |  | cachedWriter = null;
385 |  | result = new ResponseContent();
386 |  | cacheOut = null;
387 |  | fragment = false;
388 |  | status = SC_OK;
389 |  | expires = CacheFilter.EXPIRES_ON;
390 |  | lastModified = CacheFilter.LAST_MODIFIED_INITIAL;
391 |  | cacheControl = -60;
392 |  | // time ?
393 |  | */
394 |  | }
395 |  |
396 |  | /**
397 |  | * Clears the content of the underlying buffer in the response without clearing headers or status code.
398 |  | * If the response has been committed, this method throws an IllegalStateException.
399 |  | * @see javax.servlet.ServletResponseWrapper#resetBuffer()
400 |  | */
401 | 0 | public void resetBuffer() {
402 | 0 | log.info("CacheHttpServletResponseWrapper:resetBuffer()");
403 | 0 | super.resetBuffer();
404 |  | /*
405 |  | //cachedWriter = null;
406 |  | result = new ResponseContent();
407 |  | //cacheOut = null;
408 |  | //fragment = false;
409 |  | */
410 |  | }
411 |  | }