Mercurial > hg > digilib-old
annotate servlet/src/digilib/io/DocuDirectory.java @ 739:922c74a7b935 jquery
busy cursor while loading doesn't work (for me)
author | robcast |
---|---|
date | Wed, 02 Feb 2011 14:41:38 +0100 |
parents | 6e8488acb499 |
children | 3e3e1b7d659f 4f5aaa0de456 |
rev | line source |
---|---|
86 | 1 /* DocuDirectory -- Directory of DocuFilesets. |
2 | |
270 | 3 Digital Image Library servlet components |
86 | 4 |
270 | 5 Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de) |
86 | 6 |
270 | 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 | |
9 Free Software Foundation; either version 2 of the License, or (at your | |
10 option) any later version. | |
11 | |
12 Please read license.txt for the full details. A copy of the GPL | |
13 may be found at http://www.gnu.org/copyleft/lgpl.html | |
86 | 14 |
270 | 15 You should have received a copy of the GNU General Public License |
16 along with this program; if not, write to the Free Software | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
86 | 18 |
19 * Created on 25.02.2003 | |
20 */ | |
21 | |
22 package digilib.io; | |
23 | |
24 import java.io.File; | |
130 | 25 import java.io.IOException; |
91 | 26 import java.util.ArrayList; |
270 | 27 import java.util.Collections; |
159 | 28 import java.util.List; |
259 | 29 import java.util.Map; |
86 | 30 |
130 | 31 import org.xml.sax.SAXException; |
32 | |
563 | 33 import digilib.io.FileOps.FileClass; |
34 | |
86 | 35 /** |
36 * @author casties | |
37 */ | |
149 | 38 public class DocuDirectory extends Directory { |
86 | 39 |
270 | 40 /** list of files (DocuDirent) */ |
531 | 41 private List<List<DocuDirent>> list = null; |
270 | 42 |
571 | 43 /** default FileClass for unspecified calls */ |
44 public static FileClass defaultFileClass = FileClass.IMAGE; | |
45 | |
270 | 46 /** directory object is valid (exists on disk) */ |
86 | 47 private boolean isValid = false; |
270 | 48 |
49 /** reference of the parent DocuDirCache */ | |
151 | 50 private DocuDirCache cache = null; |
270 | 51 |
52 /** directory name (digilib canonical form) */ | |
86 | 53 private String dirName = null; |
270 | 54 |
55 /** directory metadata */ | |
531 | 56 private MetadataMap dirMeta = null; |
270 | 57 |
58 /** state of metadata is valid */ | |
233 | 59 private boolean metaChecked = false; |
270 | 60 |
61 /** unresolved file metadata */ | |
531 | 62 private Map<String, MetadataMap> unresolvedFileMeta = null; |
270 | 63 |
64 /** time of last access of this object (not the filesystem) */ | |
86 | 65 private long objectATime = 0; |
270 | 66 |
67 /** time directory was last modified on the file system */ | |
86 | 68 private long dirMTime = 0; |
69 | |
270 | 70 /** |
71 * Constructor with digilib directory path and a parent DocuDirCache. | |
86 | 72 * |
270 | 73 * Directory names at the given path are appended to the base directories |
74 * from the cache. The directory is checked on disk and isValid is set. | |
86 | 75 * |
76 * @see readDir | |
270 | 77 * |
78 * @param path | |
79 * digilib directory path name | |
80 * @param cache | |
81 * parent DocuDirCache | |
86 | 82 */ |
151 | 83 public DocuDirectory(String path, DocuDirCache cache) { |
84 this.dirName = path; | |
85 this.cache = cache; | |
159 | 86 initDir(); |
87 checkDir(); | |
86 | 88 } |
89 | |
270 | 90 /** |
91 * Sets and checks the dir object. | |
92 * | |
91 | 93 */ |
159 | 94 protected void initDir() { |
95 String baseDirName = cache.getBaseDirNames()[0]; | |
563 | 96 // clear directory list |
97 FileClass[] fcs = FileClass.values(); | |
98 list = new ArrayList<List<DocuDirent>>(fcs.length); | |
99 // create empty list for all classes | |
100 for (@SuppressWarnings("unused") FileClass fc: fcs) { | |
531 | 101 list.add(null); |
102 } | |
159 | 103 isValid = false; |
104 dirMTime = 0; | |
105 // the first directory has to exist | |
106 dir = new File(baseDirName, dirName); | |
107 } | |
156 | 108 |
270 | 109 /** |
110 * number of DocuFiles in this directory. | |
111 * | |
151 | 112 */ |
270 | 113 public int size() { |
571 | 114 return size(defaultFileClass); |
151 | 115 } |
91 | 116 |
270 | 117 /** |
118 * number of files of this class in this directory. | |
151 | 119 * |
270 | 120 * @param fc |
121 * fileClass | |
151 | 122 */ |
563 | 123 public int size(FileClass fc) { |
571 | 124 if (list != null) { |
125 List<DocuDirent> l = list.get(fc.ordinal()); | |
126 if (l != null) { | |
127 return l.size(); | |
128 } | |
129 } | |
130 return 0; | |
91 | 131 } |
132 | |
270 | 133 /** |
563 | 134 * Returns the ImageFileSet at the index. |
151 | 135 * |
136 * @param index | |
137 * @return | |
138 */ | |
159 | 139 public ImageFileset get(int index) { |
571 | 140 return (ImageFileset) get(index, defaultFileClass); |
159 | 141 } |
142 | |
270 | 143 /** |
144 * Returns the file of the class at the index. | |
159 | 145 * |
146 * @param index | |
270 | 147 * @param fc |
148 * fileClass | |
159 | 149 * @return |
150 */ | |
563 | 151 public DocuDirent get(int index, FileClass fc) { |
152 if ((list == null) || (list.get(fc.ordinal()) == null) || (index >= list.get(fc.ordinal()).size())) { | |
159 | 153 return null; |
154 } | |
563 | 155 return (DocuDirent) list.get(fc.ordinal()).get(index); |
159 | 156 } |
157 | |
270 | 158 /** |
159 * Checks if the directory exists on the filesystem. | |
159 | 160 * |
161 * Sets isValid. | |
162 * | |
163 * @return | |
164 */ | |
165 public boolean checkDir() { | |
166 if (dir == null) { | |
167 initDir(); | |
168 } | |
169 isValid = dir.isDirectory(); | |
170 return isValid; | |
91 | 171 } |
172 | |
270 | 173 /** |
174 * Read the filesystem directory and fill this object. | |
86 | 175 * |
130 | 176 * Clears the List and (re)reads all files. |
86 | 177 * |
178 * @return boolean the directory exists | |
179 */ | |
282 | 180 public synchronized boolean readDir() { |
159 | 181 // check directory first |
182 checkDir(); | |
183 if (!isValid) { | |
184 return false; | |
185 } | |
270 | 186 // first file extension to try for scaled directories |
187 String scalext = null; | |
259 | 188 // read all filenames |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
189 logger.debug("reading directory " + dir.getPath()); |
259 | 190 /* |
270 | 191 * using ReadableFileFilter is safer (we won't get directories with file |
192 * extensions) but slower. | |
259 | 193 */ |
194 File[] allFiles = null; | |
545 | 195 // allFiles = dir.listFiles(new FileOps.ReadableFileFilter()); |
196 allFiles = dir.listFiles(); | |
295
90bab835fc25
Servlet version 1.5.0b -- the beginning of the next generation :-)
robcast
parents:
288
diff
changeset
|
197 //logger.debug(" done"); |
259 | 198 if (allFiles == null) { |
199 // not a directory | |
200 return false; | |
201 } | |
270 | 202 // list of base dirs from the parent cache |
203 String[] baseDirNames = cache.getBaseDirNames(); | |
204 // number of base dirs | |
205 int nb = baseDirNames.length; | |
206 // array of base dirs | |
207 Directory[] dirs = new Directory[nb]; | |
208 // first entry is this directory | |
209 dirs[0] = this; | |
210 // fill array with the remaining directories | |
211 for (int j = 1; j < nb; j++) { | |
212 File d = new File(baseDirNames[j], dirName); | |
213 if (d.isDirectory()) { | |
214 dirs[j] = new Directory(d); | |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
215 logger.debug(" reading scaled directory " + d.getPath()); |
270 | 216 dirs[j].readDir(); |
295
90bab835fc25
Servlet version 1.5.0b -- the beginning of the next generation :-)
robcast
parents:
288
diff
changeset
|
217 //logger.debug(" done"); |
270 | 218 } |
219 } | |
220 | |
159 | 221 // go through all file classes |
563 | 222 //for (int classIdx = 0; classIdx < FileOps.NUM_CLASSES; classIdx++) { |
223 for (FileClass fileClass: cache.getFileClasses()) { | |
224 //fileClass = cache.getFileClasses()[classIdx]; | |
270 | 225 File[] fileList = FileOps.listFiles(allFiles, FileOps |
226 .filterForClass(fileClass)); | |
227 //logger.debug(" done"); | |
159 | 228 // number of files in the directory |
270 | 229 int numFiles = fileList.length; |
230 if (numFiles > 0) { | |
91 | 231 // create new list |
563 | 232 list.set(fileClass.ordinal(), new ArrayList<DocuDirent>(numFiles)); |
86 | 233 // sort the file names alphabetically and iterate the list |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
234 // Arrays.sort(fileList); // not needed <hertzhaft> |
531 | 235 Map<Integer, Object> hints = FileOps.newHints(FileOps.HINT_BASEDIRS, dirs); |
259 | 236 hints.put(FileOps.HINT_FILEEXT, scalext); |
270 | 237 for (int i = 0; i < numFiles; i++) { |
238 DocuDirent f = FileOps.fileForClass(fileClass, fileList[i], | |
239 hints); | |
159 | 240 // add the file to our list |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
241 // logger.debug(f.getName()); |
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
242 |
563 | 243 list.get(fileClass.ordinal()).add(f); |
159 | 244 f.setParent(this); |
86 | 245 } |
531 | 246 // we sort the inner ArrayList (the list of files not the list of file types) |
247 // for binarySearch to work (DocuDirent's natural sort order is by filename) | |
563 | 248 Collections.sort(list.get(fileClass.ordinal())); |
86 | 249 } |
250 } | |
270 | 251 // clear the scaled directories |
252 for (int j = 1; j < nb; j++) { | |
253 if (dirs[j] != null) { | |
254 dirs[j].clearFilenames(); | |
255 } | |
256 } | |
257 // update number of cached files if this was the first time | |
258 if (dirMTime == 0) { | |
259 cache.numFiles += size(); | |
260 } | |
159 | 261 dirMTime = dir.lastModified(); |
262 // read metadata as well | |
263 readMeta(); | |
86 | 264 return isValid; |
265 } | |
266 | |
270 | 267 /** |
268 * Check to see if the directory has been modified and reread if necessary. | |
86 | 269 * |
270 * @return boolean the directory is valid | |
271 */ | |
272 public boolean refresh() { | |
273 if (isValid) { | |
274 if (dir.lastModified() > dirMTime) { | |
275 // on-disk modification time is more recent | |
276 readDir(); | |
277 } | |
278 touch(); | |
279 } | |
280 return isValid; | |
281 } | |
282 | |
270 | 283 /** |
284 * Read directory metadata. | |
285 * | |
86 | 286 */ |
287 public void readMeta() { | |
288 // check for directory metadata... | |
130 | 289 File mf = new File(dir, "index.meta"); |
290 if (mf.canRead()) { | |
291 XMLMetaLoader ml = new XMLMetaLoader(); | |
292 try { | |
293 // read directory meta file | |
531 | 294 Map<String, MetadataMap> fileMeta = ml.loadURL(mf.getAbsolutePath()); |
130 | 295 if (fileMeta == null) { |
296 return; | |
297 } | |
298 // meta for the directory itself is in the "" bin | |
531 | 299 dirMeta = fileMeta.remove(""); |
151 | 300 // read meta for files in this directory |
301 readFileMeta(fileMeta, null); | |
302 // is there meta for other files left? | |
130 | 303 if (fileMeta.size() > 0) { |
151 | 304 unresolvedFileMeta = fileMeta; |
130 | 305 } |
306 } catch (SAXException e) { | |
282 | 307 logger.warn("error parsing index.meta", e); |
130 | 308 } catch (IOException e) { |
282 | 309 logger.warn("error reading index.meta", e); |
130 | 310 } |
151 | 311 } |
312 readParentMeta(); | |
233 | 313 metaChecked = true; |
151 | 314 } |
130 | 315 |
270 | 316 /** |
317 * Read metadata from all known parent directories. | |
318 * | |
151 | 319 */ |
320 public void readParentMeta() { | |
321 // check the parent directories for additional file meta | |
322 Directory dd = parent; | |
156 | 323 String path = dir.getName(); |
151 | 324 while (dd != null) { |
156 | 325 if (((DocuDirectory) dd).hasUnresolvedFileMeta()) { |
326 readFileMeta(((DocuDirectory) dd).unresolvedFileMeta, path); | |
151 | 327 } |
328 // prepend parent dir path | |
329 path = dd.dir.getName() + "/" + path; | |
330 // become next parent | |
331 dd = dd.parent; | |
332 } | |
333 } | |
334 | |
270 | 335 /** |
336 * Read metadata for the files in this directory. | |
151 | 337 * |
270 | 338 * Takes a Map with meta-information, adding the relative path before the |
339 * lookup. | |
151 | 340 * |
341 * @param fileMeta | |
342 * @param relPath | |
270 | 343 * @param fc |
344 * fileClass | |
151 | 345 */ |
531 | 346 protected void readFileMeta(Map<String,MetadataMap> fileMeta, String relPath) { |
151 | 347 if (list == null) { |
348 // there are no files | |
349 return; | |
350 } | |
351 String path = (relPath != null) ? (relPath + "/") : ""; | |
159 | 352 // go through all file classes |
563 | 353 for (FileClass fc: FileClass.values()) { |
354 if (list.get(fc.ordinal()) == null) { | |
159 | 355 continue; |
356 } | |
357 // iterate through the list of files in this directory | |
563 | 358 for (DocuDirent f: list.get(fc.ordinal())) { |
159 | 359 // prepend path to the filename |
360 String fn = path + f.getName(); | |
361 // look up meta for this file and remove from dir | |
531 | 362 MetadataMap meta = fileMeta.remove(fn); |
159 | 363 if (meta != null) { |
364 // store meta in file | |
365 f.setFileMeta(meta); | |
366 } | |
367 } | |
368 } | |
369 } | |
370 | |
531 | 371 protected void notifyChildMeta(MetadataMap childmeta) { |
372 List<DocuDirectory> children = cache.getChildren(this.dirName, true); | |
159 | 373 if (children.size() > 0) { |
531 | 374 /*for (DocuDirectory d: children) { |
159 | 375 // TODO: finish this! |
376 //((DocuDirectory) i.next()).readFileMeta() | |
531 | 377 }*/ |
130 | 378 } |
86 | 379 } |
380 | |
270 | 381 /** |
382 * Update access time. | |
86 | 383 * |
384 * @return long time of last access. | |
385 */ | |
386 public long touch() { | |
387 long t = objectATime; | |
388 objectATime = System.currentTimeMillis(); | |
389 return t; | |
390 } | |
391 | |
270 | 392 /** |
393 * Searches for the file with the name <code>fn</code>. | |
86 | 394 * |
270 | 395 * Searches the directory for the file with the name <code>fn</code> and |
396 * returns its index. Returns -1 if the file cannot be found. | |
397 * | |
398 * @param fn | |
399 * filename | |
400 * @param fc | |
401 * file class | |
86 | 402 * @return int index of file <code>fn</code> |
403 */ | |
404 public int indexOf(String fn) { | |
563 | 405 FileClass fc = FileOps.classForFilename(fn); |
159 | 406 return indexOf(fn, fc); |
407 } | |
270 | 408 |
409 /** | |
410 * Searches for the file with the name <code>fn</code> and class fc. | |
159 | 411 * |
270 | 412 * Searches the directory for the file with the name <code>fn</code> and |
413 * returns its index. Returns -1 if the file cannot be found. | |
414 * | |
415 * @param fn | |
416 * filename | |
159 | 417 * @return int index of file <code>fn</code> |
418 */ | |
563 | 419 public int indexOf(String fn, FileClass fc) { |
176 | 420 if (!isRead()) { |
421 // read directory now | |
422 if (!readDir()) { | |
423 return -1; | |
424 } | |
425 } | |
563 | 426 List<DocuDirent> fileList = list.get(fc.ordinal()); |
246 | 427 // empty directory? |
288 | 428 if (fileList == null) { |
246 | 429 return -1; |
430 } | |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
431 |
531 | 432 // search for exact match (DocuDirent does compareTo<String>) |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
433 // OBS: fileList needs to be sorted first (see )! <hertzhaft> |
288 | 434 int idx = Collections.binarySearch(fileList, fn); |
270 | 435 if (idx >= 0) { |
436 return idx; | |
437 } else { | |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
438 logger.debug(fn + " not found by binarysearch"); |
270 | 439 // try closest matches without extension |
282 | 440 idx = -idx - 1; |
288 | 441 if ((idx < fileList.size()) |
563 | 442 && isBasenameInList(fileList, idx, fn)) { |
282 | 443 // idx matches |
444 return idx; | |
445 } else if ((idx > 0) | |
563 | 446 && isBasenameInList(fileList, idx-1, fn)) { |
282 | 447 // idx-1 matches |
270 | 448 return idx - 1; |
288 | 449 } else if ((idx + 1 < fileList.size()) |
563 | 450 && isBasenameInList(fileList, idx+1, fn)) { |
282 | 451 // idx+1 matches |
270 | 452 return idx + 1; |
86 | 453 } |
270 | 454 |
86 | 455 } |
456 return -1; | |
457 } | |
458 | |
563 | 459 private boolean isBasenameInList(List<DocuDirent> fl, int idx, String fn) { |
531 | 460 String dfn = FileOps.basename((fl.get(idx)) |
341 | 461 .getName()); |
462 return (dfn.equals(fn)||dfn.equals(FileOps.basename(fn))); | |
463 } | |
464 | |
465 | |
270 | 466 /** |
467 * Finds the DocuDirent with the name <code>fn</code>. | |
86 | 468 * |
270 | 469 * Searches the directory for the DocuDirent with the name <code>fn</code> |
470 * and returns it. Returns null if the file cannot be found. | |
471 * | |
472 * @param fn | |
473 * filename | |
187 | 474 * @return DocuDirent |
86 | 475 */ |
187 | 476 public DocuDirent find(String fn) { |
571 | 477 return find(fn, defaultFileClass); |
159 | 478 } |
479 | |
270 | 480 /** |
481 * Finds the DocuDirent with the name <code>fn</code> and class | |
482 * <code>fc</code>. | |
159 | 483 * |
270 | 484 * Searches the directory for the DocuDirent with the name <code>fn</code> |
485 * and returns it. Returns null if the file cannot be found. | |
486 * | |
487 * @param fn | |
488 * filename | |
187 | 489 * @return DocuDirent |
159 | 490 */ |
563 | 491 public DocuDirent find(String fn, FileClass fc) { |
159 | 492 int i = indexOf(fn, fc); |
493 if (i >= 0) { | |
563 | 494 return (DocuDirent) list.get(fc.ordinal()).get(i); |
86 | 495 } |
496 return null; | |
497 } | |
498 | |
499 /** | |
270 | 500 * Returns the digilib canonical name. |
501 * | |
502 * @return | |
86 | 503 */ |
504 public String getDirName() { | |
505 return dirName; | |
506 } | |
507 | |
270 | 508 /** |
509 * The directory is valid (exists on disk). | |
159 | 510 * |
86 | 511 * @return boolean |
512 */ | |
513 public boolean isValid() { | |
514 return isValid; | |
515 } | |
516 | |
270 | 517 /** |
518 * The directory has been read from disk. | |
159 | 519 * |
520 * @return | |
521 */ | |
522 public boolean isRead() { | |
523 return (dirMTime != 0); | |
524 } | |
525 | |
86 | 526 /** |
527 * @return long | |
528 */ | |
529 public long getAccessTime() { | |
530 return objectATime; | |
531 } | |
532 | |
533 /** | |
534 * @return Hashtable | |
535 */ | |
531 | 536 public MetadataMap getDirMeta() { |
86 | 537 return dirMeta; |
538 } | |
270 | 539 |
233 | 540 /** |
541 * Checks metadata | |
542 * | |
543 */ | |
544 public void checkMeta() { | |
545 if (metaChecked) { | |
546 return; | |
547 } else { | |
548 readMeta(); | |
549 } | |
550 } | |
86 | 551 |
552 /** | |
553 * @return long | |
554 */ | |
555 public long getDirMTime() { | |
556 return dirMTime; | |
557 } | |
558 | |
559 /** | |
560 * Sets the dirMeta. | |
270 | 561 * |
562 * @param dirMeta | |
563 * The dirMeta to set | |
86 | 564 */ |
531 | 565 public void setDirMeta(MetadataMap dirMeta) { |
86 | 566 this.dirMeta = dirMeta; |
567 } | |
568 | |
151 | 569 public boolean hasUnresolvedFileMeta() { |
570 return (this.unresolvedFileMeta != null); | |
571 } | |
572 | |
86 | 573 } |