comparison 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
comparison
equal deleted inserted replaced
3:794a9f25f15c 339:6d2032b6121d
1 /* DigiDirectory.java -- digilib directory object
2 *
3 * Digital Image Library servlet components
4 *
5 * Copyright (C) 2004 Robert Casties (robcast@mail.berlios.de)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * Please read license.txt for the full details. A copy of the GPL may be found
13 * at http://www.gnu.org/copyleft/lgpl.html
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Created on 03.11.2004
20 */
21 package digilib.io;
22
23 import java.io.File;
24 import java.io.IOException;
25 import java.util.Arrays;
26 import java.util.Map;
27
28 import org.xml.sax.SAXException;
29
30 /**
31 * digilib directory object
32 *
33 * @author casties
34 *
35 */
36 public class DigiDirectory extends DigiDirent {
37
38 protected static boolean isFile = false;
39
40 protected static boolean isDirectory = true;
41
42 protected DigiDirent[] entries;
43
44 protected int[][] indexes;
45
46 protected File dir;
47
48 /** directory name (digilib canonical form) */
49 protected String dlPath = null;
50
51 protected long mtime = 0;
52
53 protected boolean isDirRead = false;
54
55 protected Map unresolvedMeta;
56
57 /**
58 * @param parent
59 * @param dir
60 */
61 public DigiDirectory(String dlPath) {
62 super(FileOps.dlName(dlPath), null);
63 }
64
65 /**
66 * @param dir
67 * @param parent
68 */
69 public DigiDirectory(File dir, DigiDirectory parent) {
70 super(dir.getName(), parent);
71 this.dir = dir;
72 this.dlPath = parent.getDLPath() + "/" + dir.getName();
73 }
74
75 /**
76 * @param dir
77 * @param dlpath
78 * @param parent
79 */
80 public DigiDirectory(File dir, String dlpath, DigiDirectory parent) {
81 super(dir.getName(), parent);
82 this.dlPath = dlpath;
83 this.dir = dir;
84 }
85
86 public boolean exists() {
87 return ((dir != null) && (dir.isDirectory()));
88 }
89
90 /**
91 * Returns the file of the class at the index.
92 *
93 * @param index
94 * @param fc
95 * fileClass
96 * @return
97 */
98 public DigiDirent get(int index, int fc) {
99 if (!isDirRead) {
100 // read directory now
101 if (readDir() < 1) {
102 return null;
103 }
104 }
105 try {
106 return (DigiDirent) entries[indexes[fc][index]];
107 } catch (Exception e) {
108 }
109 return null;
110 }
111
112 /**
113 * Returns the file with the name <code>fn</code>.
114 *
115 * @param fn
116 * filename
117 * @return
118 */
119 public DigiDirent get(String fn) {
120 if (!isDirRead) {
121 // read directory now
122 if (readDir() < 1) {
123 return null;
124 }
125 }
126 // search for exact match
127 int idx = Arrays.binarySearch(entries, fn);
128 if (idx >= 0) {
129 return entries[idx];
130 } else {
131 // try closest matches without extension
132 idx = -idx - 1;
133 int imax = entries.length;
134 String fb = FileOps.basename(fn);
135 if ((idx < imax)
136 && (FileOps.basename(entries[idx].getName()).equals(fb))) {
137 // idx matches
138 return entries[idx];
139 } else if ((idx > 0)
140 && (FileOps.basename(entries[idx - 1].getName()).equals(fb))) {
141 // idx-1 matches
142 return entries[idx - 1];
143 } else if ((idx + 1 < imax)
144 && (FileOps.basename(entries[idx + 1].getName()).equals(fb))) {
145 // idx+1 matches
146 return entries[idx + 1];
147 }
148 }
149 return null;
150 }
151
152
153 /**
154 * Reads the names of the files in the directory. Fills the filenames array.
155 * Returns the number of files.
156 *
157 * @return
158 */
159 public int readDir() {
160 if (!exists()) {
161 return -1;
162 }
163 File[] allFiles = null;
164 // list all files in the directory
165 allFiles = dir.listFiles();
166 if (allFiles == null) {
167 // not a directory
168 isDirRead = true;
169 return -1;
170 }
171 Arrays.sort(allFiles);
172 int nfiles = allFiles.length;
173 entries = new DigiDirent[nfiles];
174 // create new index lists for all file classes
175 int nfc = FileOps.NUM_CLASSES;
176 indexes = new int[nfc][nfiles];
177 // index pointers for the file classes
178 int[] lastidx = new int[nfc];
179 Map hints = FileOps.newHints();
180 // go through all files
181 for (int dirIdx = 0; dirIdx < nfiles; dirIdx++) {
182 File f = allFiles[dirIdx];
183 String fn = f.getName();
184 int fc = FileOps.classForFilename(fn);
185 // create the right kind of Dirent
186 DigiDirent df = FileOps.fileForClass(fc, f, this, hints);
187 // add the file to our list
188 entries[dirIdx] = df;
189 // add to the indexes
190 if (fc >= 0) {
191 indexes[fc][lastidx[fc]++] = dirIdx;
192 }
193 }
194 // copy out the index arrays
195 for (int i = 0; i < nfc; i++) {
196 int[] idxs = new int[lastidx[i]];
197 System.arraycopy(indexes[i], 0, idxs, 0, lastidx[i]);
198 indexes[i] = idxs;
199 }
200 // update modification time
201 mtime = dir.lastModified();
202 // read metadata as well
203 readMeta();
204 isDirRead = true;
205 return nfiles;
206 }
207
208 /**
209 * Check to see if the directory has been modified and reread if necessary.
210 *
211 * @return boolean the directory is valid
212 */
213 public void check() {
214 if (isDirRead && (dir.lastModified() > mtime)) {
215 // on-disk modification time is more recent
216 readDir();
217 } else if (!isDirRead) {
218 readDir();
219 }
220 }
221
222 /**
223 * Read directory metadata.
224 *
225 */
226 public void readMeta() {
227 // check for directory metadata...
228 File mf = new File(dir, "index.meta");
229 if (mf.canRead()) {
230 XMLMetaLoader ml = new XMLMetaLoader();
231 try {
232 // read directory meta file
233 Map fileMeta = ml.loadURL(mf.getAbsolutePath());
234 if (fileMeta == null) {
235 throw new IOException("XMLMetaloader returned no data!");
236 }
237 // meta for the directory itself is in the "" bin
238 meta = (Map) fileMeta.remove("");
239 // read meta for files in this directory
240 storeFileMeta(fileMeta, null);
241 // is there meta for other files left?
242 if (fileMeta.size() > 0) {
243 unresolvedMeta = fileMeta;
244 }
245 } catch (SAXException e) {
246 logger.warn("error parsing index.meta", e);
247 } catch (IOException e) {
248 logger.warn("error reading index.meta", e);
249 }
250 }
251 readParentMeta();
252 isMetaRead = true;
253 }
254
255 /**
256 * Read metadata from all known parent directories.
257 *
258 */
259 public void readParentMeta() {
260 // check the parent directories for additional file meta
261 DigiDirectory dd = getParent();
262 String path = dir.getName();
263 while (dd != null) {
264 if (dd.hasUnresolvedMeta()) {
265 storeFileMeta(dd.getUnresolvedMeta(), path);
266 }
267 // prepend parent dir path
268 path = dd.getDir().getName() + "/" + path;
269 // become next parent
270 dd = dd.getParent();
271 }
272 }
273
274 /**
275 * Stores metadata in the files in this directory.
276 *
277 * Takes a Map with meta-information, adding the relative path before the
278 * lookup.
279 *
280 * @param fileMeta
281 * @param relPath
282 * @param fc
283 * fileClass
284 */
285 protected void storeFileMeta(Map fileMeta, String relPath) {
286 if (entries == null) {
287 // there are no files
288 return;
289 }
290 String path = (relPath != null) ? (relPath + "/") : "";
291 // iterate through the list of files in this directory
292 for (int i = 0; i < entries.length; i++) {
293 DigiDirent f = entries[i];
294 // prepend path to the filename
295 String fn = path + f.getName();
296 // look up meta for this file
297 if (relPath == null) {
298 // remove from map the same directory
299 f.addMeta((Map) fileMeta.remove(fn));
300 } else {
301 // copy from map in other directories
302 f.addMeta((Map) fileMeta.get(fn));
303 }
304 }
305 }
306
307 /*
308 * boring getters and setters
309 */
310
311 public boolean hasUnresolvedMeta() {
312 return ((unresolvedMeta != null) && unresolvedMeta.isEmpty());
313 }
314
315 /**
316 * @return Returns the unresolvedMeta.
317 */
318 public Map getUnresolvedMeta() {
319 return unresolvedMeta;
320 }
321
322 /**
323 * @return Returns the dir.
324 */
325 public File getDir() {
326 return dir;
327 }
328
329 /**
330 * @param dir
331 * The dir to set.
332 */
333 public void setDir(File dir) {
334 this.dir = dir;
335 }
336
337 /**
338 * @return Returns the dlPath.
339 */
340 public String getDLPath() {
341 return dlPath;
342 }
343
344 /**
345 * @param dlPath
346 * The dlPath to set.
347 */
348 public void setDlPath(String dlPath) {
349 this.dlPath = dlPath;
350 }
351
352 /**
353 * The number of files in this directory.
354 *
355 * @return
356 */
357 public int getSize() {
358 return (entries != null) ? entries.length : 0;
359 }
360
361 /**
362 * The number of files of a file class in this directory.
363 *
364 * @return
365 */
366 public int getSize(int fc) {
367 try {
368 return indexes[fc].length;
369 } catch (Exception e) {
370 }
371 return 0;
372 }
373
374 /**
375 * @return Returns the mtime.
376 */
377 public long getMtime() {
378 return mtime;
379 }
380 }