changeset 536:e758a49258e8 digilibPDF

Merge with 9936604d466e3c44d8a2609519848f33f2801629 (changes to HEAD)
author casties
date Wed, 25 Aug 2010 18:29:08 +0200
parents 87cb3dc2aa12 (diff) 9936604d466e (current diff)
children bd1080df81ad
files CVSROOT/checkoutlist CVSROOT/commitinfo CVSROOT/config CVSROOT/cvswrappers CVSROOT/editinfo CVSROOT/loginfo CVSROOT/modules CVSROOT/notify CVSROOT/rcsinfo CVSROOT/taginfo CVSROOT/verifymsg client/digitallibrary/WEB-INF/digilib-config.xml client/digitallibrary/WEB-INF/web.xml servlet/src/digilib/Utils.java servlet/src/digilib/auth/AuthOps.java servlet/src/digilib/auth/AuthOpsImpl.java servlet/src/digilib/auth/DBAuthOpsImpl.java servlet/src/digilib/auth/HashTree.java servlet/src/digilib/auth/XMLAuthOps.java servlet/src/digilib/auth/dlDataModule.java servlet/src/digilib/image/DocuImage.java servlet/src/digilib/image/DocuImageImpl.java servlet/src/digilib/image/ImageLoaderDocuImage.java servlet/src/digilib/image/JAIDocuImage.java servlet/src/digilib/image/JAIImageLoaderDocuImage.java servlet/src/digilib/image/JIMIDocuImage.java servlet/src/digilib/io/AliasingDocuDirCache.java servlet/src/digilib/io/DocuDirCache.java servlet/src/digilib/io/DocuDirectory.java servlet/src/digilib/io/DocuDirent.java servlet/src/digilib/io/FileOps.java servlet/src/digilib/io/ImageFileset.java servlet/src/digilib/io/XMLListLoader.java servlet/src/digilib/io/XMLMetaLoader.java servlet/src/digilib/servlet/DigilibConfiguration.java servlet/src/digilib/servlet/DigilibImageWorker.java servlet/src/digilib/servlet/DigilibRequest.java servlet/src/digilib/servlet/DigilibWorker.java servlet/src/digilib/servlet/DocumentBean.java servlet/src/digilib/servlet/Initialiser.java servlet/src/digilib/servlet/Parameter.java servlet/src/digilib/servlet/ParameterMap.java servlet/src/digilib/servlet/Scaler.java
diffstat 40 files changed, 2503 insertions(+), 1020 deletions(-) [+]
line wrap: on
line diff
--- a/client/digitallibrary/WEB-INF/digilib-config.xml	Wed Jul 14 16:36:42 2010 +0200
+++ b/client/digitallibrary/WEB-INF/digilib-config.xml	Wed Aug 25 18:29:08 2010 +0200
@@ -58,5 +58,17 @@
   
   <!-- location of logger config file -->
   <parameter name="log-config-file" value="log4j-config.xml"/>
+
+
+
+  <!-- location for PDF files while still in progress -->
+  <parameter name="pdf-temp-dir" value="pdf_temp/" />
+  
+  <!-- location for PDF files upon completion -->
+  <parameter name="pdf-cache-dir" value="cache/"/>
+
+  <!-- location for PDFs while still in progress -->
+  <parameter name="pdf-logo" value="http://www.mpiwg-berlin.mpg.de/de/images/logo.png" />
+
   
 </digilib-config>
--- a/client/digitallibrary/WEB-INF/web.xml	Wed Jul 14 16:36:42 2010 +0200
+++ b/client/digitallibrary/WEB-INF/web.xml	Wed Aug 25 18:29:08 2010 +0200
@@ -54,40 +54,16 @@
             digilib.servlet.Texter
         </servlet-class>
   </servlet>
-  <!-- The Raster servlet -->
-  <servlet>
-        <servlet-name>
-            Raster
-        </servlet-name>
-        <description>
-            The servlet for rastered SVG.
-        </description>
-        <servlet-class>
-            digilib.servlet.Raster
-        </servlet-class>
-  </servlet>
-  <!-- The Mapper servlet -->
+  <!-- The PDFCache servlet -->
   <servlet>
         <servlet-name>
-            Mapper
+            PDFCache
         </servlet-name>
         <description>
-            The servlet to create image maps.
+            The servlet for PDF.
         </description>
         <servlet-class>
-            digilib.servlet.Mapper
-        </servlet-class>
-  </servlet>
-  <!-- The Relato servlet -->
-  <servlet>
-        <servlet-name>
-            Relato
-        </servlet-name>
-        <description>
-            The relato servlet
-        </description>
-        <servlet-class>
-            Relato
+            digilib.servlet.PDFCache
         </servlet-class>
   </servlet>
   <!-- We want to mess around with the default JSP servlet... -->
@@ -145,47 +121,21 @@
             /authenticated/servlet/Texter/*
         </url-pattern>
   </servlet-mapping>
-  <!-- The mapping for the Raster servlet -->
+  <!-- The mapping for the Texter servlet -->
   <servlet-mapping>
         <servlet-name>
-            Raster
+            PDFCache
         </servlet-name>
         <url-pattern>
-            /servlet/Raster/*
+            /servlet/PDFCache/*
         </url-pattern>
   </servlet-mapping>
   <servlet-mapping>
         <servlet-name>
-            Raster
-        </servlet-name>
-        <url-pattern>
-            /authenticated/servlet/Raster/*
-        </url-pattern>
-  </servlet-mapping>
-  <!-- The mapping for the Mapper servlet -->
-  <servlet-mapping>
-        <servlet-name>
-            Mapper
+            PDFCache
         </servlet-name>
         <url-pattern>
-            /servlet/Mapper/*
-        </url-pattern>
-  </servlet-mapping>
-  <servlet-mapping>
-        <servlet-name>
-            Mapper
-        </servlet-name>
-        <url-pattern>
-            /authenticated/servlet/Mapper/*
-        </url-pattern>
-  </servlet-mapping>
-  <!-- The mapping for the Relato servlet -->
-  <servlet-mapping>
-        <servlet-name>
-            Relato
-        </servlet-name>
-        <url-pattern>
-            /Relato
+            /authenticated/servlet/PDFCache/*
         </url-pattern>
   </servlet-mapping>
    <!-- The mapping for the JSP servlet -->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/digitallibrary/pdf/error.jsp	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,13 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+    pageEncoding="ISO-8859-1"%>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>Error</title>
+</head>
+<body>
+<h1>Error</h1>
+W&auml;hrend der Verarbeitung ihrer Anfrage trat ein Fehler auf. M&ouml;glicherweise sind die &uuml;bergebenen Parameter fehlerhaft.
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/digitallibrary/pdf/wip.jsp	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,14 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+    pageEncoding="ISO-8859-1"%>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<meta http-equiv="refresh" content="10">
+<title>Work in progress ...</title>
+</head>
+<body>
+<h1>Bitte warten ...</h1>
+ihre Anfrage wird bearbeitet.  Der Download beginnt automatisch, sobald das Dokument fertig generiert ist. 
+</body>
+</html>
--- a/servlet/src/digilib/auth/AuthOps.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/auth/AuthOps.java	Wed Aug 25 18:29:08 2010 +0200
@@ -81,7 +81,7 @@
 	 * @throws AuthOpException Exception thrown on error.
 	 * @return List of Strings with role names.
 	 */
-	public List rolesForPath(String filepath, HttpServletRequest request)
+	public List<String> rolesForPath(String filepath, HttpServletRequest request)
 		throws AuthOpException;
 
 	/** Authorization roles needed for request.
@@ -95,7 +95,7 @@
 	 * @throws AuthOpException Exception thrown on error.
 	 * @return List of Strings with role names.
 	 */
-	public List rolesForPath(DigilibRequest request)
+	public List<String> rolesForPath(DigilibRequest request)
 		throws AuthOpException;
 
 	/** Test request authorization against a list of roles.
@@ -103,13 +103,13 @@
 	 * @param request ServletRequest with address information.
 	 * @return true if the user information in the request authorizes one of the roles.
 	 */
-	public boolean isRoleAuthorized(List roles, HttpServletRequest request);
+	public boolean isRoleAuthorized(List<String> roles, HttpServletRequest request);
 
 	/** Test request authorization against a list of roles.
 	 * @param roles List of Strings with role names.
 	 * @param request ServletRequest with address information.
 	 * @return true if the user information in the request authorizes one of the roles.
 	 */
-	public boolean isRoleAuthorized(List roles, DigilibRequest request);
+	public boolean isRoleAuthorized(List<String> roles, DigilibRequest request);
 
 }
--- a/servlet/src/digilib/auth/AuthOpsImpl.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/auth/AuthOpsImpl.java	Wed Aug 25 18:29:08 2010 +0200
@@ -21,7 +21,6 @@
 package digilib.auth;
 
 import java.util.List;
-import java.util.ListIterator;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -56,7 +55,7 @@
    */
   public boolean isAuthRequired(String filepath, HttpServletRequest request) throws AuthOpException {
     // check permissions
-    List rolesRequired = rolesForPath(filepath, request);
+    List<String> rolesRequired = rolesForPath(filepath, request);
     return (rolesRequired != null);
   }
 
@@ -66,7 +65,7 @@
   public boolean isAuthRequired(DigilibRequest request)
 	  throws AuthOpException {
 		// check permissions
-		List rolesRequired = rolesForPath(request);
+		List<String> rolesRequired = rolesForPath(request);
 		return (rolesRequired != null);
   }
 
@@ -80,7 +79,7 @@
    * @return List of Strings with role names.
    */
   public boolean isAuthorized(String filepath, HttpServletRequest request) throws AuthOpException {
-    List rolesAllowed = rolesForPath(filepath, request);
+    List<String> rolesAllowed = rolesForPath(filepath, request);
     return isRoleAuthorized(rolesAllowed, request);
   }
 
@@ -89,7 +88,7 @@
    */
   public boolean isAuthorized(DigilibRequest request)
 	  throws AuthOpException {
-		List rolesAllowed = rolesForPath(request);
+		List<String> rolesAllowed = rolesForPath(request);
 		return isRoleAuthorized(rolesAllowed, request);
   }
 
@@ -98,11 +97,8 @@
    * @param request ServletRequest with address information.
    * @return true if the user information in the request authorizes one of the roles.
    */
-  public boolean isRoleAuthorized(List roles, HttpServletRequest request) {
-    ListIterator r = roles.listIterator();
-    String s = "";
-    while (r.hasNext()) {
-      s = (String)r.next();
+  public boolean isRoleAuthorized(List<String> roles, HttpServletRequest request) {
+    for (String s: roles) {
       logger.debug("Testing role: "+s);
       if (request.isUserInRole(s)) {
       	logger.debug("Role Authorized");
@@ -115,11 +111,8 @@
   /**
    * @see digilib.auth.AuthOps#isRoleAuthorized(java.util.List, digilib.servlet.DigilibRequest)
    */
-  public boolean isRoleAuthorized(List roles, DigilibRequest request) {
-	ListIterator r = roles.listIterator();
-	String s = "";
-	while (r.hasNext()) {
-	  s = (String)r.next();
+  public boolean isRoleAuthorized(List<String> roles, DigilibRequest request) {
+	for (String s: roles) {
 	  logger.debug("Testing role: "+s);
 	  if (((HttpServletRequest)request.getServletRequest()).isUserInRole(s)) {
 	  	logger.debug("Role Authorized");
@@ -131,8 +124,8 @@
 
   public abstract void init() throws AuthOpException;
 
-  public abstract List rolesForPath(String filepath, HttpServletRequest request) throws AuthOpException;
+  public abstract List<String> rolesForPath(String filepath, HttpServletRequest request) throws AuthOpException;
 
-  public abstract List rolesForPath(DigilibRequest request) throws AuthOpException;
+  public abstract List<String> rolesForPath(DigilibRequest request) throws AuthOpException;
 
 }
--- a/servlet/src/digilib/auth/HashTree.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/auth/HashTree.java	Wed Aug 25 18:29:08 2010 +0200
@@ -20,7 +20,10 @@
 
 package digilib.auth;
 
-import java.util.*;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
 
 /**
  * Tree representation wrapper for a HashMap.
@@ -37,7 +40,7 @@
  */
 public class HashTree {
 
-    private Map table;
+    private Map<String, String> table;
 
     private String twigSep = "/";
 
@@ -53,7 +56,7 @@
      * @param twig_separator
      * @param leaf_separator
      */
-    public HashTree(Map t, String twig_separator, String leaf_separator) {
+    public HashTree(Map<String, String> t, String twig_separator, String leaf_separator) {
         table = t;
         twigSep = twig_separator;
         leafSep = leaf_separator;
@@ -73,10 +76,10 @@
      * @param branch
      * @return
      */
-    List match(String branch) {
+    List<String> match(String branch) {
         String b = "";
         String m;
-        LinkedList matches = new LinkedList();
+        LinkedList<String> matches = new LinkedList<String>();
 
         // split branch
         StringTokenizer twig = new StringTokenizer(branch, twigSep);
@@ -87,7 +90,7 @@
             } else {
                 b += twigSep + twig.nextToken();
             }
-            m = (String) table.get(b);
+            m = table.get(b);
             if (m != null) {
                 if (m.indexOf(leafSep) < 0) {
                     // single leaf
--- a/servlet/src/digilib/auth/XMLAuthOps.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/auth/XMLAuthOps.java	Wed Aug 25 18:29:08 2010 +0200
@@ -69,8 +69,8 @@
 	 */
 	public void init() throws AuthOpException {
 		logger.debug("xmlauthops.init (" + configFile + ")");
-		Map pathList = null;
-		Map ipList = null;
+		Map<String, String> pathList = null;
+		Map<String, String> ipList = null;
 		try {
 			// load authPaths
 			XMLListLoader pathLoader =
@@ -105,7 +105,7 @@
 	 * @throws AuthOpException Exception thrown on error.
 	 * @return List of Strings with role names.
 	 */
-	public List rolesForPath(String filepath, HttpServletRequest request)
+	public List<String> rolesForPath(String filepath, HttpServletRequest request)
 		throws digilib.auth.AuthOpException {
 		logger.debug("rolesForPath ("
 				+ filepath
@@ -114,13 +114,13 @@
 				+ "]");
 
 		// check if the requests address provides a role
-		List provided = authIPs.match(request.getRemoteAddr());
+		List<String> provided = authIPs.match(request.getRemoteAddr());
 		if ((provided != null) && (provided.contains("ALL"))) {
 			// ALL switches off checking;
 			return null;
 		}
 		// which roles are required?
-		List required = authPaths.match(filepath);
+		List<String> required = authPaths.match(filepath);
 		// do any provided roles match?
 		if ((provided != null) && (required != null)) {
 			for (int i = 0; i < provided.size(); i++) {
@@ -136,7 +136,7 @@
 	/**
 	 * @see digilib.auth.AuthOps#rolesForPath(digilib.servlet.DigilibRequest)
 	 */
-	public List rolesForPath(DigilibRequest request) throws AuthOpException {
+	public List<String> rolesForPath(DigilibRequest request) throws AuthOpException {
 		logger.debug("rolesForPath ("
 				+ request.getFilePath()
 				+ ") by ["
@@ -144,14 +144,14 @@
 				+ "]");
 
 		// check if the requests address provides a role
-		List provided =
+		List<String> provided =
 			authIPs.match(request.getServletRequest().getRemoteAddr());
 		if ((provided != null) && (provided.contains("ALL"))) {
 			// ALL switches off checking;
 			return null;
 		}
 		// which roles are required?
-		List required = authPaths.match(request.getFilePath());
+		List<String> required = authPaths.match(request.getFilePath());
 		// do any provided roles match?
 		if ((provided != null) && (required != null)) {
 			for (int i = 0; i < provided.size(); i++) {
--- a/servlet/src/digilib/image/DocuImage.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/image/DocuImage.java	Wed Aug 25 18:29:08 2010 +0200
@@ -219,6 +219,12 @@
     /**
      * Returns a list of supported image formats
      */
-	public Iterator getSupportedFormats();
+	public Iterator<String> getSupportedFormats();
+	
+	/**
+	 * returns the underlying image as java.awt.Image (if possible, or null)
+	 * @return
+	 */
+	public java.awt.Image getAwtImage();
 
 }
--- a/servlet/src/digilib/image/DocuImageImpl.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/image/DocuImageImpl.java	Wed Aug 25 18:29:08 2010 +0200
@@ -20,9 +20,11 @@
 
 package digilib.image;
 
+import java.awt.Image;
 import java.awt.Rectangle;
 import java.io.File;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.RandomAccessFile;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -157,10 +159,52 @@
 		// emtpy implementation
 	}
 
-	public Iterator getSupportedFormats() {
-		List empty = new LinkedList();
+	public Iterator<String> getSupportedFormats() {
+		List<String> empty = new LinkedList<String>();
 		return empty.iterator();
 	}
-	
+
+    @Override
+    public void crop(int xoff, int yoff, int width, int height)
+            throws ImageOpException {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public Image getAwtImage() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public int getHeight() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
 
+    @Override
+    public int getWidth() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public void loadImage(ImageFile f) throws FileOpException {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public void scale(double scaleX, double scaleY) throws ImageOpException {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public void writeImage(String mt, OutputStream ostream)
+            throws FileOpException {
+        // TODO Auto-generated method stub
+    }
+	
 }
--- a/servlet/src/digilib/image/ImageLoaderDocuImage.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java	Wed Aug 25 18:29:08 2010 +0200
@@ -117,7 +117,7 @@
 	}
 
 	/* returns a list of supported image formats */
-	public Iterator getSupportedFormats() {
+	public Iterator<String> getSupportedFormats() {
 		String[] formats = ImageIO.getReaderFormatNames();
 		return Arrays.asList(formats).iterator();
 	}
@@ -140,9 +140,9 @@
          */
         RandomAccessFile raf = new RandomAccessFile(f, "r");
         ImageInputStream istream = ImageIO.createImageInputStream(raf);
-        Iterator readers = ImageIO.getImageReaders(istream);
+        Iterator<ImageReader> readers = ImageIO.getImageReaders(istream);
         if (readers.hasNext()) {
-            ImageReader reader = (ImageReader) readers.next();
+            ImageReader reader = readers.next();
             /* are there more readers? */
             logger.debug("ImageIO: this reader: " + reader.getClass());
             while (readers.hasNext()) {
@@ -202,11 +202,11 @@
 		// Iterator readers = ImageIO.getImageReaders(istream);
 		String mt = f.getMimetype();
 		logger.debug("File type:" + mt);
-		Iterator readers = ImageIO.getImageReadersByMIMEType(mt);
+		Iterator<ImageReader> readers = ImageIO.getImageReadersByMIMEType(mt);
 		if (!readers.hasNext()) {
 			throw new FileOpException("Unable to load File!");
 		}
-		reader = (ImageReader) readers.next();
+		reader = readers.next();
 		/* are there more readers? */
 		logger.debug("ImageIO: this reader: " + reader.getClass());
 		while (readers.hasNext()) {
@@ -562,7 +562,7 @@
 		img = null;
 	}
 
-	public Image getImage(){
+	public Image getAwtImage(){
 		return (Image) img;
 	}
 	
--- a/servlet/src/digilib/image/JAIDocuImage.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/image/JAIDocuImage.java	Wed Aug 25 18:29:08 2010 +0200
@@ -20,6 +20,7 @@
 
 package digilib.image;
 
+import java.awt.Image;
 import java.awt.Rectangle;
 import java.awt.RenderingHints;
 import java.awt.image.RenderedImage;
@@ -84,20 +85,19 @@
 	}
 
 	/* returns a list of supported image formats */
-	public Iterator getSupportedFormats() {
-		Enumeration codecs = ImageCodec.getCodecs();
-		List formats = new ArrayList(5);
-		for (Object codec = codecs.nextElement(); codecs.hasMoreElements(); codec = codecs
-				.nextElement()) {
-			logger
-					.debug("known format:"
-							+ ((ImageCodec) codec).getFormatName());
-			formats.add(((ImageCodec) codec).getFormatName());
-		}
-		logger.debug("tilecachesize:"
-				+ JAI.getDefaultInstance().getTileCache().getMemoryCapacity());
-		return formats.iterator();
-	}
+    @SuppressWarnings("unchecked") // ImageCodec.getCodecs() returns a naked Enumeration
+    public Iterator<String> getSupportedFormats() {
+        Enumeration<ImageCodec> codecs = ImageCodec.getCodecs();
+        List<String> formats = new ArrayList<String>();
+        for (ImageCodec codec = codecs.nextElement(); codecs.hasMoreElements(); codec = codecs
+                .nextElement()) {
+            logger.debug("known format:"+codec.getFormatName());
+            formats.add(codec.getFormatName());
+        }
+        logger.debug("tilecachesize:"
+                + JAI.getDefaultInstance().getTileCache().getMemoryCapacity());
+        return formats.iterator();
+    }
 
 	/* Check image size and type and store in ImageFile f */
 	public boolean identify(ImageFile imgf) throws IOException {
--- a/servlet/src/digilib/image/JAIImageLoaderDocuImage.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/image/JAIImageLoaderDocuImage.java	Wed Aug 25 18:29:08 2010 +0200
@@ -20,6 +20,7 @@
 
 package digilib.image;
 
+import java.awt.Image;
 import java.awt.Rectangle;
 import java.awt.image.renderable.ParameterBlock;
 import java.io.File;
@@ -98,11 +99,11 @@
 		RandomAccessFile rf = new RandomAccessFile(f.getFile(), "r");
 		ImageInputStream istream = new FileImageInputStream(rf);
 		//Iterator readers = ImageIO.getImageReaders(istream);
-		Iterator readers = ImageIO.getImageReadersByMIMEType(f.getMimetype());
+		Iterator<ImageReader> readers = ImageIO.getImageReadersByMIMEType(f.getMimetype());
 		if (! readers.hasNext()) {
 			throw new FileOpException("Unable to load File!");
 		}
-		reader = (ImageReader) readers.next();
+		reader = readers.next();
 		logger.debug("JAIImageIO: this reader: " + reader.getClass());
 		while (readers.hasNext()) {
 			logger.debug("  next reader: " + readers.next().getClass());
@@ -166,7 +167,13 @@
 		}
 	}
 
-	/* (non-Javadoc)
+	@Override
+    public Image getAwtImage() {
+        // TODO Auto-generated method stub
+        return (Image) img;
+    }
+
+    /* (non-Javadoc)
 	 * @see java.lang.Object#finalize()
 	 */
 	protected void finalize() throws Throwable {
--- a/servlet/src/digilib/io/AliasingDocuDirCache.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/io/AliasingDocuDirCache.java	Wed Aug 25 18:29:08 2010 +0200
@@ -23,8 +23,8 @@
 package digilib.io;
 
 import java.io.File;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import digilib.servlet.DigilibConfiguration;
 
@@ -45,7 +45,7 @@
 			throws FileOpException {
 		// create standard DocuDirCache
 		super(baseDirs, fileClasses, dlConfig);
-		Map pathMap = null;
+		Map<String,String> pathMap = null;
 		// read alias config file
 		try {
 			// load into pathMap
@@ -63,18 +63,16 @@
 		 * load map entries into cache
 		 */
 
-		for (Iterator i = pathMap.keySet().iterator(); i.hasNext();) {
-			String link = (String) i.next();
-			String dir = (String) pathMap.get(link);
-			if (dir == null) {
+		for (Entry<String, String> linkdir: pathMap.entrySet()) {
+			if (linkdir.getValue() == null) {
 				logger.error("Key mismatch in mapping file!");
 				break;	
 			}
-			DocuDirectory destDir = new DocuDirectory(dir, this);
+			DocuDirectory destDir = new DocuDirectory(linkdir.getValue(), this);
 			if (destDir.isValid()) {
-				logger.debug("Aliasing dir: " + link);
+				logger.debug("Aliasing dir: " + linkdir.getKey());
 				// add the alias name
-				putName(FileOps.normalName(link), destDir);
+				putName(FileOps.normalName(linkdir.getKey()), destDir);
 				// add the real dir
 				putDir(destDir);
 			}
@@ -87,13 +85,12 @@
 	 * @param name
 	 * @param newdir
 	 */
-	public void putName(String name, DocuDirectory newdir) {
-		if (map.containsKey(name)) {
-			logger
-					.warn("Duplicate key in AliasingDocuDirCache.put -- ignored!");
-		} else {
-			map.put(name, newdir);
-		}
-	}
+    public void putName(String name, DocuDirectory newdir) {
+        if (map.containsKey(name)) {
+            logger.warn("Duplicate key in AliasingDocuDirCache.put -- ignored!");
+        } else {
+            map.put(name, newdir);
+        }
+    }
 
 }
--- a/servlet/src/digilib/io/DocuDirCache.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/io/DocuDirCache.java	Wed Aug 25 18:29:08 2010 +0200
@@ -24,7 +24,6 @@
 
 import java.io.File;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -42,7 +41,7 @@
 	Logger logger = Logger.getLogger(this.getClass());
 
 	/** HashMap of directories */
-	Map map = null;
+	Map<String, DocuDirectory> map = null;
 
 	/** names of base directories */
 	String[] baseDirNames = null;
@@ -74,7 +73,7 @@
 	public DocuDirCache(String[] bd, int[] fileClasses,
 			DigilibConfiguration dlConfig) {
 		baseDirNames = bd;
-		map = new HashMap();
+		map = new HashMap<String, DocuDirectory>();
 		this.fileClasses = fileClasses;
 		safeDirIndex = dlConfig.getAsBoolean("safe-dir-index");
 	}
@@ -87,7 +86,7 @@
 	 */
 	public DocuDirCache(String[] bd) {
 		baseDirNames = bd;
-		map = new HashMap();
+		map = new HashMap<String, DocuDirectory>();
 		// default file class is CLASS_IMAGE
 		fileClasses = new int[1];
 		fileClasses[0] = FileOps.CLASS_IMAGE;
@@ -149,11 +148,9 @@
 	 *            find all children and their children.
 	 * @return
 	 */
-	public List getChildren(String dirname, boolean recurse) {
-		List l = new LinkedList();
-		for (Iterator i = map.keySet().iterator(); i.hasNext();) {
-			String n = (String) i.next();
-			DocuDirectory dd = (DocuDirectory) map.get(n);
+	public List<DocuDirectory> getChildren(String dirname, boolean recurse) {
+		List<DocuDirectory> l = new LinkedList<DocuDirectory>();
+		for (DocuDirectory dd: map.values()) {
 			if (recurse) {
 				if (dd.getDirName().startsWith(dirname)) {
 					l.add(dd);
--- a/servlet/src/digilib/io/DocuDirectory.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/io/DocuDirectory.java	Wed Aug 25 18:29:08 2010 +0200
@@ -25,7 +25,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -37,7 +36,7 @@
 public class DocuDirectory extends Directory {
 
 	/** list of files (DocuDirent) */
-	private ArrayList[] list = null;
+	private List<List<DocuDirent>> list = null;
 
 	/** directory object is valid (exists on disk) */
 	private boolean isValid = false;
@@ -49,13 +48,13 @@
 	private String dirName = null;
 
 	/** directory metadata */
-	private Map dirMeta = null;
+	private MetadataMap dirMeta = null;
 
 	/** state of metadata is valid */
 	private boolean metaChecked = false;
 
 	/** unresolved file metadata */
-	private Map unresolvedFileMeta = null;
+	private Map<String, MetadataMap> unresolvedFileMeta = null;
 
 	/** time of last access of this object (not the filesystem) */
 	private long objectATime = 0;
@@ -90,7 +89,13 @@
 	protected void initDir() {
 		String baseDirName = cache.getBaseDirNames()[0];
 		// clear directory first
-		list = new ArrayList[FileOps.NUM_CLASSES];
+		//list = new ArrayList[FileOps.NUM_CLASSES];
+
+		list = new ArrayList<List<DocuDirent>>(FileOps.NUM_CLASSES);
+		// create empty list
+		for (int i=0; i < FileOps.NUM_CLASSES; ++i) {
+		    list.add(null);
+		}
 		isValid = false;
 		dirMTime = 0;
 		// the first directory has to exist
@@ -102,7 +107,7 @@
 	 *  
 	 */
 	public int size() {
-		return ((list != null) && (list[0] != null)) ? list[0].size() : 0;
+		return ((list != null) && (list.get(0) != null)) ? list.get(0).size() : 0;
 	}
 
 	/**
@@ -112,7 +117,7 @@
 	 *            fileClass
 	 */
 	public int size(int fc) {
-		return ((list != null) && (list[fc] != null)) ? list[fc].size() : 0;
+		return ((list != null) && (list.get(fc) != null)) ? list.get(fc).size() : 0;
 	}
 
 	/**
@@ -122,10 +127,10 @@
 	 * @return
 	 */
 	public ImageFileset get(int index) {
-		if ((list == null) || (list[0] == null) || (index >= list[0].size())) {
+		if ((list == null) || (list.get(0) == null) || (index >= list.get(0).size())) {
 			return null;
 		}
-		return (ImageFileset) list[0].get(index);
+		return (ImageFileset) list.get(0).get(index);
 	}
 
 	/**
@@ -137,10 +142,10 @@
 	 * @return
 	 */
 	public DocuDirent get(int index, int fc) {
-		if ((list == null) || (list[fc] == null) || (index >= list[fc].size())) {
+		if ((list == null) || (list.get(fc) == null) || (index >= list.get(fc).size())) {
 			return null;
 		}
-		return (DocuDirent) list[fc].get(index);
+		return (DocuDirent) list.get(fc).get(index);
 	}
 
 	/**
@@ -221,10 +226,10 @@
 			int numFiles = fileList.length;
 			if (numFiles > 0) {
 				// create new list
-				list[fileClass] = new ArrayList(numFiles);
+				list.set(fileClass, new ArrayList<DocuDirent>(numFiles));
 				// sort the file names alphabetically and iterate the list
 				// Arrays.sort(fileList); // not needed <hertzhaft>
-				Map hints = FileOps.newHints(FileOps.HINT_BASEDIRS, dirs);
+				Map<Integer, Object> hints = FileOps.newHints(FileOps.HINT_BASEDIRS, dirs);
 				hints.put(FileOps.HINT_FILEEXT, scalext);
 				for (int i = 0; i < numFiles; i++) {
 					DocuDirent f = FileOps.fileForClass(fileClass, fileList[i],
@@ -232,11 +237,12 @@
 					// add the file to our list
                     // logger.debug(f.getName());
 
-					list[fileClass].add(f);
+					list.get(fileClass).add(f);
 					f.setParent(this);
 				}
-                // we sort the ArrayList, not the Array, for binarySearch to work
-                Collections.sort(list[fileClass]);
+                // we sort the inner ArrayList (the list of files not the list of file types)
+				// for binarySearch to work (DocuDirent's natural sort order is by filename)
+                Collections.sort(list.get(fileClass));
 			}
 		}
 		// clear the scaled directories
@@ -282,12 +288,12 @@
 			XMLMetaLoader ml = new XMLMetaLoader();
 			try {
 				// read directory meta file
-				Map fileMeta = ml.loadURL(mf.getAbsolutePath());
+				Map<String, MetadataMap> fileMeta = ml.loadURL(mf.getAbsolutePath());
 				if (fileMeta == null) {
 					return;
 				}
 				// meta for the directory itself is in the "" bin
-				dirMeta = (Map) fileMeta.remove("");
+				dirMeta = fileMeta.remove("");
 				// read meta for files in this directory
 				readFileMeta(fileMeta, null);
 				// is there meta for other files left?
@@ -334,25 +340,24 @@
 	 * @param fc
 	 *            fileClass
 	 */
-	protected void readFileMeta(Map fileMeta, String relPath) {
+	protected void readFileMeta(Map<String,MetadataMap> fileMeta, String relPath) {
 		if (list == null) {
 			// there are no files
 			return;
 		}
 		String path = (relPath != null) ? (relPath + "/") : "";
 		// go through all file classes
-		for (int nc = 0; nc < list.length; nc++) {
+		for (int nc = 0; nc < list.size(); nc++) {
 			int fc = cache.getFileClasses()[nc];
-			if (list[fc] == null) {
+			if (list.get(fc) == null) {
 				continue;
 			}
 			// iterate through the list of files in this directory
-			for (Iterator i = list[fc].iterator(); i.hasNext();) {
-				DocuDirent f = (DocuDirent) i.next();
+			for (DocuDirent f: list.get(fc)) {
 				// prepend path to the filename
 				String fn = path + f.getName();
 				// look up meta for this file and remove from dir
-				Map meta = (Map) fileMeta.remove(fn);
+				MetadataMap meta = fileMeta.remove(fn);
 				if (meta != null) {
 					// store meta in file
 					f.setFileMeta(meta);
@@ -361,13 +366,13 @@
 		}
 	}
 
-	protected void notifyChildMeta(Map childmeta) {
-		List children = cache.getChildren(this.dirName, true);
+	protected void notifyChildMeta(MetadataMap childmeta) {
+		List<DocuDirectory> children = cache.getChildren(this.dirName, true);
 		if (children.size() > 0) {
-			for (Iterator i = children.iterator(); i.hasNext();) {
+			/*for (DocuDirectory d: children) {
 				// TODO: finish this!
 				//((DocuDirectory) i.next()).readFileMeta()
-			}
+			}*/
 		}
 	}
 
@@ -416,13 +421,13 @@
 				return -1;
 			}
 		}
-		List fileList = list[fc];
+		List<DocuDirent> fileList = list.get(fc);
 		// empty directory?
 		if (fileList == null) {
 			return -1;
 		}
         
-		// search for exact match
+		// search for exact match (DocuDirent does compareTo<String>)
         // OBS: fileList needs to be sorted first (see )! <hertzhaft>
 		int idx = Collections.binarySearch(fileList, fn);
 		if (idx >= 0) {
@@ -449,8 +454,8 @@
 		return -1;
 	}
 
-	private boolean isBaseInList(List fl, int idx, String fn) {
-		String dfn = FileOps.basename(((DocuDirent) fl.get(idx))
+	private boolean isBaseInList(List<DocuDirent> fl, int idx, String fn) {
+		String dfn = FileOps.basename((fl.get(idx))
 				.getName());
 		return (dfn.equals(fn)||dfn.equals(FileOps.basename(fn))); 
 	}
@@ -470,7 +475,7 @@
 		int fc = FileOps.classForFilename(fn);
 		int i = indexOf(fn, fc);
 		if (i >= 0) {
-			return (DocuDirent) list[0].get(i);
+			return (DocuDirent) list.get(0).get(i);
 		}
 		return null;
 	}
@@ -489,7 +494,7 @@
 	public DocuDirent find(String fn, int fc) {
 		int i = indexOf(fn, fc);
 		if (i >= 0) {
-			return (DocuDirent) list[fc].get(i);
+			return (DocuDirent) list.get(fc).get(i);
 		}
 		return null;
 	}
@@ -531,7 +536,7 @@
 	/**
 	 * @return Hashtable
 	 */
-	public Map getDirMeta() {
+	public MetadataMap getDirMeta() {
 		return dirMeta;
 	}
 
@@ -560,7 +565,7 @@
 	 * @param dirMeta
 	 *            The dirMeta to set
 	 */
-	public void setDirMeta(Map dirMeta) {
+	public void setDirMeta(MetadataMap dirMeta) {
 		this.dirMeta = dirMeta;
 	}
 
--- a/servlet/src/digilib/io/DocuDirent.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/io/DocuDirent.java	Wed Aug 25 18:29:08 2010 +0200
@@ -33,12 +33,12 @@
  * @author casties
  *  
  */
-public abstract class DocuDirent implements Comparable {
+public abstract class DocuDirent implements Comparable<Object> {
 
 	/** the file class of this file */
 	protected static int fileClass = FileOps.CLASS_NONE;
 	/** HashMap with metadata */
-	protected Map fileMeta = null;
+	protected MetadataMap fileMeta = null;
 	/** Is the Metadata valid */
 	protected boolean metaChecked = false;
 	/** the parent directory */
@@ -73,11 +73,11 @@
 			XMLMetaLoader ml = new XMLMetaLoader();
 			try {
 				// read meta file
-				Map meta = ml.loadURL(mf.getAbsolutePath());
+				Map<String, MetadataMap> meta = ml.loadURL(mf.getAbsolutePath());
 				if (meta == null) {
 					return;
 				}
-				fileMeta = (Map) meta.get(getName());
+				fileMeta = meta.get(getName());
 			} catch (Exception e) {
 				Logger.getLogger(this.getClass()).warn("error reading file .meta", e);
 			}
@@ -121,7 +121,7 @@
 	 * 
 	 * @return HashMap
 	 */
-	public Map getFileMeta() {
+	public MetadataMap getFileMeta() {
 		return fileMeta;
 	} 
 	
@@ -131,7 +131,7 @@
 	 * @param fileMeta
 	 *            The fileMeta to set
 	 */
-	public void setFileMeta(Map fileMeta) {
+	public void setFileMeta(MetadataMap fileMeta) {
 		this.fileMeta = fileMeta;
 	} 
 	
@@ -156,9 +156,11 @@
 	 * @see java.lang.Comparable#compareTo(java.lang.Object)
 	 */
 	public int compareTo(Object arg0) {
-		return (arg0 instanceof DocuDirent)
-            ? getName().compareTo(((DocuDirent) arg0).getName())
-            : getName().compareTo((String) arg0);
+		if (arg0 instanceof DocuDirent) {
+		    return getName().compareTo(((DocuDirent) arg0).getName());
+		} else {
+		    return getName().compareTo((String) arg0);
+		}
 	}
 
 	
--- a/servlet/src/digilib/io/FileOps.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/io/FileOps.java	Wed Aug 25 18:29:08 2010 +0200
@@ -44,13 +44,13 @@
 			{ "htm", "text/html" }, { "xml", "text/xml" },
 			{ "svg", "image/svg+xml" }, { "meta", "text/xml" } };
 
-	public static Map fileTypes;
+	public static Map<String, String> fileTypes;
 
-	public static List imageExtensions;
+	public static List<String> imageExtensions;
 
-	public static List textExtensions;
+	public static List<String> textExtensions;
 
-	public static List svgExtensions;
+	public static List<String> svgExtensions;
 
 	public static final int CLASS_NONE = -1;
 
@@ -72,10 +72,10 @@
 	 * static initializer for FileOps
 	 */
 	static {
-		fileTypes = new HashMap();
-		imageExtensions = new ArrayList();
-		textExtensions = new ArrayList();
-		svgExtensions = new ArrayList();
+		fileTypes = new HashMap<String, String>();
+		imageExtensions = new ArrayList<String>();
+		textExtensions = new ArrayList<String>();
+		svgExtensions = new ArrayList<String>();
 		// iterate through file types in ft and fill the Map and Lists
 		for (int i = 0; i < ft.length; i++) {
 			String ext = ft[i][0];
@@ -129,18 +129,31 @@
 		return classForMimetype(mt);
 	}
 
-	public static Iterator getImageExtensionIterator() {
+	public static Iterator<String> getImageExtensionIterator() {
 		return imageExtensions.iterator();
 	}
 
-	public static Iterator getTextExtensionIterator() {
+    public static List<String> getImageExtensions() {
+        return imageExtensions;
+    }
+
+    public static Iterator<String> getTextExtensionIterator() {
 		return textExtensions.iterator();
 	}
 
-	public static Iterator getSVGExtensionIterator() {
+	public static List<String> getTextExtensions() {
+        return textExtensions;
+    }
+
+    public static Iterator<String> getSVGExtensionIterator() {
 		return svgExtensions.iterator();
 	}
 
+    public static List<String> getSvgExtensions() {
+        return svgExtensions;
+    }
+
+
 	/**
 	 * convert a string with a list of pathnames into an array of strings using
 	 * the system's path separator string
@@ -333,7 +346,7 @@
 	 *            optional additional parameters
 	 * @return
 	 */
-	public static DocuDirent fileForClass(int fileClass, File file, Map hints) {
+	public static DocuDirent fileForClass(int fileClass, File file, Map<Integer,Object> hints) {
 		// what class of file do we have?
 		if (fileClass == CLASS_IMAGE) {
 			// image file
@@ -379,8 +392,8 @@
 	 * @param value
 	 * @return
 	 */
-	public static Map newHints(Integer type, Object value) {
-		Map m = new HashMap();
+	public static Map<Integer, Object> newHints(Integer type, Object value) {
+		Map<Integer, Object> m = new HashMap<Integer, Object>();
 		if (type != null) {
 			m.put(type, value);
 		}
--- a/servlet/src/digilib/io/ImageFileset.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/io/ImageFileset.java	Wed Aug 25 18:29:08 2010 +0200
@@ -22,6 +22,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 
@@ -37,7 +38,7 @@
 	protected static int fileClass = FileOps.CLASS_IMAGE;
 	
 	/** list of files (ImageFile) */
-	private ArrayList list = null;
+	private List<ImageFile> list = null;
 
 	/** aspect ratio (width/height) */
 	private float aspect = 0;
@@ -55,7 +56,7 @@
 	 * @param initialCapacity
 	 */
 	public ImageFileset() {
-		list = new ArrayList();
+		list = new ArrayList<ImageFile>();
 	}
 
 	/**
@@ -66,10 +67,10 @@
 	 * @param file
 	 * @param hints
 	 */
-	public ImageFileset(File file, Map hints) {
+	public ImageFileset(File file, Map<Integer,Object> hints) {
 		Directory[] dirs = (Directory[]) hints.get(FileOps.HINT_BASEDIRS);
 		int nb = dirs.length;
-		list = new ArrayList(nb);
+		list = new ArrayList<ImageFile>(nb);
 		parent = dirs[0];
 		fill(dirs, file, hints);
 	}
@@ -105,7 +106,7 @@
 	 *  
 	 */
 	public File getFile() {
-		return (list != null) ? ((ImageFile) list.get(0)).getFile() : null;
+		return (list != null) ? list.get(0).getFile() : null;
 	}
 
 	/**
@@ -116,7 +117,7 @@
 	 * @return
 	 */
 	public ImageFile get(int index) {
-		return (ImageFile) list.get(index);
+		return list.get(index);
 	}
 
 	/**
@@ -132,8 +133,8 @@
 	 * @return
 	 */
 	public ImageFile getNextSmaller(ImageSize size) {
-		for (Iterator i = getHiresIterator(); i.hasNext();) {
-			ImageFile f = (ImageFile) i.next();
+		for (Iterator<ImageFile> i = getHiresIterator(); i.hasNext();) {
+			ImageFile f = i.next();
 			try {
 				if (!f.isChecked()) {
 					ImageOps.checkFile(f);
@@ -160,8 +161,8 @@
 	 * @return
 	 */
 	public ImageFile getNextBigger(ImageSize size) {
-		for (ListIterator i = getLoresIterator(); i.hasPrevious();) {
-			ImageFile f = (ImageFile) i.previous();
+		for (ListIterator<ImageFile> i = getLoresIterator(); i.hasPrevious();) {
+			ImageFile f = i.previous();
 			try {
 				if (!f.isChecked()) {
 					ImageOps.checkFile(f);
@@ -202,7 +203,7 @@
 	 * 
 	 * @return
 	 */
-	public ListIterator getHiresIterator() {
+	public ListIterator<ImageFile> getHiresIterator() {
 		return list.listIterator();
 	}
 
@@ -216,7 +217,7 @@
 	 * 
 	 * @return
 	 */
-	public ListIterator getLoresIterator() {
+	public ListIterator<ImageFile> getLoresIterator() {
 		return list.listIterator(list.size());
 	}
 
@@ -231,7 +232,7 @@
 	 * @param hints
 	 *  
 	 */
-	void fill(Directory[] dirs, File fl, Map hints) {
+	void fill(Directory[] dirs, File fl, Map<Integer,Object> hints) {
 		int nb = dirs.length;
 		String fn = fl.getName();
 		String baseFn = FileOps.basename(fn);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/MetadataMap.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,14 @@
+/**
+ * 
+ */
+package digilib.io;
+
+import java.util.HashMap;
+
+/** Map for metadata related to files.
+ * @author casties
+ *
+ */
+public class MetadataMap extends HashMap<String, String> {
+
+}
--- a/servlet/src/digilib/io/XMLListLoader.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/io/XMLListLoader.java	Wed Aug 25 18:29:08 2010 +0200
@@ -75,17 +75,17 @@
 	 */
 	private class XMLListParser extends DefaultHandler {
 
-		private Map listData;
-		private LinkedList tagSpace;
+		private Map<String, String> listData;
+		private LinkedList<String> tagSpace;
 
-		public Map getData() {
+		public Map<String, String> getData() {
 			return listData;
 		}
 
 		// Parser calls this once at the beginning of a document
 		public void startDocument() throws SAXException {
-			listData = new HashMap();
-			tagSpace = new LinkedList();
+			listData = new HashMap<String, String>();
+			tagSpace = new LinkedList<String>();
 		}
 
 		// Parser calls this for each element in a document
@@ -151,7 +151,7 @@
 	 *  load and parse a file (as URL)
 	 *    returns HashMap with list data
 	 */
-	public Map loadURL(String path) throws SAXException, IOException {
+	public Map<String, String> loadURL(String path) throws SAXException, IOException {
 		//System.out.println("loadurl ("+path+")");
 		// Create a JAXP SAXParserFactory and configure it
 		SAXParserFactory spf = SAXParserFactory.newInstance();
--- a/servlet/src/digilib/io/XMLMetaLoader.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/io/XMLMetaLoader.java	Wed Aug 25 18:29:08 2010 +0200
@@ -52,9 +52,9 @@
 	 */
 	private class XMLMetaParser extends DefaultHandler {
 
-		private LinkedList tags;
-		private Map files;
-		private Map meta;
+		private LinkedList<String> tags;
+		private Map<String, MetadataMap> files;
+		private MetadataMap meta;
 		private StringBuffer content;
 		private boolean collecting;
 		private StringBuffer collectedContent;
@@ -96,8 +96,8 @@
 			
 		// Parser calls this once at the beginning of a document
 		public void startDocument() throws SAXException {
-			tags = new LinkedList();
-			files = new HashMap();
+			tags = new LinkedList<String>();
+			files = new HashMap<String, MetadataMap>();
 			collecting = false;
 			collectedContent = null;
 		}
@@ -118,13 +118,13 @@
 
 			if (name.equals(metaTag)) {
 				// new meta tag
-				meta = new HashMap();
+				meta = new MetadataMap();
 				collectedContent = new StringBuffer();
 			} else if (name.equals(fileTag)) {
 				// new file tag
 				fileName = null;
 				filePath = null;
-				meta = new HashMap();
+				meta = new MetadataMap();
 				collectedContent = new StringBuffer();
 			} else if (name.equals(collectTag)) {
 				// start collecting
@@ -162,7 +162,7 @@
 			String name = getName(localName, qName);
 			// exit the tag
 			tags.removeLast();
-			String lastTag = (tags.isEmpty()) ? "" : (String) tags.getLast();
+			String lastTag = (tags.isEmpty()) ? "" : tags.getLast();
 
 			// was it a file/name tag?
 			if (name.equals(fileNameTag) && lastTag.equals(fileTag)) {
@@ -260,7 +260,7 @@
 	 *  load and parse a file (as URL)
 	 *    returns HashMap with list data
 	 */
-	public Map loadURL(String path) throws SAXException, IOException {
+	public Map<String, MetadataMap> loadURL(String path) throws SAXException, IOException {
 		logger.debug("loading meta: "+path);
 		// Create a JAXP SAXParserFactory and configure it
 		SAXParserFactory spf = SAXParserFactory.newInstance();
--- a/servlet/src/digilib/servlet/DigilibConfiguration.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/DigilibConfiguration.java	Wed Aug 25 18:29:08 2010 +0200
@@ -22,8 +22,8 @@
 package digilib.servlet;
 
 import java.io.File;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
@@ -53,7 +53,7 @@
 	private static final long serialVersionUID = -6630487070791637120L;
 
 	/** DocuImage class instance */
-	private Class docuImageClass = null;
+	private Class<DocuImageImpl> docuImageClass = null;
 
 	/** Log4J logger */
 	private Logger logger = Logger.getLogger("digilib.config");
@@ -140,9 +140,9 @@
 		// use mapping file to translate paths
 		newParameter("use-mapping", Boolean.FALSE, null, 'f');
 		// mapping file location
-		newParameter("mapping-file", new File("WEB-INF/digilib-map.xml"), null, 'f');
+		newParameter("mapping-file", new File("digilib-map.xml"), null, 'f');
 		// log4j config file location
-		newParameter("log-config-file", new File("WEB-INF/log4j-config.xml"), null, 'f');
+		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
@@ -151,6 +151,10 @@
 		newParameter("worker-threads", new Integer(1), null, 'f');
 		// max number of waiting threads
 		newParameter("max-waiting-threads", new Integer(0), null, 'f');
+        // PDF generation temp directory
+        newParameter("pdf-temp-dir", "pdf_temp", null, 'f');
+        // PDF generation cache directory
+        newParameter("pdf-cache-dir", "pdf_cache", null, 'f');
 
 	}
 
@@ -168,56 +172,54 @@
 	/**
 	 * read parameter list from the XML file in init parameter "config-file"
 	 */
-	public void readConfig(ServletConfig config) throws Exception {
+	public void readConfig(ServletConfig c) throws Exception {
 
 		/*
 		 * Get config file name. The file name is first looked for as an init
 		 * parameter, then in a fixed location in the webapp.
 		 */
-		if (config == null) {
+		if (c == null) {
 			// no config no file...
 			return;
 		}
-		String fn = config.getInitParameter("config-file");
+		String fn = c.getInitParameter("config-file");
 		if (fn == null) {
-			fn = ServletOps.getFile("WEB-INF/digilib-config.xml", config);
+			fn = ServletOps.getConfigFile("digilib-config.xml", c);
 			if (fn == null) {
 				logger.fatal("readConfig: no param config-file");
 				throw new ServletException("ERROR: no digilib config file!");
 			}
 		}
-		File configFile = new File(fn);
+		File f = new File(fn);
 		// setup config file list reader
 		XMLListLoader lilo =
 			new XMLListLoader("digilib-config", "parameter", "name", "value");
 		// read config file into HashMap
-		Map confTable = lilo.loadURL(configFile.toURL().toString());
+		Map<String,String> confTable = lilo.loadURL(f.toURL().toString());
 
 		// set config file path parameter
-		setValue("servlet.config.file", configFile.getCanonicalPath());
+		setValue("servlet.config.file", f.getCanonicalPath());
 
 		/*
-		 * process parameters from file
+		 * read parameters
 		 */
 
-		for (Iterator i = confTable.keySet().iterator(); i.hasNext();) {
-			String key = (String) i.next();
-			String val = (String) confTable.get(key);
-			Parameter p = get(key);
+		for (Entry<String, String> confEntry: confTable.entrySet()) {
+			Parameter p = get(confEntry.getKey());
 			if (p != null) {
 				if (p.getType() == 's') {
 					// type 's' Parameters are not overwritten.
 					continue;
 				}
-				if (!p.setValueFromString(val)) {
+				if (!p.setValueFromString(confEntry.getValue())) {
 					/*
 					 * automatic conversion failed -- try special cases
 					 */
 
 					// basedir-list
-					if (key.equals("basedir-list")) {
+					if (confEntry.getKey().equals("basedir-list")) {
 						// split list into directories
-						String[] sa = FileOps.pathToArray(val);
+						String[] sa = FileOps.pathToArray(confEntry.getValue());
 						if (sa != null) {
 							p.setValue(sa);
 						}
@@ -226,36 +228,9 @@
 				}
 			} else {
 				// parameter unknown -- just add
-				newParameter(key, null, val, 'f');
+				newParameter(confEntry.getKey(), null, confEntry.getValue(), 'f');
 			}
 		}
-		
-		/*
-		 * process all parameters
-		 */
-        for (Iterator i = this.keySet().iterator(); i.hasNext();) {
-            String key = (String) i.next();
-            Parameter para = (Parameter) this.get(key);
-
-            // basedir-list
-            if (key.equals("basedir-list")) {
-                // split list into directories
-                String[] dirs = (String[]) para.getValue();
-                for (int j = 0; j < dirs.length; j++) {
-                    // make relative directory paths be inside the webapp
-                    dirs[j] = ServletOps.getFile(dirs[j], config);
-                }
-                para.setValue(dirs);
-            }
-            
-            // File types
-            if (para.getValue() instanceof File) {
-               File pf = (File) para.getValue();
-               // make relative paths be inside the webapp
-               para.setValue(ServletOps.getFile(pf, config));
-            }
-            
-        }
 
 	}
 
@@ -266,13 +241,14 @@
 	 * 
 	 * @return DocuImage
 	 */
-	public DocuImage getDocuImageInstance() {
+	@SuppressWarnings("unchecked")
+    public DocuImage getDocuImageInstance() {
 		DocuImageImpl di = null;
 		try {
 			if (docuImageClass == null) {
-				docuImageClass = Class.forName(getAsString("docuimage-class"));
+				docuImageClass = (Class<DocuImageImpl>) Class.forName(getAsString("docuimage-class"));
 			}
-			di = (DocuImageImpl) docuImageClass.newInstance();
+			di = docuImageClass.newInstance();
 		} catch (Exception e) {
 		}
 		return di;
@@ -281,13 +257,13 @@
 	/**
 	 * @return Returns the docuImageClass.
 	 */
-	public Class getDocuImageClass() {
+	public Class<DocuImageImpl> getDocuImageClass() {
 		return docuImageClass;
 	}
 	/**
 	 * @param docuImageClass The docuImageClass to set.
 	 */
-	public void setDocuImageClass(Class docuImageClass) {
+	public void setDocuImageClass(Class<DocuImageImpl> docuImageClass) {
 		this.docuImageClass = docuImageClass;
 	}
 }
--- a/servlet/src/digilib/servlet/DigilibImageWorker.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/DigilibImageWorker.java	Wed Aug 25 18:29:08 2010 +0200
@@ -24,8 +24,7 @@
 import java.awt.Rectangle;
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
-
-import javax.servlet.http.HttpServletResponse;
+import java.io.OutputStream;
 
 import digilib.image.DocuImage;
 import digilib.image.ImageOpException;
@@ -43,16 +42,20 @@
 
 	private DigilibConfiguration dlConfig;
 
-	HttpServletResponse response;
+	//HttpServletResponse response;
 
+	OutputStream outstream;
+	
 	long startTime;
 
 	String mimeType;
 
 	int scaleQual;
 
-	DigilibRequest dlRequest;
+	//DigilibRequest dlRequest;
 
+	//ImageJobInformation ijd;
+	
 	float paramROT;
 
 	float paramCONT;
@@ -83,59 +86,49 @@
 
 	boolean wholeRotArea;
 
+	boolean vmir;
+	boolean hmir;
+	
 	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,
-			HttpServletResponse response, String mimeType, int scaleQual,
-			DigilibRequest dlRequest, float paramROT, float paramCONT,
-			float paramBRGT, float[] paramRGBM, float[] paramRGBA,
-			ImageFile fileToLoad, float scaleXY, Rectangle2D outerUserImgArea,
-			Rectangle2D innerUserImgArea, float minSubsample,
-			boolean wholeRotArea, int forceType) {
+
+	public DigilibImageWorker(DigilibConfiguration dlConfig, OutputStream outstream, ImageJobInformation jobinfo) {
 		super();
+		
 		this.dlConfig = dlConfig;
-		this.response = response;
-		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.outstream = outstream;
+		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();
 
@@ -190,10 +183,10 @@
 		// mirror image
 		// operation mode: "hmir": mirror horizontally, "vmir": mirror
 		// vertically
-		if (dlRequest.hasOption("mo", "hmir")) {
+		if (hmir) {
 			docuImage.mirror(0);
 		}
-		if (dlRequest.hasOption("mo", "vmir")) {
+		if (vmir) {
 			docuImage.mirror(90);
 		}
 
@@ -267,12 +260,12 @@
 		} else {
 			mimeType = "image/png";
 		}
-		response.setContentType(mimeType);
 
 		// write the image
-		img.writeImage(mimeType, response.getOutputStream());
-		response.flushBuffer();
-
+		img.writeImage(mimeType, outstream);
+		outstream.flush();
+		
+		
 		logger.info("image worker " + this.getName() + " done in "
 				+ (System.currentTimeMillis() - startTime));
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibInfoReader.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,76 @@
+package digilib.servlet;
+
+/** DigilibInfoReader 
+ * A class for reading the information from info.xml files used in digilib image directories.
+ *
+ */
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.input.SAXBuilder;
+
+
+
+public class DigilibInfoReader {
+
+	/** gengeral logger for this class */
+	protected static Logger logger = Logger.getLogger("digilib.servlet");
+	
+	private String filename = null;
+	//private static String base_element = "info";
+	
+	public DigilibInfoReader(String fn){
+		filename = fn;
+	}
+
+	/**
+	 * Returns the attribute defined by 'attr' as a String.
+	 * 
+	 * @param attr
+	 * @return
+	 */
+	@SuppressWarnings("unchecked") // Element.getChildren() returns naked List
+    public String getAsString(String attr){
+		try{
+			SAXBuilder builder = new SAXBuilder();
+			Document doc = builder.build(new File(filename));
+			Element root = doc.getRootElement();
+			List<Element> mainElements = root.getChildren();
+			// logger.debug("XML mainElements:"+mainElements.toString());
+
+			for(int i=0; i<mainElements.size(); i++){
+				Element elem = mainElements.get(i);
+				if(elem.getName()==attr){
+					// logger.debug(attr+" == "+(String)elem.getTextTrim());
+					return (String)elem.getTextTrim();
+				}
+			}
+
+		}
+		catch(Exception e){
+			logger.error(e.getMessage());
+		}
+		return null;
+	}
+	
+	
+	/**
+	 * Find out if the info.xml exists
+	 * @return
+	 */
+	public boolean hasInfo(){
+		try {
+			SAXBuilder builder = new SAXBuilder();
+			builder.build(new File(filename));
+			return true;
+		}
+		catch(Exception e){
+			return false;
+		}
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibPDFWorker.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,212 @@
+/* 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.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import com.itextpdf.text.BadElementException;
+import com.itextpdf.text.Document;
+import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.Image;
+import com.itextpdf.text.PageSize;
+import com.itextpdf.text.pdf.PdfWriter;
+
+import digilib.image.DocuImage;
+import digilib.image.ImageOpException;
+import digilib.io.FileOpException;
+
+/**
+ * Worker for pdf generation.
+ * 
+ * @author cmielack
+ * 
+ */
+public class DigilibPDFWorker extends DigilibWorker {
+
+	private DigilibConfiguration dlConfig = null;
+
+	private Document doc = null;
+
+	private File outputfile = null;
+	
+	private PDFJobInformation job_info = null;
+	
+	public DigilibPDFWorker(DigilibConfiguration dlConfig, PDFJobInformation pdfji, File outputfile) {
+		super();
+		// TODO dlConfig 
+		this.dlConfig = dlConfig;
+		this.job_info = pdfji;
+		this.outputfile = outputfile;
+	}
+
+	public void run() {
+		// create document object
+		doc = new Document(PageSize.A4, 0,0,0,0);
+		PdfWriter docwriter = null;
+		FileOutputStream fos;
+		
+		try {
+			fos = new FileOutputStream(outputfile);
+		} catch (FileNotFoundException e1) {
+			// TODO Auto-generated catch block
+			logger.error(e1.getMessage());
+			e1.printStackTrace();
+			return;
+		}
+		
+		long start_time = System.currentTimeMillis();
+		
+		try {
+			docwriter = PdfWriter.getInstance(doc, fos);
+			
+			setPDFProperties();
+
+			doc.open();
+
+			addTitlePage();
+			
+			logger.debug("- "+outputfile+" doc.open()ed ("+(System.currentTimeMillis()-start_time) + "ms)");
+			start_time = System.currentTimeMillis();
+
+			Integer[] pgs = job_info.getPageNrs();//get_pgs();
+
+			for(Integer p: pgs){
+				logger.debug(" - adding Image "+p+" to " + outputfile);
+				addImage(p);
+				logger.debug(" - done adding Image "+p+" to " + outputfile);
+			}
+			
+			logger.debug(" - done adding all Images to " + outputfile);
+			
+		} catch(Exception e) {
+			logger.error(e.getMessage());
+			error = e;
+			return;
+		} finally {
+			if (doc!=null){
+				doc.close();
+				logger.debug("- "+outputfile+" doc.close() ("+(System.currentTimeMillis()-start_time) + "ms)");
+			}
+			if (docwriter!=null){
+				docwriter.close();
+			}
+		}
+
+		try {
+			fos.flush();
+		} catch (IOException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+			error = e;
+		} finally{
+			if(fos!=null){
+				try {
+					fos.close();
+				} catch (IOException e) {
+					logger.error(e.getMessage());
+					e.printStackTrace();
+				}
+			}
+		}
+	}
+
+	/**
+	 * Set PDF-Meta-Attributes.
+	 */
+	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());
+	}
+	
+	/**
+	 * Create a title page and append it to the document (should, of course, be called first)
+	 * @throws DocumentException
+	 */
+	public void addTitlePage() throws DocumentException{
+		PDFTitlePage titlepage = new PDFTitlePage(job_info);
+		doc.add(titlepage.getPageContents());
+		doc.newPage();
+	}
+		
+	/**
+	 * add the image with page number 'pn' to the document.
+	 * 
+	 * @param pn
+	 */
+	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 {
+			DocuImage img = image_worker.render();
+
+			Image pdfimg = Image.getInstance(img.getAwtImage(),null);
+			
+			float docW = PageSize.A4.getWidth() - 2 * PageSize.A4.getBorder(); 
+			float docH = PageSize.A4.getHeight() - 2 * PageSize.A4.getBorder();
+			
+			pdfimg.scaleToFit(docW,docH);
+			
+			doc.add(pdfimg);
+			
+		} catch (FileOpException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+		} catch (IOException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+		} catch (ImageOpException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+		} catch (BadElementException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+		} catch (DocumentException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+		}
+	}
+
+
+	
+	
+	
+	@Override
+	public DocuImage render() throws Exception {
+		return null;
+	}
+
+	@Override
+	public void write(DocuImage img) throws Exception {
+		
+	}
+	
+}
\ No newline at end of file
--- a/servlet/src/digilib/servlet/DigilibRequest.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/DigilibRequest.java	Wed Aug 25 18:29:08 2010 +0200
@@ -26,27 +26,14 @@
 
 package digilib.servlet;
 
-import java.io.StringReader;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Iterator;
 import java.util.StringTokenizer;
 
 import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 
-import org.apache.log4j.Logger;
-
-import com.hp.hpl.mesa.rdf.jena.mem.ModelMem;
-import com.hp.hpl.mesa.rdf.jena.model.Model;
-import com.hp.hpl.mesa.rdf.jena.model.Property;
-import com.hp.hpl.mesa.rdf.jena.model.ResIterator;
-import com.hp.hpl.mesa.rdf.jena.model.Resource;
-import com.hp.hpl.mesa.rdf.jena.model.Statement;
-import com.hp.hpl.mesa.rdf.jena.model.StmtIterator;
-
 import digilib.image.DocuImage;
 import digilib.io.FileOps;
 
@@ -76,11 +63,7 @@
 
 	private static final long serialVersionUID = -4707707539569977901L;
 
-	private final static String ECHO = "http://echo.unibe.ch/digilib/rdf#";
-
-	private final static String DIGILIB = "Digilib";
-
-	private Logger logger = Logger.getLogger(this.getClass());
+	//private Logger logger = Logger.getLogger(this.getClass());
 
 	private boolean boolRDF = false; // use RDF Parameters
 
@@ -199,11 +182,7 @@
 		servletRequest = request;
 		// decide if it's old-style or new-style
 		String qs = ((HttpServletRequest) request).getQueryString();
-		if (request.getParameter("rdf") != null) {
-			// RDF stuff
-			boolRDF = true;
-			setWithRDF(request);
-		} else if (qs != null) {
+		if (qs != null) {
 			if (qs.indexOf("&amp;") > -1) {
 				// &amp; separator
 				setWithParamString(qs, "&amp;");
@@ -349,8 +328,7 @@
 	public String getAsString(int type) {
 		StringBuffer s = new StringBuffer(50);
 		// go through all values
-		for (Iterator i = this.values().iterator(); i.hasNext();) {
-			Parameter p = (Parameter) i.next();
+		for (Parameter p: this.values()) {
 			if ((type > 0) && (p.getType() != type)) {
 				// skip the wrong types
 				continue;
@@ -406,10 +384,11 @@
 	 * @param request
 	 *            ServletRequest to get parameters from.
 	 */
-	public void setWithParamRequest(ServletRequest request) {
+	@SuppressWarnings("unchecked") // ServletRequest.getParameterNames() returns naked Enumeration
+    public void setWithParamRequest(ServletRequest request) {
 		setValue("servlet.request", request);
 		// go through all request parameters
-		for (Enumeration i = request.getParameterNames(); i.hasMoreElements();) {
+		for (Enumeration<String> i = request.getParameterNames(); i.hasMoreElements();) {
 			String name = (String) i.nextElement();
 			// is this a known parameter?
 			if (this.containsKey(name)) {
@@ -466,76 +445,6 @@
 	}
 
 	/**
-	 * 
-	 * 
-	 */
-	public void setWithRDF(ServletRequest request) {
-		String strRDF;
-		strRDF = request.getParameter("rdf");
-		if (strRDF != null) {
-			Hashtable hashRDF = rdf2hash(strRDF);
-			// go through all parameters
-			for (Iterator i = hashRDF.keySet().iterator(); i.hasNext();) {
-				String name = (String) i.next();
-				// is this a known parameter?
-				if (this.containsKey(name)) {
-					Parameter p = (Parameter) this.get(name);
-					// internal parameters are not set
-					if (p.getType() == 'i') {
-						continue;
-					}
-					p.setValueFromString((String) hashRDF.get(name));
-				}
-			}
-		}
-		// add path from request
-		setValue("request.path", ((HttpServletRequest) request).getPathInfo());
-	}
-
-	private Hashtable rdf2hash(String strRDF) {
-		Hashtable hashParams = new Hashtable();
-		try {
-			// create an empty model
-			Model model = new ModelMem();
-			StringReader sr = new StringReader(strRDF);
-			model.read(sr, "");
-			// get Property type -> digilib
-			Property property = model.getProperty(DigilibRequest.ECHO, "type");
-			if (property != null) {
-				ResIterator resourceIterator = model
-						.listSubjectsWithProperty(property);
-				while (resourceIterator.hasNext()) {
-					Resource resource = resourceIterator.next();
-					StmtIterator statementIterator = resource.listProperties();
-					String type = resource.getProperty(property).getResource()
-							.getURI();
-					if (type == null) {
-						continue;
-					}
-					if (type.equals(DigilibRequest.ECHO
-							+ DigilibRequest.DIGILIB)) {
-						while (statementIterator.hasNext()) {
-							Statement statement = statementIterator.next();
-							Property predicate = statement.getPredicate();
-							if (predicate.getNameSpace().equals(
-									DigilibRequest.ECHO)) {
-								hashParams.put(predicate.getLocalName(),
-										statement.getObject().toString());
-							}
-						}
-					}
-				}
-			} else {
-				logger.warn("The type property was null! So the rdf-model"
-						+ " sent to Digilib was probably incorrect!");
-			}
-		} catch (Exception e) {
-			logger.warn("rdf2hash function caused an error: ", e);
-		}
-		return hashParams;
-	}
-
-	/**
 	 * Test if option string <code>opt</code> is set. Checks if the substring
 	 * <code>opt</code> is contained in the options string <code>param</code>.
 	 * 
--- a/servlet/src/digilib/servlet/DigilibWorker.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/DigilibWorker.java	Wed Aug 25 18:29:08 2010 +0200
@@ -1,4 +1,4 @@
-	/* DigilibWorker.java -- image operation worker
+/* DigilibWorker.java -- image operation worker
  * 
  * Digital Image Library servlet components
  * 
--- a/servlet/src/digilib/servlet/DocumentBean.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/DocumentBean.java	Wed Aug 25 18:29:08 2010 +0200
@@ -128,7 +128,7 @@
 	 * return a list of authorization roles needed for request to access the
 	 * specified path
 	 */
-	public List rolesForPath(DigilibRequest request) throws AuthOpException {
+	public List<String> rolesForPath(DigilibRequest request) throws AuthOpException {
 		logger.debug("rolesForPath");
 		return useAuthentication ? authOp.rolesForPath(request) : null;
 	}
@@ -136,7 +136,7 @@
 	/**
 	 * check request authorization against a list of roles
 	 */
-	public boolean isRoleAuthorized(List roles, DigilibRequest request) {
+	public boolean isRoleAuthorized(List<String> roles, DigilibRequest request) {
 		logger.debug("isRoleAuthorized");
 		return useAuthentication ? authOp.isRoleAuthorized(roles, request)
 				: true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/ImageJobInformation.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,664 @@
+package digilib.servlet;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.log4j.Logger;
+
+import digilib.image.ImageOpException;
+import digilib.image.ImageOps;
+import digilib.image.ImageSize;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
+import digilib.io.ImageFile;
+import digilib.io.ImageFileset;
+
+
+/** 
+ * A container class for storing a set of instructional parameters 
+ * used for content generating classes like MakePDF.  
+ * 
+ * This contains the functionality formerly found in Scaler, processRequest, only factorized.
+ * 
+ * TODO clean up...
+ * 
+ * @author cmielack
+ *
+ */
+
+public class ImageJobInformation extends ParameterMap {
+	
+	String[] parameter_list = {"fn","pn","dw","dh",
+								"wx", "wy", "ww", "wh", "ws", 
+								"mo", "rot", "cont", "brgt", "rgbm", "rbgm", 
+								"ddpi", "ddpix", "ddpiy", "scale"};
+	DigilibConfiguration dlConfig = null;
+	protected static Logger logger = Logger.getLogger("digilib.servlet");
+
+	ImageFile fileToLoad = null;
+	ImageFileset fileset=null;
+	String FilePath = null;
+	ImageSize expectedSourceSize = null;
+	Float scaleXY = null;
+	Rectangle2D userImgArea = null;
+	Rectangle2D outerUserImgArea= null;
+	Boolean imageSendable = null;
+//	Integer paramDW = null;
+//	Integer paramDH 
+	public ImageJobInformation(DigilibConfiguration dlcfg) {
+		super(30);
+		
+		// url of the page/document (second part)
+		newParameter("fn", "", null, 's');
+		// page number
+		newParameter("pn", new Integer(1), 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, 'i');
+
+		/*
+		 * 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) {
+		for (String param : parameter_list){
+			if (request.getParameterMap().containsKey(param)){
+				this.setValueFromString(param, request.getParameter(param));
+			}
+		}
+	setValueFromString("request.path", ((HttpServletRequest) request).getPathInfo());
+	String[] baseurl_parts = ((HttpServletRequest) request).getRequestURL().toString().split("/");
+	String baseurl = "";
+	for(int i=0; i<baseurl_parts.length-2; i++){
+		baseurl += baseurl_parts[i]+"/";
+	}
+	setValueFromString("base.url", baseurl);
+	}
+	
+	public String[] getParameterList(){
+		return parameter_list;
+	}
+	
+	
+	public boolean hasOption(String param, String opt) {
+		String s = getAsString(param);
+		if (s != null) {
+			StringTokenizer i = new StringTokenizer(s, ",");
+			while (i.hasMoreTokens()) {
+				if (i.nextToken().equals(opt)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+	
+	
+	public String get_mimeType() {
+		String mimeType = "image/png";
+		
+		
+		ImageFile fileToLoad;
+		try {
+
+			fileToLoad = get_fileToLoad();
+			
+			if(!get_fileToLoad().isChecked()){
+				ImageOps.checkFile(fileToLoad);
+			}
+
+				
+			if(fileToLoad != null)
+				mimeType = fileToLoad.getMimetype();
+
+		} catch (IOException e) {
+			e.printStackTrace();
+		} catch (ImageOpException e) {
+			e.printStackTrace();
+		}
+
+		
+		return mimeType;
+	}
+	
+	public ImageFile get_fileToLoad() throws IOException, ImageOpException{
+		
+		if(fileToLoad == null){
+			ImageFileset fileset = get_fileset();
+			
+			/* select a resolution */
+			if (get_hiresOnly()) {
+				// get first element (= highest resolution)
+				fileToLoad = fileset.getBiggest();
+			} else if (get_loresOnly()) {
+				// enforced lores uses next smaller resolution
+				fileToLoad = fileset.getNextSmaller(get_expectedSourceSize());
+				if (fileToLoad == null) {
+					// this is the smallest we have
+					fileToLoad = fileset.getSmallest();
+				}
+			} else {
+				// autores: use next higher resolution
+				fileToLoad = fileset.getNextBigger(get_expectedSourceSize());
+				if (fileToLoad == null) {
+					// this is the highest we have
+					fileToLoad = fileset.getBiggest();
+				}
+			}
+			logger.info("Planning to load: " + fileToLoad.getFile());
+		}
+		
+		return fileToLoad;
+
+	}
+	
+	public ImageFileset get_fileset() throws FileOpException{
+		if(fileset==null){
+			DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+	
+			fileset = (ImageFileset) dirCache.getFile(getFilePath(), getAsInt("pn"), FileOps.CLASS_IMAGE);
+			if (fileset == null) {
+				throw new FileOpException("File " + getFilePath() + "("
+						+ getAsInt("pn") + ") not found.");
+			}
+		}
+		return fileset;
+	}
+	
+	public String getFilePath() {
+		if(FilePath == null){
+			String s = this.getAsString("request.path");
+			s += this.getAsString("fn");
+			FilePath = FileOps.normalName(s);
+		}
+		return FilePath;
+	}
+
+	public boolean get_hiresOnly(){
+		return hasOption("mo","clip") || hasOption("mo","osize") || hasOption("mo","hires");
+	}
+	
+	public boolean get_loresOnly(){
+
+		return hasOption("mo","lores");
+	}
+
+	public boolean get_scaleToFit() {
+
+		return !(hasOption("mo","clip") || hasOption("mo","osize") || hasOption("mo","ascale"));
+	}
+
+	public boolean get_absoluteScale(){
+
+		return hasOption("mo","osize") || hasOption("mo","ascale");
+	}
+	
+	
+	public ImageSize get_expectedSourceSize() throws IOException, ImageOpException{
+
+		if (expectedSourceSize == null){
+			expectedSourceSize = new ImageSize();
+			
+			if (get_scaleToFit()) {
+				// scale to fit -- calculate minimum source size
+				float scale = (1 / Math.min(getAsFloat("ww"), getAsFloat("wh"))) * getAsFloat("ws");
+				expectedSourceSize.setSize((int) (getAsInt("dw") * scale),
+						(int) (getAsInt("dh") * scale));
+			} else if (get_absoluteScale() && hasOption("mo", "ascale")) {
+				// absolute scale -- apply scale to hires size
+				expectedSourceSize = get_hiresSize().getScaled(getAsFloat("scale"));
+			} else {
+				// clip to fit -- source = destination size
+				expectedSourceSize.setSize((int) (getAsInt("dw") * getAsFloat("ws")),
+						(int) (getAsInt("dh") * getAsFloat("ws")));
+			}
+		}
+		return expectedSourceSize;
+	}
+	
+	public ImageSize get_hiresSize() throws IOException, ImageOpException{
+		logger.debug("get_hiresSize()");
+
+		ImageSize hiresSize = null;
+		ImageFileset fileset = get_fileset();
+		if (get_absoluteScale()) {
+			ImageFile hiresFile = fileset.getBiggest();
+			if (!hiresFile.isChecked()) {
+				ImageOps.checkFile(hiresFile);
+			}
+			hiresSize = hiresFile.getSize();
+			
+			/* prepare resolution and scale factor for original size */
+			if (hasOption("mo", "osize")) {
+				// get original resolution from metadata
+				fileset.checkMeta();
+				float origResX = fileset.getResX();
+				float origResY = fileset.getResY();
+				if ((origResX == 0) || (origResY == 0)) {
+					throw new ImageOpException("Missing image DPI information!");
+				}
+
+				if ((getAsFloat("ddpix") == 0) || (getAsFloat("ddpiy") == 0)) {
+					throw new ImageOpException(
+							"Missing display DPI information!");
+				}
+				// calculate absolute scale factor
+				float sx = getAsFloat("ddpix") / origResX;
+				float sy = getAsFloat("ddpiy") / origResY;
+				// currently only same scale :-(
+				setValue("scale", (sx + sy)/2f);
+			}
+			
+		}
+		return hiresSize;
+		
+	}
+	
+	public float get_scaleXY() throws IOException, ImageOpException{
+		//logger.debug("get_scaleXY()");
+		if(scaleXY == null){
+			// coordinates and scaling
+			float areaWidth;
+			float areaHeight;
+			float scaleX;
+			float scaleY;
+			ImageSize imgSize = get_fileToLoad().getSize();
+			ImageSize hiresSize = get_hiresSize();
+			// 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(getAsFloat("wx"), getAsFloat("wy"),
+					getAsFloat("ww"), getAsFloat("wh"));
+			// 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 (get_scaleToFit()) {
+				areaWidth = (float) userImgArea.getWidth();
+				areaHeight = (float) userImgArea.getHeight();
+				scaleX = get_paramDW() / areaWidth * getAsFloat("ws");
+				scaleY = get_paramDH() / areaHeight * getAsFloat("ws");
+				scaleXY = (scaleX > scaleY) ? scaleY : scaleX;
+			} else if (get_absoluteScale()) {
+				scaleXY = getAsFloat("scale");
+				// 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 = get_paramDW() / scaleXY * getAsFloat("ws");
+				areaHeight = get_paramDH() / scaleXY * getAsFloat("ws");
+				// reset user area size
+				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+						areaWidth, areaHeight);
+			} else {
+				// crop to fit
+				areaWidth = get_paramDW() * getAsFloat("ws");
+				areaHeight = get_paramDH() * getAsFloat("ws");
+				// reset user area size
+				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+						areaWidth, areaHeight);
+				scaleX = 1f;
+				scaleY = 1f;
+				scaleXY = 1f;
+			}
+		}
+		
+		return (float) scaleXY;
+	}
+	
+	public int get_paramDW(){
+		logger.debug("get_paramDW()");
+
+		int paramDW = getAsInt("dw");
+		int paramDH = getAsInt("dh");
+		
+		float imgAspect;
+		try {
+			imgAspect = get_fileToLoad().getAspect();
+			if (paramDW == 0) {
+				paramDW = (int) Math.round(paramDH * imgAspect);
+				setValue("dw", paramDW);
+			} else if (paramDH == 0) {
+				setValue("dh",  (int) Math.round(paramDW / imgAspect));
+			}
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (ImageOpException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return paramDW;
+	}
+	
+	public int get_paramDH(){
+		logger.debug("get_paramDH()");
+
+		int paramDW = getAsInt("dw");
+		int paramDH = getAsInt("dh");
+		
+		float imgAspect;
+		try {
+			imgAspect = get_fileToLoad().getAspect();
+			if (paramDW == 0) {
+				setValue("dw", (int) Math.round(paramDH * imgAspect));
+			} else if (paramDH == 0) {
+				paramDH = (int) Math.round(paramDW / imgAspect);
+				setValue("dh", paramDH );
+			}
+
+
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (ImageOpException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return paramDH;
+	}
+	public Integer get_scaleQual(){
+		logger.debug("get_scaleQual()");
+
+		Integer qual = 	dlConfig.getAsInt("default-quality");
+		if(hasOption("mo","q0"))
+			qual = 0;
+		else if(hasOption("mo","q1"))
+			qual = 1;
+		else if(hasOption("mo","q2"))
+			qual = 2;
+		return qual;
+	}
+
+	
+	public ImageSize get_imgSize() throws IOException, ImageOpException{
+
+		ImageSize imgSize = get_fileToLoad().getSize();
+		return imgSize;
+	}
+	
+	public Rectangle2D get_userImgArea() throws IOException, ImageOpException{
+		//logger.debug("get_userImgArea()");
+		
+		if(userImgArea==null){
+			// transform from relative [0,1] to image coordinates.
+			AffineTransform imgTrafo = AffineTransform.getScaleInstance(get_imgSize()
+					.getWidth(), get_imgSize().getHeight());
+	
+			// user window area in [0,1] coordinates
+			Rectangle2D relUserArea = new Rectangle2D.Float(getAsFloat("wx"), getAsFloat("wy"),
+					getAsFloat("ww"), getAsFloat("wh"));
+	
+			// transform user coordinate area to image coordinate area
+			userImgArea = imgTrafo.createTransformedShape(
+					relUserArea).getBounds2D();
+			
+			if(get_absoluteScale()){
+				float areaWidth = getAsInt("dw") / get_scaleXY() * getAsFloat("ws");
+				float areaHeight = getAsInt("dh") / get_scaleXY() * getAsFloat("ws");
+				// reset user area size
+				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+						areaWidth, areaHeight);
+			} else if (!get_scaleToFit()){
+				// crop to fit
+				float areaWidth = getAsInt("dw") * getAsFloat("ws");
+				float areaHeight = getAsInt("dh") * getAsFloat("ws");
+				// reset user area size
+				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+						areaWidth, areaHeight);
+			}
+		}
+		return userImgArea;		
+		
+	}
+	
+	public Rectangle2D get_outerUserImgArea() throws IOException, ImageOpException{
+		//logger.debug("get_outerUserImgArea()");
+
+		if(outerUserImgArea == null){
+			Rectangle2D userImgArea = get_userImgArea();
+			
+			// image size in pixels
+			Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, get_imgSize()
+					.getWidth(), get_imgSize().getHeight());
+	
+	
+	
+			
+			outerUserImgArea = userImgArea;
+			Rectangle2D innerUserImgArea = userImgArea;
+			if (get_wholeRotArea()) {
+				if (getAsFloat("rot") != 0) {
+					try {
+						// rotate user area coordinates around center of user
+						// area
+						AffineTransform rotTrafo = AffineTransform
+								.getRotateInstance(Math.toRadians(getAsFloat("rot")),
+										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
+			logger.debug("outerUserImgArea.getWidth()=" + outerUserImgArea.getWidth());
+			logger.debug("get_scaleXY() * outerUserImgArea.getWidth() = " + (get_scaleXY() * outerUserImgArea.getWidth()));
+			
+			if ((outerUserImgArea.getWidth() < 1)
+					|| (outerUserImgArea.getHeight() < 1)
+					|| (get_scaleXY() * outerUserImgArea.getWidth() < 2)
+					|| (get_scaleXY() * outerUserImgArea.getHeight() < 2)) {
+				logger.error("ERROR: invalid scale parameter set!");
+				throw new ImageOpException("Invalid scale parameter set!");
+			}
+		}
+		return outerUserImgArea;
+	}
+	
+	
+	public Rectangle2D get_innerUserImgArea() throws IOException, ImageOpException{
+		logger.debug("get_innerUserImgArea()");
+
+		Rectangle2D userImgArea = get_userImgArea();
+		Rectangle2D innerUserImgArea = get_userImgArea();
+		if (get_wholeRotArea()) {
+			if (getAsFloat("rot") != 0) {
+				// rotate user area coordinates around center of user
+				// area
+				AffineTransform rotTrafo = AffineTransform
+						.getRotateInstance(Math.toRadians(getAsFloat("rot")),
+								userImgArea.getCenterX(), userImgArea
+										.getCenterY());
+				// get bounds from rotated end position
+				innerUserImgArea = rotTrafo.createTransformedShape(
+						userImgArea).getBounds2D();
+			}
+		}
+		return innerUserImgArea;
+
+	}
+	public boolean get_wholeRotArea(){
+		// TODO this is not really implemented yet
+		//boolean wholeRotArea = false;
+		return false;//wholeRotArea;
+	}
+	
+	public int get_forceType(){
+
+		if(hasOption("mo","jpg"))
+			return ImageOps.TYPE_JPEG;
+		if(hasOption("mo","png"))
+			return ImageOps.TYPE_PNG;
+		
+		return ImageOps.TYPE_AUTO;
+	}
+	
+	public float[] get_paramRGBM(){
+		logger.debug("get_paramRGBM()");
+
+		float[] paramRGBM = null;//{0f,0f,0f};
+		Parameter p = get("rgbm");
+		if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
+			return p.parseAsFloatArray("/");
+		}	
+		return paramRGBM;
+	}
+	
+	public float[] get_paramRGBA(){
+		logger.debug("get_paramRGBA()");
+
+		float[] paramRGBA =  null;//{0f,0f,0f};
+		Parameter p = get("rgba");
+		if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
+			paramRGBA = p.parseAsFloatArray("/");
+		}
+		return paramRGBA;
+	}
+	
+	public boolean get_hmir(){
+		logger.debug("get_hmir()");
+
+		return hasOption("mo","hmir");
+	}
+	
+	public boolean get_vmir(){
+		logger.debug("get_vmir()");
+
+		return hasOption("mo","vmir");
+	}
+	
+	public boolean checkSendAsFile(){
+		return hasOption("mo", "file")
+		|| hasOption("mo", "rawfile");
+	}
+	
+	public boolean get_imageSendable(){
+		if(imageSendable==null){
+			String mimeType = get_mimeType();
+			imageSendable = ( (mimeType.equals("image/jpeg")
+				        	|| mimeType.equals("image/png")
+				        	|| mimeType.equals("image/gif") )
+				        	&& 
+				        	!(hasOption("mo", "hmir")
+							|| hasOption("mo", "vmir") 
+							|| (getAsFloat("rot") != 0)
+							|| (get_paramRGBM() != null) 
+							|| (get_paramRGBA() != null)
+							|| (getAsFloat("cont") != 0) 
+							|| (getAsFloat("brgt") != 0)));
+		}
+		
+		return imageSendable;
+	}
+	
+	
+	public boolean noTransformRequired(){
+		try {
+			return get_imageSendable() && ((get_loresOnly() && get_fileToLoad().getSize().isSmallerThan(
+					get_expectedSourceSize())) || (!(get_loresOnly() || get_hiresOnly()) && get_fileToLoad()
+							.getSize().fitsIn(expectedSourceSize)));
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (ImageOpException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return false;
+	}
+}
\ No newline at end of file
--- a/servlet/src/digilib/servlet/Initialiser.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/Initialiser.java	Wed Aug 25 18:29:08 2010 +0200
@@ -32,6 +32,7 @@
 
 import digilib.auth.AuthOps;
 import digilib.auth.XMLAuthOps;
+import digilib.image.DocuImage;
 import digilib.image.ImageOps;
 import digilib.io.AliasingDocuDirCache;
 import digilib.io.DocuDirCache;
@@ -48,7 +49,7 @@
 	private static final long serialVersionUID = -5126621114382549343L;
 
 	/** servlet version */
-	public static final String iniVersion = "0.2";
+	public static final String iniVersion = "0.1b2";
 
 	/** gengeral logger for this class */
 	private static Logger logger = Logger.getLogger("digilib.init");
@@ -128,11 +129,9 @@
 					dlConfig.setValue("auth-file", authConf);
 				}
 				// DocuImage class
-				Class cl = Class.forName(dlConfig
-						.getAsString("docuimage-class"));
-				dlConfig.setDocuImageClass(cl);
-				dlConfig.setValue("servlet.docuimage.class", cl.getName());
-                ImageOps.setDocuImage(dlConfig.getDocuImageInstance());
+				DocuImage di = dlConfig.getDocuImageInstance();
+				dlConfig.setValue("servlet.docuimage.class", di.getClass().getName());
+                ImageOps.setDocuImage(di);
 				// worker threads
 				int nt = dlConfig.getAsInt("worker-threads");
 				DigilibWorker.setSemaphore(nt, true);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/NumRange.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,164 @@
+/**
+ * 
+ */
+package digilib.servlet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author casties
+ * 
+ */
+public class NumRange implements Iterable<Integer> {
+
+    private Integer start = 1;
+    private Integer end = Integer.MAX_VALUE;
+    private List<Integer> list = null;
+    private Integer maxnum = null;
+
+    /**
+     * @param start
+     * @param end
+     */
+    public NumRange(Integer start, Integer end) {
+        this.start = start;
+        this.end = end;
+    }
+
+    /**
+     * @param range
+     */
+    public NumRange(String range) {
+        parseString(range);
+    }
+
+    /**
+     * @param range
+     */
+    public NumRange(String range, Integer max) {
+        this.maxnum = max;
+        parseString(range);
+    }
+
+
+    public void parseString(String pages) {
+
+        ArrayList<Integer> pgs = new ArrayList<Integer>();
+
+        String intervals[] = pages.split(",");
+
+        // convert the page-interval-strings into a list containing every single
+        // page
+        for (String interval : intervals) {
+            if (interval.contains("-")) {
+                String nums[] = interval.split("-");
+                int start = Integer.valueOf(nums[0]);
+                if (nums.length > 1) {
+                    // second number is end of range
+                    int end = Integer.valueOf(nums[1]);
+                    for (int i = start; i <= end; i++) {
+                        // add all numbers to list
+                        pgs.add(i);
+                    }
+                } else {
+                    // second number missing: range to infinity
+                    pgs.add(start);
+                    pgs.add(Integer.MAX_VALUE);
+                }
+            } else {
+                // single number
+                pgs.add(Integer.valueOf(interval));
+            }
+        }
+        if (intervals.length > 1) {
+            Collections.sort(pgs);
+        }
+        list = pgs;
+    }
+
+    public int getStart() {
+        if (list == null) {
+            return start;
+        } else {
+            return list.get(0);
+        }
+    }
+
+    public int getEnd() {
+        Integer last;
+        if (list == null) {
+            last = end;
+        } else {
+            last = list.get(list.size() - 1);
+        }
+        if (maxnum == null) {
+            return last;
+        } else {
+            return Math.min(last, maxnum);
+        }
+    }
+
+    @Override
+    public Iterator<Integer> iterator() {
+        if (list == null) {
+            // return count-based iterator
+            return new Iterator<Integer>() {
+                // anonymous inner Iterator class
+                private int num = getStart();
+                private int end = getEnd();
+
+                @Override
+                public boolean hasNext() {
+                    return (num < end);
+                }
+
+                @Override
+                public Integer next() {
+                    return num++;
+                }
+
+                @Override
+                public void remove() {
+                    // don't do this
+                }
+            };
+        } else {
+            // return list-based iterator
+            return new Iterator<Integer>() {
+                // anonymous inner Iterator class
+                private int listidx = 0;
+                private int listend = list.size();
+                private int num = getStart();
+                private int end = getEnd();
+
+                @Override
+                public boolean hasNext() {
+                    return (num < end);
+                }
+
+                @Override
+                public Integer next() {
+                    if (listidx < listend) {
+                        num = list.get(listidx++);
+                        return num;
+                    } else {
+                        return num++;
+                    }
+                }
+
+                @Override
+                public void remove() {
+                    // don't do this
+                }
+            };
+        }
+    }
+
+    public void setMaxnum(Integer maxnum) {
+        this.maxnum = maxnum;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/PDFCache.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,300 @@
+package digilib.servlet;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import javax.servlet.RequestDispatcher;
+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;
+
+/**
+ * A class for handling user requests for pdf documents from digilib images.  
+ * 
+ * If a document does not already exist, it will be enqueued for generation; if it does exist, it is sent
+ * to the user.
+ * 
+ * @author cmielack
+ *
+ */
+
+@SuppressWarnings("serial")
+public class PDFCache extends RequestHandler {
+
+	private DigilibConfiguration dlConfig = null;
+	
+	public static String instanceKey = "digilib.servlet.PDFCache";
+	
+	private File cache_directory = new File("cache");  
+	
+	private File temp_directory = new File("pdf_temp");
+	
+	private static String JSP_WIP = "/pdf/wip.jsp";
+	
+	private static String JSP_ERROR = "/pdf/error.jsp";
+	
+	public static Integer STATUS_DONE = 0;  	// document exists in cache
+
+	public static Integer STATUS_WIP = 1;  		// document is "work in progress"
+	
+	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";
+	
+	private ServletContext context = null;
+
+	
+	// TODO ? functionality for the pre-generation of complete books/chapters using default values
+	
+	
+	public void init(ServletConfig config) throws ServletException{
+		super.init(config);
+		
+        System.out.println("***** Digital Image Library Image PDF-Cache Servlet (version "
+                + version + ") *****");
+// say hello in the log file
+        logger.info("***** Digital Image Library Image PDF-Cache Servlet (version "
+                + version + ") *****");
+
+		context = config.getServletContext();
+		dlConfig = (DigilibConfiguration) context.getAttribute("digilib.servlet.configuration");
+		if (dlConfig == null) {
+			// no Configuration
+			throw new ServletException("No Configuration!");
+		}
+	
+		String temp_fn = dlConfig.getAsString("pdf-temp-dir");
+		temp_directory = new File(temp_fn);
+		if (!temp_directory.isDirectory()) {
+		    throw new ServletException("Configuration error: problem with pdf-temp-dir="+temp_fn);
+		}
+        // rid the temporary directory of possible incomplete document files
+        emptyDirectory(temp_directory);
+        
+		String cache_fn = dlConfig.getAsString("pdf-cache-dir");
+       	cache_directory = new File(cache_fn);
+        if (!cache_directory.isDirectory()) {
+            throw new ServletException("Configuration error: problem with pdf-cache-dir="+cache_fn);
+        }
+
+		// register this instance globally
+		context.setAttribute(instanceKey, this);
+		
+	}
+	
+	/** 
+	 * clean up any broken and unfinished files from the temporary directory.
+	 */
+	public void emptyDirectory(File temp_dir){
+		File[] temp_files = temp_dir.listFiles();
+		
+		for (File f: temp_files){
+			f.delete();
+		}
+	}
+	
+	
+	
+	@Override
+	public void processRequest(HttpServletRequest request,
+			HttpServletResponse response) {
+
+		// evaluate request ( make a PDFJobDeclaration , get the DocumentId)
+		PDFJobInformation pdfji = new PDFJobInformation(dlConfig); 
+		pdfji.setWithRequest(request);
+		
+		String docid = pdfji.getDocumentId();
+		
+		// if some invalid data has been entered ...
+		if(!pdfji.checkValidity()) {
+			notifyUser(STATUS_ERROR, docid, request, response);
+			return;
+		}
+		
+		int status = getStatus(docid);
+		
+        if (status == STATUS_NONEXISTENT) {
+            createNewPdfDocument(pdfji, docid);
+            notifyUser(status, docid, request, response);
+        } else if (status == STATUS_DONE) {
+            try {
+                sendFile(docid, downloadFilename(pdfji), response);
+            } catch (IOException e) {
+                e.printStackTrace();
+                logger.error(e.getMessage());
+            }
+        } else {
+            notifyUser(status, docid, request, response);
+        }
+	}
+
+	/**
+	 * depending on the documents status, redirect the user to an appropriate waiting- or download-site
+	 * 
+	 * @param status
+	 * @param documentid
+	 * @param request
+	 * @param response
+	 */
+	public void notifyUser(int status, String documentid, HttpServletRequest request, HttpServletResponse response){
+		
+		String jsp=null;
+		
+		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.");
+			jsp = JSP_WIP;
+		} else if(status == STATUS_WIP){
+			logger.debug("PDFCache: "+documentid+" has STATUS_WIP.");
+			jsp = JSP_WIP;
+
+			// estimate remaining work time
+			// tell the user he/she has to wait
+		} else if(status == STATUS_DONE){
+			logger.debug("PDFCache: "+documentid+" has STATUS_DONE.");
+		} else {
+			logger.debug("PDFCache: "+documentid+" has STATUS_ERROR.");
+			jsp = JSP_ERROR;
+		}
+
+		RequestDispatcher dispatch = context.getRequestDispatcher(jsp);
+		
+		try {
+			dispatch.forward(request, response);
+		} catch (ServletException e) {
+			logger.debug(e.getMessage());
+			e.printStackTrace();
+		} catch (IOException e) {
+			logger.debug(e.getMessage());
+			e.printStackTrace();
+		}
+		
+	}
+
+	
+	/** check the status of the document corresponding to the documentid */
+	public Integer getStatus(String documentid){
+		// looks into the cache and temp directory in order to find out the status of the document
+		File cached = new File(cache_directory, documentid);
+		File wip = new File(temp_directory, documentid);
+		if(cached.exists()){
+			return STATUS_DONE;
+		} else if (wip.exists()){
+			return STATUS_WIP;
+		} else {
+			return STATUS_NONEXISTENT;
+		}
+	}
+
+	/** 
+	 * create new thread for pdf generation.
+	 * 
+	 * @param pdfji
+	 * @param filename
+	 */
+	public void createNewPdfDocument(PDFJobInformation pdfji, String filename){
+		// start new worker
+		PDFMaker pdf_maker = new PDFMaker(context, pdfji,filename);
+		new Thread(pdf_maker, "PDFMaker").start();
+	}
+	
+	
+	/**
+	 * generate the filename the user is going to receive the pdf as
+	 * 
+	 * @param pdfji
+	 * @return
+	 */
+	public String downloadFilename(PDFJobInformation pdfji){
+		// filename example: digilib_example_pgs1-3.pdf
+		String filename;
+		filename =  "digilib_";
+		filename += pdfji.getImageJobInformation().getAsString("fn");
+		filename += "_pgs" + pdfji.getAsString("pgs");
+		filename += ".pdf";
+		
+		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 {
+			// get file handle
+			cached_file = new File(cache_directory, cachefile);
+			// create necessary streams
+			fis = new FileInputStream(cached_file);
+			sos = response.getOutputStream();
+			bis = new BufferedInputStream(fis);
+
+			int bytes = 0;
+
+			// set http headers
+			response.setContentType("application/pdf");
+			response.addHeader("Content-Disposition", "attachment; filename="+filename);
+			response.setContentLength( (int) cached_file.length());
+
+			// send the bytes
+			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();
+			}
+
+	}
+	
+	public File getCacheDirectory(){
+		return cache_directory;
+	}
+	
+	public File getTempDirectory(){
+		return temp_directory;
+	}
+	
+	/** 
+	 * returns a File object based on filename in the temp directory.
+	 * @param filename
+	 * @return
+	 */
+	public File getTempFile(String filename) {
+	    return new File(temp_directory, filename);
+	}
+
+	/** 
+     * returns a File object based on filename in the cache directory.
+     * @param filename
+     * @return
+     */
+    public File getCacheFile(String filename) {
+        return new File(cache_directory, filename);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/PDFJobInformation.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,185 @@
+package digilib.servlet;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.log4j.Logger;
+
+
+/** 
+ * A container class for storing a set of instruction parameters 
+ * used for content generator classes like MakePDF.  
+ * 
+ * 
+ * @author cmielack
+ *
+ */
+@SuppressWarnings("serial")
+public class PDFJobInformation extends ParameterMap {
+
+	String[] parameter_list = {"pgs"}; // all other parameters get passed into an extra ImageJobInformation  
+									   // (this should be redesigned later...)
+	
+	
+	ImageJobInformation image_info = null;
+	DigilibConfiguration dlConfig = null;
+	/** gengeral logger for this class */
+	protected static Logger logger = Logger.getLogger("digilib.servlet");
+
+	
+	/**
+	 * Initialize the PDFJobInformation
+	 * 
+	 * @param dlcfg			
+	 * 						The DigilibConfiguration. 
+	 */
+	public PDFJobInformation(DigilibConfiguration dlcfg) {
+		super(30);
+
+		// page numbers
+		newParameter("pgs", "", null, 's');
+		dlConfig = dlcfg;
+		
+	}
+
+	
+	/**
+	 * Read in the request object.
+	 * 
+	 * @param request
+	 */
+	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));
+			}
+		}
+	}
+	
+	
+	/**
+	 * Generate the filename of the pdf to be created.
+	 * 
+	 * @return
+	 */
+	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";
+			// make safe to use as filename by urlencoding
+			try {
+                id = URLEncoder.encode(id, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+		}
+		else {
+			id = null;
+		}
+		
+		return id;
+	}
+
+	
+	public ImageJobInformation getImageJobInformation(){
+		ImageJobInformation new_image_info = (ImageJobInformation) image_info.clone();
+		return new_image_info;
+	}
+	
+	
+	/**
+	 *	Convert the "pgs"-Parameter to an Array of Integers.	
+	 *
+	 * @return
+	 * @throws Exception
+	 */
+	public Integer[] getPageNrs() throws Exception{
+		
+		String pages =	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.contains("-")){
+				String nums[] = interval.split("-");
+				int start = Integer.valueOf(nums[0]);
+				int end = Integer.valueOf(nums[1]);
+				for(int i = start; i <= end; i++){
+					// add all numbers to list
+					pgs.add(i);
+				}
+			}
+			else{
+				pgs.add(Integer.valueOf(interval));
+			}
+		}
+		out = new Integer[pgs.size()];
+
+		pgs.toArray(out);
+		return out;
+	}
+	
+	
+	/**
+	 * Check parameters for validity.
+	 * Returns true if no errors are found.
+	 * 
+	 * @return
+	 */
+	public boolean checkValidity(){
+		String pgs = getAsString("pgs");
+		try{
+			String[] intervals = null;
+            if(pgs.indexOf(",")>0){
+                intervals = pgs.split(",");
+			}
+				else{
+					intervals = new String[1];
+					intervals[0]=pgs;
+				}
+				for(String interval:intervals){
+					if(interval.indexOf("-")>=0){
+						String[] intrvl = interval.split("-");
+						int a = Integer.valueOf(intrvl[0]);
+						int b = Integer.valueOf(intrvl[1]);
+						if(a<=0 || b<a){
+							return false;
+						}
+					}
+					else {
+						int c = Integer.valueOf(interval);
+						if(c<=0)
+							return false;
+						
+					}
+				}
+		}
+		catch(Exception e){
+			logger.error("invalid pgs-input");
+			return false;
+		}
+		return true;
+	}
+	
+	public DigilibConfiguration getDlConfig(){
+		return dlConfig;
+	}
+	
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/PDFMaker.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,74 @@
+package digilib.servlet;
+
+import java.io.File;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServlet;
+
+import org.apache.log4j.Logger;
+
+
+
+
+/**
+ * A Runnable that creates the PDFWorker and moves completed files from a temporary location
+ *  (defined in PDFCache) to the cache directory.
+ * 
+ * @author cmielack
+ *
+ */
+@SuppressWarnings("serial")
+public class PDFMaker extends HttpServlet implements Runnable {
+
+	public static String version = "0.1";
+	
+	private PDFJobInformation job_info = null;
+	private String filename = null;
+	private DigilibConfiguration dlConfig = null;
+	private ServletContext context = null;
+
+	/** gengeral logger for this class */
+	protected static Logger logger = Logger.getLogger("digilib.PDFMaker");
+
+	
+	
+	public PDFMaker(ServletContext context, PDFJobInformation pdfji, String filename){
+		this.job_info = pdfji;
+		this.filename = filename;
+		this.dlConfig = pdfji.getDlConfig();
+		this.context = context;
+	}
+		
+	public void run() {
+
+		if (! DigilibWorker.canRun()) {
+			// TODO include the logger
+			logger.error("Servlet overloaded!");			
+			return;
+		}
+
+		PDFCache pdfcache = (PDFCache) context.getAttribute(PDFCache.instanceKey);
+		
+		File tempfile = pdfcache.getTempFile(filename);
+		// create PDFWorker
+		DigilibPDFWorker pdf_worker = new DigilibPDFWorker(dlConfig, job_info, tempfile);
+		
+		// run PDFWorker
+		pdf_worker.run();
+
+		if(pdf_worker.hasError()){
+			// raise error, write to logger
+			logger.error(pdf_worker.getError().getMessage());
+			tempfile.delete();
+			return;
+		}
+		else{ // move the completed file to the cache directory
+			boolean success = tempfile.renameTo(pdfcache.getCacheFile(filename));
+			if(!success){
+				// TODO raise error
+			}
+		}
+		
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/PDFTitlePage.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,181 @@
+package digilib.servlet;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.log4j.Logger;
+
+import com.itextpdf.text.Anchor;
+import com.itextpdf.text.BadElementException;
+import com.itextpdf.text.Chunk;
+import com.itextpdf.text.Element;
+import com.itextpdf.text.FontFactory;
+import com.itextpdf.text.Image;
+import com.itextpdf.text.Paragraph;
+
+
+import digilib.io.DocuDirCache;
+
+/** A class for the generation of title pages for the generated pdf documents.
+ * 
+ * 
+ */
+public class PDFTitlePage {
+	
+	private PDFJobInformation job_info = null;
+	private DigilibInfoReader info_reader= null;
+	private DocuDirCache dirCache = null;
+	protected static Logger logger = Logger.getLogger("digilib.servlet");
+
+	
+	/**
+	 * Initialize a TitlePage
+	 * @param pdfji
+	 */
+	public PDFTitlePage(PDFJobInformation pdfji){
+		job_info = pdfji;
+		dirCache = (DocuDirCache) job_info.getDlConfig().getValue("servlet.dir.cache");
+
+		String fn = getBase(dirCache.getDirectory(pdfji.getImageJobInformation().getAsString("fn")).getDir().getPath()) + "presentation/info.xml";
+		
+		info_reader = new DigilibInfoReader(fn);
+	}
+	
+	/**
+	 * generate iText-PDF-Contents for the title page
+	 * 
+	 * @return
+	 */
+	public Element getPageContents(){
+		Paragraph content = new Paragraph();
+		content.setAlignment(Element.ALIGN_CENTER);
+
+		// add vertical whitespace
+		for(int i=0; i<8; i++){
+			content.add(Chunk.NEWLINE);
+		}
+		
+		
+		// add logo
+		content.add(getLogo());
+		content.add(Chunk.NEWLINE);
+		content.add(Chunk.NEWLINE);
+
+		// add title
+		Anchor title = new Anchor(new Paragraph(getTitle(),FontFactory.getFont(FontFactory.HELVETICA,16)));
+		String burl = job_info.getImageJobInformation().getAsString("base.url");
+		
+		title.setReference(burl+"digilib.jsp?fn="+job_info.getImageJobInformation().getAsString("fn"));
+		content.add(title);		
+		content.add(Chunk.NEWLINE);
+
+		// add author
+		if(getDate()!=" ")
+			content.add(new Paragraph(getAuthor()+" ("+getDate()+")",FontFactory.getFont(FontFactory.HELVETICA,14)));
+		else
+			content.add(new Paragraph(getAuthor(),FontFactory.getFont(FontFactory.HELVETICA,14)));
+		
+		content.add(Chunk.NEWLINE);
+		
+		// add page numbers
+		content.add(new Paragraph(getPages(), FontFactory.getFont(FontFactory.HELVETICA, 12)));
+
+
+		content.add(Chunk.NEWLINE);
+		content.add(Chunk.NEWLINE);
+		content.add(Chunk.NEWLINE);
+
+		// add credits
+		content.add(new Paragraph("MPIWG Berlin 2009", FontFactory.getFont(FontFactory.HELVETICA,10)));
+
+		// add digilib version
+		content.add(new Paragraph(getDigilibVersion(),FontFactory.getFont(FontFactory.HELVETICA,10)));
+
+		for(int i=0; i<8; i++){
+			content.add(Chunk.NEWLINE);
+		}
+		Anchor address = new Anchor(
+				new Paragraph(burl+"digilib.jsp?fn="+job_info.getImageJobInformation().getAsString("fn"), FontFactory.getFont(FontFactory.COURIER, 9))
+									);
+		address.setReference(burl+"digilib.jsp?fn="+job_info.getImageJobInformation().getAsString("fn"));
+		
+		content.add(address);
+
+		
+		return content;
+	}
+	
+	/**
+	 * return base directory of an image directory
+	 * 
+	 * @param path
+	 * @return
+	 */
+	private String getBase(String path){
+		if(path.contains("/")){
+			String[] x = path.split("/");
+			String newpath = "";
+			for(int i=0; i<x.length-1; i++){
+				newpath += x[i]+"/";
+			}
+			return newpath;
+		}
+		else
+			return "";
+	}
+	
+
+	/**
+	 * Methods for the different attributes.
+	 * 
+	 */
+	
+	
+	private Image getLogo(){
+		try {
+			URL url = new URL(job_info.getDlConfig().getAsString("pdf-logo"));
+			if(url!=null && !url.equals("")){
+				Image logo = Image.getInstance(url);
+				logo.setAlignment(Element.ALIGN_CENTER);
+				return logo;
+			}
+		} catch (BadElementException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+		} catch (MalformedURLException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+		} catch (IOException e) {
+			logger.error(e.getMessage());
+			e.printStackTrace();
+		}
+		return null;
+	}
+	private String getTitle(){
+		if(info_reader.hasInfo())
+			return info_reader.getAsString("title");
+		else
+			return job_info.getImageJobInformation().getAsString("fn");
+	}
+	private String getAuthor(){
+		if(info_reader.hasInfo())
+			return info_reader.getAsString("author");
+		else
+			return " ";
+	}
+	private String getDate(){
+		if(info_reader.hasInfo())
+			return info_reader.getAsString("date");
+		else
+			return " ";
+	}
+	private String getPages(){
+		return "Pages "+job_info.getAsString("pgs") + " (scan page numbers)";
+	}
+
+	private String getDigilibVersion(){
+		return "Digilib PDFMaker v."+PDFMaker.version;
+	}
+	
+}
--- a/servlet/src/digilib/servlet/Parameter.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/Parameter.java	Wed Aug 25 18:29:08 2010 +0200
@@ -102,7 +102,7 @@
 			this.value = val;
 			return true;
 		}
-		Class c = defval.getClass();
+		Class<? extends Object> c = defval.getClass();
 		// take String as is
 		if (c == String.class) {
 			this.value = val;
--- a/servlet/src/digilib/servlet/ParameterMap.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/ParameterMap.java	Wed Aug 25 18:29:08 2010 +0200
@@ -30,7 +30,7 @@
  * @author casties
  *
  */
-public class ParameterMap extends HashMap {
+public class ParameterMap extends HashMap<String, Parameter> {
 
 	private static final long serialVersionUID = 1530820988748391313L;
 
@@ -56,7 +56,7 @@
 	 * @return
 	 */
 	public Parameter get(String key) {
-		return (Parameter) super.get(key);
+		return super.get(key);
 	}
 
 	/** Get the Parameter with the corresponding key.
@@ -67,7 +67,7 @@
 	 * @return
 	 */
 	public Object getValue(String key) {
-		Parameter p = (Parameter) super.get(key);
+		Parameter p = super.get(key);
 		return (p != null) ? p.getValue() : null;
 	}
 	
@@ -79,7 +79,7 @@
 	 * @return
 	 */
 	public String getAsString(String key) {
-		Parameter p = (Parameter) super.get(key);
+		Parameter p = super.get(key);
 		return (p != null) ? p.getAsString() : null;
 	}
 
@@ -91,7 +91,7 @@
 	 * @return
 	 */
 	public int getAsInt(String key) {
-		Parameter p = (Parameter) super.get(key);
+		Parameter p = super.get(key);
 		return (p != null) ? p.getAsInt() : 0;
 	}
 
@@ -103,7 +103,7 @@
 	 * @return
 	 */
 	public float getAsFloat(String key) {
-		Parameter p = (Parameter) super.get(key);
+		Parameter p = super.get(key);
 		return (p != null) ? p.getAsFloat() : 0f;
 	}
 
@@ -115,7 +115,7 @@
 	 * @return
 	 */
 	public boolean getAsBoolean(String key) {
-		Parameter p = (Parameter) super.get(key);
+		Parameter p = super.get(key);
 		return (p != null) ? p.getAsBoolean() : false;
 	}
 
@@ -125,7 +125,7 @@
 	 * @return
 	 */
 	public boolean hasValue(String key) {
-		Parameter p = (Parameter) super.get(key);
+		Parameter p = super.get(key);
 		return (p != null) ? p.hasValue() : false;
 	}
 	
@@ -138,7 +138,7 @@
 	 * @return
 	 */
 	public Parameter put(String key, Parameter val) {
-		return (Parameter) super.put(key, val);
+		return super.put(key, val);
 	}
 
 	/** Add the Parameter val to the map, using val's name.
@@ -149,7 +149,7 @@
 	 * @return
 	 */
 	public Parameter put(Parameter val) {
-		return (Parameter) super.put(val.getName(), val);
+		return super.put(val.getName(), val);
 	}
 	
 	/** Add a new Parameter with name, default and value.
@@ -163,7 +163,7 @@
 	 */
 	public Parameter newParameter(String name, Object def, Object val) {
 		Parameter p = new Parameter(name, def, val);
-		return (Parameter) super.put(name, p);
+		return super.put(name, p);
 	}
 
 	/** Add a new Parameter with name, default, value and type.
@@ -178,7 +178,7 @@
 	 */
 	public Parameter newParameter(String name, Object def, Object val, int type) {
 		Parameter p = new Parameter(name, def, val, type);
-		return (Parameter) super.put(name, p);
+		return super.put(name, p);
 	}
 
 	/** Set the value of an existing parameter.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/RequestHandler.java	Wed Aug 25 18:29:08 2010 +0200
@@ -0,0 +1,82 @@
+package digilib.servlet;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+
+import digilib.image.ImageOpException;
+
+public abstract class RequestHandler extends HttpServlet {
+
+	/** logger for accounting requests */
+	protected static Logger accountlog = Logger.getLogger("account.request");
+
+	/** gengeral logger for this class */
+	protected static Logger logger = Logger.getLogger("digilib.servlet");
+
+	/** logger for authentication related */
+	protected static Logger authlog = Logger.getLogger("digilib.auth");
+
+	
+	public void init(ServletConfig config) throws ServletException{
+		try {
+			super.init(config);
+		} catch (ServletException e) {
+			e.printStackTrace();
+			logger.error(e.getMessage());
+		}
+
+		
+		
+	}
+	
+	
+	public void doGet(HttpServletRequest request, HttpServletResponse response){
+		accountlog.info("GET from " + request.getRemoteAddr());
+		
+		try {
+			this.processRequest(request, response);
+		} catch (ServletException e) {
+			e.printStackTrace();
+			logger.error(e.getMessage());
+		} catch (ImageOpException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+
+	public void doPost(HttpServletRequest request, HttpServletResponse response){
+		accountlog.info("POST from " + request.getRemoteAddr());
+
+		try {
+			this.processRequest(request, response);
+		} catch (ServletException e) {
+			e.printStackTrace();
+			logger.error(e.getMessage());
+		} catch (ImageOpException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	/**
+	 * processRequest 
+	 * 
+	 * evaluate request (,generate content), send content to user
+	 * @throws ServletException 
+	 * @throws ImageOpException 
+	 * 
+	 * */
+	abstract public void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, ImageOpException;
+	
+	
+	/** send the requested content to the response */
+	// abstract public void sendFile(File f, HttpServletResponse response, String filename);
+	
+	
+}
--- a/servlet/src/digilib/servlet/Scaler.java	Wed Jul 14 16:36:42 2010 +0200
+++ b/servlet/src/digilib/servlet/Scaler.java	Wed Aug 25 18:29:08 2010 +0200
@@ -1,74 +1,33 @@
-/*
- * Scaler -- Scaler servlet main class
- * 
- * 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.File;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.util.List;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.log4j.Logger;
-
 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;
+
 
-/**
- * @author casties
- */
-// public class Scaler extends HttpServlet implements SingleThreadModel {
-public class Scaler extends HttpServlet {
+// TODO digilibError is not used anymore and may need to get reintegrated
 
-	private static final long serialVersionUID = -325080527268912852L;
+public class Scaler extends RequestHandler {
 
 	/** digilib servlet version (for all components) */
-	public static final String dlVersion = "1.7.1b";
-
-	/** 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");
+	public static final String dlVersion = "1.8.0a";
 
 	/** general error code */
 	public static final int ERROR_UNKNOWN = 0;
@@ -116,8 +75,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)
 	 */
@@ -155,554 +147,161 @@
 		defaultQuality = dlConfig.getAsInt("default-quality");
 	}
 
-	/** Process the HTTP Get request */
-	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);
-	}
+	
+	
+	
+	@Override
+	public void processRequest(HttpServletRequest request,
+			HttpServletResponse response) throws ServletException, ImageOpException {
 
-	/** Process the HTTP Post request */
-	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);
-	}
-
-	/*
-	 * (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;
-	}
-
-	/** main request handler. */
-void processRequest(HttpServletRequest request, HttpServletResponse response)
-			throws ServletException {
-
+		
 		if (dlConfig == null) {
 			throw new ServletException("ERROR: No Configuration!");
 		}
-
+		
 		accountlog.debug("request: " + request.getQueryString());
 		logger.debug("request: " + request.getQueryString());
-
-		// time for benchmarking
-		long startTime = System.currentTimeMillis();
-		// 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");
+		
 
-		// 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("/");
+		// 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;
 		}
-		// 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");
+		
+		
+		// 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();
+			}
 
-		/*
-		 * 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;
+			return;
 		}
 
-		// 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;
+		
+		
+		// if possible, send the image without actually having to transform it
+		if(jobdeclaration.noTransformRequired()){
+			logger.debug("Sending File as is.");
+
+			try {
+				ServletOps.sendFile(fileToLoad.getFile(), null, response);
+			} catch (FileOpException e) {
+				e.printStackTrace();
+			}
+
+			//logger.info("Done in "
+			//		+ (System.currentTimeMillis() - startTime) + "ms");
+			return;
 		}
-		// 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;
+		
+
+		
+		
+		OutputStream outputstream = null;
+		try {
+			outputstream =  response.getOutputStream();
+		} catch (IOException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+			logger.error(e1.getMessage());
 		}
-		// 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;
+		
+		if (! DigilibWorker.canRun()) {
+			logger.error("Servlet overloaded!");
+			try {
+				response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			return;
 		}
 
-		// 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
+		
+		DigilibWorker job=null;
 		try {
-
-			// ImageFileset of the image to load
-			ImageFileset fileset = null;
-
-			/* find the file to load/send */
-
-			// get PathInfo
-			String loadPathName = dlRequest.getFilePath();
+			
+			long startTime = System.currentTimeMillis();
 
 			/* 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!");
+				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 ((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);
-					logger.info("Done in "
-							+ (System.currentTimeMillis() - startTime) + "ms");
-					return;
+				} catch (AuthOpException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
 				}
 			}
 
-			// 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;
+			
+			job = new DigilibImageWorker(dlConfig, outputstream , jobdeclaration);
 
-			/*
-			 * 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;
-			}
+			job.run();
 
 			
-			/*
-			 * 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());
-			logger.debug("time " + (System.currentTimeMillis() - startTime)
-					+ "ms");
-
-			// 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
-			 */
-
-			DigilibWorker job = new DigilibImageWorker(dlConfig, response,
-					mimeType, scaleQual, dlRequest, paramROT, paramCONT,
-					paramBRGT, paramRGBM, paramRGBA, fileToLoad, scaleXY,
-					outerUserImgArea, innerUserImgArea, minSubsample,
-					wholeRotArea, forceType);
-
-			job.run();
 			if (job.hasError()) {
 				throw new ImageOpException(job.getError().toString());
 			}
 
-			logger.debug("servlet done in "
-					+ (System.currentTimeMillis() - startTime));
-
-			/* error handling */
+			try {
+				outputstream.flush();
+				logger.debug("Job Processing Time: "+ (System.currentTimeMillis()-startTime) + "ms");
+			} catch (IOException e) {
+				e.printStackTrace();
+				logger.error(e.getMessage());
+				response.sendError(1);
+			}
 
-		} // 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 (IOException e) {
+			e.printStackTrace();
+			logger.error(e.getClass()+": "+ e.getMessage());
+			//response.sendError(1);
 		} 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);
+			e.printStackTrace();
+			logger.error(e.getClass()+": "+ e.getMessage());
+			//response.sendError(1);
 		}
-	}
 
-	/**
-	 * 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;
+		
+	/*	boolean errorMsgHtml = false;
+		
+		if(jobdeclaration.hasOption("mo","errtxt")){
+			errorMsgHtml = true;
+		} else if (jobdeclaration.hasOption("mo","errimg")) {
+			errorMsgHtml = true;
+		} */
+		
 	}
-
+	
+	
 	/**
 	 * Sends an error to the client as text or image.
 	 * 
@@ -742,11 +341,9 @@
 
 	}
 
-	/**
-	 * @return the dlVersion
-	 */
-	public static String getVersion() {
+	public static String getVersion(){
 		return dlVersion;
 	}
+	
 
-} // Scaler class
+}