1 2 24 25 package com.lutris.util; 26 import java.io.File ; 27 import java.io.FileInputStream ; 28 import java.io.FileOutputStream ; 29 import java.io.FilenameFilter ; 30 import java.io.IOException ; 31 import java.io.InputStream ; 32 import java.io.ObjectInputStream ; 33 import java.io.ObjectOutputStream ; 34 import java.io.ObjectStreamClass ; 35 import java.io.Serializable ; 36 import java.io.StreamCorruptedException ; 37 import java.lang.reflect.Constructor ; 38 import java.util.NoSuchElementException ; 39 40 45 public class FilePersistentStore implements PersistentStore { 46 47 private final String DEFAULT_DIR_PROPERTY = "user.dir"; 48 private final String FILE_SEPARATOR_PROPERTY = "file.separator"; 49 private final String SERIAL_SUFFIX = ".srl"; 51 52 55 private class FilePersistentStoreKeys implements java.util.Enumeration { 56 57 private String [] keys; 58 private int idx = 0; 59 60 63 FilePersistentStoreKeys() { 64 keys = new String [0]; 65 } 66 67 73 FilePersistentStoreKeys(String [] keys) { 74 this.keys = keys; 75 } 76 77 78 84 public boolean hasMoreElements() { 85 return (idx < keys.length); 86 } 87 88 96 public Object nextElement() throws NoSuchElementException { 97 if (!hasMoreElements()) 98 throw new java.util.NoSuchElementException ("no more elements"); 99 100 String k = keys[idx]; 101 idx++; 102 return k; 103 } 104 } 105 106 109 private class FileStoreFilter implements FilenameFilter { 110 private String suffix = ""; 111 FileStoreFilter(String suffix) { 112 this.suffix = suffix; 113 } 114 public boolean accept(File dir, String name) { 115 return name.endsWith(suffix); 116 } 117 } 118 119 120 123 private String fileSeparator; 124 125 130 private String storeDirectory; 131 132 135 private Constructor objectInputStreamConstructor; 136 137 140 private ClassLoader loader; 141 142 158 public FilePersistentStore() 159 throws PersistentStoreException { 160 init(null, null); 161 } 162 163 181 public FilePersistentStore(ClassLoader loader) 182 throws IOException , SecurityException , PersistentStoreException { 183 init(null, loader); 184 } 185 186 205 public FilePersistentStore(String storeDirectory) 206 throws PersistentStoreException { 207 init(storeDirectory, null); 208 } 209 210 229 public FilePersistentStore(String storeDirectory, ClassLoader loader) 230 throws PersistentStoreException { 231 init(storeDirectory, loader); 232 } 233 234 250 private void init(String storeDirectory, ClassLoader loader) 251 throws PersistentStoreException { 252 try { 253 this.loader = loader; 254 fileSeparator = System.getProperty(FILE_SEPARATOR_PROPERTY); 255 if (storeDirectory == null) { 256 setStoreDirectory(fileSeparator + "tmp"); 257 } else { 258 setStoreDirectory(storeDirectory); 259 } 260 } catch (Exception e) { 261 throw new PersistentStoreException(e); 262 } 263 } 264 265 281 private void setStoreDirectory(String storeDirectory) 282 throws IOException , SecurityException { 283 File f = new File (storeDirectory); 284 if (f.exists() && !f.isDirectory()) 285 throw new IOException (storeDirectory + 286 " already exists but is not a directory."); 287 if (!f.exists() && !f.mkdirs()) 288 throw new IOException ("Unable to create directory " + 289 storeDirectory); 290 this.storeDirectory = storeDirectory; 291 } 292 293 294 301 public String getStoreDirectory() { 302 return this.storeDirectory; 303 } 304 305 313 private String filename(String key) { 314 return storeDirectory + fileSeparator + convertKeyToHex(key) + SERIAL_SUFFIX; 315 } 316 317 320 private static final char[] HexChars = { 321 '0', '1', '2', '3', '4', '5', '6', '7', 322 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 323 }; 324 325 326 338 private String convertKeyToHex(String key) { 339 byte [] bytes = key.getBytes(); 340 StringBuffer sb = new StringBuffer (); 341 int i; 342 for (i=0; i < bytes.length; i++) { 343 sb.append(HexChars[(bytes[i] >> 4) & 0xf]); 344 sb.append(HexChars[bytes[i] & 0xf]); 345 } 346 return new String (sb); 347 } 348 349 359 private String convertHexToKey(String hex) { 360 char [] chars = new char[hex.length()]; 361 hex.getChars(0, hex.length(), chars, 0); 362 StringBuffer sb = new StringBuffer (); 363 for (int i=0; i<chars.length/2; i++) { 364 int idx = 2*i; 365 sb.append((char)((hexCharToByte(chars[idx])<<4) + 366 (hexCharToByte(chars[idx+1])))); 367 } 368 return new String (sb); 369 } 370 371 377 private byte hexCharToByte(char c) { 378 switch (c) { 379 case '1': 380 return (byte)1; 381 case '2': 382 return (byte)2; 383 case '3': 384 return (byte)3; 385 case '4': 386 return (byte)4; 387 case '5': 388 return (byte)5; 389 case '6': 390 return (byte)6; 391 case '7': 392 return (byte)7; 393 case '8': 394 return (byte)8; 395 case '9': 396 return (byte)9; 397 case 'a': 398 case 'A': 399 return (byte)10; 400 case 'b': 401 case 'B': 402 return (byte)11; 403 case 'c': 404 case 'C': 405 return (byte)12; 406 case 'd': 407 case 'D': 408 return (byte)13; 409 case 'e': 410 case 'E': 411 return (byte)14; 412 case 'f': 413 case 'F': 414 return (byte)15; 415 case '0': 416 default: 417 return (byte)0; 418 } 419 } 420 421 434 public void store(String key, Serializable obj) 435 throws PersistentStoreException { 436 if (exists(key)) 437 throw new 438 PersistentStoreException("An object is already stored as " + 439 key); 440 FileOutputStream out = null; 441 try { 442 out = new FileOutputStream (filename(key)); 443 ObjectOutputStream objOut = new ObjectOutputStream (out); 444 objOut.writeObject(obj); 445 objOut.flush(); 446 out.close(); 447 } 448 catch (Exception ex) { 449 if (out != null) { 450 try { out.close(); } catch (Exception e) {} 451 } 452 delete(key); 453 throw new PersistentStoreException(ex); 454 } 455 } 456 457 458 470 public Object retrieve(String key) throws PersistentStoreException { 471 if (!exists(key)) { 472 return null; 473 } 474 try { 475 FileInputStream in = new FileInputStream (filename(key)); 476 LoaderObjectInputStream objIn = new LoaderObjectInputStream(in, loader); 477 Object obj = objIn.readObject(); 478 objIn.close(); 479 return obj; 480 } 481 catch (Exception ex) { 482 throw new PersistentStoreException(ex); 483 } 484 } 485 486 487 497 public boolean exists(String key) 498 throws PersistentStoreException { 499 File f = new File (filename(key)); 500 return f.exists(); 501 } 502 503 504 517 public Object remove(String key) throws PersistentStoreException { 518 Object obj = retrieve(key); 519 delete(key); 520 return obj; 521 } 522 523 524 532 public void delete(String key) { 533 File f = new File (filename(key)); 534 if (f.exists()) { 535 f.delete(); 536 } 537 } 538 539 540 547 public java.util.Enumeration keys() throws PersistentStoreException { 548 File dir = new File (storeDirectory); 549 FileStoreFilter filter = new FileStoreFilter(SERIAL_SUFFIX); 550 String [] hexKeys = dir.list(filter); 551 String [] keys = new String [hexKeys.length]; 552 for (int idx=0; idx<hexKeys.length; idx++) { 553 int suffixIdx = hexKeys[idx].lastIndexOf(SERIAL_SUFFIX); 555 if (suffixIdx >= 0) 556 hexKeys[idx] = hexKeys[idx].substring(0, suffixIdx); 557 keys[idx] = convertHexToKey(hexKeys[idx]); 559 } 560 561 return new FilePersistentStoreKeys(keys); 562 } 563 564 } 565 566 class LoaderObjectInputStream extends ObjectInputStream { 568 569 private ClassLoader loader; 570 571 public LoaderObjectInputStream(InputStream in, ClassLoader loader) 572 throws IOException , StreamCorruptedException { 573 super(in); 574 this.loader = loader; 575 } 576 577 597 protected Class resolveClass(ObjectStreamClass v) 598 throws IOException , ClassNotFoundException { 599 if (loader != null) { 600 return loader.loadClass(v.getName()); 601 } else { 602 return super.resolveClass(v); 603 } 604 } 605 606 } 607 | Popular Tags |