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