Mercurial > hg > digilib-old
annotate servlet/src/digilib/io/DocuDirectory.java @ 545:88ec23c2b2fb digilibPDF
fixed problem after removing old settings
author | casties |
---|---|
date | Fri, 15 Oct 2010 10:42:57 +0200 |
parents | e758a49258e8 |
children | 686086d6e6d6 |
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 | |
86 | 33 /** |
34 * @author casties | |
35 */ | |
149 | 36 public class DocuDirectory extends Directory { |
86 | 37 |
270 | 38 /** list of files (DocuDirent) */ |
531 | 39 private List<List<DocuDirent>> list = null; |
270 | 40 |
41 /** directory object is valid (exists on disk) */ | |
86 | 42 private boolean isValid = false; |
270 | 43 |
44 /** reference of the parent DocuDirCache */ | |
151 | 45 private DocuDirCache cache = null; |
270 | 46 |
47 /** directory name (digilib canonical form) */ | |
86 | 48 private String dirName = null; |
270 | 49 |
50 /** directory metadata */ | |
531 | 51 private MetadataMap dirMeta = null; |
270 | 52 |
53 /** state of metadata is valid */ | |
233 | 54 private boolean metaChecked = false; |
270 | 55 |
56 /** unresolved file metadata */ | |
531 | 57 private Map<String, MetadataMap> unresolvedFileMeta = null; |
270 | 58 |
59 /** time of last access of this object (not the filesystem) */ | |
86 | 60 private long objectATime = 0; |
270 | 61 |
62 /** time directory was last modified on the file system */ | |
86 | 63 private long dirMTime = 0; |
64 | |
270 | 65 /** |
66 * Constructor with digilib directory path and a parent DocuDirCache. | |
86 | 67 * |
270 | 68 * Directory names at the given path are appended to the base directories |
69 * from the cache. The directory is checked on disk and isValid is set. | |
86 | 70 * |
71 * @see readDir | |
270 | 72 * |
73 * @param path | |
74 * digilib directory path name | |
75 * @param cache | |
76 * parent DocuDirCache | |
86 | 77 */ |
151 | 78 public DocuDirectory(String path, DocuDirCache cache) { |
79 this.dirName = path; | |
80 this.cache = cache; | |
159 | 81 initDir(); |
82 checkDir(); | |
86 | 83 } |
84 | |
270 | 85 /** |
86 * Sets and checks the dir object. | |
87 * | |
91 | 88 */ |
159 | 89 protected void initDir() { |
90 String baseDirName = cache.getBaseDirNames()[0]; | |
91 // clear directory first | |
531 | 92 //list = new ArrayList[FileOps.NUM_CLASSES]; |
93 | |
94 list = new ArrayList<List<DocuDirent>>(FileOps.NUM_CLASSES); | |
95 // create empty list | |
96 for (int i=0; i < FileOps.NUM_CLASSES; ++i) { | |
97 list.add(null); | |
98 } | |
159 | 99 isValid = false; |
100 dirMTime = 0; | |
101 // the first directory has to exist | |
102 dir = new File(baseDirName, dirName); | |
103 } | |
156 | 104 |
270 | 105 /** |
106 * number of DocuFiles in this directory. | |
107 * | |
151 | 108 */ |
270 | 109 public int size() { |
531 | 110 return ((list != null) && (list.get(0) != null)) ? list.get(0).size() : 0; |
151 | 111 } |
91 | 112 |
270 | 113 /** |
114 * number of files of this class in this directory. | |
151 | 115 * |
270 | 116 * @param fc |
117 * fileClass | |
151 | 118 */ |
270 | 119 public int size(int fc) { |
531 | 120 return ((list != null) && (list.get(fc) != null)) ? list.get(fc).size() : 0; |
91 | 121 } |
122 | |
270 | 123 /** |
124 * Returns the ImageFile at the index. | |
151 | 125 * |
126 * @param index | |
127 * @return | |
128 */ | |
159 | 129 public ImageFileset get(int index) { |
531 | 130 if ((list == null) || (list.get(0) == null) || (index >= list.get(0).size())) { |
122 | 131 return null; |
151 | 132 } |
531 | 133 return (ImageFileset) list.get(0).get(index); |
159 | 134 } |
135 | |
270 | 136 /** |
137 * Returns the file of the class at the index. | |
159 | 138 * |
139 * @param index | |
270 | 140 * @param fc |
141 * fileClass | |
159 | 142 * @return |
143 */ | |
144 public DocuDirent get(int index, int fc) { | |
531 | 145 if ((list == null) || (list.get(fc) == null) || (index >= list.get(fc).size())) { |
159 | 146 return null; |
147 } | |
531 | 148 return (DocuDirent) list.get(fc).get(index); |
159 | 149 } |
150 | |
270 | 151 /** |
152 * Checks if the directory exists on the filesystem. | |
159 | 153 * |
154 * Sets isValid. | |
155 * | |
156 * @return | |
157 */ | |
158 public boolean checkDir() { | |
159 if (dir == null) { | |
160 initDir(); | |
161 } | |
162 isValid = dir.isDirectory(); | |
163 return isValid; | |
91 | 164 } |
165 | |
270 | 166 /** |
167 * Read the filesystem directory and fill this object. | |
86 | 168 * |
130 | 169 * Clears the List and (re)reads all files. |
86 | 170 * |
171 * @return boolean the directory exists | |
172 */ | |
282 | 173 public synchronized boolean readDir() { |
159 | 174 // check directory first |
175 checkDir(); | |
176 if (!isValid) { | |
177 return false; | |
178 } | |
270 | 179 // first file extension to try for scaled directories |
180 String scalext = null; | |
259 | 181 // read all filenames |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
182 logger.debug("reading directory " + dir.getPath()); |
259 | 183 /* |
270 | 184 * using ReadableFileFilter is safer (we won't get directories with file |
185 * extensions) but slower. | |
259 | 186 */ |
187 File[] allFiles = null; | |
545 | 188 // allFiles = dir.listFiles(new FileOps.ReadableFileFilter()); |
189 allFiles = dir.listFiles(); | |
295
90bab835fc25
Servlet version 1.5.0b -- the beginning of the next generation :-)
robcast
parents:
288
diff
changeset
|
190 //logger.debug(" done"); |
259 | 191 if (allFiles == null) { |
192 // not a directory | |
193 return false; | |
194 } | |
270 | 195 // list of base dirs from the parent cache |
196 String[] baseDirNames = cache.getBaseDirNames(); | |
197 // number of base dirs | |
198 int nb = baseDirNames.length; | |
199 // array of base dirs | |
200 Directory[] dirs = new Directory[nb]; | |
201 // first entry is this directory | |
202 dirs[0] = this; | |
203 // fill array with the remaining directories | |
204 for (int j = 1; j < nb; j++) { | |
205 File d = new File(baseDirNames[j], dirName); | |
206 if (d.isDirectory()) { | |
207 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
|
208 logger.debug(" reading scaled directory " + d.getPath()); |
270 | 209 dirs[j].readDir(); |
295
90bab835fc25
Servlet version 1.5.0b -- the beginning of the next generation :-)
robcast
parents:
288
diff
changeset
|
210 //logger.debug(" done"); |
270 | 211 } |
212 } | |
213 | |
159 | 214 // go through all file classes |
270 | 215 for (int classIdx = 0; classIdx < FileOps.NUM_CLASSES; classIdx++) { |
216 int fileClass = cache.getFileClasses()[classIdx]; | |
217 //logger.debug("filtering directory "+dir.getPath()+" for class | |
218 // "+fc); | |
219 File[] fileList = FileOps.listFiles(allFiles, FileOps | |
220 .filterForClass(fileClass)); | |
221 //logger.debug(" done"); | |
159 | 222 // number of files in the directory |
270 | 223 int numFiles = fileList.length; |
224 if (numFiles > 0) { | |
91 | 225 // create new list |
531 | 226 list.set(fileClass, new ArrayList<DocuDirent>(numFiles)); |
86 | 227 // 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
|
228 // Arrays.sort(fileList); // not needed <hertzhaft> |
531 | 229 Map<Integer, Object> hints = FileOps.newHints(FileOps.HINT_BASEDIRS, dirs); |
259 | 230 hints.put(FileOps.HINT_FILEEXT, scalext); |
270 | 231 for (int i = 0; i < numFiles; i++) { |
232 DocuDirent f = FileOps.fileForClass(fileClass, fileList[i], | |
233 hints); | |
159 | 234 // 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
|
235 // logger.debug(f.getName()); |
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
236 |
531 | 237 list.get(fileClass).add(f); |
159 | 238 f.setParent(this); |
86 | 239 } |
531 | 240 // we sort the inner ArrayList (the list of files not the list of file types) |
241 // for binarySearch to work (DocuDirent's natural sort order is by filename) | |
242 Collections.sort(list.get(fileClass)); | |
86 | 243 } |
244 } | |
270 | 245 // clear the scaled directories |
246 for (int j = 1; j < nb; j++) { | |
247 if (dirs[j] != null) { | |
248 dirs[j].clearFilenames(); | |
249 } | |
250 } | |
251 // update number of cached files if this was the first time | |
252 if (dirMTime == 0) { | |
253 cache.numFiles += size(); | |
254 } | |
159 | 255 dirMTime = dir.lastModified(); |
256 // read metadata as well | |
257 readMeta(); | |
86 | 258 return isValid; |
259 } | |
260 | |
270 | 261 /** |
262 * Check to see if the directory has been modified and reread if necessary. | |
86 | 263 * |
264 * @return boolean the directory is valid | |
265 */ | |
266 public boolean refresh() { | |
267 if (isValid) { | |
268 if (dir.lastModified() > dirMTime) { | |
269 // on-disk modification time is more recent | |
270 readDir(); | |
271 } | |
272 touch(); | |
273 } | |
274 return isValid; | |
275 } | |
276 | |
270 | 277 /** |
278 * Read directory metadata. | |
279 * | |
86 | 280 */ |
281 public void readMeta() { | |
282 // check for directory metadata... | |
130 | 283 File mf = new File(dir, "index.meta"); |
284 if (mf.canRead()) { | |
285 XMLMetaLoader ml = new XMLMetaLoader(); | |
286 try { | |
287 // read directory meta file | |
531 | 288 Map<String, MetadataMap> fileMeta = ml.loadURL(mf.getAbsolutePath()); |
130 | 289 if (fileMeta == null) { |
290 return; | |
291 } | |
292 // meta for the directory itself is in the "" bin | |
531 | 293 dirMeta = fileMeta.remove(""); |
151 | 294 // read meta for files in this directory |
295 readFileMeta(fileMeta, null); | |
296 // is there meta for other files left? | |
130 | 297 if (fileMeta.size() > 0) { |
151 | 298 unresolvedFileMeta = fileMeta; |
130 | 299 } |
300 } catch (SAXException e) { | |
282 | 301 logger.warn("error parsing index.meta", e); |
130 | 302 } catch (IOException e) { |
282 | 303 logger.warn("error reading index.meta", e); |
130 | 304 } |
151 | 305 } |
306 readParentMeta(); | |
233 | 307 metaChecked = true; |
151 | 308 } |
130 | 309 |
270 | 310 /** |
311 * Read metadata from all known parent directories. | |
312 * | |
151 | 313 */ |
314 public void readParentMeta() { | |
315 // check the parent directories for additional file meta | |
316 Directory dd = parent; | |
156 | 317 String path = dir.getName(); |
151 | 318 while (dd != null) { |
156 | 319 if (((DocuDirectory) dd).hasUnresolvedFileMeta()) { |
320 readFileMeta(((DocuDirectory) dd).unresolvedFileMeta, path); | |
151 | 321 } |
322 // prepend parent dir path | |
323 path = dd.dir.getName() + "/" + path; | |
324 // become next parent | |
325 dd = dd.parent; | |
326 } | |
327 } | |
328 | |
270 | 329 /** |
330 * Read metadata for the files in this directory. | |
151 | 331 * |
270 | 332 * Takes a Map with meta-information, adding the relative path before the |
333 * lookup. | |
151 | 334 * |
335 * @param fileMeta | |
336 * @param relPath | |
270 | 337 * @param fc |
338 * fileClass | |
151 | 339 */ |
531 | 340 protected void readFileMeta(Map<String,MetadataMap> fileMeta, String relPath) { |
151 | 341 if (list == null) { |
342 // there are no files | |
343 return; | |
344 } | |
345 String path = (relPath != null) ? (relPath + "/") : ""; | |
159 | 346 // go through all file classes |
531 | 347 for (int nc = 0; nc < list.size(); nc++) { |
159 | 348 int fc = cache.getFileClasses()[nc]; |
531 | 349 if (list.get(fc) == null) { |
159 | 350 continue; |
351 } | |
352 // iterate through the list of files in this directory | |
531 | 353 for (DocuDirent f: list.get(fc)) { |
159 | 354 // prepend path to the filename |
355 String fn = path + f.getName(); | |
356 // look up meta for this file and remove from dir | |
531 | 357 MetadataMap meta = fileMeta.remove(fn); |
159 | 358 if (meta != null) { |
359 // store meta in file | |
360 f.setFileMeta(meta); | |
361 } | |
362 } | |
363 } | |
364 } | |
365 | |
531 | 366 protected void notifyChildMeta(MetadataMap childmeta) { |
367 List<DocuDirectory> children = cache.getChildren(this.dirName, true); | |
159 | 368 if (children.size() > 0) { |
531 | 369 /*for (DocuDirectory d: children) { |
159 | 370 // TODO: finish this! |
371 //((DocuDirectory) i.next()).readFileMeta() | |
531 | 372 }*/ |
130 | 373 } |
86 | 374 } |
375 | |
270 | 376 /** |
377 * Update access time. | |
86 | 378 * |
379 * @return long time of last access. | |
380 */ | |
381 public long touch() { | |
382 long t = objectATime; | |
383 objectATime = System.currentTimeMillis(); | |
384 return t; | |
385 } | |
386 | |
270 | 387 /** |
388 * Searches for the file with the name <code>fn</code>. | |
86 | 389 * |
270 | 390 * Searches the directory for the file with the name <code>fn</code> and |
391 * returns its index. Returns -1 if the file cannot be found. | |
392 * | |
393 * @param fn | |
394 * filename | |
395 * @param fc | |
396 * file class | |
86 | 397 * @return int index of file <code>fn</code> |
398 */ | |
399 public int indexOf(String fn) { | |
159 | 400 int fc = FileOps.classForFilename(fn); |
401 return indexOf(fn, fc); | |
402 } | |
270 | 403 |
404 /** | |
405 * Searches for the file with the name <code>fn</code> and class fc. | |
159 | 406 * |
270 | 407 * Searches the directory for the file with the name <code>fn</code> and |
408 * returns its index. Returns -1 if the file cannot be found. | |
409 * | |
410 * @param fn | |
411 * filename | |
159 | 412 * @return int index of file <code>fn</code> |
413 */ | |
414 public int indexOf(String fn, int fc) { | |
176 | 415 if (!isRead()) { |
416 // read directory now | |
417 if (!readDir()) { | |
418 return -1; | |
419 } | |
420 } | |
531 | 421 List<DocuDirent> fileList = list.get(fc); |
246 | 422 // empty directory? |
288 | 423 if (fileList == null) { |
246 | 424 return -1; |
425 } | |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
426 |
531 | 427 // 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
|
428 // OBS: fileList needs to be sorted first (see )! <hertzhaft> |
288 | 429 int idx = Collections.binarySearch(fileList, fn); |
270 | 430 if (idx >= 0) { |
431 return idx; | |
432 } else { | |
472
f8ca069517a2
Bugfix for images not found in dir: added sorting for ArrayLists of ImageFilesets
hertzhaft
parents:
341
diff
changeset
|
433 logger.debug(fn + " not found by binarysearch"); |
270 | 434 // try closest matches without extension |
282 | 435 idx = -idx - 1; |
288 | 436 if ((idx < fileList.size()) |
341 | 437 && isBaseInList(fileList, idx, fn)) { |
282 | 438 // idx matches |
439 return idx; | |
440 } else if ((idx > 0) | |
341 | 441 && isBaseInList(fileList, idx-1, fn)) { |
282 | 442 // idx-1 matches |
270 | 443 return idx - 1; |
288 | 444 } else if ((idx + 1 < fileList.size()) |
341 | 445 && isBaseInList(fileList, idx+1, fn)) { |
282 | 446 // idx+1 matches |
270 | 447 return idx + 1; |
86 | 448 } |
270 | 449 |
86 | 450 } |
451 return -1; | |
452 } | |
453 | |
531 | 454 private boolean isBaseInList(List<DocuDirent> fl, int idx, String fn) { |
455 String dfn = FileOps.basename((fl.get(idx)) | |
341 | 456 .getName()); |
457 return (dfn.equals(fn)||dfn.equals(FileOps.basename(fn))); | |
458 } | |
459 | |
460 | |
270 | 461 /** |
462 * Finds the DocuDirent with the name <code>fn</code>. | |
86 | 463 * |
270 | 464 * Searches the directory for the DocuDirent with the name <code>fn</code> |
465 * and returns it. Returns null if the file cannot be found. | |
466 * | |
467 * @param fn | |
468 * filename | |
187 | 469 * @return DocuDirent |
86 | 470 */ |
187 | 471 public DocuDirent find(String fn) { |
159 | 472 int fc = FileOps.classForFilename(fn); |
473 int i = indexOf(fn, fc); | |
86 | 474 if (i >= 0) { |
531 | 475 return (DocuDirent) list.get(0).get(i); |
159 | 476 } |
477 return null; | |
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 */ |
187 | 491 public DocuDirent find(String fn, int fc) { |
159 | 492 int i = indexOf(fn, fc); |
493 if (i >= 0) { | |
531 | 494 return (DocuDirent) list.get(fc).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 } |