changeset 503:fdb824bd57ab digilibPDF

first functional version of PDFCache after restructuring the code
author cmielack
date Mon, 02 Mar 2009 17:11:26 +0100
parents 157d4c7d2343
children a370e72f2179
files servlet/src/digilib/servlet/DigilibImageWorker.java servlet/src/digilib/servlet/DigilibPDFWorker.java servlet/src/digilib/servlet/DigilibWorker.java servlet/src/digilib/servlet/ImageJobInformation.java servlet/src/digilib/servlet/OldDigilibPDFWorker.java servlet/src/digilib/servlet/PDFCache.java servlet/src/digilib/servlet/PDFJobDeclaration.java servlet/src/digilib/servlet/PDFJobInformation.java servlet/src/digilib/servlet/PDFMaker.java servlet/src/digilib/servlet/RequestHandler.java servlet/src/digilib/servlet/Scaler.java
diffstat 11 files changed, 1037 insertions(+), 1259 deletions(-) [+]
line wrap: on
line diff
--- a/servlet/src/digilib/servlet/DigilibImageWorker.java	Mon Feb 23 16:03:06 2009 +0100
+++ b/servlet/src/digilib/servlet/DigilibImageWorker.java	Mon Mar 02 17:11:26 2009 +0100
@@ -94,62 +94,44 @@
 	
 	int forceType;
 
-	/**
-	 * @param dlConfig
-	 * @param response
-	 * @param mimeType
-	 * @param scaleQual
-	 * @param dlRequest
-	 * @param paramROT
-	 * @param paramCONT
-	 * @param paramBRGT
-	 * @param paramRGBM
-	 * @param paramRGBA
-	 * @param fileToLoad
-	 * @param areaXoff
-	 * @param outerUserImgArea
-	 * @param innerUserImgArea
-	 * @param minSubsample
-	 * @param wholeRotArea
-	 * @param forceType
-	 */
-	public DigilibImageWorker(DigilibConfiguration dlConfig,
-			OutputStream outstream, String mimeType, int scaleQual,
-			//DigilibRequest dlRequest, 
-			//ImageJobInformation ijd,
-			float paramROT, float paramCONT,
-			float paramBRGT, float[] paramRGBM, float[] paramRGBA,
-			ImageFile fileToLoad, float scaleXY, Rectangle2D outerUserImgArea,
-			Rectangle2D innerUserImgArea, float minSubsample,
-			boolean wholeRotArea, int forceType, boolean hmir, boolean vmir) {
+
+	public DigilibImageWorker(DigilibConfiguration dlConfig, OutputStream outstream, ImageJobInformation jobinfo) {
 		super();
+		
 		this.dlConfig = dlConfig;
 		this.outstream = outstream;
-		this.mimeType = mimeType;
-		this.scaleQual = scaleQual;
-		//this.dlRequest = dlRequest;
-		//this.ijd = ijd;
-		this.paramROT = paramROT;
-		this.paramCONT = paramCONT;
-		this.paramBRGT = paramBRGT;
-		this.paramRGBM = paramRGBM;
-		this.paramRGBA = paramRGBA;
-		this.fileToLoad = fileToLoad;
-		this.scaleXY = scaleXY;
-		this.outerUserImgArea = outerUserImgArea;
-		this.innerUserImgArea = innerUserImgArea;
-		this.minSubsample = minSubsample;
-		this.wholeRotArea = wholeRotArea;
-		this.forceType = forceType;
-		this.hmir = hmir;
-		this.vmir = vmir;
+		this.mimeType = jobinfo.get_mimeType();
+		this.scaleQual = jobinfo.get_scaleQual();
+		this.paramROT = jobinfo.getAsFloat("rot");
+		this.paramCONT = jobinfo.getAsFloat("cont");
+		this.paramBRGT = jobinfo.getAsFloat("brgt");
+		this.paramRGBM = jobinfo.get_paramRGBM();
+		this.paramRGBA = jobinfo.get_paramRGBA();
+		try {
+			this.fileToLoad = jobinfo.get_fileToLoad();
+			this.scaleXY = jobinfo.get_scaleXY();
+			this.outerUserImgArea = jobinfo.get_outerUserImgArea();
+			this.innerUserImgArea = jobinfo.get_innerUserImgArea();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (ImageOpException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		this.minSubsample = dlConfig.getAsFloat("subsample-minimum");
+		this.wholeRotArea = jobinfo.get_wholeRotArea();
+		this.forceType = jobinfo.get_forceType();
+		this.hmir = jobinfo.get_hmir();
+		this.vmir = jobinfo.get_vmir();
 	}
 
 	/*
 	 * do the work
 	 */
 	public DocuImage render() throws FileOpException, IOException, ImageOpException {
-		;
+		
 		logger.debug("image worker " + this.getName() + " working");
 		startTime = System.currentTimeMillis();
 
--- a/servlet/src/digilib/servlet/DigilibPDFWorker.java	Mon Feb 23 16:03:06 2009 +0100
+++ b/servlet/src/digilib/servlet/DigilibPDFWorker.java	Mon Mar 02 17:11:26 2009 +0100
@@ -24,8 +24,13 @@
 import java.awt.Rectangle;
 import java.awt.geom.Rectangle2D;
 import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
 
 import javax.servlet.http.HttpServletResponse;
 
@@ -34,6 +39,7 @@
 import com.lowagie.text.DocumentException;
 import com.lowagie.text.Image;
 import com.lowagie.text.PageSize;
+import com.lowagie.text.pdf.PdfWriter;
 
 import digilib.image.DocuImage;
 import digilib.image.DocuImageImpl;
@@ -45,183 +51,185 @@
 import digilib.io.ImageFile;
 
 /**
- * worker for image operations.
+ * worker for pdf operations.
  * 
- * @author casties
+ * @author cmielack
  * 
  */
-public class DigilibPDFWorker extends DigilibImageWorker {
-
-	private DigilibConfiguration dlConfig;
-
-
-	long startTime;
-
-	String mimeType;
-
-	int scaleQual;
-
-	DigilibRequest dlRequest;
-
-	float paramROT;
-
-	float paramCONT;
-
-	float paramBRGT;
-
-	float[] paramRGBM;
-
-	float[] paramRGBA;
-
-	ImageFile fileToLoad;
+public class DigilibPDFWorker extends DigilibWorker {
 
-	float areaXoff;
-
-	float areaYoff;
-
-	float areaWidth;
-
-	float areaHeight;
-
-	float scaleXY;
-
-	Rectangle2D outerUserImgArea;
+	private DigilibConfiguration dlConfig = null;
 
-	Rectangle2D innerUserImgArea;
-
-	float minSubsample;
-
-	boolean wholeRotArea;
-
-	int forceType;
-	
-	Document doc;
-	
-	
-	//public ImageLoaderDocuImage render();// throws Exception;
-
+	private Document doc = null;
 
-	/**
-	 * @param dlConfig
-	 * @param response
-	 * @param mimeType
-	 * @param scaleQual
-	 * @param dlRequest
-	 * @param paramROT
-	 * @param paramCONT
-	 * @param paramBRGT
-	 * @param paramRGBM
-	 * @param paramRGBA
-	 * @param fileToLoad
-	 * @param areaXoff
-	 * @param outerUserImgArea
-	 * @param innerUserImgArea
-	 * @param minSubsample
-	 * @param wholeRotArea
-	 * @param forceType
-	 */
-	public DigilibPDFWorker(DigilibConfiguration dlConfig,
-			BufferedOutputStream outstream, String mimeType, int scaleQual,
-			DigilibRequest dlRequest, float paramCONT,
-			float paramBRGT, float[] paramRGBM, float[] paramRGBA,
-			ImageFile fileToLoad, float scaleXY, Rectangle2D outerUserImgArea,
-			Rectangle2D innerUserImgArea, float minSubsample,
-			boolean wholeRotArea, int forceType, Document doc) {
-		super(dlConfig,
-				outstream, mimeType, scaleQual,
-				dlRequest, 0.0f , paramCONT,
-				paramBRGT, paramRGBM,paramRGBA,
-				fileToLoad, scaleXY, outerUserImgArea,
-				innerUserImgArea,minSubsample,
-				wholeRotArea, forceType);
-		
+	private String filename = null;
+	
+	private PDFJobInformation job_info = null;
+	
+	public DigilibPDFWorker(DigilibConfiguration dlConfig, PDFJobInformation pdfji, String filename) {
+		super();
+		// TODO dlConfig 
 		this.dlConfig = dlConfig;
-		this.outstream = outstream;
-		this.mimeType = mimeType;
-		this.scaleQual = scaleQual;
-		this.dlRequest = dlRequest;
-		//this.paramROT = paramROT;
-		this.paramCONT = paramCONT;
-		this.paramBRGT = paramBRGT;
-		this.paramRGBM = paramRGBM;
-		this.paramRGBA = paramRGBA;
-		this.fileToLoad = fileToLoad;
-		this.scaleXY = scaleXY;
-		this.outerUserImgArea = outerUserImgArea;
-		this.innerUserImgArea = innerUserImgArea;
-		this.minSubsample = minSubsample;
-		this.wholeRotArea = wholeRotArea;
-		this.forceType = forceType;
-		this.doc = doc;
+		this.job_info = pdfji;
+		this.filename = filename;
 	}
 
 	public void run() {
-		//logger.debug((++waitingThreads) + " waiting threads");
-		ImageLoaderDocuImage img = null;
+		// create document object
+		doc = new Document(PageSize.A4, 0,0,0,0);
+		PdfWriter docwriter = null;
+		File output_file = new File(PDFCache.cache_directory + filename);
+		FileOutputStream fos;
+
 		try {
-			sem.acquire();
-			//waitingThreads--;
-		} catch (InterruptedException e) {
-			error = e;
-			//waitingThreads--;
-			// should we reinterrupt?
+			fos = new FileOutputStream(output_file);
+		} catch (FileNotFoundException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
 			return;
 		}
-		//logger.debug((++runningThreads) + " running threads");
+
+		
+		long start_time = System.currentTimeMillis();
+
+		
 		try {
-			/* 
-			 * do rendering under the semaphore 
-			 */
-			img = (ImageLoaderDocuImage) super.render();
-		} catch (Throwable e) {
+			docwriter = PdfWriter.getInstance(doc, fos);
+			
+			setPDFProperties();
+
+			doc.open();
+
+			logger.debug("- doc.open()ed ("+(System.currentTimeMillis()-start_time) + "ms)");
+			start_time = System.currentTimeMillis();
+			
+
+			Integer[] pgs = get_pgs();
+
+			for(Integer p: pgs){
+				addImage(p);
+			}
+			
+			
+			
+		}
+		catch(Exception e) {
+			logger.error(e.getMessage());
 			error = e;
-			logger.error(e);
-		} finally {
-		//	runningThreads--;
-			sem.release();
+			return;
+		}
+		
+		finally {
+			if (doc!=null){
+				doc.close();
+				logger.debug("- doc.close() ("+(System.currentTimeMillis()-start_time) + "ms)");
+			}
+			if (docwriter!=null){
+				docwriter.close();
+			}
 		}
-		/* 
-		 * write the result without semaphore
-		 */
-		if (!hasError()) {
-			try{
-				write(img);
-			} catch (Throwable e) {
-				error = e;
-				logger.error(e);
+
+		
+		
+		try {
+			fos.flush();
+		} catch (IOException e) {
+			e.printStackTrace();
+			error = e;
+		}
+		finally{
+			if(fos!=null){
+				try {
+					fos.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
 			}
 		}
 	}
 
-	public void write(ImageLoaderDocuImage img) throws FileOpException, IOException {
-		/* write the resulting image */
+	public void setPDFProperties(){
+		// TODO get proper Information from dlConfig
+		doc.addAuthor(this.getClass().getName());
+		doc.addCreationDate();
+		doc.addKeywords("digilib");
+		doc.addTitle("digilib PDF");
+		doc.addCreator(this.getClass().getName());
+	}
+	
+	public Integer[] get_pgs(){
+		String pages = job_info.getAsString("pgs");
+		ArrayList<Integer> pgs = new ArrayList<Integer>();
+		Integer[] out = null;
+		
+		String intervals[] = pages.split(",");
+		
+		
+		// convert the page-interval-strings into a list containing every single page
+		for(String interval: intervals){
+			if(interval.indexOf("-") > -1){
+				String nums[] = interval.split("-");
+				
+				for(int i=Integer.valueOf(nums[0]); i <= Integer.valueOf(nums[1]); i++){
+					pgs.add(i);
+				}
+			}
+			else{
+				pgs.add(Integer.valueOf(interval));
+			}
+		}
+		out = new Integer[pgs.size()];
 
-
+		pgs.toArray(out);
+		return out;
+	}
+	
+	public void addImage(int pn) {
+		// create ImageJobInformation
+		ImageJobInformation iji = job_info.getImageJobInformation();
+		iji.setValue("pn", pn);
+		// create image worker
+		DigilibImageWorker image_worker = new DigilibImageWorker(dlConfig, null, iji);
 		try {
-			long timing = System.currentTimeMillis();
+			ImageLoaderDocuImage img = (ImageLoaderDocuImage) image_worker.render();
+
 			Image theimg = Image.getInstance(img.getImage(),null);
 			
-			theimg.scaleToFit(PageSize.A4.getWidth(),PageSize.A4.getHeight());
+			float docW = PageSize.A4.getWidth() - 2*PageSize.A4.getBorder(); 
+			float docH= PageSize.A4.getHeight()- 2*PageSize.A4.getBorder();
+
 			
-			logger.debug(" --- loading and scaling took "+(-timing+System.currentTimeMillis())+"ms");
-
-			timing = System.currentTimeMillis();
+			theimg.scaleToFit(docW,docH);
+			
 			
 			doc.add(theimg);
-			logger.debug(" --- adding took "+(-timing+System.currentTimeMillis())+"ms");
-
+			
+		} catch (FileOpException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		} catch (ImageOpException e) {
+			e.printStackTrace();
 		} catch (BadElementException e) {
 			e.printStackTrace();
-			logger.debug("------DigilibPDFWorker write BadElementException");
-
 		} catch (DocumentException e) {
 			e.printStackTrace();
-			logger.debug("------DigilibPDFWorker write DocumentException");
+		}
+	}
+
 
-		}
+	
+	
+	
+	// unnecessary 
+	@Override
+	public DocuImage render() throws Exception {
+		return null;
+	}
+
+	@Override
+	public void write(DocuImage img) throws Exception {
 		
-		logger.info("pdf worker " + this.getName() + " done in "
-				+ (System.currentTimeMillis() - startTime));
-
 	}
+	
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibWorker.java	Mon Mar 02 17:11:26 2009 +0100
@@ -0,0 +1,195 @@
+/* DigilibWorker.java -- image operation worker
+ * 
+ * Digital Image Library servlet components
+ * 
+ * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *  
+ * Created on 18.10.2004
+ */
+package digilib.servlet;
+
+import java.util.concurrent.Semaphore;
+
+import org.apache.log4j.Logger;
+
+import digilib.image.DocuImage;
+
+/**
+ * image operation worker.
+ * 
+ * @author casties
+ */
+public abstract class DigilibWorker {
+
+	protected static Logger logger = Logger.getLogger(DigilibWorker.class);
+
+	private static int maxRunningThreads = 0;
+
+	private static int runningThreads = 0;
+
+	private static int waitingThreads = 0;
+
+	private static int maxWaitingThreads = 0;
+
+	public static Semaphore sem = new Semaphore(2, true);
+
+	protected Throwable error;
+
+	/**
+	 * @param job
+	 */
+	public DigilibWorker() {
+		super();
+		error = null;
+	}
+
+	public abstract DocuImage render() throws Exception;
+
+	public abstract void write(DocuImage img) throws Exception;
+
+	/**
+	 * Do the work.
+	 */
+	public void run() {
+		logger.debug((++waitingThreads) + " waiting threads");
+		DocuImage img = null;
+		try {
+			sem.acquire();
+			waitingThreads--;
+		} catch (InterruptedException e) {
+			error = e;
+			waitingThreads--;
+			// should we reinterrupt?
+			return;
+		}
+		logger.debug((++runningThreads) + " running threads");
+		try {
+			/* 
+			 * do rendering under the semaphore 
+			 */
+			img = render();
+		} catch (Throwable e) {
+			error = e;
+			logger.error(e);
+		} finally {
+			runningThreads--;
+			sem.release();
+		}
+		/* 
+		 * write the result without semaphore
+		 */
+		if (!hasError()) {
+			try{
+				write(img);
+			} catch (Throwable e) {
+				error = e;
+				logger.error(e);
+			}
+		}
+	}
+
+	/**
+	 * Returns the name of this thread.
+	 * 
+	 * @return
+	 */
+	public String getName() {
+		return Thread.currentThread().getName();
+	}
+
+	/** Returns if the worker could run (i.e. is not overloaded).
+	 * 
+	 * @return
+	 */
+	public static boolean canRun() {
+		return ((DigilibWorker.maxWaitingThreads == 0) || (DigilibWorker.getNumWaiting() <= DigilibWorker.maxWaitingThreads));
+	}
+
+	/**
+	 * returns if an error occurred.
+	 * 
+	 * @return
+	 */
+	public boolean hasError() {
+		return (error != null);
+	}
+
+	/**
+	 * @return Returns the error.
+	 */
+	public Throwable getError() {
+		return error;
+	}
+
+	/**
+	 * @return Returns the semaphore.
+	 */
+	public static Semaphore getSemaphore() {
+		return sem;
+	}
+
+	/**
+	 * @param sem
+	 *            The semaphore to set.
+	 */
+	public static void setSemaphore(Semaphore sem) {
+		DigilibWorker.sem = sem;
+	}
+
+	public static void setSemaphore(int maxrun, boolean fair) {
+		sem = new Semaphore(maxrun, fair);
+		maxRunningThreads = maxrun;
+	}
+
+	/**
+	 * The number of currently running threads (approximate).
+	 * 
+	 * @return
+	 */
+	public static int getNumRunning() {
+		return (maxRunningThreads - sem.availablePermits());
+	}
+
+	/**
+	 * The number of currently waiting threads (approximate).
+	 * 
+	 * @return
+	 */
+	public static int getNumWaiting() {
+		return sem.getQueueLength();
+	}
+
+	/**
+	 * @return Returns the maxWaitingThreads.
+	 */
+	public static int getMaxWaitingThreads() {
+		return maxWaitingThreads;
+	}
+
+	/**
+	 * @param maxWaitingThreads The maxWaitingThreads to set.
+	 */
+	public static void setMaxWaitingThreads(int maxWaitingThreads) {
+		DigilibWorker.maxWaitingThreads = maxWaitingThreads;
+	}
+
+	public static int getMaxRunningThreads() {
+		return maxRunningThreads;
+	}
+
+	public static void setMaxRunningThreads(int maxRunningThreads) {
+		DigilibWorker.maxRunningThreads = maxRunningThreads;
+	}
+}
--- a/servlet/src/digilib/servlet/ImageJobInformation.java	Mon Feb 23 16:03:06 2009 +0100
+++ b/servlet/src/digilib/servlet/ImageJobInformation.java	Mon Mar 02 17:11:26 2009 +0100
@@ -51,7 +51,7 @@
 	Boolean imageSendable = null;
 //	Integer paramDW = null;
 //	Integer paramDH 
-	public ImageJobInformation() {
+	public ImageJobInformation(DigilibConfiguration dlcfg) {
 		super(30);
 		
 		// url of the page/document (second part)
@@ -126,11 +126,13 @@
 		// marks
 		newParameter("mk", "", null, 'c');
 */	
+		dlConfig = dlcfg;
 	}
 
-	public void setConfig(DigilibConfiguration dlcfg){
-		dlConfig = dlcfg;
-	}
+
+	/*public void setPageNumber(int pn){
+		put("pn",pn);
+	}*/
 	
 	public void setWithRequest(HttpServletRequest request) {
 		for (String param : parameter_list){
@@ -148,7 +150,7 @@
 		return parameter_list;
 	}
 	
-
+	
 	public boolean hasOption(String param, String opt) {
 		String s = getAsString(param);
 		if (s != null) {
@@ -464,7 +466,6 @@
 
 	
 	public ImageSize get_imgSize() throws IOException, ImageOpException{
-		logger.debug("get_imgSize()");
 
 		ImageSize imgSize = get_fileToLoad().getSize();
 		return imgSize;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/OldDigilibPDFWorker.java	Mon Mar 02 17:11:26 2009 +0100
@@ -0,0 +1,205 @@
+/* DigilibImageWorker.java -- worker for image operations
+ * 
+ * Digital Image Library servlet components
+ * 
+ * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *  
+ * Created on 19.10.2004
+ */
+
+package digilib.servlet;
+
+import java.awt.Rectangle;
+import java.awt.geom.Rectangle2D;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.lowagie.text.BadElementException;
+import com.lowagie.text.Document;
+import com.lowagie.text.DocumentException;
+import com.lowagie.text.Image;
+import com.lowagie.text.PageSize;
+
+import digilib.image.DocuImage;
+import digilib.image.DocuImageImpl;
+import digilib.image.ImageLoaderDocuImage;
+import digilib.image.ImageOpException;
+import digilib.image.ImageOps;
+import digilib.servlet.DigilibImageWorker;
+import digilib.io.FileOpException;
+import digilib.io.ImageFile;
+
+/**
+ * worker for image operations.
+ * 
+ * @author casties
+ * 
+ */
+public class OldDigilibPDFWorker extends DigilibImageWorker {
+
+	private DigilibConfiguration dlConfig;
+
+
+	long startTime;
+
+	String mimeType;
+
+	int scaleQual;
+
+	DigilibRequest dlRequest;
+
+	float paramROT;
+
+	float paramCONT;
+
+	float paramBRGT;
+
+	float[] paramRGBM;
+
+	float[] paramRGBA;
+
+	ImageFile fileToLoad;
+
+	float areaXoff;
+
+	float areaYoff;
+
+	float areaWidth;
+
+	float areaHeight;
+
+	float scaleXY;
+
+	Rectangle2D outerUserImgArea;
+
+	Rectangle2D innerUserImgArea;
+
+	float minSubsample;
+
+	boolean wholeRotArea;
+
+	int forceType;
+	
+	Document doc;
+	
+	
+
+	public OldDigilibPDFWorker(DigilibConfiguration dlConfig,
+			BufferedOutputStream outstream, String mimeType, int scaleQual,
+			DigilibRequest dlRequest, float paramCONT,
+			float paramBRGT, float[] paramRGBM, float[] paramRGBA,
+			ImageFile fileToLoad, float scaleXY, Rectangle2D outerUserImgArea,
+			Rectangle2D innerUserImgArea, float minSubsample,
+			boolean wholeRotArea, int forceType, Document doc) {
+		super(dlConfig,
+				outstream, mimeType, scaleQual,
+				//dlRequest, 
+				0.0f , paramCONT,
+				paramBRGT, paramRGBM,paramRGBA,
+				fileToLoad, scaleXY, outerUserImgArea,
+				innerUserImgArea,minSubsample,
+				wholeRotArea, forceType, false, false);
+		
+		this.dlConfig = dlConfig;
+		this.outstream = outstream;
+		this.mimeType = mimeType;
+		this.scaleQual = scaleQual;
+		this.dlRequest = dlRequest;
+		//this.paramROT = paramROT;
+		this.paramCONT = paramCONT;
+		this.paramBRGT = paramBRGT;
+		this.paramRGBM = paramRGBM;
+		this.paramRGBA = paramRGBA;
+		this.fileToLoad = fileToLoad;
+		this.scaleXY = scaleXY;
+		this.outerUserImgArea = outerUserImgArea;
+		this.innerUserImgArea = innerUserImgArea;
+		this.minSubsample = minSubsample;
+		this.wholeRotArea = wholeRotArea;
+		this.forceType = forceType;
+		this.doc = doc;
+	}
+
+	public void run() {
+		//logger.debug((++waitingThreads) + " waiting threads");
+		ImageLoaderDocuImage img = null;
+		try {
+			sem.acquire();
+			//waitingThreads--;
+		} catch (InterruptedException e) {
+			error = e;
+			//waitingThreads--;
+			// should we reinterrupt?
+			return;
+		}
+		//logger.debug((++runningThreads) + " running threads");
+		try {
+			/* 
+			 * do rendering under the semaphore 
+			 */
+			img = (ImageLoaderDocuImage) super.render();
+		} catch (Throwable e) {
+			error = e;
+			logger.error(e);
+		} finally {
+		//	runningThreads--;
+			sem.release();
+		}
+		/* 
+		 * write the result without semaphore
+		 */
+		if (!hasError()) {
+			try{
+				write(img);
+			} catch (Throwable e) {
+				error = e;
+				logger.error(e);
+			}
+		}
+	}
+
+	public void write(ImageLoaderDocuImage img) throws FileOpException, IOException {
+		/* write the resulting image */
+
+
+		try {
+			long timing = System.currentTimeMillis();
+			Image theimg = Image.getInstance(img.getImage(),null);
+			
+			theimg.scaleToFit(PageSize.A4.getWidth(),PageSize.A4.getHeight());
+			
+			logger.debug(" --- loading and scaling took "+(-timing+System.currentTimeMillis())+"ms");
+
+			timing = System.currentTimeMillis();
+			
+			doc.add(theimg);
+			logger.debug(" --- adding took "+(-timing+System.currentTimeMillis())+"ms");
+
+		} catch (BadElementException e) {
+			e.printStackTrace();
+			logger.error("DigilibPDFWorker write BadElementException");
+		} catch (DocumentException e) {
+			e.printStackTrace();
+			logger.error("DigilibPDFWorker write DocumentException");
+		}
+		
+		logger.info("pdf worker " + this.getName() + " done in "
+				+ (System.currentTimeMillis() - startTime));
+
+	}
+}
\ No newline at end of file
--- a/servlet/src/digilib/servlet/PDFCache.java	Mon Feb 23 16:03:06 2009 +0100
+++ b/servlet/src/digilib/servlet/PDFCache.java	Mon Mar 02 17:11:26 2009 +0100
@@ -1,12 +1,29 @@
 package digilib.servlet;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
+import java.util.HashMap;
 
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 public class PDFCache extends RequestHandler {
 
+	private DigilibConfiguration dlConfig = null;
+	
+	public static String cache_directory = "cache/";  // TODO set using dlConfig
+	
+	public static String cache_hash_id = "digilib.servlet.PDFCache";
+	
+	HashMap<String,Integer> cache_hash = null;
+	
 	
 	public static Integer STATUS_DONE = 0;  	// document exists in cache
 
@@ -15,7 +32,67 @@
 	public static Integer STATUS_NONEXISTENT = 2;  	// document does not exist in cache and is not in progress
 	
 	public static Integer STATUS_ERROR = 3;     // an error occurred while processing the request
+	
+	public static String version = "0.2";
+	
+	// TODO functionality for the pre-generation of complete books/chapters using default values
+	// TODO use DLConfig for default values
+	// TODO use JSPs for automatically refreshing waiting-pages and download-pages
+	// TODO register the PDFCache instance globally and implement getters for cache_dir 
+	
+	
+	public void init(ServletConfig config) throws ServletException{
+		
+		super.init(config);
+		
+		
+		
+		logger.info("initialized PDFCache v."+version);
+		
+		// create and register hashtable
+		ServletContext context = config.getServletContext();
+		
+		dlConfig = (DigilibConfiguration) context.getAttribute("digilib.servlet.configuration");
+		
+		if (dlConfig == null) {
+			// no Configuration
+			throw new ServletException("No Configuration!");
+		}
+		
+		context.setAttribute(cache_hash_id, new HashMap<String,Integer>());
+		
+		cache_hash = (HashMap<String,Integer>) context.getAttribute(cache_hash_id);
 
+		if (cache_hash==null){
+			cache_hash = new HashMap<String,Integer>();
+			context.setAttribute(cache_hash_id, cache_hash);
+		}
+		
+		// scan the directory
+		scanCacheDirectory();
+		
+	}
+	
+	
+	public void scanCacheDirectory(){
+		// search the cache-directory for existing files and fill them into the Hashtable as STATUS_DONE
+
+		ServletContext context = this.getServletContext();
+		HashMap<String,Integer> cache_hash = (HashMap<String,Integer>) context.getAttribute(cache_hash_id);
+
+		File cache_dir = new File(cache_directory);
+		String[] cached_files = cache_dir.list();
+		
+		
+		for (String file: cached_files){
+			String docid = file.substring(0,file.length()-4);
+			logger.debug("docid = "+docid);
+			if (file.endsWith(".pdf") && !cache_hash.containsKey(docid)){
+				logger.debug("PDFCache reads in "+file);
+				cache_hash.put(file, STATUS_DONE);
+			}
+		}
+	}
 	
 	
 	
@@ -24,37 +101,133 @@
 			HttpServletResponse response) {
 
 		// evaluate request ( make a PDFJobDeclaration , get the DocumentId)
+		PDFJobInformation pdfji = new PDFJobInformation(dlConfig); 
+		pdfji.setWithRequest(request);
 		
-		// check, which state the requested document is in (ready, work in progress, non existent) 
+		
+		String docid = pdfji.getDocumentId();
+		
+		
+		int status = getStatus(docid);
+		
+		
 		
-		// if necessary, initialize document generation (and notify the user)
-		
-		// send the document
+		if(status == STATUS_NONEXISTENT){
+			createNewPdfDocument(pdfji, docid); 
+			informUser(status, docid, response);
+		}
+		else if (status == STATUS_DONE){
+			try {
+				sendFile(docid, downloadFilename(pdfji), response);
+			} catch (IOException e) {
+				e.printStackTrace();
+				logger.error(e.getMessage());
+			}
+		}
+		else {
+			informUser(status, docid, response);			
+		}
 	}
 
-	@Override
-	public void sendFile(InputStream is, HttpServletResponse response, String filename) {
+
+	public void informUser(int status, String documentid, HttpServletResponse response){
+		// depending on the documents status, redirect the user to an appropriate waiting- or download-site
+		// TODO
 		
-	}
+		if(status == STATUS_NONEXISTENT){
+			// tell the user that the document has to be created before he/she can download it
+			logger.debug("PDFCache: "+documentid+" has STATUS_NONEXISTENT.");
+		}
+		else if(status == STATUS_WIP){
+			logger.debug("PDFCache: "+documentid+" has STATUS_WIP.");
 
-	public String getDocumentId(PDFJobDeclaration jobdeclaration){
-		// generate an unambiguous ID from the request (this is used for filenames etc)
-		String id;
+			// estimate remaining work time
+			// tell the user he/she has to wait
+		}
+		else if(status == STATUS_DONE){
+			logger.debug("PDFCache: "+documentid+" has STATUS_DONE.");
 
-		String fn = jobdeclaration.getAsString("fn");
-		String dh = jobdeclaration.getAsString("dh");
-		String pgs = jobdeclaration.getAsString("pgs");
-		
-		id = "fn=" + fn + "&dh=" + dh + "&pgs=" + pgs + ".pdf";		
+		// do nothing or refresh
+		}
+		else {
+			logger.debug("PDFCache: "+documentid+" has STATUS_ERROR.");
 
-		return id;
+			// status == STATUS_ERROR
+			// an error must have occured; show error page
+		}
+	
 	}
 
 	
 	/** check the status of the document corresponding to the documentid */
 	public Integer getStatus(String documentid){
-		
+		// rescan directory?  might be useful if more than one instance uses the same cache directory ;  Problem: wip-files occur in the list
+		if(cache_hash.containsKey(documentid))
+			return cache_hash.get(documentid);
+		else
+			return STATUS_NONEXISTENT;
+	}
+
+
+	public void createNewPdfDocument(PDFJobInformation pdfji, String filename){
+		// start new worker
+		PDFMaker pdf_maker = new PDFMaker(dlConfig, cache_hash, pdfji,filename);
+		new Thread(pdf_maker, "PDFMaker").start();
+	}
+	
+	
+	public String downloadFilename(PDFJobInformation pdfji){
+		String filename;
+		filename =  "digilib_";
+		filename += pdfji.getImageJobInformation().getAsString("fn");
+		filename += "_pgs" + pdfji.getAsString("pgs");
+		filename += ".pdf";
 		
-		return 0;
+		return filename;
+	}
+	
+	/**
+	 *  sends a document to the user
+	 * 
+	 * @param cachefile  The filename of the  document in cache.
+	 * @param filename  The filename used for downloading.
+	 * @param response  
+	 * @throws IOException
+	 */
+	public void sendFile(String cachefile, String filename, HttpServletResponse response) throws IOException{
+		File cached_file = null;
+		FileInputStream fis = null;
+		ServletOutputStream sos = null;
+		BufferedInputStream bis = null;
+
+		try {
+			cached_file = new File(cache_directory + cachefile);
+			fis = new FileInputStream(cached_file);
+			sos = response.getOutputStream();
+			bis = new BufferedInputStream(fis);
+
+			int bytes = 0;
+
+			response.setContentType("application/pdf");
+			response.addHeader("Content-Disposition", "attachment; filename="+filename);
+			response.setContentLength( (int) cached_file.length());
+			
+			while ((bytes = bis.read()) != -1){ 
+				sos.write(bytes);
+			}
+			}
+			catch(Exception e){
+				logger.error(e.getMessage());
+			}
+			finally{
+				// close all streams
+				if (fis != null)
+					fis.close();
+				if (bis != null)
+					bis.close();
+				if (sos != null)
+					sos.close();
+			}
+
 	}
 }
--- a/servlet/src/digilib/servlet/PDFJobDeclaration.java	Mon Feb 23 16:03:06 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-package digilib.servlet;
-
-import javax.servlet.http.HttpServletRequest;
-
-
-/** 
- * A container class for storing a set of instructional parameters 
- * used for content generating classes like MakePDF.  
- * 
- * 
- * @author cmielack
- *
- */
-
-
-
-public class PDFJobDeclaration extends ParameterMap {
-
-	String[] parameter_list = {"fn","pgs","dw","dh"};/*,
-			"wx", "wy", "ww", "wh", "ws", 
-			"mo", "rot", "cont", "brgt", "rgbm", "rbgm", 
-			"ddpi", "ddpix", "ddpiy", "scale"};*/
-	
-	public PDFJobDeclaration() {
-		super(30);
-		
-		// url of the page/document (second part)
-		newParameter("fn", "", null, 's');
-		// page number
-		newParameter("pgs", "", null, 's');
-		// width of client in pixels
-		newParameter("dw", new Integer(0), null, 's');
-		// height of client in pixels
-		newParameter("dh", new Integer(0), null, 's');
-		// left edge of image (float from 0 to 1)
-/*		newParameter("wx", new Float(0), null, 's');
-		// top edge in image (float from 0 to 1)
-		newParameter("wy", new Float(0), null, 's');
-		// width of image (float from 0 to 1)
-		newParameter("ww", new Float(1), null, 's');
-		// height of image (float from 0 to 1)
-		newParameter("wh", new Float(1), null, 's');
-		// scale factor
-		newParameter("ws", new Float(1), null, 's');
-		// special options like 'fit' for gifs
-		newParameter("mo", "", null, 's');
-		// rotation angle (degree)
-		newParameter("rot", new Float(0), null, 's');
-		// contrast enhancement factor
-		newParameter("cont", new Float(0), null, 's');
-		// brightness enhancement factor
-		newParameter("brgt", new Float(0), null, 's');
-		// color multiplicative factors
-		newParameter("rgbm", "0/0/0", null, 's');
-		// color additive factors
-		newParameter("rgba", "0/0/0", null, 's');
-		// display dpi resolution (total)
-		newParameter("ddpi", new Float(0), null, 's');
-		// display dpi X resolution
-		newParameter("ddpix", new Float(0), null, 's');
-		// display dpi Y resolution
-		newParameter("ddpiy", new Float(0), null, 's');
-		// scale factor for mo=ascale
-		newParameter("scale", new Float(1), null, 's');
-*/
-		/*
-		 * Parameters of type 'i' are not exchanged between client and server,
-		 * but are for the servlets or JSPs internal use.
-		 */
-
-/*		// url of the page/document (first part, may be empty)
-		newParameter("request.path", "", null, 'i');
-		// base URL (from http:// to below /servlet)
-		newParameter("base.url", null, null, 'i');
-		// DocuImage instance for this request
-*/
-		/*
-		 * Parameters of type 'c' are for the clients use
-		 */
-
-/*		// "real" filename
-		newParameter("img.fn", "", null, 'c');
-		// image dpi x
-		newParameter("img.dpix", new Integer(0), null, 'c');
-		// image dpi y
-		newParameter("img.dpiy", new Integer(0), null, 'c');
-		// hires image size x
-		newParameter("img.pix_x", new Integer(0), null, 'c');
-		// hires image size y
-		newParameter("img.pix_y", new Integer(0), null, 'c');
-		// total number of pages
-		newParameter("pt", new Integer(0), null, 'c');
-		// display level of digilib (0 = just image, 1 = one HTML page
-		// 2 = in frameset, 3 = XUL-'frameset'
-		// 4 = XUL-Sidebar )
-		newParameter("lv", new Integer(2), null, 'c');
-		// marks
-		newParameter("mk", "", null, 'c');
-*/	
-		
-	}
-
-	public void setWithRequest(HttpServletRequest request) {
-		for (String param : parameter_list){
-			if (request.getParameterMap().containsKey(param)){
-				put(param, request.getAttribute(param));
-			}
-		}
-	}
-	
-	
-}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/PDFJobInformation.java	Mon Mar 02 17:11:26 2009 +0100
@@ -0,0 +1,179 @@
+package digilib.servlet;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/** 
+ * A container class for storing a set of instructional parameters 
+ * used for content generating classes like MakePDF.  
+ * 
+ * 
+ * @author cmielack
+ *
+ */
+
+
+
+public class PDFJobInformation extends ParameterMap {
+
+	String[] parameter_list = {"pgs"};//{"fn","pgs","dw","dh"};
+	/*,
+			"wx", "wy", "ww", "wh", "ws", 
+			"mo", "rot", "cont", "brgt", "rgbm", "rbgm", 
+			"ddpi", "ddpix", "ddpiy", "scale"};*/
+	
+	
+	ImageJobInformation image_info = null;
+	DigilibConfiguration dlConfig = null;
+	
+	public PDFJobInformation(DigilibConfiguration dlcfg) {
+		super(30);
+		
+		// url of the page/document (second part)
+//		newParameter("fn", "", null, 's');
+		// page number
+		newParameter("pgs", "", null, 's');
+		// width of client in pixels
+//		newParameter("dw", new Integer(0), null, 's');
+		// height of client in pixels
+//		newParameter("dh", new Integer(0), null, 's');
+		// left edge of image (float from 0 to 1)
+/*		newParameter("wx", new Float(0), null, 's');
+		// top edge in image (float from 0 to 1)
+		newParameter("wy", new Float(0), null, 's');
+		// width of image (float from 0 to 1)
+		newParameter("ww", new Float(1), null, 's');
+		// height of image (float from 0 to 1)
+		newParameter("wh", new Float(1), null, 's');
+		// scale factor
+		newParameter("ws", new Float(1), null, 's');
+		// special options like 'fit' for gifs
+		newParameter("mo", "", null, 's');
+		// rotation angle (degree)
+		newParameter("rot", new Float(0), null, 's');
+		// contrast enhancement factor
+		newParameter("cont", new Float(0), null, 's');
+		// brightness enhancement factor
+		newParameter("brgt", new Float(0), null, 's');
+		// color multiplicative factors
+		newParameter("rgbm", "0/0/0", null, 's');
+		// color additive factors
+		newParameter("rgba", "0/0/0", null, 's');
+		// display dpi resolution (total)
+		newParameter("ddpi", new Float(0), null, 's');
+		// display dpi X resolution
+		newParameter("ddpix", new Float(0), null, 's');
+		// display dpi Y resolution
+		newParameter("ddpiy", new Float(0), null, 's');
+		// scale factor for mo=ascale
+		newParameter("scale", new Float(1), null, 's');
+*/
+		/*
+		 * Parameters of type 'i' are not exchanged between client and server,
+		 * but are for the servlets or JSPs internal use.
+		 */
+
+/*		// url of the page/document (first part, may be empty)
+		newParameter("request.path", "", null, 'i');
+		// base URL (from http:// to below /servlet)
+		newParameter("base.url", null, null, 'i');
+		// DocuImage instance for this request
+*/
+		/*
+		 * Parameters of type 'c' are for the clients use
+		 */
+
+/*		// "real" filename
+		newParameter("img.fn", "", null, 'c');
+		// image dpi x
+		newParameter("img.dpix", new Integer(0), null, 'c');
+		// image dpi y
+		newParameter("img.dpiy", new Integer(0), null, 'c');
+		// hires image size x
+		newParameter("img.pix_x", new Integer(0), null, 'c');
+		// hires image size y
+		newParameter("img.pix_y", new Integer(0), null, 'c');
+		// total number of pages
+		newParameter("pt", new Integer(0), null, 'c');
+		// display level of digilib (0 = just image, 1 = one HTML page
+		// 2 = in frameset, 3 = XUL-'frameset'
+		// 4 = XUL-Sidebar )
+		newParameter("lv", new Integer(2), null, 'c');
+		// marks
+		newParameter("mk", "", null, 'c');
+*/	
+		dlConfig = dlcfg;
+		
+	}
+
+	public void setWithRequest(HttpServletRequest request) {
+		image_info = new ImageJobInformation(dlConfig);
+		image_info.setWithRequest(request);
+		
+		for (String param : parameter_list){
+			if (request.getParameterMap().containsKey(param)){
+				setValueFromString(param, request.getParameter(param));
+			}
+		}
+	}
+	
+	public String getDocumentId(){
+		String id;
+
+		// TODO use complete request information for id generation
+		
+		if(this.image_info!=null){
+			String fn = image_info.getAsString("fn");
+			String dh = image_info.getAsString("dh");
+			String pgs = getAsString("pgs");
+			
+			id = "fn=" + fn + "&dh=" + dh + "&pgs=" + pgs + ".pdf";		
+		}
+		else {
+			id = null;
+		}
+		
+		return id;
+	}
+
+	public ImageJobInformation getImageJobInformation(){
+		ImageJobInformation new_image_info = (ImageJobInformation) image_info.clone();
+		return new_image_info;
+	}
+	
+	public Integer[] getPageNrs() throws Exception{
+		ArrayList<Integer> pgs=new ArrayList<Integer>(); 
+		Integer[] numarray = null;
+
+		String intervals[] = getAsString("pgs").split(",");
+		
+		// convert the page-interval-strings into a list containing every single page
+		for(String interval: intervals){
+			if(interval.indexOf("-") > 1){
+				String nums[] = interval.split("-");
+				
+//				if(nums.length!=2){
+//					throw new Exception("Malformed pageset expression: "+getAsString("pgs"));
+//				}
+				
+				for(int i=Integer.valueOf(nums[0]); i <= Integer.valueOf(nums[1]); i++){
+					pgs.add(i);
+				}
+			}
+			else if (interval.indexOf("-") < 0){
+				pgs.add(Integer.valueOf(interval));
+			}
+//			else{
+//				throw new Exception("Malformed pageset expression: "+getAsString("pgs"));
+//			}
+		}
+
+		pgs.toArray(numarray);
+		return numarray;
+	}
+	
+}
\ No newline at end of file
--- a/servlet/src/digilib/servlet/PDFMaker.java	Mon Feb 23 16:03:06 2009 +0100
+++ b/servlet/src/digilib/servlet/PDFMaker.java	Mon Mar 02 17:11:26 2009 +0100
@@ -1,931 +1,60 @@
-/*
- * MakePDF
- * 
- * Digital Image Library servlet components
- * 
- * Copyright (C) 200-2004 Robert Casties (robcast@mail.berlios.de)
- * 
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- * 
- * Please read license.txt for the full details. A copy of the GPL may be found
- * at http://www.gnu.org/copyleft/lgpl.html
- * 
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA
- *  
- */
-
 package digilib.servlet;
 
-import java.awt.geom.AffineTransform;
-import java.awt.geom.NoninvertibleTransformException;
-import java.awt.geom.Rectangle2D;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
+import java.util.HashMap;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.log4j.Logger;
-
-import com.lowagie.text.*;
-import com.lowagie.text.pdf.PdfWriter;
-
-import digilib.auth.AuthOpException;
-import digilib.auth.AuthOps;
-import digilib.image.ImageOpException;
-import digilib.image.ImageOps;
-import digilib.image.ImageSize;
-import digilib.io.DocuDirCache;
-import digilib.io.DocuDirectory;
-import digilib.io.DocuDirent;
-import digilib.io.FileOpException;
-import digilib.io.FileOps;
-import digilib.io.ImageFile;
-import digilib.io.ImageFileset;
+public class PDFMaker extends HttpServlet implements Runnable {
 
-/**
- * generates pdf-files from a digilib images.
- * This is a very quick and dirty but functional version and will 
- * (hopefully soon) be replaced by a parallelized and more sophisticated one.
- *	
- * @author cmielack
- */
-
-public class PDFMaker extends HttpServlet implements Runnable{
-
-	private static final long serialVersionUID = -325080527268912852L;
-
-	/** digilib servlet version (for all components) */
-	public static final String dlVersion = "1.7.0b";
-
-	/** logger for accounting requests */
-	private static Logger accountlog = Logger.getLogger("account.request");
-
-	/** gengeral logger for this class */
-	private static Logger logger = Logger.getLogger("digilib.servlet");
-
-	/** logger for authentication related */
-	private static Logger authlog = Logger.getLogger("digilib.auth");
-
-	/** general error code */
-	public static final int ERROR_UNKNOWN = 0;
+	private PDFJobInformation job_info = null;
+	private String filename = null;
+	private HashMap cache_hash = null;
+	private DigilibConfiguration dlConfig = null;
+	
 
-	/** 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 image operation error */
-	public static final int ERROR_IMAGE = 3;
-
-	/** DocuDirCache instance */
-	DocuDirCache dirCache;
-
-	/** authentication error image file */
-	File denyImgFile;
-
-	/** image error image file */
-	File errorImgFile;
-
-	/** not found error image file */
-	File notfoundImgFile;
+/**	public void init(ServletConfig config){
+		ServletContext context = config.getServletContext();
+		cache_hash = (HashMap<String,Integer>) context.getAttribute(PDFCache.cache_hash_id);
+	}*/
 
-	/** subsampling before scaling */
-	float minSubsample = 2f;
-
-	/** send files as is? */
-	boolean sendFileAllowed = true;
-
-	/** default scaling quality */
-	int defaultQuality = 1;
-
-	/** DigilibConfiguration instance */
-	DigilibConfiguration dlConfig;
+	
+	public PDFMaker(DigilibConfiguration dlConfig, HashMap cache_hash, PDFJobInformation pdfji, String filename){
+		this.cache_hash = cache_hash;
+		this.job_info = pdfji;
+		this.filename = filename;
+		this.dlConfig = dlConfig;
+	}
+	
 
-	/** use authorization database */
-	boolean useAuthorization = true;
-
-	/** AuthOps instance */
-	AuthOps authOp;
-
-	HttpServletRequest mpdf_request = null;
-	HttpServletResponse mpdf_response = null;
-	String mpdf_filename = "";
-	
-	String default_filename = "digilib_pages.pdf";
 	
 	
-	// EXPRIMENTAL
-	/** try to enlarge cropping area for "oblique" angles */
-	boolean wholeRotArea = false;
+	public void run() {
 
-	/**
-	 * Initialisation on first run.
-	 * 
-	 * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
-	 */
-	public void init(ServletConfig config) throws ServletException {
-		super.init(config);
-
-		System.out
-				.println("***** Digital Image Library Image MakePDF Servlet (version "
-						+ dlVersion + ") *****");
-		// say hello in the log file
-		logger
-				.info("***** Digital Image Library Image MakePDF Servlet (version "
-						+ dlVersion + ") *****");
+		if (! DigilibWorker.canRun()) {
+			// logger.error("Servlet overloaded!");
+			cache_hash.put(filename, PDFCache.STATUS_ERROR);
+			return;
+		}
 
-		// 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!");
+		cache_hash.put(filename, PDFCache.STATUS_WIP);
+		
+		// create PDFWorker
+		DigilibPDFWorker pdf_worker = new DigilibPDFWorker(dlConfig, job_info, filename);
+		
+		// run PDFWorker
+		pdf_worker.run();
+		
+		if(pdf_worker.hasError()){
+			cache_hash.put(filename, PDFCache.STATUS_ERROR);
+			return;
 		}
-		// set our AuthOps
-		useAuthorization = dlConfig.getAsBoolean("use-authorization");
-		authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
-
-		// DocuDirCache instance
-		dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
-		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");
-
-	
-		context.setAttribute("digilib.servlet.MakePDF", this); // register this instance globally, so PDFCache can access it
+		cache_hash.put(filename, PDFCache.STATUS_DONE);
 	}
 
 	
-	public void doCreate(HttpServletRequest request, HttpServletResponse response, String filename)
-		throws ServletException, IOException {
-
-		accountlog.info("GET from " + request.getRemoteAddr());
-		// create new request with defaults
-		DigilibRequest dlReq = new DigilibRequest();
-		// set with request parameters
-		dlReq.setWithRequest(request);
-		// add DigilibRequest to ServletRequest
-		request.setAttribute("digilib.servlet.request", dlReq);
-
-		
-		mpdf_request = request;
-		mpdf_response = response;
-		mpdf_filename = filename;
-		
-	}
 	
-/*	public void doGet(HttpServletRequest request, HttpServletResponse response)
-			throws ServletException, IOException {
-		
-		accountlog.info("GET from " + request.getRemoteAddr());
-		// create new request with defaults
-		DigilibRequest dlReq = new DigilibRequest();
-		// set with request parameters
-		dlReq.setWithRequest(request);
-		// add DigilibRequest to ServletRequest
-		request.setAttribute("digilib.servlet.request", dlReq);
-		// do the processing
-		processRequest(request, response,default_filename);
-	}*/
-
-/*	public void doPost(HttpServletRequest request, HttpServletResponse response)
-			throws ServletException, IOException {
-		
-		accountlog.info("POST from " + request.getRemoteAddr());
-		// create new request with defaults
-		DigilibRequest dlReq = new DigilibRequest();
-		// set with request parameters
-		dlReq.setWithRequest(request);
-		// add DigilibRequest to ServletRequest
-		request.setAttribute("digilib.servlet.request", dlReq);
-		// do the processing
-		processRequest(request, response,default_filename);
-	}*/
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest)
-	 */
-
-	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;
-	}
-
-	void createPDFfile(HttpServletRequest request, HttpServletResponse response, String filename)
-		throws javax.servlet.ServletException, java.io.IOException {
-		
-		Hashtable<String,Integer> cache_hash = (Hashtable<String,Integer>) this.getServletContext().getAttribute("digilib.servlet.PDFCache");
-		BufferedOutputStream pdfOutStream = null;
-		FileOutputStream fos = null;
-
-		String file_only = filename.split("/")[filename.split("/").length-1]; 
-		
-		try {
-
-			cache_hash.put(file_only, 2); // register the file as 'pending'
-	
-			// TODO check, if file can be created without overwriting another file etc.
-
-			fos = new FileOutputStream(filename);
-			
-			pdfOutStream = generatePDFcontent(request, response, this.getServletContext(), fos);
-			
-			fos.flush();
-
-			cache_hash.put(file_only, 1); // register the file as 'done'
-
-		}
-		catch (DocumentException de){
-			// inform the user about what went wrong
-			response.setContentType("text/html");
-			PrintWriter writer = response.getWriter();
-			writer.println(this.getClass().getName() + " caught an exception: "  
-						   + de.getClass().getName() + "<br/> <pre>");
-			de.printStackTrace(writer);
-			writer.println("</pre>");
-		}
-		
-		finally {
-			if (pdfOutStream != null){
-				pdfOutStream.close();
-			}
-			if (fos!=null){
-				fos.close();
-			}
-		}
-	}
-	
-		
-	
-	
-	void addImageToPDF(HttpServletRequest request, HttpServletResponse response, int pn, Document doc)
-			throws ServletException {
-		/** until now, this is taken from the Scaler-method processRequest and modified ...*/
-		
-		
-		if (dlConfig == null) {
-			throw new ServletException("ERROR: No Configuration!");
-		}
-
-		accountlog.debug("request: " + request.getQueryString());
-		logger.debug("request: " + request.getQueryString());
-
-		// output mime-type
-		String mimeType = "image/png";
-
-		/* preset request parameters */
-
-		// scale the image file to fit window size i.e. respect dw,dh
-		boolean scaleToFit = true;
-		// scale the image by a fixed factor only
-		boolean absoluteScale = false;
-		// use low resolution images only
-		boolean loresOnly = false;
-		// use hires images only
-		boolean hiresOnly = false;
-		// send the image always as a specific type (e.g. JPEG or PNG)
-		int forceType = ImageOps.TYPE_AUTO;
-		// interpolation to use for scaling
-		int scaleQual = defaultQuality;
-		// send html error message (or image file)
-		boolean errorMsgHtml = false;
-		// original (hires) image resolution
-		float origResX = 0;
-		float origResY = 0;
-
-		/* request parameters */
-
-		DigilibRequest dlRequest = (DigilibRequest) request
-				.getAttribute("digilib.servlet.request");
-
-		dlRequest.setValue("pn", pn);
-		//dlRequest.setValue("mo", "osize");
-		//dlRequest.setValue("ddpix",72);
-		//dlRequest.setValue("ddpix",72);
-		
-		// destination image width
-		int paramDW = dlRequest.getAsInt("dw");
-		// destination image height
-		int paramDH = dlRequest.getAsInt("dh");
-		// relative area x_offset (0..1)
-		float paramWX = dlRequest.getAsFloat("wx");
-		// relative area y_offset
-		float paramWY = dlRequest.getAsFloat("wy");
-		// relative area width (0..1)
-		float paramWW = dlRequest.getAsFloat("ww");
-		// relative area height
-		float paramWH = dlRequest.getAsFloat("wh");
-		// scale factor (additional to dw/width, dh/height)
-		float paramWS = dlRequest.getAsFloat("ws");
-		// rotation angle
-		float paramROT = dlRequest.getAsFloat("rot");
-		// contrast enhancement
-		float paramCONT = dlRequest.getAsFloat("cont");
-		// brightness enhancement
-		float paramBRGT = dlRequest.getAsFloat("brgt");
-		// color modification
-		float[] paramRGBM = null;
-		Parameter p = dlRequest.get("rgbm");
-		if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
-			paramRGBM = p.parseAsFloatArray("/");
-		}
-		float[] paramRGBA = null;
-		p = dlRequest.get("rgba");
-		if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
-			paramRGBA = p.parseAsFloatArray("/");
-		}
-		// destination resolution (DPI)
-		float paramDDPIX = dlRequest.getAsFloat("ddpix");
-		float paramDDPIY = dlRequest.getAsFloat("ddpiy");
-		if ((paramDDPIX == 0) || (paramDDPIY == 0)) {
-			// if X or Y resolution isn't set, use DDPI
-			paramDDPIX = dlRequest.getAsFloat("ddpi");
-			paramDDPIY = paramDDPIX;
-		}
-		// absolute scale factor for mo=ascale (and mo=osize)
-		float paramSCALE = dlRequest.getAsFloat("scale");
-
-		/*
-		 * operation mode: "fit": always fit to page, "clip": send original
-		 * resolution cropped, "file": send whole file (if allowed)
-		 */
-		if (dlRequest.hasOption("mo", "clip")) {
-			scaleToFit = false;
-			absoluteScale = false;
-			hiresOnly = true;
-		} else if (dlRequest.hasOption("mo", "fit")) {
-			scaleToFit = true;
-			absoluteScale = false;
-			hiresOnly = false;
-		} else if (dlRequest.hasOption("mo", "osize")) {
-			scaleToFit = false;
-			absoluteScale = true;
-			hiresOnly = true;
-		} else if (dlRequest.hasOption("mo", "ascale")) {
-			scaleToFit = false;
-			absoluteScale = true;
-			hiresOnly = false;
-		}
-
-		// operation mode: "lores": try to use scaled image, "hires": use
-		// unscaled image
-		// "autores": try best fitting resolution
-		if (dlRequest.hasOption("mo", "lores")) {
-			loresOnly = true;
-			hiresOnly = false;
-		} else if (dlRequest.hasOption("mo", "hires")) {
-			loresOnly = false;
-			hiresOnly = true;
-		} else if (dlRequest.hasOption("mo", "autores")) {
-			loresOnly = false;
-			hiresOnly = false;
-		}
-		// operation mode: "errtxt": error message in html, "errimg": error
-		// image
-		if (dlRequest.hasOption("mo", "errtxt")) {
-			errorMsgHtml = true;
-		} else if (dlRequest.hasOption("mo", "errimg")) {
-			errorMsgHtml = false;
-		}
-		// operation mode: "q0" - "q2": interpolation quality
-		if (dlRequest.hasOption("mo", "q0")) {
-			scaleQual = 0;
-		} else if (dlRequest.hasOption("mo", "q1")) {
-			scaleQual = 1;
-		} else if (dlRequest.hasOption("mo", "q2")) {
-			scaleQual = 2;
-		}
-		// operation mode: "jpg": always use JPEG
-		if (dlRequest.hasOption("mo", "jpg")) {
-			forceType = ImageOps.TYPE_JPEG;
-		}
-		// operation mode: "png": always use PNG
-		if (dlRequest.hasOption("mo", "png")) {
-			forceType = ImageOps.TYPE_PNG;
-		}
-
-		// check with the maximum allowed size (if set)
-		int maxImgSize = dlConfig.getAsInt("max-image-size");
-		if (maxImgSize > 0) {
-			paramDW = (paramDW * paramWS > maxImgSize) ? (int) (maxImgSize / paramWS)
-					: paramDW;
-			paramDH = (paramDH * paramWS > maxImgSize) ? (int) (maxImgSize / paramWS)
-					: paramDH;
-		}
-
-		// "big" try for all file/image actions
-		try {
-
-			// ImageFileset of the image to load
-			ImageFileset fileset = null;
-
-			/* find the file to load/send */
-
-			// get PathInfo
-			String loadPathName = dlRequest.getFilePath();
-
-			/* check permissions */
-			if (useAuthorization) {
-				// get a list of required roles (empty if no restrictions)
-				List rolesRequired = authOp.rolesForPath(loadPathName, 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();
-					}
-				}
-			}
-
-			// find the file
-			fileset = (ImageFileset) findFile(dlRequest);
-			if (fileset == null) {
-				throw new FileOpException("File " + loadPathName + "("
-						+ dlRequest.getAsInt("pn") + ") not found.");
-			}
-
-			/* for absolute scale and original size we need the hires size */
-			ImageSize hiresSize = null;
-			if (absoluteScale) {
-				ImageFile hiresFile = fileset.getBiggest();
-				if (!hiresFile.isChecked()) {
-					ImageOps.checkFile(hiresFile);
-				}
-				hiresSize = hiresFile.getSize();
-				
-				/* prepare resolution and scale factor for original size */
-				if (dlRequest.hasOption("mo", "osize")) {
-					// get original resolution from metadata
-					fileset.checkMeta();
-					origResX = fileset.getResX();
-					origResY = fileset.getResY();
-					if ((origResX == 0) || (origResY == 0)) {
-						throw new ImageOpException("Missing image DPI information!");
-					}
-
-					if ((paramDDPIX == 0) || (paramDDPIY == 0)) {
-						throw new ImageOpException(
-								"Missing display DPI information!");
-					}
-					// calculate absolute scale factor
-					float sx = paramDDPIX / origResX;
-					float sy = paramDDPIY / origResY;
-					// currently only same scale :-(
-					paramSCALE = (sx + sy)/2f;
-				}
-				
-			}
-			
-
-			/* calculate expected source image size */
-			ImageSize expectedSourceSize = new ImageSize();
-			if (scaleToFit) {
-				// scale to fit -- calculate minimum source size
-				float scale = (1 / Math.min(paramWW, paramWH)) * paramWS;
-				expectedSourceSize.setSize((int) (paramDW * scale),
-						(int) (paramDH * scale));
-			} else if (absoluteScale && dlRequest.hasOption("mo", "ascale")) {
-				// absolute scale -- apply scale to hires size
-				expectedSourceSize = hiresSize.getScaled(paramSCALE);
-			} else {
-				// clip to fit -- source = destination size
-				expectedSourceSize.setSize((int) (paramDW * paramWS),
-						(int) (paramDH * paramWS));
-			}
-
-			ImageFile fileToLoad;
-			/* select a resolution */
-			if (hiresOnly) {
-				// get first element (= highest resolution)
-				fileToLoad = fileset.getBiggest();
-			} else if (loresOnly) {
-				// enforced lores uses next smaller resolution
-				fileToLoad = fileset.getNextSmaller(expectedSourceSize);
-				if (fileToLoad == null) {
-					// this is the smallest we have
-					fileToLoad = fileset.getSmallest();
-				}
-			} else {
-				// autores: use next higher resolution
-				fileToLoad = fileset.getNextBigger(expectedSourceSize);
-				if (fileToLoad == null) {
-					// this is the highest we have
-					fileToLoad = fileset.getBiggest();
-				}
-			}
-			logger.info("Planning to load: " + fileToLoad.getFile());
-
-			/*
-			 * send the image if its mo=(raw)file
-			 */
-			if (dlRequest.hasOption("mo", "file")
-					|| dlRequest.hasOption("mo", "rawfile")) {
-				if (sendFileAllowed) {
-					String mt = null;
-					if (dlRequest.hasOption("mo", "rawfile")) {
-						mt = "application/octet-stream";
-					}
-					logger.debug("Sending RAW File as is.");
-					ServletOps.sendFile(fileToLoad.getFile(), mt, response);
-					return;
-				}
-			}
-
-			// check the source image
-			if (!fileToLoad.isChecked()) {
-				ImageOps.checkFile(fileToLoad);
-			}
-			// get the source image type
-			mimeType = fileToLoad.getMimetype();
-			// get the source image size
-			ImageSize imgSize = fileToLoad.getSize();
-
-			// decide if the image can be sent as is
-			boolean mimetypeSendable = mimeType.equals("image/jpeg")
-					|| mimeType.equals("image/png")
-					|| mimeType.equals("image/gif");
-			boolean imagoOptions = dlRequest.hasOption("mo", "hmir")
-					|| dlRequest.hasOption("mo", "vmir") || (paramROT != 0)
-					|| (paramRGBM != null) || (paramRGBA != null)
-					|| (paramCONT != 0) || (paramBRGT != 0);
-			boolean imageSendable = mimetypeSendable && !imagoOptions;
-
-			/*
-			 * if not autoRes and image smaller than requested size then send as
-			 * is. if autoRes and image has requested size then send as is. if
-			 * not autoScale and not scaleToFit nor cropToFit then send as is
-			 * (mo=file)
-			 */
-/*			if (imageSendable
-					&& ((loresOnly && fileToLoad.getSize().isSmallerThan(
-							expectedSourceSize)) || (!(loresOnly || hiresOnly) && fileToLoad
-							.getSize().fitsIn(expectedSourceSize)))) {
-
-				logger.debug("Sending File as is.");
-
-				ServletOps.sendFile(fileToLoad.getFile(), null, response);
-
-				logger.info("Done in "
-						+ (System.currentTimeMillis() - startTime) + "ms");
-				return;
-			}
-*/
- 
-			
-			/*
-			 * stop here if we're overloaded...
-			 * 
-			 * 503 Service Unavailable 
-			 * The server is currently unable to
-			 * handle the request due to a temporary overloading or maintenance
-			 * of the server. The implication is that this is a temporary
-			 * condition which will be alleviated after some delay. If known,
-			 * the length of the delay MAY be indicated in a Retry-After header.
-			 * If no Retry-After is given, the client SHOULD handle the response
-			 * as it would for a 500 response. Note: The existence of the 503
-			 * status code does not imply that a server must use it when
-			 * becoming overloaded. Some servers may wish to simply refuse the
-			 * connection.
-			 * (RFC2616 HTTP1.1)
-			 */
-			if (! DigilibWorker.canRun()) {
-				logger.error("Servlet overloaded!");
-				response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
-				return;
-			}
-			
-			// set missing dw or dh from aspect ratio
-			float imgAspect = fileToLoad.getAspect();
-			if (paramDW == 0) {
-				paramDW = (int) Math.round(paramDH * imgAspect);
-			} else if (paramDH == 0) {
-				paramDH = (int) Math.round(paramDW / imgAspect);
-			}
-
-			/* crop and scale the image */
-
-			logger.debug("IMG: " + imgSize.getWidth() + "x"
-					+ imgSize.getHeight());
-
-			// coordinates and scaling
-			float areaWidth;
-			float areaHeight;
-			float scaleX;
-			float scaleY;
-			float scaleXY;
-
-			// coordinates using Java2D
-			// image size in pixels
-			Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize
-					.getWidth(), imgSize.getHeight());
-			// user window area in [0,1] coordinates
-			Rectangle2D relUserArea = new Rectangle2D.Float(paramWX, paramWY,
-					paramWW, paramWH);
-			// transform from relative [0,1] to image coordinates.
-			AffineTransform imgTrafo = AffineTransform.getScaleInstance(imgSize
-					.getWidth(), imgSize.getHeight());
-			// transform user coordinate area to image coordinate area
-			Rectangle2D userImgArea = imgTrafo.createTransformedShape(
-					relUserArea).getBounds2D();
-
-			// calculate scaling factors based on inner user area
-			if (scaleToFit) {
-				areaWidth = (float) userImgArea.getWidth();
-				areaHeight = (float) userImgArea.getHeight();
-				scaleX = paramDW / areaWidth * paramWS;
-				scaleY = paramDH / areaHeight * paramWS;
-				scaleXY = (scaleX > scaleY) ? scaleY : scaleX;
-			} else if (absoluteScale) {
-				scaleXY = paramSCALE;
-				// we need to correct the factor if we use a pre-scaled image
-				if (imgSize.getWidth() != hiresSize.getWidth()) {
-					scaleXY *= (float)hiresSize.getWidth() / (float)imgSize.getWidth();
-				}
-				scaleX = scaleXY;
-				scaleY = scaleXY;
-				areaWidth = paramDW / scaleXY * paramWS;
-				areaHeight = paramDH / scaleXY * paramWS;
-				// reset user area size
-				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
-						areaWidth, areaHeight);
-			} else {
-				// crop to fit
-				areaWidth = paramDW * paramWS;
-				areaHeight = paramDH * paramWS;
-				// reset user area size
-				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
-						areaWidth, areaHeight);
-				scaleX = 1f;
-				scaleY = 1f;
-				scaleXY = 1f;
-			}
-
-			// enlarge image area for rotations to cover additional pixels
-			Rectangle2D outerUserImgArea = userImgArea;
-			Rectangle2D innerUserImgArea = userImgArea;
-			if (wholeRotArea) {
-				if (paramROT != 0) {
-					try {
-						// rotate user area coordinates around center of user
-						// area
-						AffineTransform rotTrafo = AffineTransform
-								.getRotateInstance(Math.toRadians(paramROT),
-										userImgArea.getCenterX(), userImgArea
-												.getCenterY());
-						// get bounds from rotated end position
-						innerUserImgArea = rotTrafo.createTransformedShape(
-								userImgArea).getBounds2D();
-						// get bounds from back-rotated bounds
-						outerUserImgArea = rotTrafo.createInverse()
-								.createTransformedShape(innerUserImgArea)
-								.getBounds2D();
-					} catch (NoninvertibleTransformException e1) {
-						// this shouldn't happen anyway
-						logger.error(e1);
-					}
-				}
-			}
-
-			logger.debug("Scale " + scaleXY + "(" + scaleX + "," + scaleY
-					+ ") on " + outerUserImgArea);
-
-			// clip area at the image border
-			outerUserImgArea = outerUserImgArea.createIntersection(imgBounds);
-
-			// check image parameters sanity
-			if ((outerUserImgArea.getWidth() < 1)
-					|| (outerUserImgArea.getHeight() < 1)
-					|| (scaleXY * outerUserImgArea.getWidth() < 2)
-					|| (scaleXY * outerUserImgArea.getHeight() < 2)) {
-				logger.error("ERROR: invalid scale parameter set!");
-				throw new ImageOpException("Invalid scale parameter set!");
-			}
-
-			/*
-			 * submit the image worker job
-			 */
-
-			DigilibPDFWorker job = new DigilibPDFWorker(dlConfig, response,
-					mimeType, scaleQual, dlRequest, paramCONT,
-					paramBRGT, paramRGBM, paramRGBA, fileToLoad, scaleXY,
-					outerUserImgArea, innerUserImgArea, minSubsample,
-					wholeRotArea, forceType, doc);
-
-			job.run();
-			if (job.hasError()) {
-				throw new ImageOpException(job.getError().toString());
-			}
-
-			/* error handling */
-
-		} // end of "big" try
-		catch (IOException e) {
-			logger.error("ERROR: File IO Error: " + e);
-			digilibError(errorMsgHtml, ERROR_FILE,
-					"ERROR: File IO Error: " + e, response);
-		} catch (AuthOpException e) {
-			logger.error("ERROR: Authorization error: " + e);
-			digilibError(errorMsgHtml, ERROR_AUTH,
-					"ERROR: Authorization error: " + e, response);
-		} catch (ImageOpException e) {
-			logger.error("ERROR: Image Error: " + e);
-			digilibError(errorMsgHtml, ERROR_IMAGE,
-					"ERROR: Image Operation Error: " + e, response);
-		} catch (RuntimeException e) {
-			// JAI likes to throw RuntimeExceptions ;-(
-			logger.error("ERROR: Other Image Error: " + e);
-			digilibError(errorMsgHtml, ERROR_IMAGE,
-					"ERROR: Other Image Operation Error: " + e, response);
-		}
-	}
-
-	/**
-	 * 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;
-	}
-
-	/**
-	 * 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);
-		}
-
-	}
-
-	/**
-	 * @return the dlVersion
-	 */
-	public static String getVersion() {
-		return dlVersion;
-	}
-
-	
-	protected BufferedOutputStream generatePDFcontent(HttpServletRequest request, HttpServletResponse response, 
-																	ServletContext servletcontext, OutputStream out)
-	 	throws DocumentException {
-		
-		/** This method sets up a document and calls the addImage method to add all the images */
-		Document doc = new Document(PageSize.A4,0,0,0,0);
-		BufferedOutputStream outstream = new BufferedOutputStream(out);
-
-		PdfWriter docwriter = null;
-
-
-		try{
-
-			docwriter = PdfWriter.getInstance(doc, outstream);
-
-	
-			doc.addAuthor(this.getClass().getName());
-			doc.addCreationDate();
-			doc.addKeywords("digilib");
-			doc.addTitle("digilib PDF");
-			doc.addCreator(this.getClass().getName());
-			
-			doc.open();
-		
-			
-			// get width and height from the request
-/*			float docW = PageSize.A4.getWidth() - 2*PageSize.A4.getBorder(); 
-			float docH= PageSize.A4.getHeight()- 2*PageSize.A4.getBorder();
-*/
-			
-			// evaluate the pgs parameter (which pages go into the pdf)
-			String pages    = request.getParameter("pgs");
-			ArrayList<Integer> pgs=new ArrayList<Integer>(); // a list of the requested page numbers
-			String intervals[] = pages.split(",");
-		
-			// convert the page-interval-strings into a list containing every single page
-			for(String interval: intervals){
-				if(interval.indexOf("-") > -1){
-					String nums[] = interval.split("-");
-					
-					for(int i=Integer.valueOf(nums[0]); i <= Integer.valueOf(nums[1]); i++){
-						pgs.add(i);
-					}
-				}
-				else{
-					pgs.add(Integer.valueOf(interval));
-				}
-			}
-
-	
-
-		
-			// add all the images/pages to the pdf
-			for(int i=0; i<pgs.size(); i++){
-				int pn=pgs.get(i);
-				this.addImageToPDF(request, response, pn, doc);
-			}
-		
-	
-	
-		}
-		catch (Exception de) {
-			logger.debug(de.getMessage());
-		} 
-		finally{
-			if (doc!=null){
-				doc.close();
-			}
-			if (docwriter!=null){
-				docwriter.close();
-			}
-		}
-		return outstream;
-	}
-
-
-	public void run() {
-		if(mpdf_request!=null && mpdf_response!=null && mpdf_filename!=""){
-			try {
-				createPDFfile(mpdf_request, mpdf_response, mpdf_filename);
-			} catch (ServletException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			} catch (IOException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			}
-		}
-	}
-}
\ No newline at end of file
+}
--- a/servlet/src/digilib/servlet/RequestHandler.java	Mon Feb 23 16:03:06 2009 +0100
+++ b/servlet/src/digilib/servlet/RequestHandler.java	Mon Mar 02 17:11:26 2009 +0100
@@ -2,6 +2,7 @@
 
 import java.io.InputStream;
 
+import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -23,9 +24,9 @@
 	protected static Logger authlog = Logger.getLogger("digilib.auth");
 
 	
-	public void init(){
+	public void init(ServletConfig config) throws ServletException{
 		try {
-			super.init();
+			super.init(config);
 		} catch (ServletException e) {
 			e.printStackTrace();
 			logger.error(e.getMessage());
--- a/servlet/src/digilib/servlet/Scaler.java	Mon Feb 23 16:03:06 2009 +0100
+++ b/servlet/src/digilib/servlet/Scaler.java	Mon Mar 02 17:11:26 2009 +0100
@@ -21,6 +21,7 @@
 import digilib.auth.AuthOps;
 import digilib.image.ImageOpException;
 import digilib.io.DocuDirCache;
+import digilib.io.DocuDirectory;
 import digilib.io.DocuDirent;
 import digilib.io.FileOpException;
 import digilib.io.FileOps;
@@ -78,8 +79,41 @@
 	/** 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)
 	 */
@@ -134,9 +168,8 @@
 		
 
 		// define the job information
-		ImageJobInformation jobdeclaration = new ImageJobInformation();
+		ImageJobInformation jobdeclaration = new ImageJobInformation(dlConfig);
 		jobdeclaration.setWithRequest(request);
-		jobdeclaration.setConfig(dlConfig);
 	
 		ImageFile fileToLoad = null;
 		try {
@@ -238,27 +271,11 @@
 			}
 
 			
-			job = new DigilibImageWorker(dlConfig, 
-					outputstream ,
-					jobdeclaration.get_mimeType(), 
-					jobdeclaration.get_scaleQual(), 
-					jobdeclaration.getAsFloat("rot"), 
-					jobdeclaration.getAsFloat("cont"),
-					jobdeclaration.getAsFloat("brgt"), 
-					jobdeclaration.get_paramRGBM(), 
-					jobdeclaration.get_paramRGBA(), 
-					jobdeclaration.get_fileToLoad(), 
-					jobdeclaration.get_scaleXY(),
-					jobdeclaration.get_outerUserImgArea(),
-					jobdeclaration.get_innerUserImgArea(),
-					minSubsample,
-					jobdeclaration.get_wholeRotArea(), 
-					jobdeclaration.get_forceType(),
-					jobdeclaration.get_hmir(),
-					jobdeclaration.get_vmir());
+			job = new DigilibImageWorker(dlConfig, outputstream , jobdeclaration);
 
 			job.run();
 
+			
 			if (job.hasError()) {
 				throw new ImageOpException(job.getError().toString());
 			}