1 5 package com.oreilly.servlet; 6 7 import java.io.*; 8 import java.util.*; 9 import javax.servlet.*; 10 import javax.servlet.http.*; 11 12 53 54 public abstract class CacheHttpServlet extends HttpServlet { 55 56 58 CacheHttpServletResponse cacheResponse; 59 long cacheLastMod = -1; 60 String cacheQueryString = null; 61 String cachePathInfo = null; 62 String cacheServletPath = null; 63 Object lock = new Object (); 64 65 67 protected void service(HttpServletRequest req, HttpServletResponse res) 68 throws ServletException, IOException { 69 String method = req.getMethod(); 71 if (!method.equals("GET")) { 72 super.service(req, res); 73 return; 74 } 75 76 long servletLastMod = getLastModified(req); 78 79 if (servletLastMod == -1) { 81 super.service(req, res); 82 return; 83 } 84 85 if ((servletLastMod / 1000 * 1000) <= 89 req.getDateHeader("If-Modified-Since")) { 90 res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); 91 return; 92 } 93 94 CacheHttpServletResponse localResponseCopy = null; 96 synchronized (lock) { 97 if (servletLastMod <= cacheLastMod && 98 cacheResponse.isValid() && 99 equal(cacheQueryString, req.getQueryString()) && 100 equal(cachePathInfo, req.getPathInfo()) && 101 equal(cacheServletPath, req.getServletPath())) { 102 localResponseCopy = cacheResponse; 103 } 104 } 105 if (localResponseCopy != null) { 106 localResponseCopy.writeTo(res); 107 return; 108 } 109 110 localResponseCopy = new CacheHttpServletResponse(res); 112 super.service(req, localResponseCopy); 113 synchronized (lock) { 114 cacheResponse = localResponseCopy; 115 cacheLastMod = servletLastMod; 116 cacheQueryString = req.getQueryString(); 117 cachePathInfo = req.getPathInfo(); 118 cacheServletPath = req.getServletPath(); 119 } 120 } 121 122 124 private static boolean equal(String s1, String s2) { 125 if (s1 == null && s2 == null) { 126 return true; 127 } 128 else if (s1 == null || s2 == null) { 129 return false; 130 } 131 else { 132 return s1.equals(s2); 133 } 134 } 135 } 136 137 139 class CacheHttpServletResponse implements HttpServletResponse { 140 private int status; 142 private Hashtable headers; 143 private int contentLength; 144 private String contentType; 145 private Locale locale; 146 private Vector cookies; 147 private boolean didError; 148 private boolean didRedirect; 149 private boolean gotStream; 150 private boolean gotWriter; 151 152 private HttpServletResponse delegate; 153 private CacheServletOutputStream out; 154 private PrintWriter writer; 155 156 158 CacheHttpServletResponse(HttpServletResponse res) { 159 delegate = res; 160 try { 161 out = new CacheServletOutputStream(res.getOutputStream()); 162 } 163 catch (IOException e) { 164 System.out.println( 165 "Got IOException constructing cached response: " + e.getMessage()); 166 } 167 internalReset(); 168 } 169 170 172 private void internalReset() { 173 status = 200; 174 headers = new Hashtable(); 175 contentLength = -1; 176 contentType = null; 177 locale = null; 178 cookies = new Vector(); 179 didError = false; 180 didRedirect = false; 181 gotStream = false; 182 gotWriter = false; 183 out.getBuffer().reset(); 184 } 185 186 public boolean isValid() { 187 return (!didError) && (!didRedirect); 189 } 190 191 193 private void internalSetHeader(String name, Object value) { 194 Vector v = new Vector(); 195 v.addElement(value); 196 headers.put(name, v); 197 } 198 199 201 private void internalAddHeader(String name, Object value) { 202 Vector v = (Vector) headers.get(name); 203 if (v == null) { 204 v = new Vector(); 205 } 206 v.addElement(value); 207 headers.put(name, v); 208 } 209 210 212 public void writeTo(HttpServletResponse res) { 213 res.setStatus(status); 215 if (contentType != null) res.setContentType(contentType); 217 if (locale != null) res.setLocale(locale); 218 Enumeration cookieenum = cookies.elements(); 220 while (cookieenum.hasMoreElements()) { 221 Cookie c = (Cookie) cookieenum.nextElement(); 222 res.addCookie(c); 223 } 224 Enumeration headerenum = headers.keys(); 226 while (headerenum.hasMoreElements()) { 227 String name = (String ) headerenum.nextElement(); 228 Vector values = (Vector) headers.get(name); Enumeration enum2 = values.elements(); 230 while (enum2.hasMoreElements()) { 231 Object value = enum2.nextElement(); 232 if (value instanceof String ) { 233 res.setHeader(name, (String )value); 234 } 235 if (value instanceof Integer ) { 236 res.setIntHeader(name, ((Integer )value).intValue()); 237 } 238 if (value instanceof Long ) { 239 res.setDateHeader(name, ((Long )value).longValue()); 240 } 241 } 242 } 243 res.setContentLength(out.getBuffer().size()); 245 try { 247 out.getBuffer().writeTo(res.getOutputStream()); 248 } 249 catch (IOException e) { 250 System.out.println( 251 "Got IOException writing cached response: " + e.getMessage()); 252 } 253 } 254 255 257 public String getContentType() { 258 return delegate.getContentType(); 259 } 260 261 263 public ServletOutputStream getOutputStream() 264 throws IOException,IllegalStateException { 265 if (gotWriter) { 266 throw new IllegalStateException ( 267 "Cannot get output stream after getting writer"); 268 } 269 gotStream = true; 270 return out; 271 } 272 273 275 public PrintWriter getWriter() 276 throws UnsupportedEncodingException,IllegalStateException { 277 if (gotStream) { 278 throw new IllegalStateException ( 279 "Cannot get writer after getting output stream"); 280 } 281 gotWriter = true; 282 if (writer == null) { 283 OutputStreamWriter w = 284 new OutputStreamWriter(out, getCharacterEncoding()); 285 writer = new PrintWriter(w, true); } 287 return writer; 288 } 289 290 292 public void setContentLength(int len) { 293 delegate.setContentLength(len); 294 } 296 297 299 public void setContentType(String type) { 300 delegate.setContentType(type); 301 contentType = type; 302 } 303 304 306 public String getCharacterEncoding() { 307 return delegate.getCharacterEncoding(); 308 } 309 310 312 public void setBufferSize(int size) throws IllegalStateException { 313 delegate.setBufferSize(size); 314 } 315 316 318 public int getBufferSize() { 319 return delegate.getBufferSize(); 320 } 321 322 324 public void resetBuffer() throws IllegalStateException { 325 delegate.reset(); 326 internalReset(); 327 } 328 329 331 public void reset() throws IllegalStateException { 332 delegate.reset(); 333 internalReset(); 334 } 335 336 338 345 346 348 public boolean isCommitted() { 349 return delegate.isCommitted(); 350 } 351 352 354 public void flushBuffer() throws IOException { 355 delegate.flushBuffer(); 356 } 357 358 360 public void setLocale(Locale loc) { 361 delegate.setLocale(loc); 362 locale = loc; 363 } 364 365 367 public Locale getLocale() { 368 return delegate.getLocale(); 369 } 370 371 373 public void addCookie(Cookie cookie) { 374 delegate.addCookie(cookie); 375 cookies.addElement(cookie); 376 } 377 378 380 public boolean containsHeader(String name) { 381 return delegate.containsHeader(name); 382 } 383 384 386 public void setCharacterEncoding(String enc) { 387 delegate.setCharacterEncoding(enc); 388 } 389 390 392 393 public void setStatus(int sc, String sm) { 394 delegate.setStatus(sc, sm); 395 status = sc; 396 } 397 398 400 public void setStatus(int sc) { 401 delegate.setStatus(sc); 402 status = sc; 403 } 404 405 407 public void setHeader(String name, String value) { 408 delegate.setHeader(name, value); 409 internalSetHeader(name, value); 410 } 411 412 414 public void setIntHeader(String name, int value) { 415 delegate.setIntHeader(name, value); 416 internalSetHeader(name, new Integer (value)); 417 } 418 419 421 public void setDateHeader(String name, long date) { 422 delegate.setDateHeader(name, date); 423 internalSetHeader(name, new Long (date)); 424 } 425 426 428 public void sendError(int sc, String msg) throws IOException { 429 delegate.sendError(sc, msg); 430 didError = true; 431 } 432 433 435 public void sendError(int sc) throws IOException { 436 delegate.sendError(sc); 437 didError = true; 438 } 439 440 442 public void sendRedirect(String location) throws IOException { 443 delegate.sendRedirect(location); 444 didRedirect = true; 445 } 446 447 449 public String encodeURL(String url) { 450 return delegate.encodeURL(url); 451 } 452 453 455 public String encodeRedirectURL(String url) { 456 return delegate.encodeRedirectURL(url); 457 } 458 459 461 public void addHeader(String name, String value) { 462 internalAddHeader(name, value); 463 } 464 465 467 public void addIntHeader(String name, int value) { 468 internalAddHeader(name, new Integer (value)); 469 } 470 471 473 public void addDateHeader(String name, long value) { 474 internalAddHeader(name, new Long (value)); 475 } 476 477 479 480 public String encodeUrl(String url) { 481 return this.encodeURL(url); 482 } 483 484 486 487 public String encodeRedirectUrl(String url) { 488 return this.encodeRedirectURL(url); 489 } 490 } 491 492 494 class CacheServletOutputStream extends ServletOutputStream { 495 496 ServletOutputStream delegate; 497 ByteArrayOutputStream cache; 498 499 CacheServletOutputStream(ServletOutputStream out) { 500 delegate = out; 501 cache = new ByteArrayOutputStream(4096); 502 } 503 504 public ByteArrayOutputStream getBuffer() { 505 return cache; 506 } 507 508 public void write(int b) throws IOException { 509 delegate.write(b); 510 cache.write(b); 511 } 512 513 public void write(byte b[]) throws IOException { 514 delegate.write(b); 515 cache.write(b); 516 } 517 518 public void write(byte buf[], int offset, int len) throws IOException { 519 delegate.write(buf, offset, len); 520 cache.write(buf, offset, len); 521 } 522 } | Popular Tags |