comparison servlet/src/digilib/io/DocuDirectory.java @ 569:1f666c2b4578

Merge with PDF branch 8beefd1142b28ca9b2433205e7eea82a517bb215
author robcast
date Tue, 21 Dec 2010 09:52:16 +0100
parents 686086d6e6d6
children 6e8488acb499 790cbfb58b52
comparison
equal deleted inserted replaced
535:9936604d466e 569:1f666c2b4578
23 23
24 import java.io.File; 24 import java.io.File;
25 import java.io.IOException; 25 import java.io.IOException;
26 import java.util.ArrayList; 26 import java.util.ArrayList;
27 import java.util.Collections; 27 import java.util.Collections;
28 import java.util.Iterator;
29 import java.util.List; 28 import java.util.List;
30 import java.util.Map; 29 import java.util.Map;
31 30
32 import org.xml.sax.SAXException; 31 import org.xml.sax.SAXException;
32
33 import digilib.io.FileOps.FileClass;
33 34
34 /** 35 /**
35 * @author casties 36 * @author casties
36 */ 37 */
37 public class DocuDirectory extends Directory { 38 public class DocuDirectory extends Directory {
38 39
39 /** list of files (DocuDirent) */ 40 /** list of files (DocuDirent) */
40 private ArrayList[] list = null; 41 private List<List<DocuDirent>> list = null;
41 42
42 /** directory object is valid (exists on disk) */ 43 /** directory object is valid (exists on disk) */
43 private boolean isValid = false; 44 private boolean isValid = false;
44 45
45 /** reference of the parent DocuDirCache */ 46 /** reference of the parent DocuDirCache */
47 48
48 /** directory name (digilib canonical form) */ 49 /** directory name (digilib canonical form) */
49 private String dirName = null; 50 private String dirName = null;
50 51
51 /** directory metadata */ 52 /** directory metadata */
52 private Map dirMeta = null; 53 private MetadataMap dirMeta = null;
53 54
54 /** state of metadata is valid */ 55 /** state of metadata is valid */
55 private boolean metaChecked = false; 56 private boolean metaChecked = false;
56 57
57 /** unresolved file metadata */ 58 /** unresolved file metadata */
58 private Map unresolvedFileMeta = null; 59 private Map<String, MetadataMap> unresolvedFileMeta = null;
59 60
60 /** time of last access of this object (not the filesystem) */ 61 /** time of last access of this object (not the filesystem) */
61 private long objectATime = 0; 62 private long objectATime = 0;
62 63
63 /** time directory was last modified on the file system */ 64 /** time directory was last modified on the file system */
87 * Sets and checks the dir object. 88 * Sets and checks the dir object.
88 * 89 *
89 */ 90 */
90 protected void initDir() { 91 protected void initDir() {
91 String baseDirName = cache.getBaseDirNames()[0]; 92 String baseDirName = cache.getBaseDirNames()[0];
92 // clear directory first 93 // clear directory list
93 list = new ArrayList[FileOps.NUM_CLASSES]; 94 FileClass[] fcs = FileClass.values();
95 list = new ArrayList<List<DocuDirent>>(fcs.length);
96 // create empty list for all classes
97 for (@SuppressWarnings("unused") FileClass fc: fcs) {
98 list.add(null);
99 }
94 isValid = false; 100 isValid = false;
95 dirMTime = 0; 101 dirMTime = 0;
96 // the first directory has to exist 102 // the first directory has to exist
97 dir = new File(baseDirName, dirName); 103 dir = new File(baseDirName, dirName);
98 } 104 }
100 /** 106 /**
101 * number of DocuFiles in this directory. 107 * number of DocuFiles in this directory.
102 * 108 *
103 */ 109 */
104 public int size() { 110 public int size() {
105 return ((list != null) && (list[0] != null)) ? list[0].size() : 0; 111 return ((list != null) && (list.get(0) != null)) ? list.get(0).size() : 0;
106 } 112 }
107 113
108 /** 114 /**
109 * number of files of this class in this directory. 115 * number of files of this class in this directory.
110 * 116 *
111 * @param fc 117 * @param fc
112 * fileClass 118 * fileClass
113 */ 119 */
114 public int size(int fc) { 120 public int size(FileClass fc) {
115 return ((list != null) && (list[fc] != null)) ? list[fc].size() : 0; 121 return ((list != null) && (list.get(fc.ordinal()) != null)) ? list.get(fc.ordinal()).size() : 0;
116 } 122 }
117 123
118 /** 124 /**
119 * Returns the ImageFile at the index. 125 * Returns the ImageFileSet at the index.
120 * 126 *
121 * @param index 127 * @param index
122 * @return 128 * @return
123 */ 129 */
124 public ImageFileset get(int index) { 130 public ImageFileset get(int index) {
125 if ((list == null) || (list[0] == null) || (index >= list[0].size())) { 131 if ((list == null) || (list.get(0) == null) || (index >= list.get(0).size())) {
126 return null; 132 return null;
127 } 133 }
128 return (ImageFileset) list[0].get(index); 134 return (ImageFileset) list.get(0).get(index);
129 } 135 }
130 136
131 /** 137 /**
132 * Returns the file of the class at the index. 138 * Returns the file of the class at the index.
133 * 139 *
134 * @param index 140 * @param index
135 * @param fc 141 * @param fc
136 * fileClass 142 * fileClass
137 * @return 143 * @return
138 */ 144 */
139 public DocuDirent get(int index, int fc) { 145 public DocuDirent get(int index, FileClass fc) {
140 if ((list == null) || (list[fc] == null) || (index >= list[fc].size())) { 146 if ((list == null) || (list.get(fc.ordinal()) == null) || (index >= list.get(fc.ordinal()).size())) {
141 return null; 147 return null;
142 } 148 }
143 return (DocuDirent) list[fc].get(index); 149 return (DocuDirent) list.get(fc.ordinal()).get(index);
144 } 150 }
145 151
146 /** 152 /**
147 * Checks if the directory exists on the filesystem. 153 * Checks if the directory exists on the filesystem.
148 * 154 *
178 /* 184 /*
179 * using ReadableFileFilter is safer (we won't get directories with file 185 * using ReadableFileFilter is safer (we won't get directories with file
180 * extensions) but slower. 186 * extensions) but slower.
181 */ 187 */
182 File[] allFiles = null; 188 File[] allFiles = null;
183 if (cache.safeDirIndex) { 189 // allFiles = dir.listFiles(new FileOps.ReadableFileFilter());
184 allFiles = dir.listFiles(new FileOps.ReadableFileFilter()); 190 allFiles = dir.listFiles();
185 } else {
186 allFiles = dir.listFiles();
187 }
188 //logger.debug(" done"); 191 //logger.debug(" done");
189 if (allFiles == null) { 192 if (allFiles == null) {
190 // not a directory 193 // not a directory
191 return false; 194 return false;
192 } 195 }
208 //logger.debug(" done"); 211 //logger.debug(" done");
209 } 212 }
210 } 213 }
211 214
212 // go through all file classes 215 // go through all file classes
213 for (int classIdx = 0; classIdx < FileOps.NUM_CLASSES; classIdx++) { 216 //for (int classIdx = 0; classIdx < FileOps.NUM_CLASSES; classIdx++) {
214 int fileClass = cache.getFileClasses()[classIdx]; 217 for (FileClass fileClass: cache.getFileClasses()) {
215 //logger.debug("filtering directory "+dir.getPath()+" for class 218 //fileClass = cache.getFileClasses()[classIdx];
216 // "+fc);
217 File[] fileList = FileOps.listFiles(allFiles, FileOps 219 File[] fileList = FileOps.listFiles(allFiles, FileOps
218 .filterForClass(fileClass)); 220 .filterForClass(fileClass));
219 //logger.debug(" done"); 221 //logger.debug(" done");
220 // number of files in the directory 222 // number of files in the directory
221 int numFiles = fileList.length; 223 int numFiles = fileList.length;
222 if (numFiles > 0) { 224 if (numFiles > 0) {
223 // create new list 225 // create new list
224 list[fileClass] = new ArrayList(numFiles); 226 list.set(fileClass.ordinal(), new ArrayList<DocuDirent>(numFiles));
225 // sort the file names alphabetically and iterate the list 227 // sort the file names alphabetically and iterate the list
226 // Arrays.sort(fileList); // not needed <hertzhaft> 228 // Arrays.sort(fileList); // not needed <hertzhaft>
227 Map hints = FileOps.newHints(FileOps.HINT_BASEDIRS, dirs); 229 Map<Integer, Object> hints = FileOps.newHints(FileOps.HINT_BASEDIRS, dirs);
228 hints.put(FileOps.HINT_FILEEXT, scalext); 230 hints.put(FileOps.HINT_FILEEXT, scalext);
229 for (int i = 0; i < numFiles; i++) { 231 for (int i = 0; i < numFiles; i++) {
230 DocuDirent f = FileOps.fileForClass(fileClass, fileList[i], 232 DocuDirent f = FileOps.fileForClass(fileClass, fileList[i],
231 hints); 233 hints);
232 // add the file to our list 234 // add the file to our list
233 // logger.debug(f.getName()); 235 // logger.debug(f.getName());
234 236
235 list[fileClass].add(f); 237 list.get(fileClass.ordinal()).add(f);
236 f.setParent(this); 238 f.setParent(this);
237 } 239 }
238 // we sort the ArrayList, not the Array, for binarySearch to work 240 // we sort the inner ArrayList (the list of files not the list of file types)
239 Collections.sort(list[fileClass]); 241 // for binarySearch to work (DocuDirent's natural sort order is by filename)
242 Collections.sort(list.get(fileClass.ordinal()));
240 } 243 }
241 } 244 }
242 // clear the scaled directories 245 // clear the scaled directories
243 for (int j = 1; j < nb; j++) { 246 for (int j = 1; j < nb; j++) {
244 if (dirs[j] != null) { 247 if (dirs[j] != null) {
280 File mf = new File(dir, "index.meta"); 283 File mf = new File(dir, "index.meta");
281 if (mf.canRead()) { 284 if (mf.canRead()) {
282 XMLMetaLoader ml = new XMLMetaLoader(); 285 XMLMetaLoader ml = new XMLMetaLoader();
283 try { 286 try {
284 // read directory meta file 287 // read directory meta file
285 Map fileMeta = ml.loadURL(mf.getAbsolutePath()); 288 Map<String, MetadataMap> fileMeta = ml.loadURL(mf.getAbsolutePath());
286 if (fileMeta == null) { 289 if (fileMeta == null) {
287 return; 290 return;
288 } 291 }
289 // meta for the directory itself is in the "" bin 292 // meta for the directory itself is in the "" bin
290 dirMeta = (Map) fileMeta.remove(""); 293 dirMeta = fileMeta.remove("");
291 // read meta for files in this directory 294 // read meta for files in this directory
292 readFileMeta(fileMeta, null); 295 readFileMeta(fileMeta, null);
293 // is there meta for other files left? 296 // is there meta for other files left?
294 if (fileMeta.size() > 0) { 297 if (fileMeta.size() > 0) {
295 unresolvedFileMeta = fileMeta; 298 unresolvedFileMeta = fileMeta;
332 * @param fileMeta 335 * @param fileMeta
333 * @param relPath 336 * @param relPath
334 * @param fc 337 * @param fc
335 * fileClass 338 * fileClass
336 */ 339 */
337 protected void readFileMeta(Map fileMeta, String relPath) { 340 protected void readFileMeta(Map<String,MetadataMap> fileMeta, String relPath) {
338 if (list == null) { 341 if (list == null) {
339 // there are no files 342 // there are no files
340 return; 343 return;
341 } 344 }
342 String path = (relPath != null) ? (relPath + "/") : ""; 345 String path = (relPath != null) ? (relPath + "/") : "";
343 // go through all file classes 346 // go through all file classes
344 for (int nc = 0; nc < list.length; nc++) { 347 for (FileClass fc: FileClass.values()) {
345 int fc = cache.getFileClasses()[nc]; 348 if (list.get(fc.ordinal()) == null) {
346 if (list[fc] == null) {
347 continue; 349 continue;
348 } 350 }
349 // iterate through the list of files in this directory 351 // iterate through the list of files in this directory
350 for (Iterator i = list[fc].iterator(); i.hasNext();) { 352 for (DocuDirent f: list.get(fc.ordinal())) {
351 DocuDirent f = (DocuDirent) i.next();
352 // prepend path to the filename 353 // prepend path to the filename
353 String fn = path + f.getName(); 354 String fn = path + f.getName();
354 // look up meta for this file and remove from dir 355 // look up meta for this file and remove from dir
355 Map meta = (Map) fileMeta.remove(fn); 356 MetadataMap meta = fileMeta.remove(fn);
356 if (meta != null) { 357 if (meta != null) {
357 // store meta in file 358 // store meta in file
358 f.setFileMeta(meta); 359 f.setFileMeta(meta);
359 } 360 }
360 } 361 }
361 } 362 }
362 } 363 }
363 364
364 protected void notifyChildMeta(Map childmeta) { 365 protected void notifyChildMeta(MetadataMap childmeta) {
365 List children = cache.getChildren(this.dirName, true); 366 List<DocuDirectory> children = cache.getChildren(this.dirName, true);
366 if (children.size() > 0) { 367 if (children.size() > 0) {
367 for (Iterator i = children.iterator(); i.hasNext();) { 368 /*for (DocuDirectory d: children) {
368 // TODO: finish this! 369 // TODO: finish this!
369 //((DocuDirectory) i.next()).readFileMeta() 370 //((DocuDirectory) i.next()).readFileMeta()
370 } 371 }*/
371 } 372 }
372 } 373 }
373 374
374 /** 375 /**
375 * Update access time. 376 * Update access time.
393 * @param fc 394 * @param fc
394 * file class 395 * file class
395 * @return int index of file <code>fn</code> 396 * @return int index of file <code>fn</code>
396 */ 397 */
397 public int indexOf(String fn) { 398 public int indexOf(String fn) {
398 int fc = FileOps.classForFilename(fn); 399 FileClass fc = FileOps.classForFilename(fn);
399 return indexOf(fn, fc); 400 return indexOf(fn, fc);
400 } 401 }
401 402
402 /** 403 /**
403 * Searches for the file with the name <code>fn</code> and class fc. 404 * Searches for the file with the name <code>fn</code> and class fc.
407 * 408 *
408 * @param fn 409 * @param fn
409 * filename 410 * filename
410 * @return int index of file <code>fn</code> 411 * @return int index of file <code>fn</code>
411 */ 412 */
412 public int indexOf(String fn, int fc) { 413 public int indexOf(String fn, FileClass fc) {
413 if (!isRead()) { 414 if (!isRead()) {
414 // read directory now 415 // read directory now
415 if (!readDir()) { 416 if (!readDir()) {
416 return -1; 417 return -1;
417 } 418 }
418 } 419 }
419 List fileList = list[fc]; 420 List<DocuDirent> fileList = list.get(fc.ordinal());
420 // empty directory? 421 // empty directory?
421 if (fileList == null) { 422 if (fileList == null) {
422 return -1; 423 return -1;
423 } 424 }
424 425
425 // search for exact match 426 // search for exact match (DocuDirent does compareTo<String>)
426 // OBS: fileList needs to be sorted first (see )! <hertzhaft> 427 // OBS: fileList needs to be sorted first (see )! <hertzhaft>
427 int idx = Collections.binarySearch(fileList, fn); 428 int idx = Collections.binarySearch(fileList, fn);
428 if (idx >= 0) { 429 if (idx >= 0) {
429 return idx; 430 return idx;
430 } else { 431 } else {
431 logger.debug(fn + " not found by binarysearch"); 432 logger.debug(fn + " not found by binarysearch");
432 // try closest matches without extension 433 // try closest matches without extension
433 idx = -idx - 1; 434 idx = -idx - 1;
434 if ((idx < fileList.size()) 435 if ((idx < fileList.size())
435 && isBaseInList(fileList, idx, fn)) { 436 && isBasenameInList(fileList, idx, fn)) {
436 // idx matches 437 // idx matches
437 return idx; 438 return idx;
438 } else if ((idx > 0) 439 } else if ((idx > 0)
439 && isBaseInList(fileList, idx-1, fn)) { 440 && isBasenameInList(fileList, idx-1, fn)) {
440 // idx-1 matches 441 // idx-1 matches
441 return idx - 1; 442 return idx - 1;
442 } else if ((idx + 1 < fileList.size()) 443 } else if ((idx + 1 < fileList.size())
443 && isBaseInList(fileList, idx+1, fn)) { 444 && isBasenameInList(fileList, idx+1, fn)) {
444 // idx+1 matches 445 // idx+1 matches
445 return idx + 1; 446 return idx + 1;
446 } 447 }
447 448
448 } 449 }
449 return -1; 450 return -1;
450 } 451 }
451 452
452 private boolean isBaseInList(List fl, int idx, String fn) { 453 private boolean isBasenameInList(List<DocuDirent> fl, int idx, String fn) {
453 String dfn = FileOps.basename(((DocuDirent) fl.get(idx)) 454 String dfn = FileOps.basename((fl.get(idx))
454 .getName()); 455 .getName());
455 return (dfn.equals(fn)||dfn.equals(FileOps.basename(fn))); 456 return (dfn.equals(fn)||dfn.equals(FileOps.basename(fn)));
456 } 457 }
457 458
458 459
465 * @param fn 466 * @param fn
466 * filename 467 * filename
467 * @return DocuDirent 468 * @return DocuDirent
468 */ 469 */
469 public DocuDirent find(String fn) { 470 public DocuDirent find(String fn) {
470 int fc = FileOps.classForFilename(fn); 471 FileClass fc = FileOps.classForFilename(fn);
471 int i = indexOf(fn, fc); 472 int i = indexOf(fn, fc);
472 if (i >= 0) { 473 if (i >= 0) {
473 return (DocuDirent) list[0].get(i); 474 return (DocuDirent) list.get(0).get(i);
474 } 475 }
475 return null; 476 return null;
476 } 477 }
477 478
478 /** 479 /**
484 * 485 *
485 * @param fn 486 * @param fn
486 * filename 487 * filename
487 * @return DocuDirent 488 * @return DocuDirent
488 */ 489 */
489 public DocuDirent find(String fn, int fc) { 490 public DocuDirent find(String fn, FileClass fc) {
490 int i = indexOf(fn, fc); 491 int i = indexOf(fn, fc);
491 if (i >= 0) { 492 if (i >= 0) {
492 return (DocuDirent) list[fc].get(i); 493 return (DocuDirent) list.get(fc.ordinal()).get(i);
493 } 494 }
494 return null; 495 return null;
495 } 496 }
496 497
497 /** 498 /**
529 } 530 }
530 531
531 /** 532 /**
532 * @return Hashtable 533 * @return Hashtable
533 */ 534 */
534 public Map getDirMeta() { 535 public MetadataMap getDirMeta() {
535 return dirMeta; 536 return dirMeta;
536 } 537 }
537 538
538 /** 539 /**
539 * Checks metadata 540 * Checks metadata
558 * Sets the dirMeta. 559 * Sets the dirMeta.
559 * 560 *
560 * @param dirMeta 561 * @param dirMeta
561 * The dirMeta to set 562 * The dirMeta to set
562 */ 563 */
563 public void setDirMeta(Map dirMeta) { 564 public void setDirMeta(MetadataMap dirMeta) {
564 this.dirMeta = dirMeta; 565 this.dirMeta = dirMeta;
565 } 566 }
566 567
567 public boolean hasUnresolvedFileMeta() { 568 public boolean hasUnresolvedFileMeta() {
568 return (this.unresolvedFileMeta != null); 569 return (this.unresolvedFileMeta != null);