changeset 804:587c90bc5976 stream

first version using officially approved Servlet 3.0 async support.
author robcast
date Sat, 19 Feb 2011 22:01:12 +0100
parents 034ab33984d2
children 5591163f47ee
files client/digitallibrary/WEB-INF/web.xml servlet/src/digilib/servlet/AsyncServletWorker.java servlet/src/digilib/servlet/Initialiser.java servlet/src/digilib/servlet/Scaler.java servlet/src/digilib/servlet/ServletOps.java servlet/src/digilib/util/DigilibJobCenter.java
diffstat 6 files changed, 129 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/client/digitallibrary/WEB-INF/web.xml	Sat Feb 19 12:32:20 2011 +0100
+++ b/client/digitallibrary/WEB-INF/web.xml	Sat Feb 19 22:01:12 2011 +0100
@@ -1,8 +1,10 @@
-<!DOCTYPE web-app 
-    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
-    "http://java.sun.com/dtd/web-app_2_3.dtd">
-
-<web-app>
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app
+        version="3.0"
+        xmlns="http://java.sun.com/xml/ns/javaee"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
+        
   <!-- General description of your web application -->
   <display-name>
         digilib
@@ -10,14 +12,11 @@
   <description>
         This is the web frontend of the Digital Document Library.
   </description>
-  <!-- The Initaliser servlet -->
+  <!-- The Initaliser servlet (must run first) -->
   <servlet>
         <servlet-name>
             Initialiser
         </servlet-name>
-        <description>
-            The inialisation servlet (must run first).
-        </description>
         <servlet-class>
             digilib.servlet.Initialiser
         </servlet-class>
@@ -31,9 +30,6 @@
         <servlet-name>
             Scaler
         </servlet-name>
-        <description>
-            The servlet to scale the digilib images.
-        </description>
         <servlet-class>
             digilib.servlet.Scaler
         </servlet-class>
@@ -47,9 +43,6 @@
         <servlet-name>
             Texter
         </servlet-name>
-        <description>
-            The servlet for text.
-        </description>
         <servlet-class>
             digilib.servlet.Texter
         </servlet-class>
@@ -59,9 +52,6 @@
         <servlet-name>
             PDFCache
         </servlet-name>
-        <description>
-            The servlet for PDF.
-        </description>
         <servlet-class>
             digilib.servlet.PDFCache
         </servlet-class>
@@ -80,6 +70,14 @@
             Scaler
         </servlet-name>
         <url-pattern>
+            /Scaler
+        </url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+        <servlet-name>
+            Scaler
+        </servlet-name>
+        <url-pattern>
             /authenticated/servlet/Scaler/*
         </url-pattern>
   </servlet-mapping>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/AsyncServletWorker.java	Sat Feb 19 22:01:12 2011 +0100
@@ -0,0 +1,80 @@
+/**
+ * 
+ */
+package digilib.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+
+import digilib.image.DocuImage;
+import digilib.image.ImageJobDescription;
+import digilib.image.ImageOpException;
+import digilib.image.ImageWorker;
+import digilib.servlet.Scaler.ErrMsg;
+import digilib.servlet.Scaler.Error;
+
+/**
+ * @author casties
+ * 
+ */
+public class AsyncServletWorker implements Runnable {
+
+    /** the AsyncServlet context */
+    private AsyncContext asyncContext;
+
+    /** the ImageWorker we use */
+    private ImageWorker imageWorker;
+
+    protected static Logger logger = Logger.getLogger(AsyncServletWorker.class);
+    private long startTime;
+    ErrMsg errMsgType = ErrMsg.IMAGE;
+
+    /**
+     * @param dlConfig
+     * @param jobinfo
+     */
+    public AsyncServletWorker(DigilibConfiguration dlConfig,
+            ImageJobDescription jobinfo, AsyncContext asyncContext,
+            ErrMsg errMsgType, long startTime) {
+        // set up image worker
+        imageWorker = new ImageWorker(dlConfig, jobinfo);
+        // save AsyncContext
+        this.asyncContext = asyncContext;
+        this.startTime = startTime;
+        this.errMsgType = errMsgType;
+    }
+
+    /**
+     * runs the ImakeWorker and writes the image to the ServletResponse.
+     */
+    public void run() {
+        // get fresh response
+        HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
+        try {
+            // render the image
+            DocuImage img = imageWorker.call();
+            // send image
+            ServletOps.sendImage(img, null, response, logger);
+            logger.debug("Job Processing Time: "
+                    + (System.currentTimeMillis() - startTime) + "ms");
+        } catch (ImageOpException e) {
+            logger.error(e.getClass() + ": " + e.getMessage());
+            Scaler.digilibError(errMsgType, Error.IMAGE, null, response);
+        } catch (IOException e) {
+            logger.error(e.getClass() + ": " + e.getMessage());
+            Scaler.digilibError(errMsgType, Error.FILE, null, response);
+        } catch (ServletException e) {
+            logger.error("Servlet error: ", e);
+        } finally {
+            // submit response
+            asyncContext.complete();
+        }
+
+    }
+
+}
--- a/servlet/src/digilib/servlet/Initialiser.java	Sat Feb 19 12:32:20 2011 +0100
+++ b/servlet/src/digilib/servlet/Initialiser.java	Sat Feb 19 22:01:12 2011 +0100
@@ -61,7 +61,7 @@
 	/** DigilibConfiguration instance */
 	DigilibConfiguration dlConfig;
 
-	/** Executor for digilib image jobs */
+	/** Executor for digilib image jobs (AsyncServletWorker doesn't return anything) */
 	DigilibJobCenter<DocuImage> imageEx;
 	
 	/** Executor for PDF jobs */
--- a/servlet/src/digilib/servlet/Scaler.java	Sat Feb 19 12:32:20 2011 +0100
+++ b/servlet/src/digilib/servlet/Scaler.java	Sat Feb 19 22:01:12 2011 +0100
@@ -3,12 +3,12 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
 
+import javax.servlet.AsyncContext;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -20,17 +20,18 @@
 import digilib.image.DocuImage;
 import digilib.image.ImageJobDescription;
 import digilib.image.ImageOpException;
-import digilib.image.ImageWorker;
 import digilib.io.DocuDirCache;
 import digilib.io.DocuDirectory;
 import digilib.io.ImageInput;
 import digilib.util.DigilibJobCenter;
 
-@SuppressWarnings("serial")
+@WebServlet(name="Scaler", urlPatterns={"/Scaler", "/servlet/Scaler/*"}, asyncSupported=true)
 public class Scaler extends HttpServlet {
 
+    private static final long serialVersionUID = 5289386646192471549L;
+
     /** digilib servlet version (for all components) */
-    public static final String version = "1.9.0a3";
+    public static final String version = "1.9.1a2";
 
     /** servlet error codes */
     public static enum Error {UNKNOWN, AUTH, FILE, IMAGE};
@@ -54,13 +55,13 @@
     DigilibJobCenter<DocuImage> imageJobCenter;
 
     /** authentication error image file */
-    File denyImgFile;
+    static File denyImgFile;
 
     /** image error image file */
-    File errorImgFile;
+    static File errorImgFile;
 
     /** not found error image file */
-    File notfoundImgFile;
+    static File notfoundImgFile;
 
     /** send files as is? */
     boolean sendFileAllowed = true;
@@ -183,12 +184,13 @@
 
         accountlog.debug("request: " + request.getQueryString());
         logger.debug("request: " + request.getQueryString());
-        long startTime = System.currentTimeMillis();
+        logger.debug("response:"+ response + " committed=" + response.isCommitted());
+        final long startTime = System.currentTimeMillis();
 
         // parse request
         DigilibRequest dlRequest = new DigilibRequest(request);
         // extract the job information
-        ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
+        final ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
 
         // type of error reporting
         ErrMsg errMsgType = ErrMsg.IMAGE;
@@ -246,16 +248,14 @@
                 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
                 return;
             }
+            
+            // worker job is done asynchronously
+            AsyncContext asyncCtx = request.startAsync(request, response); 
             // create job
-            ImageWorker job = new ImageWorker(dlConfig, jobTicket);
+            AsyncServletWorker job = new AsyncServletWorker(dlConfig, jobTicket, asyncCtx, errMsgType, startTime);
             // submit job
-            Future<DocuImage> jobResult = imageJobCenter.submit(job);
-            // wait for result
-            DocuImage img = jobResult.get();
-            // send image
-            ServletOps.sendImage(img, null, response, logger);
-            logger.debug("Job Processing Time: "
-                    + (System.currentTimeMillis() - startTime) + "ms");
+            imageJobCenter.submit(job);
+            // we're done for now
 
         } catch (ImageOpException e) {
             logger.error(e.getClass() + ": " + e.getMessage());
@@ -266,15 +266,7 @@
         } catch (AuthOpException e) {
             logger.error(e.getClass() + ": " + e.getMessage());
             digilibError(errMsgType, Error.AUTH, null, response);
-        } catch (InterruptedException e) {
-            logger.error(e.getClass() + ": " + e.getMessage());
-        } catch (ExecutionException e) {
-            logger.error(e.getClass() + ": " + e.getMessage());
-            String causeMsg = e.getCause().getMessage();
-            logger.error("caused by: " + causeMsg);
-            digilibError(errMsgType, Error.IMAGE, causeMsg, response);
         }
-
     }
 
     /**
@@ -285,7 +277,7 @@
      * @param msg
      * @param response
      */
-    public void digilibError(ErrMsg type, Error error, String msg,
+    public static void digilibError(ErrMsg type, Error error, String msg,
             HttpServletResponse response) {
         try {
             File img = null;
@@ -306,13 +298,12 @@
                 if (msg == null) {
                     msg = "ERROR: Other image error!";
                 }
-                img = this.errorImgFile;
+                img = errorImgFile;
                 status = HttpServletResponse.SC_BAD_REQUEST;
             }
             if (response.isCommitted()) {
                 // response already committed
-                logger.error("Unable to send error: " + msg);
-                return;
+                logger.warn("Response committed for error "+msg);
             }
             if (type == ErrMsg.TEXT) {
                 ServletOps.htmlMessage(msg, response);
--- a/servlet/src/digilib/servlet/ServletOps.java	Sat Feb 19 12:32:20 2011 +0100
+++ b/servlet/src/digilib/servlet/ServletOps.java	Sat Feb 19 22:01:12 2011 +0100
@@ -297,6 +297,7 @@
     public static void sendImage(DocuImage img, String mimeType,
             HttpServletResponse response, Logger logger) throws ImageOpException,
             ServletException {
+        logger.debug("snding to response:"+ response + " committed=" + response.isCommitted());
     	if (response.isCommitted()) {
         	logger.warn("sendImage: response already committed!");
         	//return;
--- a/servlet/src/digilib/util/DigilibJobCenter.java	Sat Feb 19 12:32:20 2011 +0100
+++ b/servlet/src/digilib/util/DigilibJobCenter.java	Sat Feb 19 22:01:12 2011 +0100
@@ -51,7 +51,7 @@
         }
     }
     
-    /** Submit job to execute
+    /** Submit Callable job that returns a Value to execute.
      * 
      * @param job
      * @return Future to control the job
@@ -60,6 +60,15 @@
         return executor.submit(job);
     }
 
+    /** Submit Runnable job to execute.
+     * 
+     * @param job
+     * @return Future to control the job
+     */
+    public Future<?> submit(Runnable job) {
+        return executor.submit(job);
+    }
+
     /** Returns if the service is overloaded.
      *  
      * @return