changeset 544:5ff500d6812a digilibPDF

more steps towards more standard java.util.concurrent design
author robcast
date Thu, 14 Oct 2010 20:47:31 +0200
parents 919e008ab1fb
children 88ec23c2b2fb
files client/digitallibrary/server/dlConfig.jsp servlet/src/digilib/image/ImageLoaderDocuImage.java servlet/src/digilib/servlet/DigilibConfiguration.java servlet/src/digilib/servlet/DigilibJobCenter.java servlet/src/digilib/servlet/Initialiser.java servlet/src/digilib/servlet/Scaler.java servlet/src/digilib/servlet/ServletOps.java
diffstat 7 files changed, 397 insertions(+), 355 deletions(-) [+]
line wrap: on
line diff
--- a/client/digitallibrary/server/dlConfig.jsp	Thu Oct 14 14:24:33 2010 +0200
+++ b/client/digitallibrary/server/dlConfig.jsp	Thu Oct 14 20:47:31 2010 +0200
@@ -1,3 +1,4 @@
+<%@page import="digilib.servlet.DigilibJobCenter"%>
 <%@ page language="java" %>
 
 <%!
@@ -26,6 +27,9 @@
 dlRequest.setValue("pt", docBean.getNumPages(dlRequest));
 // dir cache
 digilib.io.DocuDirCache dirCache = (digilib.io.DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+// image JobCenter
+DigilibJobCenter imageProcessor =  (DigilibJobCenter)dlConfig.getValue("servlet.worker.imageexecutor");        
+
 %>
 
 <html>
@@ -70,11 +74,11 @@
 
 <table>
   <tr>
-    <td>currently waiting</td><td><b><%= digilib.servlet.DigilibWorker.getNumWaiting() %></b></td>
+    <td>currently waiting</td><td><b><%= imageProcessor.getWaitingJobs() %></b></td>
     <td></td>
   </tr>
   <tr>
-    <td>currently running</td><td><b><%= digilib.servlet.DigilibWorker.getNumRunning() %></b></td>
+    <td>currently running</td><td><b><%= imageProcessor.getRunningJobs() %></b></td>
     <td></td>
   </tr>
 </table>
--- a/servlet/src/digilib/image/ImageLoaderDocuImage.java	Thu Oct 14 14:24:33 2010 +0200
+++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java	Thu Oct 14 20:47:31 2010 +0200
@@ -176,9 +176,6 @@
 		logger.debug("loadImage " + f.getFile());
 		try {
 			img = ImageIO.read(f.getFile());
-			if (img == null) {
-				throw new FileOpException("Unable to load File!");
-			}
             mimeType = f.getMimetype();
 		} catch (IOException e) {
 			throw new FileOpException("Error reading image.");
@@ -223,7 +220,6 @@
 	public void loadSubimage(ImageFile f, Rectangle region, int prescale)
 			throws FileOpException {
 		logger.debug("loadSubimage");
-		// System.gc();
 		try {
 			if ((reader == null) || (imgFile != f.getFile())) {
 				getReader(f);
@@ -242,9 +238,6 @@
 		} catch (IOException e) {
 			throw new FileOpException("Unable to load File!");
 		}
-		if (img == null) {
-			throw new FileOpException("Unable to load File!");
-		}
 	}
 
 	/* write image of type mt to Stream */
@@ -346,7 +339,6 @@
 		logger.debug("SCALE: " + scale + " ->" + scaledImg.getWidth() + "x"
 				+ scaledImg.getHeight());
 		img = scaledImg;
-		scaledImg = null;
 	}
 
 	public void blur(int radius) throws ImageOpException {
@@ -373,9 +365,6 @@
 					.getType());
 		}
 		blurredImg = blurOp.filter(img, blurredImg);
-		if (blurredImg == null) {
-			throw new ImageOpException("Unable to scale");
-		}
 		img = blurredImg;
 	}
 
@@ -501,9 +490,6 @@
 		BufferedImage rotImg = rotOp.filter(img, null);
 		// calculate new bounding box
 		// Rectangle2D bounds = rotOp.getBounds2D(img);
-		if (rotImg == null) {
-			throw new ImageOpException("Unable to rotate");
-		}
 		img = rotImg;
 		// crop new image (with self-made rounding)
 		/*
@@ -538,9 +524,6 @@
 		AffineTransformOp mirOp = new AffineTransformOp(new AffineTransform(mx,
 				0, 0, my, tx, ty), renderHint);
 		BufferedImage mirImg = mirOp.filter(img, null);
-		if (mirImg == null) {
-			throw new ImageOpException("Unable to mirror");
-		}
 		img = mirImg;
 	}
 
--- a/servlet/src/digilib/servlet/DigilibConfiguration.java	Thu Oct 14 14:24:33 2010 +0200
+++ b/servlet/src/digilib/servlet/DigilibConfiguration.java	Thu Oct 14 20:47:31 2010 +0200
@@ -91,6 +91,8 @@
 			's');
 		// AuthOps instance for authentication
 		newParameter("servlet.auth.op", null, null, 's');
+        // Executor for image operations
+        newParameter("servlet.worker.imageexecutor", null, null, 's');
 
 		/*
 		 * parameters that can be read from config file have a type 'f'
@@ -123,8 +125,6 @@
 		newParameter("auth-file", new File("digilib-auth.xml"), null, 'f');
 		// sending image files as-is allowed
 		newParameter("sendfile-allowed", Boolean.TRUE, null, 'f');
-		// Debug level
-		newParameter("debug-level", new Integer(5), null, 'f');
 		// Type of DocuImage instance
 		newParameter(
 			"docuimage-class",
@@ -145,12 +145,10 @@
 		newParameter("log-config-file", new File("log4j-config.xml"), null, 'f');
 		// maximum destination image size (0 means no limit)
 		newParameter("max-image-size", new Integer(0), null, 'f');
-		// use safe (but slower) directory indexing
-		newParameter("safe-dir-index", Boolean.FALSE, null, 'f');
 		// number of working threads
 		newParameter("worker-threads", new Integer(1), null, 'f');
 		// max number of waiting threads
-		newParameter("max-waiting-threads", new Integer(0), null, 'f');
+		newParameter("max-waiting-threads", new Integer(20), null, 'f');
         // PDF generation temp directory
         newParameter("pdf-temp-dir", "pdf_temp", null, 'f');
         // PDF generation cache directory
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibJobCenter.java	Thu Oct 14 20:47:31 2010 +0200
@@ -0,0 +1,110 @@
+/** Wrapper around ExecutionService.
+ * 
+ */
+package digilib.servlet;
+
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.apache.log4j.Logger;
+
+import digilib.image.DocuImage;
+
+/** Wrapper around ExecutionService.
+ * 
+ * @author casties
+ *
+ */
+public class DigilibJobCenter {
+    /** general logger for this class */
+    private static Logger logger = Logger.getLogger("digilib.jobcenter");
+    /** ExecutorService */
+    private ExecutorService executor;
+    /** max number of running threads */
+    private int maxThreads = 1;
+    /** max number of waiting threads */
+    private int maxQueueLen = 50;
+    
+    /**
+     * @param maxThreads
+     * @param maxQueueLength
+     */
+    public DigilibJobCenter(int maxThreads, int maxQueueLen, boolean prestart) {
+        super();
+        this.maxThreads = maxThreads;
+        this.maxQueueLen = maxQueueLen;
+        executor = Executors.newFixedThreadPool(maxThreads);
+        if (prestart) {
+            // prestart threads so Tomcat's leak protection doesn't complain
+            int st = ((ThreadPoolExecutor)executor).prestartAllCoreThreads();
+            logger.debug("prestarting threads: "+st);
+        }
+    }
+    
+    /** Submit job to execute
+     * 
+     * @param job
+     * @return Future to control the job
+     */
+    public Future<DocuImage> submit(Callable<DocuImage> job) {
+        return executor.submit(job);
+    }
+
+    /** Returns if the service is not overloaded.
+     *  
+     * @return
+     */
+    public boolean canRun() {
+        int jql = getWaitingJobs();
+        int jrl = getRunningJobs();
+        logger.debug("canRun: waiting jobs="+jql+" running jobs="+jrl);
+        return (jql <= maxQueueLen);
+    }
+    
+    /** Returns if the service is overloaded.
+     *  
+     * @return
+     */
+    public boolean isBusy() {
+        int jql = getWaitingJobs();
+        int jrl = getRunningJobs();
+        logger.debug("isBusy: waiting jobs="+jql+" running jobs="+jrl);
+        return (jql > maxQueueLen);
+    }
+    
+    public int getRunningJobs() {
+        return ((ThreadPoolExecutor)executor).getActiveCount();
+    }
+    
+    public int getWaitingJobs() {
+        BlockingQueue<Runnable> jq = ((ThreadPoolExecutor)executor).getQueue();
+        int jql = jq.size();
+        return jql;
+    }
+
+    public void setMaxThreads(int maxThreads) {
+        this.maxThreads = maxThreads;
+    }
+
+    public int getMaxThreads() {
+        return maxThreads;
+    }
+
+    public void setMaxQueueLen(int maxQueueLen) {
+        this.maxQueueLen = maxQueueLen;
+    }
+
+    public int getMaxQueueLen() {
+        return maxQueueLen;
+    }
+
+    public List<Runnable> shutdownNow() {
+        return executor.shutdownNow();
+    }
+
+}
--- a/servlet/src/digilib/servlet/Initialiser.java	Thu Oct 14 14:24:33 2010 +0200
+++ b/servlet/src/digilib/servlet/Initialiser.java	Thu Oct 14 20:47:31 2010 +0200
@@ -21,8 +21,7 @@
 package digilib.servlet;
 
 import java.io.File;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.List;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
@@ -41,33 +40,28 @@
 import digilib.io.FileOps;
 
 /**
- * Initalisation servlet for setup tasks.
+ * Singleton initalisation servlet for setup tasks and resources.
  * 
  * @author casties
  *  
  */
 public class Initialiser extends HttpServlet {
 
-	private static final long serialVersionUID = -5126621114382549343L;
-
 	/** servlet version */
-	public static final String iniVersion = "0.1b2";
+	public static final String iniVersion = "0.2";
 
 	/** gengeral logger for this class */
 	private static Logger logger = Logger.getLogger("digilib.init");
 
-	/** AuthOps instance */
-	AuthOps authOp;
-
 	/** DocuDirCache instance */
 	DocuDirCache dirCache;
 
 	/** DigilibConfiguration instance */
 	DigilibConfiguration dlConfig;
 
-	/** use authorization database */
-	boolean useAuthentication = false;
-
+	/** Executor for image jobs */
+	DigilibJobCenter imageEx;
+	
 	/**
 	 * Initialisation on first run.
 	 * 
@@ -83,8 +77,7 @@
 		// get our ServletContext
 		ServletContext context = config.getServletContext();
 		// see if there is a Configuration instance
-		dlConfig = (DigilibConfiguration) context
-				.getAttribute("digilib.servlet.configuration");
+		dlConfig = (DigilibConfiguration) context.getAttribute("digilib.servlet.configuration");
 		if (dlConfig == null) {
 			// create new Configuration
 			try {
@@ -126,7 +119,7 @@
 					// XML version
 					File authConf = ServletOps.getConfigFile((File) dlConfig
 							.getValue("auth-file"), config);
-					authOp = new XMLAuthOps(authConf);
+					AuthOps authOp = new XMLAuthOps(authConf);
 					dlConfig.setValue("servlet.auth.op", authOp);
 					dlConfig.setValue("auth-file", authConf);
 				}
@@ -136,11 +129,9 @@
                 ImageOps.setDocuImage(di);
 				// worker threads
 				int nt = dlConfig.getAsInt("worker-threads");
-				//DigilibWorker1.setSemaphore(nt, true);
-				ExecutorService imageEx = Executors.newFixedThreadPool(nt);
+                int mt = dlConfig.getAsInt("max-waiting-threads");
+				imageEx = new DigilibJobCenter(nt, mt, true);
                 dlConfig.setValue("servlet.worker.imageexecutor", imageEx);				
-				int mt = dlConfig.getAsInt("max-waiting-threads");
-				//DigilibWorker1.setMaxWaitingThreads(mt);
 				// set as the servlets main config
 				context.setAttribute("digilib.servlet.configuration", dlConfig);
 
@@ -152,14 +143,28 @@
 			logger
 					.info("***** Digital Image Library Initialisation Servlet (version "
 							+ iniVersion + ") *****");
-			logger.warn("Already initialised?");
-			// set our AuthOps
-			useAuthentication = dlConfig.getAsBoolean("use-authorization");
-			// AuthOps instance
-			authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
-			// DocuDirCache instance
-			dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+			logger.warn("Already initialised!");
 		}
 	}
 
+    /** clean up local resources
+     * @see javax.servlet.GenericServlet#destroy()
+     */
+    @Override
+    public void destroy() {
+        if (dirCache != null) {
+            // shut down dirCache?
+            dirCache = null;
+        }
+        if (imageEx != null) {
+            // shut down image thread pool
+            List<Runnable> rj = imageEx.shutdownNow();
+            int nrj = rj.size();
+            if (nrj > 0) {
+                logger.error("Still running threads when shutting down image job queue: "+nrj);
+            }
+        }
+        super.destroy();
+    }
+
 }
--- a/servlet/src/digilib/servlet/Scaler.java	Thu Oct 14 14:24:33 2010 +0200
+++ b/servlet/src/digilib/servlet/Scaler.java	Thu Oct 14 20:47:31 2010 +0200
@@ -2,10 +2,8 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 
 import javax.servlet.ServletConfig;
@@ -21,327 +19,268 @@
 import digilib.io.DocuDirCache;
 import digilib.io.DocuDirectory;
 import digilib.io.DocuDirent;
-import digilib.io.FileOpException;
 import digilib.io.FileOps;
 import digilib.io.ImageFile;
 
-
 // TODO digilibError is not used anymore and may need to get reintegrated
 
 public class Scaler extends RequestHandler {
 
-	/** digilib servlet version (for all components) */
-	public static final String dlVersion = "1.8.1a";
+    /** digilib servlet version (for all components) */
+    public static final String dlVersion = "1.8.1a";
 
-	/** general error code */
-	public static final int ERROR_UNKNOWN = 0;
+    /** general error code */
+    public static final int ERROR_UNKNOWN = 0;
 
-	/** error code for authentication error */
-	public static final int ERROR_AUTH = 1;
+    /** error code for authentication error */
+    public static final int ERROR_AUTH = 1;
 
-	/** error code for file operation error */
-	public static final int ERROR_FILE = 2;
+    /** error code for file operation error */
+    public static final int ERROR_FILE = 2;
 
-	/** error code for image operation error */
-	public static final int ERROR_IMAGE = 3;
+    /** error code for image operation error */
+    public static final int ERROR_IMAGE = 3;
 
-	/** DocuDirCache instance */
-	DocuDirCache dirCache;
+    /** DocuDirCache instance */
+    DocuDirCache dirCache;
 
     /** Image executor */
-    ExecutorService imageJobCenter;
+    DigilibJobCenter imageJobCenter;
 
-	/** authentication error image file */
-	File denyImgFile;
+    /** authentication error image file */
+    File denyImgFile;
 
-	/** image error image file */
-	File errorImgFile;
+    /** image error image file */
+    File errorImgFile;
 
-	/** not found error image file */
-	File notfoundImgFile;
-
-	/** subsampling before scaling */
-	float minSubsample = 2f;
+    /** not found error image file */
+    File notfoundImgFile;
 
-	/** send files as is? */
-	boolean sendFileAllowed = true;
+    /** send files as is? */
+    boolean sendFileAllowed = true;
 
-	/** default scaling quality */
-	int defaultQuality = 1;
-
-	/** DigilibConfiguration instance */
-	DigilibConfiguration dlConfig;
+    /** DigilibConfiguration instance */
+    DigilibConfiguration dlConfig;
 
-	/** use authorization database */
-	boolean useAuthorization = true;
+    /** use authorization database */
+    boolean useAuthorization = true;
 
-	/** AuthOps instance */
-	AuthOps authOp;
+    /** AuthOps instance */
+    AuthOps authOp;
 
-	// EXPRIMENTAL
-	/** try to enlarge cropping area for "oblique" angles */
-	boolean wholeRotArea = false;
+    // EXPRIMENTAL
+    /** try to enlarge cropping area for "oblique" angles */
+    boolean wholeRotArea = false;
 
-	
-	protected long getLastModified(HttpServletRequest request) {
-		accountlog.debug("GetLastModified from " + request.getRemoteAddr()
-				+ " for " + request.getQueryString());
-		long mtime = -1;
-		// create new request with defaults
-		DigilibRequest dlReq = new DigilibRequest();
-		// set with request parameters
-		dlReq.setWithRequest(request);
-		// find the requested file
-		DocuDirent f = findFile(dlReq);
-		if (f != null) {
-			DocuDirectory dd = (DocuDirectory) f.getParent();
-			mtime = dd.getDirMTime() / 1000 * 1000;
-		}
-		return mtime;
-	}
-	
-	/**
-	 * Returns the DocuDirent corresponding to the DigilibRequest.
-	 * 
-	 * @param dlRequest
-	 * @return
-	 */
-	public DocuDirent findFile(DigilibRequest dlRequest) {
-		// find the file(set)
-		DocuDirent f = dirCache.getFile(dlRequest.getFilePath(), dlRequest
-				.getAsInt("pn"), FileOps.CLASS_IMAGE);
-		return f;
-	}
-	
-	
-	
-	/**
-	 * Initialisation on first run.
-	 * @throws ServletException 
-	 * 
-	 * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
-	 */
-	public void init(ServletConfig config) throws ServletException {
-		super.init(config);
+    protected long getLastModified(HttpServletRequest request) {
+        accountlog.debug("GetLastModified from " + request.getRemoteAddr()
+                + " for " + request.getQueryString());
+        long mtime = -1;
+        // create new request with defaults
+        DigilibRequest dlReq = new DigilibRequest();
+        // set with request parameters
+        dlReq.setWithRequest(request);
+        // find the requested file
+        DocuDirent f = findFile(dlReq);
+        if (f != null) {
+            DocuDirectory dd = (DocuDirectory) f.getParent();
+            mtime = dd.getDirMTime() / 1000 * 1000;
+        }
+        return mtime;
+    }
 
-		System.out
-				.println("***** Digital Image Library Image Scaler Servlet (version "
-						+ dlVersion + ") *****");
-		// say hello in the log file
-		logger
-				.info("***** Digital Image Library Image Scaler Servlet (version "
-						+ dlVersion + ") *****");
+    /**
+     * Returns the DocuDirent corresponding to the DigilibRequest.
+     * 
+     * @param dlRequest
+     * @return
+     */
+    public DocuDirent findFile(DigilibRequest dlRequest) {
+        // find the file(set)
+        DocuDirent f = dirCache.getFile(dlRequest.getFilePath(),
+                dlRequest.getAsInt("pn"), FileOps.CLASS_IMAGE);
+        return f;
+    }
 
-		// get our ServletContext
-		ServletContext context = config.getServletContext();
-		// see if there is a Configuration instance
-		dlConfig = (DigilibConfiguration) context
-				.getAttribute("digilib.servlet.configuration");
-		if (dlConfig == null) {
-			// no Configuration
-			throw new ServletException("No Configuration!");
-		}
-		// set our AuthOps
-		useAuthorization = dlConfig.getAsBoolean("use-authorization");
-		authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+    /**
+     * Initialisation on first run.
+     * 
+     * @throws ServletException
+     * 
+     * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+     */
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
 
-		// DocuDirCache instance
-		dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
-		
-		// Executor
-		imageJobCenter = (ExecutorService) dlConfig.get("servlet.worker.imageexecutor");
-		
-		denyImgFile = ServletOps.getFile((File) dlConfig.getValue("denied-image"), config);
-		errorImgFile = ServletOps.getFile((File) dlConfig.getValue("error-image"), config);
-		notfoundImgFile = ServletOps.getFile((File) dlConfig.getValue("notfound-image"), config);
-		sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed");
-		minSubsample = dlConfig.getAsFloat("subsample-minimum");
-		defaultQuality = dlConfig.getAsInt("default-quality");
-	}
+        System.out
+                .println("***** Digital Image Library Image Scaler Servlet (version "
+                        + dlVersion + ") *****");
+        // say hello in the log file
+        logger.info("***** Digital Image Library Image Scaler Servlet (version "
+                + dlVersion + ") *****");
 
-	
-	
-	
-	@Override
-	public void processRequest(HttpServletRequest request,
-			HttpServletResponse response) throws ServletException, ImageOpException {
+        // get our ServletContext
+        ServletContext context = config.getServletContext();
+        // see if there is a Configuration instance
+        dlConfig = (DigilibConfiguration) context
+                .getAttribute("digilib.servlet.configuration");
+        if (dlConfig == null) {
+            // no Configuration
+            throw new ServletException("No Configuration!");
+        }
+        // set our AuthOps
+        useAuthorization = dlConfig.getAsBoolean("use-authorization");
+        authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
 
-		
-		if (dlConfig == null) {
-			throw new ServletException("ERROR: No Configuration!");
-		}
-		
-		accountlog.debug("request: " + request.getQueryString());
-		logger.debug("request: " + request.getQueryString());
-		
+        // DocuDirCache instance
+        dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+
+        // Executor
+        imageJobCenter = (DigilibJobCenter) dlConfig
+                .getValue("servlet.worker.imageexecutor");
 
-		// define the job information
-		ImageJobInformation jobdeclaration = new ImageJobInformation(dlConfig);
-		jobdeclaration.setWithRequest(request);
-	
-		ImageFile fileToLoad = null;
-		try {
-			fileToLoad = jobdeclaration.get_fileToLoad();
-		} catch (IOException e2) {
-			// TODO Auto-generated catch block
-			e2.printStackTrace();
-			return;
-		}
-		
-		
-		// if requested, send image as a file
-		if(sendFileAllowed && jobdeclaration.checkSendAsFile()){
-			String mt = null;
-			if (jobdeclaration.hasOption("mo", "rawfile")) {
-				mt = "application/octet-stream";
-			}
-			logger.debug("Sending RAW File as is.");
-			try {
-				ServletOps.sendFile(fileToLoad.getFile(), mt, response);
-			} catch (FileOpException e) {
-				e.printStackTrace();
-			}
+        denyImgFile = ServletOps.getFile(
+                (File) dlConfig.getValue("denied-image"), config);
+        errorImgFile = ServletOps.getFile(
+                (File) dlConfig.getValue("error-image"), config);
+        notfoundImgFile = ServletOps.getFile(
+                (File) dlConfig.getValue("notfound-image"), config);
+        sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed");
+    }
 
-			return;
-		}
+    @Override
+    public void processRequest(HttpServletRequest request,
+            HttpServletResponse response) throws ServletException,
+            ImageOpException {
 
-		
-		
-		// if possible, send the image without actually having to transform it
-		if(jobdeclaration.noTransformRequired()){
-			logger.debug("Sending File as is.");
+        if (dlConfig == null) {
+            throw new ServletException("ERROR: No Configuration!");
+        }
 
-			try {
-				ServletOps.sendFile(fileToLoad.getFile(), null, response);
-			} catch (FileOpException e) {
-				e.printStackTrace();
-			}
+        accountlog.debug("request: " + request.getQueryString());
+        logger.debug("request: " + request.getQueryString());
+        long startTime = System.currentTimeMillis();
+
+        // define the job information
+        ImageJobInformation jobdeclaration = new ImageJobInformation(dlConfig);
+        jobdeclaration.setWithRequest(request);
 
-			//logger.info("Done in "
-			//		+ (System.currentTimeMillis() - startTime) + "ms");
-			return;
-		}
-		
+        // DigilibWorker1 job=null;
+        ImageWorker job = null;
+        try {
+
+            ImageFile fileToLoad = jobdeclaration.get_fileToLoad();
 
-		
-		
-		if (! DigilibWorker1.canRun()) {
-			logger.error("Servlet overloaded!");
-			try {
-				response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
-			} catch (IOException e) {
-				e.printStackTrace();
-			}
-			return;
-		}
-
-		
-		//DigilibWorker1 job=null;
-		ImageWorker job = null;
-		try {
-			
-			long startTime = System.currentTimeMillis();
+            /* check permissions */
+            if (useAuthorization) {
+                // get a list of required roles (empty if no restrictions)
+                List<String> rolesRequired = authOp.rolesForPath(
+                        jobdeclaration.getFilePath(), request);
+                if (rolesRequired != null) {
+                    authlog.debug("Role required: " + rolesRequired);
+                    authlog.debug("User: " + request.getRemoteUser());
+                    // is the current request/user authorized?
+                    if (!authOp.isRoleAuthorized(rolesRequired, request)) {
+                        // send deny answer and abort
+                        throw new AuthOpException();
+                    }
+                }
+            }
 
-	        OutputStream outputstream = null;
-	        outputstream =  response.getOutputStream();
-	        
-			/* check permissions */
-			if (useAuthorization) {
-				// get a list of required roles (empty if no restrictions)
-				List<String> rolesRequired;
-				try {
-					rolesRequired = authOp.rolesForPath(jobdeclaration.getFilePath(), request);
-					if (rolesRequired != null) {
-						authlog.debug("Role required: " + rolesRequired);
-						authlog.debug("User: " + request.getRemoteUser());
-						// is the current request/user authorized?
-						if (!authOp.isRoleAuthorized(rolesRequired, request)) {
-							// send deny answer and abort
-							throw new AuthOpException();
-						}
-					}
+            // if requested, send image as a file
+            if (sendFileAllowed && jobdeclaration.checkSendAsFile()) {
+                String mt = null;
+                if (jobdeclaration.hasOption("mo", "rawfile")) {
+                    mt = "application/octet-stream";
+                }
+                logger.debug("Sending RAW File as is.");
+                logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms");
+                ServletOps.sendFile(fileToLoad.getFile(), mt, response);
+                return;
+            }
 
-				} catch (AuthOpException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			}
+            // if possible, send the image without actually having to transform
+            // it
+            if (jobdeclaration.noTransformRequired()) {
+                logger.debug("Sending File as is.");
+                ServletOps.sendFile(fileToLoad.getFile(), null, response);
+                logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms");
+                return;
+            }
 
-			
-			//job = new DigilibImageWorker1(dlConfig, outputstream , jobdeclaration);
-			//job.run();
-
-			// create job
-			job = new ImageWorker(dlConfig, jobdeclaration);
-			// submit job
+            // check load of workers
+            if (imageJobCenter.isBusy()) {
+                logger.error("Servlet overloaded!");
+                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                return;
+            }
+            // create job
+            job = new ImageWorker(dlConfig, jobdeclaration);
+            // submit job
             Future<DocuImage> jobResult = imageJobCenter.submit(job);
             // wait for result
             DocuImage img = jobResult.get();
             // send image
-            ServletOps.writeImage(img, null, outputstream);
-			
-            logger.debug("Job Processing Time: "+ (System.currentTimeMillis()-startTime) + "ms");
-			
-		} catch (IOException e) {
-			e.printStackTrace();
-			logger.error(e.getClass()+": "+ e.getMessage());
-			//response.sendError(1);
-		} catch (InterruptedException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-            logger.error(e.getClass()+": "+ e.getMessage());
+            ServletOps.sendImage(img, null, response);
+            logger.debug("Job Processing Time: "
+                    + (System.currentTimeMillis() - startTime) + "ms");
+
+        } catch (IOException e) {
+            logger.error(e.getClass() + ": " + e.getMessage());
+            // response.sendError(1);
+        } catch (AuthOpException e) {
+            logger.error(e.getClass() + ": " + e.getMessage());
+            // response.sendError(1);
+        } catch (InterruptedException e) {
+            logger.error(e.getClass() + ": " + e.getMessage());
         } catch (ExecutionException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-            logger.error(e.getClass()+": "+ e.getMessage());
-            logger.error("caused by: "+ e.getCause().getMessage());
+            logger.error(e.getClass() + ": " + e.getMessage());
+            logger.error("caused by: " + e.getCause().getMessage());
         }
 
-	}
-	
-	
-	/**
-	 * Sends an error to the client as text or image.
-	 * 
-	 * @param asHTML
-	 * @param type
-	 * @param msg
-	 * @param response
-	 */
-	public void digilibError(boolean asHTML, int type, String msg,
-			HttpServletResponse response) {
-		try {
-			File img = null;
-			if (type == ERROR_AUTH) {
-				if (msg == null) {
-					msg = "ERROR: Unauthorized access!";
-				}
-				img = denyImgFile;
-			} else if (type == ERROR_FILE) {
-				if (msg == null) {
-					msg = "ERROR: Image file not found!";
-				}
-				img = notfoundImgFile;
-			} else {
-				if (msg == null) {
-					msg = "ERROR: Other image error!";
-				}
-				img = this.errorImgFile;
-			}
-			if (asHTML && (img != null)) {
-				ServletOps.htmlMessage(msg, response);
-			} else {
-				ServletOps.sendFile(img, null, response);
-			}
-		} catch (IOException e) {
-			logger.error("Error sending error!", e);
-		}
+    }
 
-	}
+    /**
+     * Sends an error to the client as text or image.
+     * 
+     * @param asHTML
+     * @param type
+     * @param msg
+     * @param response
+     */
+    public void digilibError(boolean asHTML, int type, String msg,
+            HttpServletResponse response) {
+        try {
+            File img = null;
+            if (type == ERROR_AUTH) {
+                if (msg == null) {
+                    msg = "ERROR: Unauthorized access!";
+                }
+                img = denyImgFile;
+            } else if (type == ERROR_FILE) {
+                if (msg == null) {
+                    msg = "ERROR: Image file not found!";
+                }
+                img = notfoundImgFile;
+            } else {
+                if (msg == null) {
+                    msg = "ERROR: Other image error!";
+                }
+                img = this.errorImgFile;
+            }
+            if (asHTML && (img != null)) {
+                ServletOps.htmlMessage(msg, response);
+            } else {
+                ServletOps.sendFile(img, null, response);
+            }
+        } catch (IOException e) {
+            logger.error("Error sending error!", e);
+        }
 
-	public static String getVersion(){
-		return dlVersion;
-	}
-	
+    }
+
+    public static String getVersion() {
+        return dlVersion;
+    }
 
 }
--- a/servlet/src/digilib/servlet/ServletOps.java	Thu Oct 14 14:24:33 2010 +0200
+++ b/servlet/src/digilib/servlet/ServletOps.java	Thu Oct 14 20:47:31 2010 +0200
@@ -34,7 +34,6 @@
 import org.apache.log4j.Logger;
 
 import digilib.image.DocuImage;
-import digilib.image.ImageOps;
 import digilib.io.FileOpException;
 import digilib.io.FileOps;
 
@@ -189,9 +188,10 @@
      *            ServletResponse where the image file will be sent.
      * @throws FileOpException
      *             Exception is thrown for a IOException.
+     * @throws IOException 
      */
     public static void sendFile(File f, String mt, HttpServletResponse response)
-            throws FileOpException {
+            throws FileOpException, IOException {
         logger.debug("sendRawFile(" + mt + ", " + f + ")");
         if (mt == null) {
             // auto-detect mime-type
@@ -202,37 +202,42 @@
         }
         response.setContentType(mt);
         // open file
-        try {
-            if (mt.equals("application/octet-stream")) {
-                response.addHeader("Content-Disposition",
-                        "attachment; filename=\"" + f.getName() + "\"");
-            }
-            FileInputStream inFile = new FileInputStream(f);
-            OutputStream outStream = response.getOutputStream();
-            byte dataBuffer[] = new byte[4096];
-            int len;
-            while ((len = inFile.read(dataBuffer)) != -1) {
-                // copy out file
-                outStream.write(dataBuffer, 0, len);
-            }
-            inFile.close();
-            response.flushBuffer();
-        } catch (IOException e) {
-            throw new FileOpException("Unable to send file.");
+        if (mt.equals("application/octet-stream")) {
+            response.addHeader("Content-Disposition", "attachment; filename=\""
+                    + f.getName() + "\"");
         }
+        FileInputStream inFile = new FileInputStream(f);
+        OutputStream outStream = response.getOutputStream();
+        byte dataBuffer[] = new byte[4096];
+        int len;
+        while ((len = inFile.read(dataBuffer)) != -1) {
+            // copy out file
+            outStream.write(dataBuffer, 0, len);
+            outStream.flush();
+        }
+        inFile.close();
+        response.flushBuffer();
     }
 
-    public static void writeImage(DocuImage img, String mimeType, OutputStream outstream) throws FileOpException,
-            IOException {
-        /* write the resulting image */
-
+    /**
+     * Write image img to ServletResponse response.
+     * 
+     * @param img
+     * @param mimeType
+     * @param response
+     * @throws FileOpException
+     * @throws IOException
+     */
+    public static void sendImage(DocuImage img, String mimeType,
+            HttpServletResponse response) throws FileOpException, IOException {
+        OutputStream outstream = response.getOutputStream();
         // setup output -- if mime type is set use that otherwise
         // if source is JPG then dest will be JPG else it's PNG
         if (mimeType == null) {
             mimeType = img.getMimetype();
         }
-        if ((mimeType.equals("image/jpeg")
-                || mimeType.equals("image/jp2") || mimeType.equals("image/fpx"))) {
+        if ((mimeType.equals("image/jpeg") || mimeType.equals("image/jp2") || mimeType
+                .equals("image/fpx"))) {
             mimeType = "image/jpeg";
         } else {
             mimeType = "image/png";
@@ -241,8 +246,6 @@
         // write the image
         img.writeImage(mimeType, outstream);
         outstream.flush();
-        
-        logger.debug("write image done");
         img.dispose();
     }