Mercurial > hg > digilib-old
annotate servlet/src/digilib/io/DocuDirCache.java @ 270:b21915a3fc24
Servlet version 1.21b3
- searching in directories got faster (real binarySearch now!)
- cached file lists get disposed
- some code cleaning (Map types instead of HashMap)
| author | robcast |
|---|---|
| date | Tue, 12 Oct 2004 16:06:43 +0200 |
| parents | beed92ee6022 |
| children | 87dca7119596 |
| rev | line source |
|---|---|
| 176 | 1 /* |
| 2 * DocuDirCache.java | |
| 3 * | |
| 4 * Digital Image Library servlet components | |
| 5 * | |
| 6 * Copyright (C) 2003 Robert Casties (robcast@mail.berlios.de) | |
| 7 * | |
| 8 * This program is free software; you can redistribute it and/or modify it | |
| 9 * under the terms of the GNU General Public License as published by the Free | |
| 10 * Software Foundation; either version 2 of the License, or (at your option) | |
| 11 * any later version. | |
| 12 * | |
| 13 * Please read license.txt for the full details. A copy of the GPL may be found | |
| 14 * at http://www.gnu.org/copyleft/lgpl.html | |
| 15 * | |
| 16 * You should have received a copy of the GNU General Public License along with | |
| 17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
| 18 * Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 * | |
| 86 | 20 * Created on 03.03.2003 |
| 21 */ | |
| 22 | |
| 23 package digilib.io; | |
| 24 | |
| 25 import java.io.File; | |
| 91 | 26 import java.util.HashMap; |
| 159 | 27 import java.util.Iterator; |
| 28 import java.util.LinkedList; | |
| 29 import java.util.List; | |
| 270 | 30 import java.util.Map; |
| 86 | 31 |
| 181 | 32 import org.apache.log4j.Logger; |
| 33 | |
| 259 | 34 import digilib.servlet.DigilibConfiguration; |
| 35 | |
| 86 | 36 /** |
| 37 * @author casties | |
| 38 */ | |
| 91 | 39 public class DocuDirCache { |
| 86 | 40 |
| 181 | 41 /** general logger for this class */ |
| 270 | 42 Logger logger = Logger.getLogger(this.getClass()); |
| 159 | 43 /** HashMap of directories */ |
| 270 | 44 Map map = null; |
| 159 | 45 /** names of base directories */ |
| 270 | 46 String[] baseDirNames = null; |
| 159 | 47 /** array of allowed file classes (image/text) */ |
| 48 private int[] fileClasses = null; | |
| 49 /** number of files in the whole cache (approximate) */ | |
| 270 | 50 long numFiles = 0; |
| 159 | 51 /** number of cache hits */ |
| 270 | 52 long hits = 0; |
| 159 | 53 /** number of cache misses */ |
| 270 | 54 long misses = 0; |
| 259 | 55 /** use safe (but slow) indexing */ |
| 56 boolean safeDirIndex = false; | |
| 270 | 57 /** the root directory element */ |
| 58 public static Directory ROOT = null; | |
| 86 | 59 |
| 176 | 60 /** |
| 61 * Constructor with array of base directory names and file classes. | |
| 62 * | |
| 63 * @param bd | |
| 64 * base directory names | |
| 159 | 65 */ |
| 259 | 66 public DocuDirCache(String[] bd, int[] fileClasses, DigilibConfiguration dlConfig) { |
| 159 | 67 baseDirNames = bd; |
| 68 map = new HashMap(); | |
| 69 this.fileClasses = fileClasses; | |
| 259 | 70 safeDirIndex = dlConfig.getAsBoolean("safe-dir-index"); |
| 159 | 71 } |
| 176 | 72 /** |
| 73 * Constructor with array of base directory names. | |
| 74 * | |
| 75 * @param bd | |
| 76 * base directory names | |
| 86 | 77 */ |
| 78 public DocuDirCache(String[] bd) { | |
| 79 baseDirNames = bd; | |
| 91 | 80 map = new HashMap(); |
| 159 | 81 // default file class is CLASS_IMAGE |
| 82 fileClasses = new int[1]; | |
| 83 fileClasses[0] = FileOps.CLASS_IMAGE; | |
| 91 | 84 } |
| 85 | |
| 176 | 86 /** |
| 87 * The number of directories in the cache. | |
| 88 * | |
| 91 | 89 * @return |
| 90 */ | |
| 91 public int size() { | |
| 92 return (map != null) ? map.size() : 0; | |
| 86 | 93 } |
| 94 | |
| 176 | 95 /** |
| 96 * Add a DocuDirectory to the cache. | |
| 86 | 97 * |
| 98 * @param newdir | |
| 99 */ | |
| 100 public void put(DocuDirectory newdir) { | |
| 101 String s = newdir.getDirName(); | |
| 91 | 102 if (map.containsKey(s)) { |
| 197 | 103 logger.warn("Duplicate key in DocuDirCache.put -- ignoring!"); |
| 86 | 104 } else { |
| 91 | 105 map.put(s, newdir); |
| 86 | 106 numFiles += newdir.size(); |
| 107 } | |
| 108 } | |
| 109 | |
| 176 | 110 /** |
| 111 * Add a directory to the cache and check its parents. | |
| 151 | 112 * |
| 113 * @param newDir | |
| 114 */ | |
| 115 public void putDir(DocuDirectory newDir) { | |
| 116 put(newDir); | |
| 270 | 117 String parent = FileOps.parent(newDir.getDirName()); |
| 118 if (parent != "") { | |
| 151 | 119 // check the parent in the cache |
| 176 | 120 DocuDirectory pd = (DocuDirectory) map.get(parent); |
| 151 | 121 if (pd == null) { |
| 122 // the parent is unknown | |
| 123 pd = new DocuDirectory(parent, this); | |
| 124 putDir(pd); | |
| 125 } | |
| 126 newDir.setParent(pd); | |
| 127 } | |
| 128 } | |
| 129 | |
| 176 | 130 /** |
| 131 * Get a list with all children of a directory. | |
| 159 | 132 * |
| 176 | 133 * Returns a List of DocuDirectory's. Returns an empty List if the |
| 134 * directory has no children. If recurse is false then only direct children | |
| 135 * are returned. | |
| 159 | 136 * |
| 137 * @param dirname | |
| 176 | 138 * @param recurse |
| 139 * find all children and their children. | |
| 159 | 140 * @return |
| 141 */ | |
| 142 public List getChildren(String dirname, boolean recurse) { | |
| 143 List l = new LinkedList(); | |
| 176 | 144 for (Iterator i = map.keySet().iterator(); i.hasNext();) { |
| 209 | 145 String n = (String) i.next(); |
| 146 DocuDirectory dd = (DocuDirectory) map.get(n); | |
| 159 | 147 if (recurse) { |
| 148 if (dd.getDirName().startsWith(dirname)) { | |
| 149 l.add(dd); | |
| 150 } | |
| 151 } else { | |
| 270 | 152 if (FileOps.parent(dd.getDirName()).equals(dirname)) { |
| 159 | 153 l.add(dd); |
| 154 } | |
| 155 } | |
| 156 } | |
| 157 return l; | |
| 158 } | |
| 159 | |
| 176 | 160 /** |
| 187 | 161 * Returns the DocuDirent with the pathname <code>fn</code> and the |
| 159 | 162 * index <code>in</code> and the class <code>fc</code>. |
| 91 | 163 * |
| 187 | 164 * If <code>fn</code> is a file then the corresponding DocuDirent is |
| 91 | 165 * returned and the index is ignored. |
| 166 * | |
| 176 | 167 * @param fn |
| 168 * digilib pathname | |
| 169 * @param in | |
| 170 * file index | |
| 246 | 171 * @param fc |
| 172 * file class | |
| 176 | 173 * @return |
| 91 | 174 */ |
| 159 | 175 public DocuDirent getFile(String fn, int in, int fc) { |
| 86 | 176 DocuDirectory dd; |
| 177 // file number is 1-based, vector index is 0-based | |
| 178 int n = in - 1; | |
| 179 // first, assume fn is a directory and look in the cache | |
| 91 | 180 dd = (DocuDirectory) map.get(fn); |
| 181 if (dd == null) { | |
| 182 // cache miss | |
| 183 misses++; | |
| 176 | 184 /* |
| 185 * see if it's a directory | |
| 186 */ | |
| 152 | 187 File f = new File(baseDirNames[0], fn); |
| 91 | 188 if (f.isDirectory()) { |
| 151 | 189 dd = new DocuDirectory(fn, this); |
| 91 | 190 if (dd.isValid()) { |
| 191 // add to the cache | |
| 151 | 192 putDir(dd); |
| 91 | 193 } |
| 194 } else { | |
| 176 | 195 /* |
| 196 * maybe it's a file | |
| 197 */ | |
| 198 // get the parent directory string (like we store it in the | |
| 199 // cache) | |
| 246 | 200 String d = FileOps.parent(fn); |
| 176 | 201 // try it in the cache |
| 202 dd = (DocuDirectory) map.get(d); | |
| 203 if (dd == null) { | |
| 204 // try to read from disk | |
| 205 dd = new DocuDirectory(d, this); | |
| 206 if (dd.isValid()) { | |
| 207 // add to the cache | |
| 208 putDir(dd); | |
| 91 | 209 } else { |
| 176 | 210 // invalid path |
| 211 return null; | |
| 91 | 212 } |
|
99
226624784fe3
Small bug lead to null pointer exception when directory doesn't exist.
robcast
parents:
91
diff
changeset
|
213 } else { |
| 176 | 214 // it was not a real cache miss |
| 215 misses--; | |
| 91 | 216 } |
| 176 | 217 // get the file's index |
| 218 n = dd.indexOf(f.getName(), fc); | |
| 91 | 219 } |
| 220 } else { | |
| 221 // cache hit | |
| 222 hits++; | |
| 223 } | |
| 224 dd.refresh(); | |
| 225 if (dd.isValid()) { | |
| 226 try { | |
| 159 | 227 return dd.get(n, fc); |
| 187 | 228 } catch (IndexOutOfBoundsException e) { |
| 91 | 229 } |
| 230 } | |
| 231 return null; | |
| 232 } | |
| 233 | |
| 176 | 234 /** |
| 235 * Returns the DocuDirectory indicated by the pathname <code>fn</code>. | |
| 91 | 236 * |
| 237 * If <code>fn</code> is a file then its parent directory is returned. | |
| 238 * | |
| 176 | 239 * @param fn |
| 240 * digilib pathname | |
| 91 | 241 * @return |
| 242 */ | |
| 243 public DocuDirectory getDirectory(String fn) { | |
| 244 DocuDirectory dd; | |
| 245 // first, assume fn is a directory and look in the cache | |
| 246 dd = (DocuDirectory) map.get(fn); | |
| 86 | 247 if (dd == null) { |
| 248 // cache miss | |
| 249 misses++; | |
| 250 // see if it's a directory | |
| 152 | 251 File f = new File(baseDirNames[0], fn); |
| 86 | 252 if (f.isDirectory()) { |
| 151 | 253 dd = new DocuDirectory(fn, this); |
| 86 | 254 if (dd.isValid()) { |
| 255 // add to the cache | |
| 151 | 256 putDir(dd); |
| 86 | 257 } |
| 258 } else { | |
| 259 // maybe it's a file | |
| 260 if (f.canRead()) { | |
| 261 // try the parent directory in the cache | |
| 91 | 262 dd = (DocuDirectory) map.get(f.getParent()); |
| 86 | 263 if (dd == null) { |
| 264 // try to read from disk | |
| 151 | 265 dd = new DocuDirectory(f.getParent(), this); |
| 86 | 266 if (dd.isValid()) { |
| 267 // add to the cache | |
| 151 | 268 putDir(dd); |
| 86 | 269 } else { |
| 270 // invalid path | |
| 271 return null; | |
| 272 } | |
| 91 | 273 } else { |
| 274 // not a real cache miss then | |
| 275 misses--; | |
| 86 | 276 } |
|
99
226624784fe3
Small bug lead to null pointer exception when directory doesn't exist.
robcast
parents:
91
diff
changeset
|
277 } else { |
|
226624784fe3
Small bug lead to null pointer exception when directory doesn't exist.
robcast
parents:
91
diff
changeset
|
278 // it's not even a file :-( |
|
226624784fe3
Small bug lead to null pointer exception when directory doesn't exist.
robcast
parents:
91
diff
changeset
|
279 return null; |
| 86 | 280 } |
| 281 } | |
| 282 } else { | |
| 283 // cache hit | |
| 284 hits++; | |
| 285 } | |
| 286 dd.refresh(); | |
| 287 if (dd.isValid()) { | |
| 288 return dd; | |
| 289 } | |
| 290 return null; | |
| 291 } | |
| 292 | |
| 293 /** | |
| 294 * @return String[] | |
| 295 */ | |
| 296 public String[] getBaseDirNames() { | |
| 297 return baseDirNames; | |
| 298 } | |
| 299 | |
| 300 /** | |
| 301 * @return long | |
| 302 */ | |
| 303 public long getNumFiles() { | |
| 304 return numFiles; | |
| 305 } | |
| 306 | |
| 307 /** | |
| 308 * Sets the baseDirNames. | |
| 176 | 309 * |
| 310 * @param baseDirNames | |
| 311 * The baseDirNames to set | |
| 86 | 312 */ |
| 313 public void setBaseDirNames(String[] baseDirNames) { | |
| 314 this.baseDirNames = baseDirNames; | |
| 315 } | |
| 316 | |
| 317 /** | |
| 318 * @return long | |
| 319 */ | |
| 320 public long getHits() { | |
| 321 return hits; | |
| 322 } | |
| 323 | |
| 324 /** | |
| 325 * @return long | |
| 326 */ | |
| 327 public long getMisses() { | |
| 328 return misses; | |
| 329 } | |
| 330 | |
| 159 | 331 /** |
| 332 * @return | |
| 333 */ | |
| 334 public int[] getFileClasses() { | |
| 335 return fileClasses; | |
| 336 } | |
| 337 | |
| 338 /** | |
| 339 * @param fileClasses | |
| 340 */ | |
| 341 public void setFileClasses(int[] fileClasses) { | |
| 342 this.fileClasses = fileClasses; | |
| 343 } | |
| 176 | 344 |
| 86 | 345 } |
