changeset 1234:6c1f198b292b

introduce factory for DocuDirectorys. moving directory layout policy to BaseDirDocuDirectory.
author robcast
date Thu, 09 Jan 2014 18:07:32 +0100
parents 3017ade24bbb
children c8e7f5552849
files common/src/main/java/digilib/conf/DigilibConfiguration.java common/src/main/java/digilib/io/AliasingDocuDirCache.java common/src/main/java/digilib/io/BaseDirDocuDirectory.java common/src/main/java/digilib/io/DocuDirCache.java common/src/main/java/digilib/io/DocuDirectory.java common/src/main/java/digilib/io/DocuDirectoryFactory.java common/src/main/java/digilib/io/ImageSet.java servlet/src/main/java/digilib/conf/DigilibServletConfiguration.java
diffstat 8 files changed, 297 insertions(+), 155 deletions(-) [+]
line wrap: on
line diff
--- a/common/src/main/java/digilib/conf/DigilibConfiguration.java	Fri Jan 03 17:35:13 2014 +0100
+++ b/common/src/main/java/digilib/conf/DigilibConfiguration.java	Thu Jan 09 18:07:32 2014 +0100
@@ -25,6 +25,8 @@
  * Author: Robert Casties (robcast@berlios.de)
  */
 
+import java.util.Iterator;
+
 import javax.imageio.ImageIO;
 
 import org.apache.log4j.BasicConfigurator;
@@ -78,7 +80,7 @@
         newParameter("img-diskcache-allowed", Boolean.TRUE, null, 'f');
         // default type of error message (image, text, code)
         newParameter("default-errmsg-type", "image", null, 'f');
-        // prefix for IIIF image API paths
+        // prefix for IIIF image API paths (used by DigilibRequest)
         newParameter("iiif-prefix", "IIIF", null, 'f');
     }
 
@@ -104,8 +106,18 @@
             Class<DocuImage> docuImageClass = (Class<DocuImage>) Class.forName(config.getAsString("docuimage-class"));
             DocuImageFactory.setDocuImageClass(docuImageClass);
             // DocuImage class instance
+            DocuImage di = DocuImageFactory.getInstance();
             config.newParameter("servlet.docuimage.class", docuImageClass, null, 's');
-            config.newParameter("servlet.docuimage.version", DocuImageFactory.getInstance().getVersion(), null, 's');
+            config.newParameter("servlet.docuimage.version", di.getVersion(), null, 's');
+            logger.debug("DocuImage ("+docuImageClass+") "+di.getVersion()); 
+            // log supported formats
+            StringBuilder fmts = new StringBuilder();
+            Iterator<String> dlfs = di.getSupportedFormats();
+            for (String f = dlfs.next(); dlfs.hasNext(); f = dlfs.next()) {
+                fmts.append(f);
+                fmts.append(", ");
+            }
+            logger.debug("DocuImage supported image formats: "+fmts);
         } catch (ClassNotFoundException e) {
             logger.error("Error setting DocuImage class!");
         }
--- a/common/src/main/java/digilib/io/AliasingDocuDirCache.java	Fri Jan 03 17:35:13 2014 +0100
+++ b/common/src/main/java/digilib/io/AliasingDocuDirCache.java	Thu Jan 09 18:07:32 2014 +0100
@@ -76,7 +76,7 @@
 				logger.error("Key mismatch in mapping file!");
 				break;	
 			}
-			DocuDirectory destDir = new DocuDirectory(linkdir.getValue(), this);
+			DocuDirectory destDir = DocuDirectoryFactory.getDocuDirectoryInstance(linkdir.getValue(), this);
 			if (destDir.isValid()) {
 				logger.debug("Aliasing dir: " + linkdir.getKey());
 				// add the alias name
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/digilib/io/BaseDirDocuDirectory.java	Thu Jan 09 18:07:32 2014 +0100
@@ -0,0 +1,170 @@
+package digilib.io;
+
+/*
+ * #%L
+ * BaseDirDocuDirectory.java -- DocuDirectory with different base directories.
+ * 
+ * Digital Image Library servlet components
+ * %%
+ * Copyright (C) 2014 MPIWG Berlin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as 
+ * published by the Free Software Foundation, either version 3 of the 
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Lesser Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Lesser Public 
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ * Author: Robert Casties (robcast@berlios.de)
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import digilib.io.FileOps.FileClass;
+import digilib.meta.MetaFactory;
+
+/**
+ * DocuDirectory implementation that looks for scaled images in parallel paths
+ * with different base directories.
+ * 
+ * @author casties
+ * 
+ */
+public class BaseDirDocuDirectory extends DocuDirectory {
+
+    /** array of parallel dirs for scaled images */
+    protected Directory[] dirs = null;
+    /** reference of the parent DocuDirCache */
+    protected DocuDirCache cache = null;
+
+    /**
+     * Configure object with digilib directory path and a parent DocuDirCache.
+     * 
+     * Directory names at the given path are appended to the base directories
+     * from the cache. The directory is checked on disk and isValid is set.
+     * 
+     * @see readDir
+     * 
+     * @param path
+     *            digilib directory path name
+     * @param cache
+     *            parent DocuDirCache
+     * @return 
+     */
+    @Override
+    public void configure(String path, DocuDirCache cache) {
+        this.dirName = path;
+        this.cache = cache;
+        String baseDirName = cache.getBaseDirNames()[0];
+        // clear directory list
+        list = new ArrayList<DocuDirent>();
+        dirMTime = 0;
+        // the first directory has to exist
+        dir = new File(baseDirName, path);
+        isValid = dir.isDirectory();
+        meta = MetaFactory.getDirMetaInstance();
+    }
+
+    @Override
+    public synchronized boolean readDir() {
+    	// check directory first
+    	if (!isValid) {
+    		return false;
+    	}
+    	// re-check modification time because the thread may have slept
+    	if (dir.lastModified() <= dirMTime) {
+    		return true;
+    	}
+    	// read all filenames
+    	logger.debug("reading directory "+this+" = "+dir.getPath());
+    	File[] allFiles = null;
+    	/*
+    	 * using ReadableFileFilter is safer (we won't get directories with file
+    	 * extensions) but slower.
+    	 */
+    	// allFiles = dir.listFiles(new FileOps.ReadableFileFilter());
+    	allFiles = dir.listFiles();
+    	if (allFiles == null) {
+    		// not a directory
+    		return false;
+    	}
+    	// init parallel directories
+    	if (dirs == null) {
+    		// list of base dirs from the parent cache
+    		String[] baseDirNames = cache.getBaseDirNames();
+    		// number of base dirs
+    		int nb = baseDirNames.length;
+    		// array of parallel dirs
+    		dirs = new Directory[nb];
+    		// first entry is this directory
+    		dirs[0] = this;
+    		// fill array with the remaining directories
+    		for (int j = 1; j < nb; j++) {
+    			// add dirName to baseDirName
+    			File d = new File(baseDirNames[j], dirName);
+    			if (d.isDirectory()) {
+    				dirs[j] = new Directory(d);
+    				logger.debug("  reading scaled directory " + d.getPath());
+    				dirs[j].readDir();
+    			}
+    		}
+    	}
+    
+    	FileClass fileClass = cache.getFileClass();
+    	File[] fileList = FileOps.listFiles(allFiles, FileOps.filterForClass(fileClass));
+    	// number of files in the directory
+    	int numFiles = fileList.length;
+    	if (numFiles > 0) {
+    		// create new list
+    		ArrayList<DocuDirent> dl = new ArrayList<DocuDirent>(numFiles);
+    		list = dl;
+    		for (File f : fileList) {
+    			DocuDirent df = FileOps.fileForClass(fileClass, f, dirs);
+    			df.setParent(this);
+    			// add the file to our list
+    			dl.add(df);
+    		}
+    		/*
+    		 * we sort the ArrayList (the list of files) for binarySearch to work 
+    		 * (DocuDirent's natural sort order is by filename)
+    		 */
+    		Collections.sort(dl);
+    	}
+    	// clear the scaled directories
+    	for (Directory d: dirs) {
+    		if (d != null) {
+    			d.clearFilenames();
+    		}
+    	}
+    	// update number of cached files if this was the first time
+    	if (dirMTime == 0) {
+    		cache.numFiles.addAndGet(size());
+    	}
+    	dirMTime = dir.lastModified();
+    	// read metadata as well
+    	readMeta();
+    	return isValid;
+    }
+
+    @Override
+    public boolean refresh() {
+    	if (isValid) {
+    		if (dir.lastModified() > dirMTime) {
+    			// on-disk modification time is more recent
+    			readDir();
+    		}
+    		touch();
+    	}
+    	return isValid;
+    }
+
+}
--- a/common/src/main/java/digilib/io/DocuDirCache.java	Fri Jan 03 17:35:13 2014 +0100
+++ b/common/src/main/java/digilib/io/DocuDirCache.java	Thu Jan 09 18:07:32 2014 +0100
@@ -28,8 +28,6 @@
  */
 
 import java.io.File;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -138,7 +136,7 @@
 				DocuDirectory pd = map.get(parent);
 				if (pd == null) {
 					// the parent is unknown
-					pd = new DocuDirectory(parent, this);
+					pd = DocuDirectoryFactory.getDocuDirectoryInstance(parent, this);
 					pd = putDir(pd);
 				}
 				newDir.setParent(pd);
@@ -147,34 +145,6 @@
 		return dd;
 	}
 
-	/**
-	 * Get a list with all children of a directory.
-	 * 
-	 * Returns a List of DocuDirectory's. Returns an empty List if the directory
-	 * has no children. If recurse is false then only direct children are
-	 * returned.
-	 * 
-	 * @param dirname
-	 * @param recurse
-	 *            find all children and their children.
-	 * @return
-	 */
-	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);
-				}
-			} else {
-				if (FileOps.parent(dd.getDirName()).equals(dirname)) {
-					l.add(dd);
-				}
-			}
-		}
-		return l;
-	}
-
     /**
      * Returns the DocuDirent with the pathname <code>fn</code> and the index
      * <code>in</code>.
@@ -225,7 +195,7 @@
 			File f = new File(baseDirNames[0], fn);
 			if (f.isDirectory()) {
                 // logger.debug(fn + " is a dir");
-				dd = new DocuDirectory(fn, this);
+				dd = DocuDirectoryFactory.getDocuDirectoryInstance(fn, this);
 				if (dd.isValid()) {
 					// add to the cache
 					dd = putDir(dd);
@@ -241,7 +211,7 @@
 				dd = map.get(d);
 				if (dd == null) {
 					// try to read from disk
-					dd = new DocuDirectory(d, this);
+					dd = DocuDirectoryFactory.getDocuDirectoryInstance(d, this);
 					if (dd.isValid()) {
 						// add to the cache
                         // logger.debug(dd + " is valid");
@@ -291,7 +261,7 @@
 			// see if it's a directory
 			File f = new File(baseDirNames[0], fn);
 			if (f.isDirectory()) {
-				dd = new DocuDirectory(fn, this);
+				dd = DocuDirectoryFactory.getDocuDirectoryInstance(fn, this);
 				if (dd.isValid()) {
 					// add to the cache
 					dd = putDir(dd);
@@ -303,7 +273,7 @@
 					dd = map.get(f.getParent());
 					if (dd == null) {
 						// try to read from disk
-						dd = new DocuDirectory(f.getParent(), this);
+						dd = DocuDirectoryFactory.getDocuDirectoryInstance(f.getParent(), this);
 						if (dd.isValid()) {
 							// add to the cache
 							dd = putDir(dd);
--- a/common/src/main/java/digilib/io/DocuDirectory.java	Fri Jan 03 17:35:13 2014 +0100
+++ b/common/src/main/java/digilib/io/DocuDirectory.java	Thu Jan 09 18:07:32 2014 +0100
@@ -39,34 +39,28 @@
 /**
  * @author casties
  */
-public class DocuDirectory extends Directory {
+public abstract class DocuDirectory extends Directory {
 
 	/** list of files (DocuDirent) */
-	private List<DocuDirent> list = null;
+	protected List<DocuDirent> list = null;
 
 	/** directory object is valid (exists on disk) */
-	private boolean isValid = false;
-
-	/** reference of the parent DocuDirCache */
-	private DocuDirCache cache = null;
+	protected boolean isValid = false;
 
 	/** directory name (digilib canonical form) */
-	private String dirName = null;
-
-	/** array of parallel dirs for scaled images */
-	private Directory[] dirs = null;
+	protected String dirName = null;
 
 	/** directory metadata */
 	protected DirMeta meta = null;
 
 	/** time of last access of this object (not the filesystem) */
-	private long objectATime = 0;
+	protected long objectATime = 0;
 
 	/** time directory was last modified on the file system */
-	private long dirMTime = 0;
+	protected long dirMTime = 0;
 
 	/**
-	 * Constructor with digilib directory path and a parent DocuDirCache.
+	 * Configure object with digilib directory path and a parent DocuDirCache.
 	 * 
 	 * Directory names at the given path are appended to the base directories
 	 * from the cache. The directory is checked on disk and isValid is set.
@@ -77,16 +71,15 @@
 	 *            digilib directory path name
 	 * @param cache
 	 *            parent DocuDirCache
+	 * @return 
 	 */
-	public DocuDirectory(String path, DocuDirCache cache) {
+	public void configure(String path, DocuDirCache cache) {
 		this.dirName = path;
-		this.cache = cache;
-		String baseDirName = cache.getBaseDirNames()[0];
 		// clear directory list
 		list = new ArrayList<DocuDirent>();
 		dirMTime = 0;
 		// the first directory has to exist
-		dir = new File(baseDirName, path);
+		dir = new File(path);
 		isValid = dir.isDirectory();
 		meta = MetaFactory.getDirMetaInstance();
 	}
@@ -142,101 +135,14 @@
 	 * 
 	 * @return boolean the directory exists
 	 */
-	public synchronized boolean readDir() {
-		// check directory first
-		if (!isValid) {
-			return false;
-		}
-		// re-check modification time because the thread may have slept
-		if (dir.lastModified() <= dirMTime) {
-			return true;
-		}
-		// read all filenames
-		logger.debug("reading directory "+this+" = "+dir.getPath());
-		File[] allFiles = null;
-		/*
-		 * using ReadableFileFilter is safer (we won't get directories with file
-		 * extensions) but slower.
-		 */
-		// allFiles = dir.listFiles(new FileOps.ReadableFileFilter());
-		allFiles = dir.listFiles();
-		if (allFiles == null) {
-			// not a directory
-			return false;
-		}
-		// init parallel directories
-		if (dirs == null) {
-			// list of base dirs from the parent cache
-			String[] baseDirNames = cache.getBaseDirNames();
-			// number of base dirs
-			int nb = baseDirNames.length;
-			// array of parallel dirs
-			dirs = new Directory[nb];
-			// first entry is this directory
-			dirs[0] = this;
-			// fill array with the remaining directories
-			for (int j = 1; j < nb; j++) {
-				// add dirName to baseDirName
-				File d = new File(baseDirNames[j], dirName);
-				if (d.isDirectory()) {
-					dirs[j] = new Directory(d);
-					logger.debug("  reading scaled directory " + d.getPath());
-					dirs[j].readDir();
-				}
-			}
-		}
-
-		FileClass fileClass = cache.getFileClass();
-		File[] fileList = FileOps.listFiles(allFiles, FileOps.filterForClass(fileClass));
-		// number of files in the directory
-		int numFiles = fileList.length;
-		if (numFiles > 0) {
-			// create new list
-			ArrayList<DocuDirent> dl = new ArrayList<DocuDirent>(numFiles);
-			list = dl;
-			for (File f : fileList) {
-				DocuDirent df = FileOps.fileForClass(fileClass, f, dirs);
-				df.setParent(this);
-				// add the file to our list
-				dl.add(df);
-			}
-			/*
-			 * we sort the ArrayList (the list of files) for binarySearch to work 
-			 * (DocuDirent's natural sort order is by filename)
-			 */
-			Collections.sort(dl);
-		}
-		// clear the scaled directories
-		for (Directory d: dirs) {
-			if (d != null) {
-				d.clearFilenames();
-			}
-		}
-		// update number of cached files if this was the first time
-		if (dirMTime == 0) {
-			cache.numFiles.addAndGet(size());
-		}
-		dirMTime = dir.lastModified();
-		// read metadata as well
-		readMeta();
-		return isValid;
-	}
+	public abstract boolean readDir();
 
 	/**
 	 * Check to see if the directory has been modified and reread if necessary.
 	 * 
 	 * @return boolean the directory is valid
 	 */
-	public boolean refresh() {
-		if (isValid) {
-			if (dir.lastModified() > dirMTime) {
-				// on-disk modification time is more recent
-				readDir();
-			}
-			touch();
-		}
-		return isValid;
-	}
+	public abstract boolean refresh();
 
 	/**
 	 * Read directory metadata.
@@ -334,12 +240,6 @@
 		return -1;
 	}
 
-	private boolean isBasenameInList(List<DocuDirent> fileList, int idx, String fn) {
-		String dfn = FileOps.basename((fileList.get(idx)).getName());
-		return (dfn.equals(fn) || dfn.equals(FileOps.basename(fn))); 
-	}
-	
-	
 	/**
 	 * Finds the DocuDirent with the name <code>fn</code>.
 	 * 
@@ -418,11 +318,9 @@
         return meta;
     }
 
-    /**
-     * @return the cache
-     */
-    public DocuDirCache getCache() {
-        return cache;
+    private boolean isBasenameInList(List<DocuDirent> fileList, int idx, String fn) {
+    	String dfn = FileOps.basename((fileList.get(idx)).getName());
+    	return (dfn.equals(fn) || dfn.equals(FileOps.basename(fn))); 
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/src/main/java/digilib/io/DocuDirectoryFactory.java	Thu Jan 09 18:07:32 2014 +0100
@@ -0,0 +1,77 @@
+package digilib.io;
+
+/*
+ * #%L
+ * digilib-common
+ * %%
+ * Copyright (C) 2014 MPIWG Berlin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as 
+ * published by the Free Software Foundation, either version 3 of the 
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Lesser Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Lesser Public 
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ * Author: Robert Casties (robcast@berlios.de)
+ */
+
+import org.apache.log4j.Logger;
+
+/**
+ * Static factory for DocuDirectory implementations.
+ * 
+ * @author casties
+ * 
+ */
+public class DocuDirectoryFactory {
+
+    /** Log4J logger */
+    protected static Logger logger = Logger.getLogger(DocuDirectoryFactory.class);
+
+    /** DocuDirectory implementation class */
+    protected static Class<DocuDirectory> docuDirClass;
+
+    /**
+     * Returns a unconfigured DocuDirectory instance.
+     * @return
+     */
+    public static DocuDirectory getInstance() {
+        DocuDirectory dd = null;
+        try {
+            dd = docuDirClass.newInstance();
+        } catch (Exception e) {
+            logger.error("Unable to create DocuDirectory instance!", e);
+        }
+        return dd;
+    }
+
+    /**
+     * Returns a DocuDirectory instance with the given path and DocuDirCache.
+     *  
+     * @param path
+     * @param cache
+     * @return
+     */
+    public static DocuDirectory getDocuDirectoryInstance(String path, DocuDirCache cache) {
+        DocuDirectory dd = getInstance();
+        dd.configure(path, cache);
+        return dd;        
+    }
+    
+    /**
+     * @param dirMetaClass the dirMetaClass to set
+     */
+    public static void setDocuDirectoryClass(Class<DocuDirectory> dirMetaClass) {
+        DocuDirectoryFactory.docuDirClass = dirMetaClass;
+    }
+
+
+}
--- a/common/src/main/java/digilib/io/ImageSet.java	Fri Jan 03 17:35:13 2014 +0100
+++ b/common/src/main/java/digilib/io/ImageSet.java	Thu Jan 09 18:07:32 2014 +0100
@@ -33,6 +33,8 @@
 import digilib.util.ImageSize;
 
 /**
+ * Set of ImageInputs of the same image in different resolutions.
+ * 
  * @author casties
  */
 public class ImageSet {
--- a/servlet/src/main/java/digilib/conf/DigilibServletConfiguration.java	Fri Jan 03 17:35:13 2014 +0100
+++ b/servlet/src/main/java/digilib/conf/DigilibServletConfiguration.java	Thu Jan 09 18:07:32 2014 +0100
@@ -44,6 +44,8 @@
 import digilib.image.DocuImage;
 import digilib.io.AliasingDocuDirCache;
 import digilib.io.DocuDirCache;
+import digilib.io.DocuDirectory;
+import digilib.io.DocuDirectoryFactory;
 import digilib.io.FileOps;
 import digilib.io.FileOps.FileClass;
 import digilib.meta.DirMeta;
@@ -109,6 +111,7 @@
         newParameter("servlet.filemeta.class", null, null, 's');
         newParameter("servlet.dirmeta.class", null, null, 's');
         newParameter("servlet.authops.class", null, null, 's');
+        newParameter("servlet.docudirectory.class", null, null, 's');
         newParameter("servlet.version", DigilibServletConfiguration.getVersion(), null, 's');
 
         /*
@@ -146,6 +149,8 @@
         newParameter("dirmeta-class", "digilib.meta.IndexMetaDirMeta", null, 'f');
         // AuthOps implementation
         newParameter("authops-class", "digilib.auth.PathServletAuthOps", null, 'f');
+        // DocuDirectory implementation
+        newParameter("docudirectory-class", "digilib.io.BaseDirDocuDirectory", null, 'f');
 
     }
 
@@ -257,6 +262,14 @@
         } catch (ClassNotFoundException e) {
             logger.error("Error setting AuthOps class!");
         }
+        try {
+            // initialise DocuDirectoryFactory
+            Class<DocuDirectory> docuDirectoryClass = (Class<DocuDirectory>) Class.forName(config.getAsString("docudirectory-class"));
+            config.setValue("servlet.docudirectory.class", docuDirectoryClass);
+            DocuDirectoryFactory.setDocuDirectoryClass(docuDirectoryClass);
+        } catch (ClassNotFoundException e) {
+            logger.error("Error setting DocuDirectory class!");
+        }
         /*
          * configure singletons
          */