diff servlet/src/digilib/io/DigiDirectory.java @ 339:6d2032b6121d gen2_1

new directory and cache work
author robcast
date Wed, 17 Nov 2004 18:17:34 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/DigiDirectory.java	Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,380 @@
+/* DigiDirectory.java -- digilib directory object
+ * 
+ * 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 03.11.2004
+ */
+package digilib.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.xml.sax.SAXException;
+
+/**
+ * digilib directory object
+ * 
+ * @author casties
+ *  
+ */
+public class DigiDirectory extends DigiDirent {
+
+	protected static boolean isFile = false;
+
+	protected static boolean isDirectory = true;
+
+	protected DigiDirent[] entries;
+
+	protected int[][] indexes;
+
+	protected File dir;
+
+	/** directory name (digilib canonical form) */
+	protected String dlPath = null;
+
+	protected long mtime = 0;
+
+	protected boolean isDirRead = false;
+
+	protected Map unresolvedMeta;
+
+	/**
+	 * @param parent
+	 * @param dir
+	 */
+	public DigiDirectory(String dlPath) {
+		super(FileOps.dlName(dlPath), null);
+	}
+
+	/**
+	 * @param dir
+	 * @param parent
+	 */
+	public DigiDirectory(File dir, DigiDirectory parent) {
+		super(dir.getName(), parent);
+		this.dir = dir;
+		this.dlPath = parent.getDLPath() + "/" + dir.getName();
+	}
+
+	/**
+	 * @param dir
+	 * @param dlpath
+	 * @param parent
+	 */
+	public DigiDirectory(File dir, String dlpath, DigiDirectory parent) {
+		super(dir.getName(), parent);
+		this.dlPath = dlpath;
+		this.dir = dir;
+	}
+
+	public boolean exists() {
+		return ((dir != null) && (dir.isDirectory()));
+	}
+
+	/**
+	 * Returns the file of the class at the index.
+	 * 
+	 * @param index
+	 * @param fc
+	 *            fileClass
+	 * @return
+	 */
+	public DigiDirent get(int index, int fc) {
+		if (!isDirRead) {
+			// read directory now
+			if (readDir() < 1) {
+				return null;
+			}
+		}
+		try {
+			return (DigiDirent) entries[indexes[fc][index]];
+		} catch (Exception e) {
+		}
+		return null;
+	}
+
+	/**
+	 * Returns the file with the name <code>fn</code>.
+	 * 
+	 * @param fn
+	 *            filename
+	 * @return
+	 */
+	public DigiDirent get(String fn) {
+		if (!isDirRead) {
+			// read directory now
+			if (readDir() < 1) {
+				return null;
+			}
+		}
+		// search for exact match
+		int idx = Arrays.binarySearch(entries, fn);
+		if (idx >= 0) {
+			return entries[idx];
+		} else {
+			// try closest matches without extension
+			idx = -idx - 1;
+			int imax = entries.length;
+			String fb = FileOps.basename(fn);
+			if ((idx < imax)
+					&& (FileOps.basename(entries[idx].getName()).equals(fb))) {
+				// idx matches
+				return entries[idx];
+			} else if ((idx > 0)
+					&& (FileOps.basename(entries[idx - 1].getName()).equals(fb))) {
+				// idx-1 matches
+				return entries[idx - 1];
+			} else if ((idx + 1 < imax)
+					&& (FileOps.basename(entries[idx + 1].getName()).equals(fb))) {
+				// idx+1 matches
+				return entries[idx + 1];
+			}
+		}
+		return null;
+	}
+
+	
+	/**
+	 * Reads the names of the files in the directory. Fills the filenames array.
+	 * Returns the number of files.
+	 * 
+	 * @return
+	 */
+	public int readDir() {
+		if (!exists()) {
+			return -1;
+		}
+		File[] allFiles = null;
+		// list all files in the directory
+		allFiles = dir.listFiles();
+		if (allFiles == null) {
+			// not a directory
+			isDirRead = true;
+			return -1;
+		}
+		Arrays.sort(allFiles);
+		int nfiles = allFiles.length;
+		entries = new DigiDirent[nfiles];
+		// create new index lists for all file classes
+		int nfc = FileOps.NUM_CLASSES;
+		indexes = new int[nfc][nfiles];
+		// index pointers for the file classes
+		int[] lastidx = new int[nfc];
+		Map hints = FileOps.newHints();
+		// go through all files
+		for (int dirIdx = 0; dirIdx < nfiles; dirIdx++) {
+			File f = allFiles[dirIdx];
+			String fn = f.getName();
+			int fc = FileOps.classForFilename(fn);
+			// create the right kind of Dirent
+			DigiDirent df = FileOps.fileForClass(fc, f, this, hints);
+			// add the file to our list
+			entries[dirIdx] = df;
+			// add to the indexes
+			if (fc >= 0) {
+				indexes[fc][lastidx[fc]++] = dirIdx;
+			}
+		}
+		// copy out the index arrays
+		for (int i = 0; i < nfc; i++) {
+			int[] idxs = new int[lastidx[i]];
+			System.arraycopy(indexes[i], 0, idxs, 0, lastidx[i]);
+			indexes[i] = idxs;
+		}
+		// update modification time
+		mtime = dir.lastModified();
+		// read metadata as well
+		readMeta();
+		isDirRead = true;
+		return nfiles;
+	}
+
+	/**
+	 * Check to see if the directory has been modified and reread if necessary.
+	 * 
+	 * @return boolean the directory is valid
+	 */
+	public void check() {
+		if (isDirRead && (dir.lastModified() > mtime)) {
+			// on-disk modification time is more recent
+			readDir();
+		} else if (!isDirRead) {
+			readDir();
+		}
+	}
+
+	/**
+	 * Read directory metadata.
+	 *  
+	 */
+	public void readMeta() {
+		// check for directory metadata...
+		File mf = new File(dir, "index.meta");
+		if (mf.canRead()) {
+			XMLMetaLoader ml = new XMLMetaLoader();
+			try {
+				// read directory meta file
+				Map fileMeta = ml.loadURL(mf.getAbsolutePath());
+				if (fileMeta == null) {
+					throw new IOException("XMLMetaloader returned no data!");
+				}
+				// meta for the directory itself is in the "" bin
+				meta = (Map) fileMeta.remove("");
+				// read meta for files in this directory
+				storeFileMeta(fileMeta, null);
+				// is there meta for other files left?
+				if (fileMeta.size() > 0) {
+					unresolvedMeta = fileMeta;
+				}
+			} catch (SAXException e) {
+				logger.warn("error parsing index.meta", e);
+			} catch (IOException e) {
+				logger.warn("error reading index.meta", e);
+			}
+		}
+		readParentMeta();
+		isMetaRead = true;
+	}
+
+	/**
+	 * Read metadata from all known parent directories.
+	 *  
+	 */
+	public void readParentMeta() {
+		// check the parent directories for additional file meta
+		DigiDirectory dd = getParent();
+		String path = dir.getName();
+		while (dd != null) {
+			if (dd.hasUnresolvedMeta()) {
+				storeFileMeta(dd.getUnresolvedMeta(), path);
+			}
+			// prepend parent dir path
+			path = dd.getDir().getName() + "/" + path;
+			// become next parent
+			dd = dd.getParent();
+		}
+	}
+
+	/**
+	 * Stores metadata in the files in this directory.
+	 * 
+	 * Takes a Map with meta-information, adding the relative path before the
+	 * lookup.
+	 * 
+	 * @param fileMeta
+	 * @param relPath
+	 * @param fc
+	 *            fileClass
+	 */
+	protected void storeFileMeta(Map fileMeta, String relPath) {
+		if (entries == null) {
+			// there are no files
+			return;
+		}
+		String path = (relPath != null) ? (relPath + "/") : "";
+		// iterate through the list of files in this directory
+		for (int i = 0; i < entries.length; i++) {
+			DigiDirent f = entries[i];
+			// prepend path to the filename
+			String fn = path + f.getName();
+			// look up meta for this file
+			if (relPath == null) {
+				// remove from map the same directory
+				f.addMeta((Map) fileMeta.remove(fn));
+			} else {
+				// copy from map in other directories
+				f.addMeta((Map) fileMeta.get(fn));
+			}
+		}
+	}
+
+	/*
+	 * boring getters and setters
+	 */
+
+	public boolean hasUnresolvedMeta() {
+		return ((unresolvedMeta != null) && unresolvedMeta.isEmpty());
+	}
+
+	/**
+	 * @return Returns the unresolvedMeta.
+	 */
+	public Map getUnresolvedMeta() {
+		return unresolvedMeta;
+	}
+
+	/**
+	 * @return Returns the dir.
+	 */
+	public File getDir() {
+		return dir;
+	}
+
+	/**
+	 * @param dir
+	 *            The dir to set.
+	 */
+	public void setDir(File dir) {
+		this.dir = dir;
+	}
+
+	/**
+	 * @return Returns the dlPath.
+	 */
+	public String getDLPath() {
+		return dlPath;
+	}
+
+	/**
+	 * @param dlPath
+	 *            The dlPath to set.
+	 */
+	public void setDlPath(String dlPath) {
+		this.dlPath = dlPath;
+	}
+
+	/**
+	 * The number of files in this directory.
+	 * 
+	 * @return
+	 */
+	public int getSize() {
+		return (entries != null) ? entries.length : 0;
+	}
+
+	/**
+	 * The number of files of a file class in this directory.
+	 * 
+	 * @return
+	 */
+	public int getSize(int fc) {
+		try {
+			return indexes[fc].length;
+		} catch (Exception e) {
+		}
+		return 0;
+	}
+
+	/**
+	 * @return Returns the mtime.
+	 */
+	public long getMtime() {
+		return mtime;
+	}
+}