Mercurial > hg > digilib
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 */