org.hd.d.pg2k.webSvr.exhibit
Class ExhibitServlet

java.lang.Object
  extended by javax.servlet.GenericServlet
      extended by javax.servlet.http.HttpServlet
          extended by org.hd.d.pg2k.webSvr.exhibit.ExhibitServlet
All Implemented Interfaces:
java.io.Serializable, javax.servlet.Servlet, javax.servlet.ServletConfig

public final class ExhibitServlet
extends javax.servlet.http.HttpServlet

This is the servlet that serves exhibit data. This is optimised to serve large quantities of binary data efficiently, and to get headers right to optimise performance of caches, spiders, etc, while not losing site of usage logging.

This expects to be loaded when the whole Web application starts and remain there until the Web application shuts down, and so creates and destroys the data pipeline as a side-effect.

See Also:
Serialized Form

Field Summary
private static int DEFAULT_BUF_SIZE
          Default transfer buffer size; chosen to be efficient but not huge.
private static boolean ENABLE_READAHEAD
          If true then enable async read-ahead for large exhibits where throughput is low.
private  boolean initialised
          Private to init(); ensure exactly-once semantics for init().
private static int MIN_BLOCKS_FOR_READAHEAD
          Minimum number of blocks to consider using async read-ahead; strictly positive.
static boolean ONLY_DESTROYED_ON_SHUTDOWN
          True if we know that this servlet is only unloaded when the site is brought down.
private static byte[] QUEUE_POISON
          Can be inserted into the data queue by the async thread to force the foreground thread to quit.
private static long serialVersionUID
          Unique Serialisation class ID generated by http://random.hd.org/.
 
Constructor Summary
ExhibitServlet()
           
 
Method Summary
 void destroy()
          Shut down gracefully.
 void doAction(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, boolean isHEAD)
          Respond to a GET/HEAD request for the content served by this servlet.
 void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Respond to a GET request for the content served by this servlet.
 void doHead(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Respond to a HEAD request for the content served by this servlet.
private static DataSourceBean getDataSource(javax.servlet.ServletConfig config, javax.servlet.http.HttpServletRequest request)
          Get singleton (per-servlet-context) data pipeline/cache instance.
 long getLastModified(javax.servlet.http.HttpServletRequest request)
          Get `last-modified' time for exhibit.
 void init(javax.servlet.ServletConfig config)
          Retrieve some important configuration data and cache it away.
private static byte[] readNextBlock(long startTime, java.nio.ByteBuffer buffer, java.util.concurrent.ArrayBlockingQueue<byte[]> byteBufs, DataSourceBean ds, ExhibitStaticAttr esa, int start, javax.servlet.ServletContext servletContext, javax.servlet.ServletOutputStream os)
          Read the next block of data from the exhibit using the given buffer returning it as a byte[]; never null nor zero-length.
 
Methods inherited from class javax.servlet.http.HttpServlet
doDelete, doOptions, doPost, doPut, doTrace, service, service
 
Methods inherited from class javax.servlet.GenericServlet
getInitParameter, getInitParameterNames, getServletConfig, getServletContext, getServletInfo, getServletName, init, log, log
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

DEFAULT_BUF_SIZE

private static final int DEFAULT_BUF_SIZE
Default transfer buffer size; chosen to be efficient but not huge.

See Also:
Constant Field Values

ONLY_DESTROYED_ON_SHUTDOWN

public static final boolean ONLY_DESTROYED_ON_SHUTDOWN
True if we know that this servlet is only unloaded when the site is brought down. We can use this to quickly destroy an old cache, for example.

See Also:
Constant Field Values

initialised

private boolean initialised
Private to init(); ensure exactly-once semantics for init().


ENABLE_READAHEAD

private static final boolean ENABLE_READAHEAD
If true then enable async read-ahead for large exhibits where throughput is low.

See Also:
Constant Field Values

MIN_BLOCKS_FOR_READAHEAD

private static final int MIN_BLOCKS_FOR_READAHEAD
Minimum number of blocks to consider using async read-ahead; strictly positive. This reflects the fact that starting an additional thread may have a significant overhead.

See Also:
Constant Field Values

QUEUE_POISON

private static final byte[] QUEUE_POISON
Can be inserted into the data queue by the async thread to force the foreground thread to quit.


serialVersionUID

private static final long serialVersionUID
Unique Serialisation class ID generated by http://random.hd.org/.

See Also:
Constant Field Values
Constructor Detail

ExhibitServlet

public ExhibitServlet()
Method Detail

destroy

public void destroy()
Shut down gracefully.

Specified by:
destroy in interface javax.servlet.Servlet
Overrides:
destroy in class javax.servlet.GenericServlet

getDataSource

private static DataSourceBean getDataSource(javax.servlet.ServletConfig config,
                                            javax.servlet.http.HttpServletRequest request)
Get singleton (per-servlet-context) data pipeline/cache instance. The config param must not be null, but for some operations (such as calling destroy()) request can be null.


init

public void init(javax.servlet.ServletConfig config)
          throws javax.servlet.ServletException
Retrieve some important configuration data and cache it away. A bug in Tomcat V3.1--V3.2.1 can cause this init() method to be called twice (concurrently) on the same instance of this servlet, so this routine must be safe in that scenario.

Specified by:
init in interface javax.servlet.Servlet
Overrides:
init in class javax.servlet.GenericServlet
Throws:
javax.servlet.ServletException

doGet

public void doGet(javax.servlet.http.HttpServletRequest request,
                  javax.servlet.http.HttpServletResponse response)
           throws java.io.IOException
Respond to a GET request for the content served by this servlet.

Overrides:
doGet in class javax.servlet.http.HttpServlet
Parameters:
request - The servlet request we are processing
response - The servlet response we are producing
Throws:
java.io.IOException - if an input/output error occurs

doHead

public void doHead(javax.servlet.http.HttpServletRequest request,
                   javax.servlet.http.HttpServletResponse response)
            throws java.io.IOException
Respond to a HEAD request for the content served by this servlet.

Overrides:
doHead in class javax.servlet.http.HttpServlet
Parameters:
request - The servlet request we are processing
response - The servlet response we are producing
Throws:
java.io.IOException - if an input/output error occurs

doAction

public void doAction(javax.servlet.http.HttpServletRequest request,
                     javax.servlet.http.HttpServletResponse response,
                     boolean isHEAD)
              throws java.io.IOException
Respond to a GET/HEAD request for the content served by this servlet. Returns the exhibit data, with a correct MIME type.

If an exhibit is requested by a syntactically-invalid name, we produce an HTTP `forbidden' (403) response.

If we request an exhibit with a valid name, but that does not exist, return return a `non found' (404) response (unless there are no exhibits available, perhaps because of a database problem, in which case we may return `service unavailable' in the hope that that will prevent search engines from purging our exhibits if they happen to visit when we are reloading the database).

We refuse to deal with some dubious requests (eg apparently links directly to our exhibits from external sites) if we are too busy, or if this server is marked as slow/expensive, so as to conserve resources for bona fide users. Dubious requests are rejected with a temporary failure (5xx) code or a redirection to an alternate URL.

Were we observe poor throughput due to excessive time in data fetches then we may switch to an asynchronous read-ahead mode.

TODO:

Parameters:
request - The servlet request we are processing
response - The servlet response we are producing
Throws:
java.io.IOException - if an input/output error occurs

readNextBlock

private static byte[] readNextBlock(long startTime,
                                    java.nio.ByteBuffer buffer,
                                    java.util.concurrent.ArrayBlockingQueue<byte[]> byteBufs,
                                    DataSourceBean ds,
                                    ExhibitStaticAttr esa,
                                    int start,
                                    javax.servlet.ServletContext servletContext,
                                    javax.servlet.ServletOutputStream os)
                             throws java.io.IOException,
                                    java.lang.InterruptedException
Read the next block of data from the exhibit using the given buffer returning it as a byte[]; never null nor zero-length. Retries failed reads up to a time proportional to that already spent on the entire transfer (to reflect the cost of restarting).

Parameters:
os - if non-null may be used to flush() data down to the user; not safe to call from any thread other than the servlet thread
byteBufs - source of recycled byte buffers that we can use rather than using new, we freely discard anything we find that isn't suitable for our purposes; never null
Throws:
java.io.IOException
java.lang.InterruptedException

getLastModified

public final long getLastModified(javax.servlet.http.HttpServletRequest request)
Get `last-modified' time for exhibit. If we can't find out, eg because the exhibit is not present, we return -1L, the default value.

If returning a last-modified value causes difficulty (eg with Tomcat 4.0.1) then we return -1.

Overrides:
getLastModified in class javax.servlet.http.HttpServlet
Parameters:
request - The servlet request we are processing

DHD Multimedia Gallery V1.57.21

Copyright (c) 1996-2011, Damon Hart-Davis. All rights reserved.