Home
What's
New?
com.oreilly.servlet
Servlet
Polls
Mailing
Lists
Servlet
Engines
Servlet
ISPs
Servlet
Tools
Documentation
Online
Articles
The
Soapbox
"Java
Servlet
Programming,
Second Edition"
"Java
Enterprise
Best Practices"
Speaking
& Slides
About
Jason
XQuery
Affiliate
|
Free Cache: Source code for CacheHttpServlet |
The following is the source to the com.oreilly.servlet.CacheHttpServlet class,
as written about in the soapbox article Free Cache:
Come and Get It!
// Copyright (C) 1999 by Jason Hunter <jhunter@acm.org>. All rights reserved.
// Use of this class is limited. Please see the com.oreilly.servlet LICENSE
// for more information.
//
// DO NOT CUT AND PASTE THIS CODE. This class is available in source and
// compiled form from http://www.servlets.com/cos/.
package com.oreilly.servlet;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public abstract class CacheHttpServlet extends HttpServlet {
CacheHttpServletResponse cacheResponse;
long cacheLastMod = -1;
String cacheQueryString = null;
String cachePathInfo = null;
String cacheServletPath = null;
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// Only do caching for GET requests
String method = req.getMethod();
if (!method.equals("GET")) {
super.service(req, res);
return;
}
// Check the last modified time for this servlet
long servletLastMod = getLastModified(req);
// A last modified of -1 means we shouldn't use any cache logic
if (servletLastMod == -1) {
super.service(req, res);
}
// If the client sent an If-Modified-Since header equal or after the
// servlet's last modified time, send a short "Not Modified" status code
// Round down to the nearest second since client headers are in seconds
else if ((servletLastMod / 1000 * 1000) <=
req.getDateHeader("If-Modified-Since")) {
res.setStatus(res.SC_NOT_MODIFIED);
}
// Use the existing cache if it's current and valid
else if (servletLastMod <= cacheLastMod &&
cacheResponse.isValid() &&
equal(cacheQueryString, req.getQueryString()) &&
equal(cachePathInfo, req.getPathInfo()) &&
equal(cacheServletPath, req.getServletPath())) {
cacheResponse.writeTo(res);
}
// Otherwise make a new cache to capture the response
else {
cacheResponse = new CacheHttpServletResponse(res);
cacheLastMod = servletLastMod;
cacheQueryString = req.getQueryString();
cachePathInfo = req.getPathInfo();
cacheServletPath = req.getServletPath();
super.service(req, cacheResponse);
}
}
private boolean equal(String s1, String s2) {
if (s1 == null && s2 == null) {
return true;
}
else if (s1 == null || s2 == null) {
return false;
}
else {
return s1.equals(s2);
}
}
}
class CacheHttpServletResponse implements HttpServletResponse {
// Store key response variables so they can be set later
private int status;
private Hashtable headers;
private int contentLength;
private String contentType;
private Locale locale;
private Vector cookies;
private boolean didError;
private boolean didRedirect;
private boolean gotStream;
private boolean gotWriter;
private HttpServletResponse delegate;
private CacheServletOutputStream out;
private PrintWriter writer;
CacheHttpServletResponse(HttpServletResponse res) {
delegate = res;
try {
out = new CacheServletOutputStream(res.getOutputStream());
}
catch (IOException e) {
System.out.println(
"Got IOException constructing cached response: " + e.getMessage());
}
internalReset();
}
private void internalReset() {
status = 200;
headers = new Hashtable();
contentLength = -1;
contentType = null;
locale = null;
cookies = new Vector();
didError = false;
didRedirect = false;
gotStream = false;
gotWriter = false;
out.getBuffer().reset();
}
public boolean isValid() {
// We don't cache error pages or redirects
return didError != true && didRedirect != true;
}
private void internalSetHeader(String name, Object value) {
Vector v = new Vector();
v.addElement(value);
headers.put(name, v);
}
private void internalAddHeader(String name, Object value) {
Vector v = (Vector) headers.get(name);
if (v == null) {
v = new Vector();
}
v.addElement(value);
headers.put(name, v);
}
public void writeTo(HttpServletResponse res) {
// Write status code
res.setStatus(status);
// Write convenience headers
if (contentType != null) res.setContentType(contentType);
if (locale != null) res.setLocale(locale);
// Write cookies
Enumeration enum = cookies.elements();
while (enum.hasMoreElements()) {
Cookie c = (Cookie) enum.nextElement();
res.addCookie(c);
}
// Write standard headers
enum = headers.keys();
while (enum.hasMoreElements()) {
String name = (String) enum.nextElement();
Vector values = (Vector) headers.get(name); // may have multiple values
Enumeration enum2 = values.elements();
while (enum2.hasMoreElements()) {
Object value = enum2.nextElement();
if (value instanceof String) {
res.setHeader(name, (String)value);
}
if (value instanceof Integer) {
res.setIntHeader(name, ((Integer)value).intValue());
}
if (value instanceof Long) {
res.setDateHeader(name, ((Long)value).longValue());
}
}
}
// Write content length
res.setContentLength(out.getBuffer().size());
// Write body
try {
out.getBuffer().writeTo(res.getOutputStream());
}
catch (IOException e) {
System.out.println(
"Got IOException writing cached response: " + e.getMessage());
}
}
public ServletOutputStream getOutputStream() throws IOException {
if (gotWriter) {
throw new IllegalStateException(
"Cannot get output stream after getting writer");
}
gotStream = true;
return out;
}
public PrintWriter getWriter() throws UnsupportedEncodingException {
if (gotStream) {
throw new IllegalStateException(
"Cannot get writer after getting output stream");
}
gotWriter = true;
if (writer == null) {
OutputStreamWriter w =
new OutputStreamWriter(out, getCharacterEncoding());
writer = new PrintWriter(w, true); // autoflush is necessary
}
return writer;
}
public void setContentLength(int len) {
delegate.setContentLength(len);
// No need to save the length; we can calculate it later
}
public void setContentType(String type) {
delegate.setContentType(type);
contentType = type;
}
public String getCharacterEncoding() {
return delegate.getCharacterEncoding();
}
public void setBufferSize(int size) throws IllegalStateException {
delegate.setBufferSize(size);
}
public int getBufferSize() {
return delegate.getBufferSize();
}
public void reset() throws IllegalStateException {
delegate.reset();
internalReset();
}
public boolean isCommitted() {
return delegate.isCommitted();
}
public void flushBuffer() throws IOException {
delegate.flushBuffer();
}
public void setLocale(Locale loc) {
delegate.setLocale(loc);
locale = loc;
}
public Locale getLocale() {
return delegate.getLocale();
}
public void addCookie(Cookie cookie) {
delegate.addCookie(cookie);
cookies.addElement(cookie);
}
public boolean containsHeader(String name) {
return delegate.containsHeader(name);
}
/** @deprecated */
public void setStatus(int sc, String sm) {
delegate.setStatus(sc, sm);
status = sc;
}
public void setStatus(int sc) {
delegate.setStatus(sc);
status = sc;
}
public void setHeader(String name, String value) {
delegate.setHeader(name, value);
internalSetHeader(name, value);
}
public void setIntHeader(String name, int value) {
delegate.setIntHeader(name, value);
internalSetHeader(name, new Integer(value));
}
public void setDateHeader(String name, long date) {
delegate.setDateHeader(name, date);
internalSetHeader(name, new Long(date));
}
public void sendError(int sc, String msg) throws IOException {
delegate.sendError(sc, msg);
didError = true;
}
public void sendError(int sc) throws IOException {
delegate.sendError(sc);
didError = true;
}
public void sendRedirect(String location) throws IOException {
delegate.sendRedirect(location);
didRedirect = true;
}
public String encodeURL(String url) {
return delegate.encodeURL(url);
}
public String encodeRedirectURL(String url) {
return delegate.encodeRedirectURL(url);
}
public void addHeader(String name, String value) {
internalAddHeader(name, value);
}
public void addIntHeader(String name, int value) {
internalAddHeader(name, new Integer(value));
}
public void addDateHeader(String name, long value) {
internalAddHeader(name, new Long(value));
}
/** @deprecated */
public String encodeUrl(String url) {
return this.encodeURL(url);
}
/** @deprecated */
public String encodeRedirectUrl(String url) {
return this.encodeRedirectURL(url);
}
}
class CacheServletOutputStream extends ServletOutputStream {
ServletOutputStream delegate;
ByteArrayOutputStream cache;
CacheServletOutputStream(ServletOutputStream out) {
delegate = out;
cache = new ByteArrayOutputStream(4096);
}
public ByteArrayOutputStream getBuffer() {
return cache;
}
public void write(int b) throws IOException {
delegate.write(b);
cache.write(b);
}
public void write(byte b[]) throws IOException {
delegate.write(b);
cache.write(b);
}
public void write(byte buf[], int offset, int len) throws IOException {
delegate.write(buf, offset, len);
cache.write(buf, offset, len);
}
}
Copyright
© 1999-2005 Jason Hunter
| |
webmaster@servlets.com
Last updated:
March 1, 2009
|
|