1 17 package org.apache.excalibur.store.impl; 18 19 import java.io.*; 20 import java.util.BitSet; 21 import java.util.Enumeration; 22 23 import EDU.oswego.cs.dl.util.concurrent.Sync; 24 25 import org.apache.avalon.framework.thread.ThreadSafe; 26 import org.apache.excalibur.store.Store; 27 28 36 public abstract class AbstractFilesystemStore 37 extends AbstractReadWriteStore 38 implements Store, ThreadSafe { 39 40 41 protected File m_directoryFile; 42 protected volatile String m_directoryPath; 43 44 47 public void setDirectory(final String directory) 48 throws IOException 49 { 50 this.setDirectory(new File(directory)); 51 } 52 53 56 public void setDirectory(final File directory) 57 throws IOException 58 { 59 this.m_directoryFile = directory; 60 61 62 this.m_directoryPath = this.getFullFilename(this.m_directoryFile); 63 this.m_directoryPath += File.separator; 64 65 66 if (!this.m_directoryFile.exists()) 67 { 68 69 if (!this.m_directoryFile.mkdir()) 70 { 71 throw new IOException( 72 "Error creating store directory '" + this.m_directoryPath + "': "); 73 } 74 } 75 76 77 if (!this.m_directoryFile.isDirectory()) 78 { 79 throw new IOException("'" + this.m_directoryPath + "' is not a directory"); 80 } 81 82 83 if (!(this.m_directoryFile.canRead() && this.m_directoryFile.canWrite())) 84 { 85 throw new IOException( 86 "Directory '" + this.m_directoryPath + "' is not readable/writable" 87 ); 88 } 89 } 90 91 94 public String getDirectoryPath() 95 { 96 return this.m_directoryPath; 97 } 98 99 102 protected Object doGet(final Object key) 103 { 104 final File file = fileFromKey(key); 105 106 if (file != null && file.exists()) 107 { 108 if (getLogger().isDebugEnabled()) 109 { 110 getLogger().debug("Found file: " + key); 111 } 112 try 113 { 114 return this.deserializeObject(file); 115 } 116 catch (Exception any) { 117 getLogger().error("Error during deseralization.", any); 118 } 119 } 120 else 121 { 122 if (getLogger().isDebugEnabled()) 123 { 124 getLogger().debug("NOT Found file: " + key); 125 } 126 } 127 128 return null; 129 } 130 131 137 protected void doStore(final Object key, final Object value) 138 throws IOException 139 { 140 final File file = fileFromKey(key); 141 142 143 final File parent = file.getParentFile(); 144 if (parent != null) 145 { 146 parent.mkdirs(); 147 } 148 149 150 if (value == null) 151 { 152 if (file.exists()) 153 { 154 if (!file.delete()) 155 { 156 getLogger().error("File cannot be deleted: " + file.toString()); 157 return; 158 } 159 } 160 161 file.mkdir(); 162 } 163 else if (value instanceof String) 164 { 165 166 this.serializeString(file, (String) value); 167 } 168 else 169 { 170 171 this.serializeObject(file, value); 172 } 173 } 174 175 178 protected void doRemove(final Object key) 179 { 180 final File file = fileFromKey(key); 181 if (file != null) 182 { 183 file.delete(); 184 } 185 } 186 187 190 protected void doClear() 191 { 192 Enumeration enum = this.keys(); 193 while (enum.hasMoreElements()) 194 { 195 Object key = enum.nextElement(); 196 if (key == null) 197 { 198 continue; 199 } 200 this.remove(key); 201 } 202 } 203 204 207 protected boolean doContainsKey(final Object key) 208 { 209 final File file = fileFromKey(key); 210 if (file == null) 211 { 212 return false; 213 } 214 return file.exists(); 215 } 216 217 220 protected Enumeration doGetKeys() 221 { 222 final FSEnumeration enum = new FSEnumeration(); 223 this.addKeys(enum, this.m_directoryFile); 224 return enum; 225 } 226 227 231 protected int doGetSize() 232 { 233 return countKeys(this.m_directoryFile); 234 } 235 236 protected void addKeys(FSEnumeration enum, File directory) 237 { 238 final int subStringBegin = this.m_directoryFile.getAbsolutePath().length() + 1; 239 final File[] files = directory.listFiles(); 240 for (int i=0; i<files.length; i++) 241 { 242 if (files[i].isDirectory()) 243 { 244 this.addKeys(enum, files[i]); 245 } 246 else 247 { 248 enum.add(this.decode(files[i].getAbsolutePath().substring(subStringBegin))); 249 } 250 } 251 } 252 253 protected int countKeys(File directory) 254 { 255 int count = 0; 256 final File[] files = directory.listFiles(); 257 for (int i=0; i<files.length; i++) 258 { 259 if (files[i].isDirectory()) 260 { 261 count += this.countKeys(files[i]); 262 } 263 else 264 { 265 count ++; 266 } 267 } 268 return count; 269 } 270 271 final class FSEnumeration implements Enumeration 272 { 273 private String[] array; 274 private int index; 275 private int length; 276 277 FSEnumeration() 278 { 279 this.array = new String[16]; 280 this.length = 0; 281 this.index = 0; 282 } 283 284 public void add(String key) 285 { 286 if (this.length == array.length) 287 { 288 String[] newarray = new String[this.length + 16]; 289 System.arraycopy(this.array, 0, newarray, 0, this.array.length); 290 this.array = newarray; 291 } 292 this.array[this.length] = key; 293 this.length++; 294 } 295 296 public boolean hasMoreElements() 297 { 298 return (this.index < this.length); 299 } 300 301 public Object nextElement() 302 { 303 if (this.hasMoreElements()) 304 { 305 this.index++; 306 return this.array[index-1]; 307 } 308 return null; 309 } 310 } 311 312 313 protected File fileFromKey(final Object key) 314 { 315 File file = new File(this.m_directoryFile, this.encode(key.toString())); 316 File parent = file.getParentFile(); 317 if (parent != null) parent.mkdirs(); 318 return file; 319 } 320 321 public String getString(final Object key) 322 throws IOException 323 { 324 final File file = this.fileFromKey(key); 325 if (file != null) 326 { 327 return this.deserializeString(file); 328 } 329 330 return null; 331 } 332 333 public void free() 334 { 335 } 337 338 341 protected void doFree() 342 { 343 } 344 345 public synchronized Object getObject(final Object key) 346 throws IOException, ClassNotFoundException 347 { 348 Sync sync = this.lock.writeLock(); 349 try 350 { 351 sync.acquire(); 352 try 353 { 354 final File file = this.fileFromKey(key); 355 if (file != null) { 356 return this.deserializeObject(file); 357 } 358 } 359 finally 360 { 361 sync.release(); 362 } 363 } 364 catch (InterruptedException ignore) 365 { 366 } 367 368 return null; 369 } 370 371 377 protected String decode( String filename ) 378 { 379 if (filename.length() > 127) 382 { 383 int c = filename.length() / 127; 384 int pos = c * 127; 385 StringBuffer out = new StringBuffer(filename); 386 while (pos > 0) { 387 out.delete(pos,pos+1); 388 pos -= 127; 389 } 390 filename = out.toString(); 391 } 392 return java.net.URLDecoder.decode( filename ); 394 } 396 397 398 static BitSet charactersDontNeedingEncoding; 399 static final int characterCaseDiff = ('a' - 'A'); 400 401 402 static 403 { 404 charactersDontNeedingEncoding = new BitSet(256); 405 int i; 406 for (i = 'a'; i <= 'z'; i++) 407 { 408 charactersDontNeedingEncoding.set(i); 409 } 410 for (i = 'A'; i <= 'Z'; i++) 411 { 412 charactersDontNeedingEncoding.set(i); 413 } 414 for (i = '0'; i <= '9'; i++) 415 { 416 charactersDontNeedingEncoding.set(i); 417 } 418 charactersDontNeedingEncoding.set('-'); 419 charactersDontNeedingEncoding.set('_'); 420 charactersDontNeedingEncoding.set('('); 421 charactersDontNeedingEncoding.set(')'); 422 } 423 424 432 protected String encode(String s) 433 { 434 final StringBuffer out = new StringBuffer( s.length() ); 435 final ByteArrayOutputStream buf = new ByteArrayOutputStream( 32 ); 436 final OutputStreamWriter writer = new OutputStreamWriter( buf ); 437 for (int i = 0; i < s.length(); i++) 438 { 439 int c = s.charAt(i); 440 if (charactersDontNeedingEncoding.get(c)) 441 { 442 out.append((char)c); 443 } 444 else 445 { 446 try 447 { 448 writer.write(c); 449 writer.flush(); 450 } 451 catch(IOException e) 452 { 453 buf.reset(); 454 continue; 455 } 456 byte[] ba = buf.toByteArray(); 457 for (int j = 0; j < ba.length; j++) 458 { 459 out.append('%'); 460 char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16); 461 if (Character.isLetter(ch)) 464 { 465 ch -= characterCaseDiff; 466 } 467 out.append(ch); 468 ch = Character.forDigit(ba[j] & 0xF, 16); 469 if (Character.isLetter(ch)) 470 { 471 ch -= characterCaseDiff; 472 } 473 out.append(ch); 474 } 475 buf.reset(); 476 } 477 } 478 479 int pos = 127; 482 while (out.length() > pos) { 483 out.insert(pos, File.separatorChar); 484 pos += 127; 485 } 486 return out.toString(); 487 } 488 489 496 public void serializeString(File file, String string) 497 throws IOException 498 { 499 final Writer fw = new FileWriter(file); 500 try 501 { 502 fw.write(string); 503 fw.flush(); 504 } 505 finally 506 { 507 if (fw != null) fw.close(); 508 } 509 } 510 511 519 public String deserializeString(File file) 520 throws IOException 521 { 522 int len; 523 char[] chr = new char[4096]; 524 final StringBuffer buffer = new StringBuffer(); 525 final FileReader reader = new FileReader(file); 526 try 527 { 528 while ((len = reader.read(chr)) > 0) 529 { 530 buffer.append(chr, 0, len); 531 } 532 } 533 finally 534 { 535 if (reader != null) reader.close(); 536 } 537 return buffer.toString(); 538 } 539 540 547 548 public void serializeObject(File file, Object object) 549 throws IOException 550 { 551 FileOutputStream fos = new FileOutputStream(file); 552 try 553 { 554 ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos)); 555 oos.writeObject(object); 556 oos.flush(); 557 } 558 finally 559 { 560 if (fos != null) fos.close(); 561 } 562 } 563 564 571 public Object deserializeObject(File file) 572 throws IOException, ClassNotFoundException 573 { 574 FileInputStream fis = new FileInputStream(file); 575 Object object = null; 576 try 577 { 578 ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis)); 579 object = ois.readObject(); 580 } 581 finally 582 { 583 if (fis != null) fis.close(); 584 } 585 return object; 586 } 587 588 598 public String getFullFilename(File file) 599 { 600 try 601 { 602 return file.getCanonicalPath(); 603 } 604 catch (Exception e) 605 { 606 return file.getAbsolutePath(); 607 } 608 } 609 610 } 611 | Popular Tags |