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