1 18 19 package org.objectweb.jac.aspects.persistence; 20 21 import gnu.regexp.RE; 22 import gnu.regexp.REException; 23 import java.util.Arrays ; 24 import java.util.Collection ; 25 import java.util.Date ; 26 import java.util.HashMap ; 27 import java.util.Hashtable ; 28 import java.util.Iterator ; 29 import java.util.Map ; 30 import java.util.Vector ; 31 import org.apache.log4j.Logger; 32 import org.objectweb.jac.core.AspectComponent; 33 import org.objectweb.jac.core.BaseProgramListener; 34 import org.objectweb.jac.core.Collaboration; 35 import org.objectweb.jac.core.MethodPointcut; 36 import org.objectweb.jac.core.NameRepository; 37 import org.objectweb.jac.core.Naming; 38 import org.objectweb.jac.core.ObjectRepository; 39 import org.objectweb.jac.core.SerializedJacObject; 40 import org.objectweb.jac.core.Wrappee; 41 import org.objectweb.jac.core.Wrapper; 42 import org.objectweb.jac.core.Wrapping; 43 import org.objectweb.jac.core.rtti.ClassItem; 44 import org.objectweb.jac.core.rtti.CollectionItem; 45 import org.objectweb.jac.core.rtti.FieldItem; 46 import org.objectweb.jac.util.ExtArrays; 47 48 51 52 public class PersistenceAC extends AspectComponent implements PersistenceConf { 53 54 static Logger logger = Logger.getLogger("persistence"); 55 static Logger loggerCache = Logger.getLogger("persistence.cache"); 56 static Logger loggerNaming = Logger.getLogger("persistence.naming"); 57 58 60 public static final String ROOT = "root"; 61 62 63 public static final String PERSISTENT = "persistent"; 64 65 public static final String VALUE_CONVERTER = "valueConverter"; 66 public static final String PRELOAD_FIELD = "preloadField"; 67 68 public static final String DISABLE_PRELOAD = "PersistenceAC.DISABLE_PRELOAD"; 69 public static final String NO_CACHE = "PersistenceAC.NO_CACHE"; 70 public static final String RESTORE = "PersistenceAC.RESTORE"; 71 72 Hashtable oids = new Hashtable (); 74 Hashtable objects = new Hashtable (); 76 77 private boolean connected = false; 78 79 81 protected StorageSpec defaultStorage = null; 82 83 protected Vector storages = new Vector (); 84 class StorageSpec { 85 StorageSpec(String id, 86 ClassItem storageClass, String [] parameters) 87 { 88 this.id = id; 89 this.storageClass = storageClass; 90 this.parameters = parameters; 91 } 92 public void addClasses(String classExpr) throws REException { 93 classExprs = (RE[]) 94 ExtArrays.add( 95 MethodPointcut.buildRegexp(classExpr), 96 classExprs); 97 } 98 private RE[] classExprs = new RE[0]; 99 private Storage storage; 100 private String [] parameters; 101 private ClassItem storageClass; 102 private String id; 103 synchronized Storage getStorage() { 104 if (storage == null) { 105 if (storageClass == null) { 106 throw new RuntimeException ("Persistence: storage is not configured"); 107 } 108 logger.debug( 109 getClass().getName() + ".connectStorage(" 110 + storageClass + "," 111 + (parameters != null 112 ? Arrays.asList(parameters).toString() 113 : "null") 114 + ")"); 115 try { 116 storage = 117 (Storage)storageClass.newInstance( 118 ExtArrays.add(0,PersistenceAC.this,parameters,Object .class)); 119 } catch (Exception e) { 120 logger.error("Failed to connect to storage ", e); 121 } 122 } 123 return storage; 124 } 125 128 boolean match(ClassItem cli) { 129 if (classExprs==null) 130 return false; 131 String className = cli.getName(); 132 for (int i=0; i<classExprs.length; i++) { 133 if (classExprs[i].isMatch(className)) 134 return true; 135 } 136 return false; 137 } 138 String getId() { 139 return id; 140 } 141 } 142 143 147 protected Storage getStorage(String id) { 148 if (id==null) { 149 return defaultStorage.getStorage(); 150 } else { 151 Iterator it = storages.iterator(); 152 while (it.hasNext()) { 153 StorageSpec storageSpec = (StorageSpec)it.next(); 154 if (id.equals(storageSpec.getId())) 155 return storageSpec.getStorage(); 156 } 157 logger.error("No such storage: "+id); 158 return null; 159 } 160 } 161 162 protected Storage[] getStorages() { 163 Storage[] result = 164 new Storage[storages.size()+ (defaultStorage!=null ? 1 : 0)]; 165 Iterator it = storages.iterator(); 166 int i=0; 167 while (it.hasNext()) { 168 StorageSpec storageSpec = (StorageSpec)it.next(); 169 result[i] = storageSpec.getStorage(); 170 i++; 171 } 172 if (defaultStorage!=null) 173 result[i] = defaultStorage.getStorage(); 174 return result; 175 } 176 177 179 181 184 public void onExit() { 185 Storage[] storages = getStorages(); 186 for (int i=0; i<storages.length; i++){ 187 storages[i].close(); 188 } 189 } 190 191 193 195 public void setValueConverter(ClassItem cl, ClassItem converterClass) { 196 StringConverter converter; 197 try { 198 converter = (StringConverter)converterClass.newInstance(); 199 } catch (ClassCastException e) { 200 error("Converter class "+converterClass.getName()+ 201 " does not implement StringConverter"); 202 return; 203 } catch (Exception e) { 204 error("Failed to instantiate value converter "+converterClass.getName()); 205 return; 206 } 207 cl.setAttribute(VALUE_CONVERTER, converter); 208 } 209 210 220 221 public void checkUnload() { 222 223 Iterator it = collectionIdles.entrySet().iterator(); 224 while (it.hasNext()) { 225 Map.Entry entry = (Map.Entry ) it.next(); 226 227 CollectionItem coll = (CollectionItem) entry.getKey(); 228 long idle = ((Long ) entry.getValue()).longValue(); 229 230 loggerCache.debug("checking collection " + coll + " (idle=" + idle + ")"); 231 ClassItem cl = coll.getClassItem(); 232 Object [] objects = ObjectRepository.getMemoryObjects(cl); 233 for (int i = 0; i < objects.length; i++) { 234 Wrappee wrappee = (Wrappee) coll.get(objects[i]); 235 loggerCache.debug("checking wrappee " 236 + NameRepository.get().getName(objects[i]) 237 + "." + wrappee); 238 Date useDate = 239 (Date ) Wrapping.invokeRoleMethod( 240 wrappee, 241 CollectionWrapper.class, 242 "getUseDate", 243 ExtArrays.emptyObjectArray); 244 Date now = new Date (); 245 long lastUsed = now.getTime() - useDate.getTime(); 246 loggerCache.debug("last used=" + lastUsed + " ms ago"); 247 if (lastUsed > idle) { 248 loggerCache.debug("unloading collection " 249 + NameRepository.get().getName(objects[i]) 250 + "." + coll); 251 Wrapping.invokeRoleMethod( 252 wrappee, 253 CollectionWrapper.class, 254 "unload", 255 ExtArrays.emptyObjectArray); 256 } 257 } 258 } 259 } 260 261 long checkPeriod = -1; 262 263 public void defineMaxIdleCheckPeriod(long period) { 264 checkPeriod = period; 265 } 266 267 HashMap collectionIdles = new HashMap (); 268 269 public void maxIdle(CollectionItem collection, long maxIdle) { 270 collectionIdles.put(collection, new Long (maxIdle)); 271 } 272 273 public void whenConfigured() { 274 if (checkPeriod == -1) { 275 checkPeriod = 200000; 276 } 277 defineTimer( 278 checkPeriod, 279 cr.getClass(PersistenceAC.class).getMethod( 280 "checkUnload"), 281 new Object [] { 282 }); 283 } 284 285 public void configureStorage(ClassItem storageClass, 286 String [] storageParameters) 287 { 288 try { 289 this.defaultStorage = 290 new StorageSpec(null,storageClass,storageParameters); 291 this.defaultStorage.addClasses("ALL"); 292 } catch (REException e) { 293 error(e.toString()); 294 } 295 } 296 297 public void configureStorage(String id, 298 ClassItem storageClass, 299 String [] storageParameters) 300 { 301 storages.add( 302 new StorageSpec(id,storageClass,storageParameters)); 303 } 304 305 public void setStorage(String classExpr, String storageId) { 306 try { 307 getStorageSpec(storageId).addClasses(classExpr); 308 } catch (REException e) { 309 error(e.toString()); 310 } 311 } 312 313 314 Vector staticPointcuts = new Vector (); 315 316 public void registerStatics(String classExpr, String nameExpr) { 317 318 logger.debug("registerStatics " + classExpr + " " + nameExpr); 319 staticPointcuts.add( 320 pointcut( 321 nameExpr, 322 classExpr, 323 "CONSTRUCTORS", 324 PersistenceWrapper.class.getName(), 325 null, 326 SHARED)); 327 } 328 329 330 Vector persistentPointcuts = new Vector (); 331 332 public void makePersistent(String classExpr, String nameExpr) { 333 persistentPointcuts.add( 336 pointcut( 337 nameExpr, 338 classExpr, 339 "MODIFIERS({!transient}) || COLACCESSORS({!transient}) || REFACCESSORS({!transient}) && !CONSTRUCTORS", 340 PersistenceWrapper.class.getName(), 341 null, 342 NOT_SHARED)); 343 } 344 345 350 boolean isPersistent(Wrappee wrappee) { 351 Iterator it = persistentPointcuts.iterator(); 352 ClassItem cli = cr.getClass(wrappee); 353 while (it.hasNext()) { 354 MethodPointcut pointcut = (MethodPointcut) it.next(); 355 if (pointcut.isClassMatching(wrappee, cli)) 356 return true; 357 } 358 return false; 359 } 360 361 367 boolean isStatic(Wrappee wrappee, String objName) { 368 ClassItem cli = cr.getClass(wrappee); 369 Iterator it = staticPointcuts.iterator(); 371 while (it.hasNext()) { 372 MethodPointcut pointcut = (MethodPointcut) it.next(); 373 if (pointcut.isClassMatching(wrappee, cli) 374 && pointcut.isNameMatching(wrappee, objName)) 375 return true; 376 } 377 return false; 378 } 379 380 382 388 public Storage getStorage(ClassItem cli) { 389 Iterator it = storages.iterator(); 390 while (it.hasNext()) { 391 StorageSpec storageSpec = (StorageSpec)it.next(); 392 if (storageSpec.match(cli)) { 393 return storageSpec.getStorage(); 394 } 395 } 396 if (defaultStorage!=null) 397 return defaultStorage.getStorage(); 398 throw new RuntimeException ( 399 "Cannot find storage for class "+cli.getName()); 400 } 401 402 public StorageSpec getStorageSpec(String storageId) { 403 Iterator it = storages.iterator(); 404 while (it.hasNext()) { 405 StorageSpec storageSpec = (StorageSpec)it.next(); 406 if (storageSpec.getId().equals(storageId)) { 407 return storageSpec; 408 } 409 } 410 throw new RuntimeException (); 411 } 412 413 419 public Storage getStorage(Object obj) { 420 return getStorage(cr.getClass(obj)); 421 } 422 423 429 public void whenObjectMiss(String name) { 430 loggerNaming.debug("whenObjectMiss " + name); 431 Storage[] storages = getStorages(); 433 for (int i=0; i<storages.length; i++){ 434 try { 435 OID oid = storages[i].getOIDFromName(name); 436 if (oid != null) { 437 loggerNaming.debug("found name " + name + " -> " + oid); 438 attrdef(BaseProgramListener.FOUND_OBJECT, getObject(oid, null)); 439 return; 440 } 441 } catch (Exception e) { 442 logger.error("whenObjectMiss "+name,e); 443 } 444 } 445 } 446 447 450 public String whenNameObject(Object object, String name) { 451 loggerNaming.debug("whenNameObject " + object + " <- " + name); 452 if (!(object instanceof Wrappee)) 453 return name; 454 Wrappee wrappee = (Wrappee) object; 455 if (isPersistent(wrappee) && !isStatic(wrappee, name)) { 456 try { 457 name = getStorage(object).newName(object.getClass().getName()); 458 } catch (Exception e) { 459 logger.error("Failed to name object "+object,e); 460 } 461 loggerNaming.debug(" -> " + name); 462 } 463 return name; 464 } 465 466 public void getNameCounters(Map counters) { 467 try { 468 Storage[] storages = getStorages(); 469 for(int i=0; i<storages.length; i++) { 470 counters.putAll(storages[i].getNameCounters()); 471 } 472 } catch (Exception e) { 473 logger.error("getNameCounters failed",e); 474 } 475 } 476 477 public synchronized void updateNameCounters(Map counters) { 478 try { 479 Storage[] storages = getStorages(); 480 for(int i=0; i<storages.length; i++) { 481 storages[i].updateNameCounters(counters); 482 } 483 } catch (Exception e) { 484 logger.error("updateNameCounters failed",e); 485 } 486 } 487 488 494 protected void registerObject(OID oid, Object object) { 495 logger.debug("registerObject(" + oid + "," + object.getClass() + ")"); 496 Object currentObject = objects.get(oid); 497 if (currentObject!=null) { 498 if (currentObject!=object) { 499 logger.error("registerObject "+oid+","+object,new Exception ()); 500 throw new Error ( 501 "PersistenceAC.registerObject("+oid+","+object+"): an object "+ 502 currentObject+" is already registered with this oid"); 503 } else { 504 logger.warn("PersistenceAC.registerObject("+oid+","+object+ 505 "): already registered"); 506 } 507 } 508 objects.put(oid, object); 509 oids.put(object, oid); 510 logger.debug("object " + oid + " added"); 511 } 512 513 522 synchronized Object getObject(OID oid, Object newObject) { 523 Object result = objects.get(oid); 524 try { 525 if (result != null) { 526 logger.debug("Object " + oid + " found in cache -> " + result); 527 return result; 528 } else { 529 logger.debug(this + ".Object " + oid 530 + " NOT found in cache; Loading from storage\n"); 531 Storage storage = oid.getStorage(); 532 String lClassID = storage.getClassID(oid); 533 if (lClassID == null) 534 logger.error("getClassID(" + oid + ") -> NULL"); 535 ClassItem lClass = cr.getClass(lClassID); 536 logger.debug("Class = " + lClass.getName()); 537 if (newObject == null) { 538 Naming.setName(storage.getNameFromOID(oid)); 539 Collaboration collab = Collaboration.get(); 540 collab.addAttribute(RESTORE, Boolean.TRUE); 541 try { 542 newObject = lClass.newInstance(); 543 } finally { 544 collab.removeAttribute(RESTORE); 545 } 546 } 547 Wrappee wrappee = (Wrappee) newObject; 548 registerObject(oid, wrappee); 550 Wrapping 552 .invokeRoleMethod( 553 wrappee, 554 PersistenceWrapper.class, 555 "loadAllFields", 556 new Object [] {oid}); 557 Wrapping.invokeRoleMethod( 559 wrappee, 560 PersistenceWrapper.class, 561 "wrapCollections", 562 new Object [] { oid, Boolean.FALSE }); 563 logger.debug("New object " + oid + " : " + newObject); 564 logger.debug("Object loaded"); 565 result = newObject; 566 } 567 } catch (Exception e) { 568 logger.error("getObject "+oid,e); 569 } 570 return result; 571 } 572 573 public OID getOID(Wrappee wrappee) { 574 return (OID) oids.get(wrappee); 575 } 576 577 584 585 public void whenDeserialized(SerializedJacObject orgObject) { 586 594 } 595 596 604 605 public void whenSerialized(SerializedJacObject finalObject) { 606 613 } 614 615 618 public void whenGetObjects(Collection objects, ClassItem cl) { 619 logger.debug("PersistenceAC.whenGetObjects " + cl); 620 if (cl == null) 621 return; 622 try { 623 logger.debug("PersistenceAC.whenGetObjects " + cl); 624 Collection oids = getStorage(cl).getObjects(cl); 625 Iterator i = oids.iterator(); 626 while (i.hasNext()) { 627 OID oid = (OID) i.next(); 628 Object object = getObject(oid, null); 629 if (!objects.contains(object)) 630 objects.add(object); 631 } 632 } catch (Exception e) { 633 e.printStackTrace(); 634 } 635 } 636 637 public boolean beforeRunningWrapper( 638 Wrapper wrapper, 639 String wrappingMethod) { 640 if (attr("Persistence.disabled") != null) { 641 return false; 642 } else { 643 return true; 644 } 645 } 646 647 public void whenDeleted(Wrappee object) { 648 try { 649 OID oid = getOID(object); 650 Storage storage = oid.getStorage(); 651 if (storage != null) { 652 if (oid != null) 653 storage.deleteObject(oid); 654 whenFree(object); 655 } 656 } catch (Exception e) { 657 logger.error("whenDeleted "+object+" failed",e); 658 } 659 } 660 661 public void whenFree(Wrappee object) { 662 try { 663 OID oid = getOID(object); 664 Storage storage = oid.getStorage(); 665 if (storage != null) { 666 if (oid != null) 667 oids.remove(oid); 668 if (objects.contains(object)) 669 objects.remove(object); 670 } 671 } catch (Exception e) { 672 logger.error("whenFree "+object+" failed",e); 673 } 674 } 675 676 public void preloadField(FieldItem field) { 677 field.setAttribute(PRELOAD_FIELD, Boolean.TRUE); 678 } 679 680 public void preloadAllFields(ClassItem cl) { 681 FieldItem[] fields = cl.getFields(); 682 if (fields != null) { 683 for (int i = 0; i < fields.length; i++) { 684 fields[i].setAttribute(PRELOAD_FIELD, Boolean.TRUE); 685 } 686 } 687 } 688 689 public static boolean isFieldPreloaded(FieldItem field) { 690 Boolean value = (Boolean ) field.getAttribute(PRELOAD_FIELD); 691 return value != null && value.booleanValue(); 692 } 693 694 public void disableCache(CollectionItem collection) { 695 collection.setAttribute(NO_CACHE, "true"); 696 } 697 698 public String [] getDefaultConfigs() { 699 return new String [] { 700 "org/objectweb/jac/aspects/persistence/persistence.acc", 701 "org/objectweb/jac/aspects/user/persistence.acc" }; 702 } 703 704 public static class NoSuchWrapperException extends RuntimeException { 705 } 706 707 715 public LongOID parseLongOID(String str, Storage defaultStorage) { 716 int index = str.indexOf('@'); 717 if (index==-1) { 718 return 719 new LongOID(defaultStorage,Long.parseLong(str)); 720 } else { 721 return 722 new LongOID( 723 getStorage(str.substring(index+1)), 724 Long.parseLong(str.substring(0,index))); 725 } 726 } 727 } 728 | Popular Tags |