jacquard 1.12.0 by The Web Engineering Factory and Toolworks

uk.co.weft.domutil
Class CachedPage

java.lang.Object
  extended byjavax.servlet.GenericServlet
      extended byjavax.servlet.http.HttpServlet
          extended byuk.co.weft.maybeupload.MaybeUploadServlet
              extended byuk.co.weft.htform.Servlet
                  extended byuk.co.weft.htform.WithExceptionHandlerServlet
                      extended byuk.co.weft.domutil.DocPage
                          extended byuk.co.weft.domutil.TransformPage
                              extended byuk.co.weft.domutil.CachedPage
All Implemented Interfaces:
ResourceConsumer, java.io.Serializable, javax.servlet.Servlet, javax.servlet.ServletConfig
Direct Known Subclasses:
ClientsideXslSensitivePage

public class CachedPage
extends TransformPage

a CachedPage is a servlet which generates a page which doesn't often change. A lot of our pages are generated off databases where change to the underlying database is infrequent, and where exact up-to-the-minute up to dateness is not critical. The idea of this class is to reduce the load on the server by cacheing pages as they are generated and then delivering from the cache; the cache is only refreshed if the age of the document in the cache exceeds the document's time-to-live.

This class is not perfect.

Where CachedPage might be used but is contra-indicated by any of the considerations above, use DocPage, q.v.

Nevertheless, this class has very broad applicability for generating near-real-time public content on data-driven Websites. If the content will on average be requested more than once in the cache time-to-live assigned, this class will show performance benefits over DocPage, q.v. The more hits within the cache TTL, the greater the performance gain.

In addition to all the configuration paramaters which DocPage knows about, CachedPage also handles:

cache_path
String, the path to the cache directory within the file system. The cache directory must exist and must be writable by the Servlet engine process. Optional. Defaults to the value of javax.servlet.context.tempdir within the ServletContext. Note that if the path starts with the separator character it will be looked for in the file system root; if it doesn't, in the servlet context.
cache_ttl
Integer, the number of seconds that documents should live in the cache. Defaults to twenty minutes.
cache_updating_page
URL: The url of a page to serve if a request is received while the cache is updating. Should point to a plain HTML file with a meta refresh of about 20 seconds. No default.

Because CachedPage's configuration is a superset of DocPage's, the two are plug-compatible, and you can switch between them in configuration without having to recompile anything.

A note on locking: because Servlets don't have access to the thread that drives them, you can't sleep() while servicing a request. But two invocations of the same Servlet may be running simultaneously. Write locks are implemented, so that while one invocation is writing to a cache file, no other will either write or read it. Unfortunately, because they can't sleep for the few moments required, they will throw an UnavailableException. Ideally there would be a reciprocal lock set by a reading process so that no invocation will start to write while another is reading, but that has not yet been implemented.

TODO: Add something to periodically clean the cache; add something to fail gracefully if insufficient disk space. Fixup so that necessary subdirectories within the cache are created automatically - at present they aren't.

Version:
$Revision: 1.21.4.5 $ This revision: $Author: simon $
Author:
Simon Brooke
See Also:
DocPage, Serialized Form

Field Summary
protected  int bufferBlockSize
          how large a buffer I use for schlurping files out to the net
protected  java.lang.String cachePath
          where my cache is in the file system; default to /tmp
protected static int hits
          number of requests satisfied from the cache
protected  java.util.Hashtable locks
          Holds write locks on the cache when writing to it so as to prevent a pull happening when a write is in progress
protected static int misses
          number of hits satisfied by regenerating
static java.lang.String REFRESHMAGICTOKEN
          A token which, if it has the value 'true' in the service context, will cause the cache to be refreshed immediately.
protected  int ttl
          how long things live in my cache; default is twenty minutes
static java.lang.String UPDATINGPAGECONFIGTOKEN
          A token on which I shall look in my config for the URL of a page template to serve if a request is received when my cache is updating
protected  java.net.URL updatingPageURL
          the url of our when-updating page
static java.lang.String WHENLOCKEDERROR
          The error message to send when the cache is locked and there is no updating template available.
 
Fields inherited from class uk.co.weft.domutil.TransformPage
transforms
 
Fields inherited from class uk.co.weft.domutil.DocPage
ACCEPTHEADER, ACCEPTSXMLMAGICTOKEN, AXMLMIMETYPE, caxton, chosenGeneratorMagicToken, CHOSENGENERATORMAGICTOKEN, entitiesFileName, generators, processClientSide, PROCESSCLIENTSIDECONFIGTOKEN, transformerFactory, TXMLMIMETYPE, xslDocument, xslStylesheetName, XSLTRANSFORMCONFIGTOKEN
 
Fields inherited from class uk.co.weft.htform.WithExceptionHandlerServlet
EXCEPTIONHANDLERCLASSCONFIGTOKEN
 
Fields inherited from class uk.co.weft.htform.Servlet
calendar, conf, contentType, CONTENTTYPECONFIGTOKEN, cookieDomain, cookiePath, COOKIESCONFIGTOKEN, cookieTTL, dbPassword, dbUrl, dbUsername, debug, DEBUGCONFIGTOKEN, driverName, embedded, here, identity, localeMagicToken, LOCALEMAGICTOKEN, outputStreamMagicToken, OUTPUTSTREAMMAGICTOKEN, parsePathInfo, PATHINFOMAGICTOKEN, ready, redirectMagicToken, REDIRECTMAGICTOKEN, requestMagicToken, REQUESTMAGICTOKEN, resourceBundleName, responseMagicToken, RESPONSEMAGICTOKEN, servletMagicToken, SERVLETMAGICTOKEN, sessionMagicToken, SESSIONMAGICTOKEN, USEHTTPSCONFIGTOKEN, zone
 
Fields inherited from class uk.co.weft.maybeupload.MaybeUploadServlet
allowOverwrite, maxUpload, saveUploadedFilesToDisk, silentlyRename, uploadDir, uploadDirPath, uploadDirURL
 
Fields inherited from interface uk.co.weft.htform.ResourceConsumer
RESOURCEBUNDLEMAGICTOKEN
 
Constructor Summary
CachedPage()
           
 
Method Summary
protected  boolean checkLock(java.lang.String key, Context context)
          Check to see if this cache is currently locked for updating.
protected  void doPost(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse res)
          Specialisation: we can't effectively cache post requests, so we must handle doPost differently from doGet.
protected  void generateContent(Context context)
          produce my content, pulling it from cache if available and not aged out
protected  java.lang.String getCacheName(Context context)
          compute, as a string, the cache name associated with this request and return it.
 void init(Context config)
          Initialisation: Set up my variables from my configuration.
protected  void useCache(java.io.File file, Context context)
          take the document from this file and print it to the output stream
 
Methods inherited from class uk.co.weft.domutil.TransformPage
getXSLDocument
 
Methods inherited from class uk.co.weft.domutil.DocPage
clientAcceptsXML, destroy, generateContent, generateDocument, getContentType, printDocument, tryGenerators
 
Methods inherited from class uk.co.weft.htform.WithExceptionHandlerServlet
whinge, whinge, whinge
 
Methods inherited from class uk.co.weft.htform.Servlet
addCookie, addCookie, coerceCookiesToContext, coerceToContext, coerceToContext, coerceToContext, coerceToContext, coerceToUrl, createContext, doGet, doPost, fixupMagicValues, getCalendar, getDebug, getLocale, getOutputStream, getResource, getResourceString, getServletInfo, grs, grs, handleAction, handleCookies, handleRedirect, init, makeReady, outputRedirectBlock, setCookieValues, storeOnSession
 
Methods inherited from class uk.co.weft.maybeupload.MaybeUploadServlet
doDelete, doHead, doOptions, doPut, doTrace, getUploadDir, getUploadURL, service
 
Methods inherited from class javax.servlet.http.HttpServlet
doDelete, doGet, doHead, doOptions, doPut, doTrace, getLastModified, service
 
Methods inherited from class javax.servlet.GenericServlet
getInitParameter, getInitParameterNames, getServletConfig, getServletContext, getServletName, init, log, log
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

REFRESHMAGICTOKEN

public static final java.lang.String REFRESHMAGICTOKEN
A token which, if it has the value 'true' in the service context, will cause the cache to be refreshed immediately. This token and its value never form part of the cache key

See Also:
Constant Field Values

UPDATINGPAGECONFIGTOKEN

public static final java.lang.String UPDATINGPAGECONFIGTOKEN
A token on which I shall look in my config for the URL of a page template to serve if a request is received when my cache is updating

See Also:
Constant Field Values

WHENLOCKEDERROR

public static final java.lang.String WHENLOCKEDERROR
The error message to send when the cache is locked and there is no updating template available.

See Also:
Constant Field Values

hits

protected static int hits
number of requests satisfied from the cache


misses

protected static int misses
number of hits satisfied by regenerating


locks

protected java.util.Hashtable locks
Holds write locks on the cache when writing to it so as to prevent a pull happening when a write is in progress


cachePath

protected java.lang.String cachePath
where my cache is in the file system; default to /tmp


updatingPageURL

protected java.net.URL updatingPageURL
the url of our when-updating page


bufferBlockSize

protected int bufferBlockSize
how large a buffer I use for schlurping files out to the net


ttl

protected int ttl
how long things live in my cache; default is twenty minutes

Constructor Detail

CachedPage

public CachedPage()
Method Detail

init

public void init(Context config)
          throws InitialisationException
Initialisation: Set up my variables from my configuration.

Overrides:
init in class TransformPage
Throws:
InitialisationException

getCacheName

protected java.lang.String getCacheName(Context context)
compute, as a string, the cache name associated with this request and return it. Note that by this algorithm, GET foo?a=1&b=2 is treated as being different from GET foo?b=2&a=1. It would be a good thing to normalise this, but this method is exceedingly time critical. Note also that where the servlet path of a request contain one or more file separator characters (i.e. '/' on UNX) these will be replaced by the non-separator-character, by default '_'. Consequently if the cache is fed the paths 'servlet/foo' and 'servlet_foo', those two names will collide. Again, it would be better if they didn't but this code is time critical.

Parameters:
context - The context of this request
Returns:
a unique file name for this request

checkLock

protected boolean checkLock(java.lang.String key,
                            Context context)
Check to see if this cache is currently locked for updating.

Parameters:
key - the cache file name to check
context - the context for this request
Returns:
true if the cache is unlocked, false if it is locked
See Also:
getCacheName(Context)

doPost

protected void doPost(javax.servlet.http.HttpServletRequest req,
                      javax.servlet.http.HttpServletResponse res)
               throws javax.servlet.ServletException,
                      java.io.IOException
Specialisation: we can't effectively cache post requests, so we must handle doPost differently from doGet. Note that this method is closely bound to htform.Servlet.doGet and to DocPage.generateContent; if they are changed so must this be.

Parameters:
req - , the request
res - , the response object
Throws:
javax.servlet.ServletException
java.io.IOException

generateContent

protected void generateContent(Context context)
                        throws GenerationException,
                               java.io.IOException,
                               javax.servlet.ServletException
produce my content, pulling it from cache if available and not aged out

Overrides:
generateContent in class DocPage
Parameters:
context - the context of this request
Throws:
throws - GenerationException on failure to generate
throws - UnavailableException if locked for updating
java.io.IOException - if anything goes wrong while printing.
GenerationException - if anything goes wrong while generating
javax.servlet.ServletException - if cannot generate for other reasons

useCache

protected void useCache(java.io.File file,
                        Context context)
                 throws GenerationException
take the document from this file and print it to the output stream

Parameters:
file - the cache file to print
context - the context of this request
Throws:
throws - GenerationException if for any reason the file can't be copied out
GenerationException

jacquard 1.12.0 by The Web Engineering Factory and Toolworks