001 /* 002 Copyright (C) 2002-2003 Laurent Martelli <laurent@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.aspects.persistence; 019 020 import java.util.Arrays; 021 import java.util.Collection; 022 import java.util.HashMap; 023 import java.util.HashSet; 024 import java.util.Iterator; 025 import java.util.List; 026 import java.util.Map; 027 import java.util.Set; 028 import java.util.Vector; 029 import org.aopalliance.intercept.ConstructorInvocation; 030 import org.aopalliance.intercept.MethodInvocation; 031 import org.apache.log4j.Logger; 032 import org.objectweb.jac.core.AspectComponent; 033 import org.objectweb.jac.core.Interaction; 034 import org.objectweb.jac.core.NameRepository; 035 import org.objectweb.jac.core.Wrappee; 036 import org.objectweb.jac.core.Wrapping; 037 import org.objectweb.jac.core.rtti.ClassItem; 038 import org.objectweb.jac.core.rtti.CollectionItem; 039 import org.objectweb.jac.core.rtti.FieldItem; 040 import org.objectweb.jac.core.rtti.MethodItem; 041 import org.objectweb.jac.util.ExtArrays; 042 043 /** 044 * This wrapper defines persistence extensions for objects that a 045 * defined persitent by a persistent aspect component. */ 046 047 public class PersistenceWrapper extends AbstractPersistenceWrapper { 048 static final Logger loggerRef = Logger.getLogger("persistence.ref"); 049 static final Logger loggerCol = Logger.getLogger("persistence.col"); 050 static final Logger loggerWrap = Logger.getLogger("persistence.wrap"); 051 052 public final static String[] toWrapForLists = 053 new String[] { 054 "add", 055 "addAll", 056 "clear", 057 "contains", 058 "get", 059 "remove", 060 "removeRange", 061 "set", 062 "size", 063 "indexOf", 064 "lastIndexOf", 065 "isEmpty", 066 // -- preloads -- 067 "toArray", "iterator", "clone" /*"equals"*/ 068 }; 069 070 public final static String[] toWrapForSets = 071 new String[] { "add", "clear", "contains", "remove", "size", "isEmpty", 072 // -- preloads -- 073 "toArray", "iterator", "clone" /*"equals"*/ 074 }; 075 076 public final static String[] toWrapForMaps = 077 new String[] { 078 "clear", 079 "isEmpty", 080 "size", 081 "containsKey", 082 "containsValue", 083 "get", 084 "put", 085 "remove", 086 // -- preloads -- 087 "keySet", "entrySet", "values", "clone" /*"equals"*/ 088 }; 089 090 public PersistenceWrapper(AspectComponent ac) { 091 super(ac); 092 } 093 094 boolean doStatics = false; 095 096 public PersistenceWrapper(AspectComponent ac, Boolean doStatics) { 097 super(ac); 098 this.doStatics = doStatics.booleanValue(); 099 } 100 101 //public static final String ATTR_ADDED = "persistence.added"; 102 103 // names of already loaded collections 104 private HashSet loadedVectors = new HashSet(); 105 // names of already loaded references 106 private HashSet loadedReferences = new HashSet(); 107 // oids of not yet loaded references (FieldItem -> oid) 108 private HashMap notloadedReferences = new HashMap(); 109 110 static boolean isWrapped(Wrappee wrappee, FieldItem field) { 111 Object value = field.get(wrappee); 112 if (value instanceof Wrappee 113 && Wrapping.isExtendedBy( 114 (Wrappee) value, 115 null, 116 CollectionWrapper.class)) { 117 logger.debug(field + " is wrapped"); 118 return true; 119 } else { 120 logger.debug(field + " is not wrapped"); 121 return false; 122 } 123 } 124 125 /** 126 * This wrapping method is called on static objects constructors as 127 * defined by the pointcut of <code>PersistenceAC</code>. 128 * 129 * @see PersistenceAC#registerStatics 130 */ 131 public Object handleStatic(Interaction interaction) { 132 logger.debug("handle static "+interaction.wrappee.getClass().getName()); 133 Object ret = interaction.proceed(); 134 //wrap(null,true); 135 try { 136 String name = NameRepository.get().getName(interaction.wrappee); 137 ClassItem cli = cr.getClass(interaction.wrappee); 138 Storage storage = getStorage(cli); 139 OID oid = storage.getOIDFromName(name); 140 if (oid == null) { 141 oid = storage.createObject(cli.getName()); 142 setOID(interaction.wrappee, oid); 143 storage.bindOIDToName(oid, name); 144 logger.debug(interaction.wrappee.getClass().getName() + " isNew"); 145 CollectionItem[] array = new CollectionItem[0]; 146 wrapCollections(interaction.wrappee, oid, true); 147 initAllFields(interaction.wrappee, oid); 148 } else { 149 setOID(interaction.wrappee, oid); 150 // Call loadAllFields before wrapCollections so that it 151 // preloads the OID of collections 152 loadAllFields(interaction.wrappee, oid); 153 wrapCollections(interaction.wrappee, oid, false); 154 } 155 } catch (Exception e) { 156 logger.error("handleStatic "+interaction,e); 157 } 158 return ret; 159 } 160 161 /** 162 * Makes an object persistent if it is not already. Is is assigned 163 * an OID, and its members are saved in the storage. 164 * @param wrappee the object to make persistent 165 */ 166 public OID makePersistent(Wrappee wrappee) throws Exception { 167 OID oid = null; 168 169 logger.debug("makePersistent(" + wrappee + ")"); 170 oid = getOID(wrappee); 171 if (oid!=null) { 172 logger.debug(wrappee + " is already persistent"); 173 } else { 174 ClassItem cli = cr.getClass(wrappee); 175 Storage storage = getStorage(cli); 176 oid = storage.createObject(cli.getName()); 177 setOID(wrappee, oid); 178 storage.bindOIDToName( 179 oid, 180 NameRepository.get().getName(wrappee)); 181 logger.debug(wrappee + " isNew"); 182 183 // Initialize loadedVectors and loadedReferences. 184 // It's important to do this as early as possible, in case 185 // someone accesses them. 186 187 FieldItem[] refs = cli.getReferences(); 188 for (int i = 0; i < refs.length; i++) { 189 loadedReferences.add(refs[i].getName()); 190 } 191 CollectionItem[] colls = cli.getCollections(); 192 for (int i = 0; i < colls.length; i++) { 193 loadedVectors.add(colls[i].getName()); 194 } 195 196 wrapCollections(wrappee, oid, true); 197 initAllFields(wrappee, oid); 198 } 199 200 return oid; 201 } 202 203 /** 204 * Load all the fields of an object from the storage and initialize 205 * the object. 206 * 207 * @param wrappee the object 208 */ 209 210 public void loadAllFields(Wrappee wrappee, OID oid) throws Exception { 211 logger.debug("loadAllFields(" + oid + ")"); 212 String lClassID = wrappee.getClass().getName(); 213 214 // Load all fields from the storage 215 ClassItem cli = cr.getClass(lClassID); 216 217 // this should be faster because only one call to the storage is done 218 FieldItem[] fields = cli.getFields(); 219 if (fields.length > 0) { 220 Storage storage = oid.getStorage(); 221 StorageField[] values = storage.getFields(oid, cli, fields); 222 for (int i = 0; i < values.length; i++) { 223 if (values[i] != null) { 224 FieldItem field = values[i].fieldID; 225 if (field.getActualField() != null) { 226 try { 227 boolean force = 228 PersistenceAC.isFieldPreloaded(field); 229 if (field.isPrimitive() 230 && values[i].value != null) { 231 // TODO: preload for primitive fields here 232 if (field.setConvert(wrappee, values[i].value)) { 233 logger.warn(oid+"."+field.getName()+ 234 " value converted from "+values[i].value.getClass()+ 235 " to "+field.getType()); 236 storage.updateField(oid, field, field.get(wrappee)); 237 } 238 } else if (field.isReference()) { 239 if (!field.hasAccessingMethods()) { 240 // load a reference if it has no getter 241 getReference(wrappee, oid, field); 242 } else { 243 // test if reference must be loaded here 244 // instead of being loaded when accessed 245 if (force) { 246 getReference(wrappee, oid, field); 247 } else { 248 logger.debug("storing OID for reference " 249 + field 250 + "=" 251 + values[i].value); 252 notloadedReferences.put( 253 field, 254 values[i].value); 255 } 256 } 257 } else if (field instanceof CollectionItem) { 258 if (!((CollectionItem) field) 259 .isWrappable(wrappee)) { 260 logger.debug("loadAllFields -> invoking getCollection for " 261 + field); 262 Wrapping.invokeRoleMethod( 263 wrappee, 264 "getCollection", 265 new Object[] { field }); 266 } else { 267 // test if collection must be loaded here 268 // instead of being loaded when accessed 269 if (force) { 270 getCollection( 271 wrappee, oid, 272 (CollectionItem) field); 273 } else { 274 logger.debug("storing OID for collection " 275 + field 276 + "=" 277 + values[i].value); 278 notloadedReferences.put( 279 field, 280 values[i].value); 281 } 282 } 283 } 284 } catch (Exception e) { 285 logger.error( 286 "Failed to load field "+ field.getLongName() 287 + " for " + oid, 288 e); 289 } 290 } 291 } 292 } 293 } 294 } 295 296 /** 297 * This role method wraps all the collection of the current wrappee 298 * so that they will trigger the needed loads from the storage when 299 * they are accessed. 300 * 301 * @param wrappee the object whose collections to wrap 302 * @param oid the oid of wrappee 303 * @param isNew must true if the object is newly created, false if 304 * loaded from storage 305 */ 306 public void wrapCollections(Wrappee wrappee, OID oid, boolean isNew) { 307 logger.debug("wrapCollections(" 308 + wrappee.getClass().getName() 309 + "), isNew=" + isNew); 310 // Wrap collections 311 try { 312 ClassItem cli = cr.getClass(wrappee); 313 Vector collectionsToInit = new Vector(); 314 CollectionItem[] collections = cli.getCollections(); 315 Storage storage = oid.getStorage(); 316 for (int i = 0; i < collections.length; i++) { 317 CollectionItem collection = collections[i]; 318 if (collection.isTransient()) 319 continue; 320 Object coll_value = collections[i].get(wrappee); 321 Class collType = collections[i].getType(); 322 if (coll_value == null) { 323 logger.warn( 324 "uninitialized collection " +collections[i].getLongName()+ 325 ". Do you have a constructor with no parameters?"); 326 // uninitialized field 327 if (collType.isArray()) { 328 coll_value = 329 java.lang.reflect.Array.newInstance( 330 collType.getComponentType(), 331 0); 332 } else { 333 try { 334 // This will fail if the declared type of the 335 // attribute is an interface 336 if (!collType.isInterface()) { 337 coll_value = collType.newInstance(); 338 } 339 } catch (Exception e) { 340 logger.error("wrapCollections "+wrappee+"("+oid+")",e); 341 } 342 } 343 collections[i].set(wrappee, coll_value); 344 } 345 Class actualCollType = coll_value.getClass(); 346 if (//isWrapped(collections[i]) || 347 actualCollType 348 == org.objectweb.jac.lib.java.util.Vector.class 349 || actualCollType 350 == org.objectweb.jac.lib.java.util.HashMap.class 351 || actualCollType 352 == org.objectweb.jac.lib.java.util.Hashtable.class 353 || actualCollType 354 == org.objectweb.jac.lib.java.util.HashSet.class) { 355 OID coll_oid; 356 if (isNew) { 357 coll_oid = 358 storage.createObject( 359 collections[i].getType().getName()); 360 } else { 361 coll_oid = 362 (OID) notloadedReferences.get(collections[i]); 363 if (coll_oid == null) 364 coll_oid = 365 (OID) storage.getField( 366 oid, 367 collections[i]); 368 else 369 notloadedReferences.remove(collections[i]); 370 // classes may change after objects were created and 371 // made persistent 372 if (coll_oid == null) { 373 coll_oid = initCollection(wrappee, oid, collections[i]); 374 logger.debug( 375 "OID of new collection "+collections[i]+": "+coll_oid); 376 } 377 } 378 379 logger.debug(collections[i] + " -> " + coll_oid); 380 381 boolean preloaded = 382 PersistenceAC.isFieldPreloaded(collections[i]); 383 String[] toWrap; 384 CollectionWrapper wrapper; 385 if (collections[i].isList()) { 386 // lists 387 logger.debug( 388 "wrapping List "+ collections[i].getName() 389 + " " + System.identityHashCode(coll_value)); 390 wrapper = 391 new ListWrapper(getAspectComponent(), 392 wrappee, 393 collection, 394 preloaded); 395 toWrap = toWrapForLists; 396 } else if (collections[i].isSet()) { 397 // sets 398 logger.debug("wrapping Set " + collections[i].getName()); 399 wrapper = 400 new SetWrapper(getAspectComponent(), 401 wrappee, 402 collection, 403 preloaded); 404 toWrap = toWrapForSets; 405 } else if (collections[i].isMap()) { 406 // maps 407 logger.debug("wrapping Map " + collections[i].getName()); 408 wrapper = 409 new MapWrapper(getAspectComponent(), 410 wrappee, 411 collection, 412 preloaded); 413 toWrap = toWrapForMaps; 414 } else { 415 throw new Exception("unsuported collection type"); 416 } 417 418 Wrappee coll = (Wrappee) coll_value; 419 setOID(coll, coll_oid); 420 if (coll != null) { 421 Wrapping.wrap(coll, null, wrapper); 422 Wrapping.wrap(coll, wrapper, toWrap); 423 //Wrapping.wrap(map,wrapper,"memorizeUseDate",preloads); 424 } else { 425 logger.warn( 426 "Collection " 427 + cli.getName() + "." + collections[i].getName() 428 + " is null, not wrapped"); 429 } 430 } 431 } 432 } catch (Exception e) { 433 logger.error("wrapCollections "+wrappee+"("+oid+")",e); 434 } 435 } 436 437 /** 438 * This wrapping method apply the persistence aspect for a given 439 * call on a persistent object. 440 * 441 * <p>It uses the RTTI aspect to determine the accessed and written 442 * field types.<p> 443 * 444 * Default behavior is:<p> 445 * 446 * <ul> 447 * <li>get the fields that are accessed for reading by this wrapped 448 * method 449 * <li>if the field is a collection, get the collection from the 450 * storage 451 * <li>if the field is a reference, get the referenced object from 452 * the storage 453 * <li>proceed the wrappee (and other wrappers if needed) 454 * <li>get the fields that were written by this wrapped method 455 * <li>if the field is a collection, update the storage depending 456 * on the wrapped method type (adder or remover) 457 * <li>if the field is a reference, update the storage to change 458 * the referenced object 459 * <li> if the field is a simple field, just update the storage 460 * with its value. 461 * </ul> 462 * 463 * @return the value returned by the wrapped method 464 * 465 * @see org.objectweb.jac.core.rtti.MethodItem#getAccessedFields() 466 * @see #getCollection(Wrappee,OID,CollectionItem) 467 * @see #getReference(Wrappee,OID,FieldItem) 468 * @see #addToCollection(Interaction,OID,CollectionItem,Object) 469 * @see #removeFromCollection(Interaction,OID,CollectionItem,Object) 470 * @see #setReference(Wrappee,OID,FieldItem,Wrappee) 471 * @see #setField(Wrappee,OID,FieldItem) 472 * @see org.objectweb.jac.core.rtti.MethodItem#getWrittenFields() 473 * @see org.objectweb.jac.core.rtti 474 */ 475 public Object applyPersistence(Interaction interaction) throws Exception { 476 if (interaction.method.isStatic()) { 477 return proceed(interaction); 478 } 479 OID oid = getOID(interaction.wrappee); 480 logger.debug( 481 "applyPersistence on " 482 + oid + "(" + interaction.wrappee + ")." 483 + interaction.method); 484 MethodItem method = (MethodItem) interaction.method; 485 FieldItem[] fields; 486 487 // the object may be wrapped but not persistent yet 488 if (oid != null) { 489 490 ClassItem cli = 491 cr.getClass(interaction.wrappee.getClass()); 492 // preload accessed fields and collections 493 fields = method.getAccessedFields(); 494 for (int i = 0; fields != null && i < fields.length; i++) { 495 FieldItem field = fields[i]; 496 497 if (!field.isTransient() && !field.isFinal()) { 498 if (field instanceof CollectionItem 499 && !isWrapped(interaction.wrappee, field)) { 500 getCollection( 501 interaction.wrappee, oid, 502 (CollectionItem) field); 503 } else if (field.isReference()) { 504 getReference(interaction.wrappee, oid, field); 505 } 506 } 507 } 508 } 509 510 Object result = proceed(interaction); 511 512 oid = getOID(interaction.wrappee); 513 if (oid != null) { 514 515 // save written fields 516 fields = method.getWrittenFields(); 517 for (int i = 0; fields!=null && i<fields.length; i++) { 518 FieldItem field = fields[i]; 519 if (!field.isTransient()) { 520 logger.debug("Save written field in " 521 + interaction.method + " : " 522 + field.getName()); 523 if (field.isReference()) { 524 setReference( 525 interaction.wrappee, oid, 526 field, 527 (Wrappee) field.get(interaction.wrappee)); 528 } else if (field instanceof CollectionItem) { 529 // Nothing to do if the collection is wrapped 530 // BUT THE COLLECTION MUST BE SAVED IN THE CASE OF ARRAYS 531 // storage.updateCollection(collection); 532 CollectionItem collection = (CollectionItem) field; 533 if (collection.isArray() 534 && ((MethodItem) interaction.method) 535 .getCollectionIndexArgument() 536 != -1) { 537 updateCollection( 538 collection, 539 ((MethodItem) interaction.method) 540 .getCollectionIndexArgument()); 541 } 542 } else { 543 setField(interaction.wrappee, oid, field); 544 } 545 } 546 } 547 548 // handle added collections (adder) 549 CollectionItem[] collections = method.getAddedCollections(); 550 for (int i = 0; 551 collections != null && i < collections.length; 552 i++) { 553 if (!collections[i].isTransient() 554 && !isWrapped(interaction.wrappee, collections[i])) { 555 addToCollection( 556 interaction, 557 oid, 558 collections[i], 559 interaction.args[0]); 560 } 561 } 562 // handle removed collections (remover) 563 collections = method.getRemovedCollections(); 564 for (int i = 0; 565 collections != null && i < collections.length; 566 i++) { 567 if (!collections[i].isTransient() 568 && !isWrapped(interaction.wrappee, collections[i])) { 569 removeFromCollection( 570 interaction, 571 oid, 572 collections[i], 573 interaction.args[0]); 574 } 575 } 576 577 // UNCOMMENT THIS WHEN UNWRAP WILL BE THREAD-SAFE!!! 578 // unwrap the method if it was only a getter 579 //if ( ! method.hasAddedCollections() && 580 // ! method.hasRemovedCollections() && 581 // ! method.hasWrittenFields() ) 582 //{ 583 // logger.debug("persistence.ref","unwrapping "+getOID()+" "+method); 584 // Wrapping.unwrap(interaction.wrappee,this,"applyPersistence",method); 585 //} 586 } 587 return result; 588 } 589 590 /** 591 * This method loads alls the persistent objects that are contained 592 * in this collection from the storage. 593 * 594 * <p>If the collection has already been loaded from the storage, 595 * do nothing.<p> 596 * 597 * @param collection the collection to load */ 598 599 public void getCollection(Wrappee wrappee, OID oid, CollectionItem collection) 600 throws Exception 601 { 602 logger.debug(oid + ".getCollection(" + collection.getName() + ")"); 603 if (!loadedVectors.contains(collection.getName())) { 604 String classID = collection.getParent().getName(); 605 List vector = null; 606 Map map = null; 607 Storage storage = oid.getStorage(); 608 OID cid = storage.getCollectionID(oid, collection); 609 loggerCol.debug("cid=" + cid); 610 if (cid == null) { 611 // Handle the case of a new collection added in the model 612 initCollection(wrappee, oid, collection); 613 } 614 if (collection.isList() || collection.isArray()) { 615 vector = storage.getList(oid, collection); 616 } else if (collection.isSet()) { 617 vector = storage.getSet(oid, collection); 618 } else if (collection.isMap()) { 619 map = storage.getMap(oid, collection); 620 } else { 621 logger.error( 622 "unhandled collection type : " + collection.getType()); 623 logger.error( 624 "please see the JAC programming guidelines for more details"); 625 //new Exception().printStackTrace(); 626 return; 627 } 628 629 collection.clear(wrappee); 630 631 if (collection.isMap()) { 632 Iterator it = map.entrySet().iterator(); 633 while (it.hasNext()) { 634 Map.Entry entry = (Map.Entry) it.next(); 635 attrdef(ATTR_ADDED, "true"); 636 collection.add( 637 wrappee, 638 normalizeOutput(entry.getValue()), 639 normalizeOutput(entry.getKey())); 640 attrdef(ATTR_ADDED, null); 641 } 642 } else { 643 for (int i = 0; i < vector.size(); i++) { 644 attrdef(ATTR_ADDED, "true"); 645 loggerCol.debug( 646 "adding " 647 + normalizeOutput(vector.get(i)) 648 + " to " + collection 649 + "(wrappee=" + wrappee + ")"); 650 collection.add( 651 wrappee, 652 normalizeOutput(vector.get(i)), 653 null); 654 attrdef(ATTR_ADDED, null); 655 } 656 } 657 loadedVectors.add(collection.getName()); 658 } 659 } 660 661 /** 662 * This method stores the persistent object that is added to the 663 * collection into the storage.<p> 664 * 665 * @param interaction the current interaction 666 * @param oid the oid of the object holding the collection 667 * @param collection the collection to add to 668 * @param value the value to add to the collection 669 * 670 * @see #removeFromCollection(Interaction,OID,CollectionItem,Object) 671 * @see #getCollection(Wrappee,OID,CollectionItem) 672 */ 673 protected void addToCollection(Interaction interaction, 674 OID oid, 675 CollectionItem collection, 676 Object value) 677 throws Exception 678 { 679 logger.debug(oid + ".addToCollection: " 680 + interaction.method + Arrays.asList(interaction.args)); 681 682 if (interaction.args.length == 1) { 683 // the method's arguments look correct 684 value = normalizeInput(value); 685 Storage storage = oid.getStorage(); 686 OID cid = 687 storage.getCollectionID(oid,collection); 688 if (collection.isList() || collection.isArray()) { 689 storage.addToList(cid, value); 690 } else if (collection.isSet()) { 691 storage.addToSet(cid, value); 692 } else { 693 logger.error( 694 "unhandled collection type : " + collection.getType(),new Exception()); 695 } 696 697 } else { 698 logger.error("NOT IMPLEMENTED YET !!!"); 699 // the method's arguments are weird, so let's diff 700 // storage.updateCollection(collection); 701 } 702 } 703 704 /** 705 * This method delete the persistent object that is removed from 706 * the collection from the storage.<p> 707 * 708 * @param interaction the current interaction 709 * @param oid the oid of the object holding the collection 710 * @param collection the collection to remove from 711 * @param value the value to remove from the collection 712 * 713 * @see #addToCollection(Interaction,OID,CollectionItem,Object) 714 * @see #getCollection(Wrappee,OID,CollectionItem) 715 */ 716 protected void removeFromCollection(Interaction interaction, 717 OID oid, 718 CollectionItem collection, 719 Object value) 720 throws Exception 721 { 722 logger.debug(oid + ".removeFromCollection " + interaction.method); 723 724 value = normalizeInput(value); 725 Storage storage = oid.getStorage(); 726 OID cid = 727 storage.getCollectionID(oid, collection); 728 if (collection.isList() || collection.isArray()) { 729 storage.removeFromList(cid, value); 730 } else if (collection.isSet()) { 731 storage.removeFromSet(cid, value); 732 } else { 733 logger.error( 734 "unhandled collection type : " + collection.getType(), new Exception()); 735 } 736 } 737 738 /** 739 * Update the element of a collection at a gievn position 740 */ 741 public void updateCollection(CollectionItem collection, int position) 742 throws Exception { 743 /* 744 checkOid(); 745 logger.debug( 746 getOID()+".updateCollection: "+method()+Arrays.asList(args())); 747 748 if (isPersistent()) 749 { 750 // the method's arguments look correct 751 value = normalizeInput(value); 752 OID cid = getStorage().getCollectionID(getOID(), collection); 753 if ( collection.isList() || collection.isArray() ) { 754 Object value = collection.get(wrappee(),position); 755 getStorage().setListItem(cid, position, value); 756 } else { 757 logger.error("unhandled collection type : "+collection.getType()); 758 } 759 } 760 */ 761 } 762 763 /** 764 * This method loads the persistent object that is pointed by the 765 * reference from the storage.<p> 766 * 767 * If the reference has already been loaded from the storage, do 768 * nothing.<p> 769 * 770 * @param reference the reference to load 771 * 772 * @see #setReference(Wrappee,OID,FieldItem,Wrappee) 773 */ 774 public void getReference(Wrappee wrappee, OID oid, FieldItem reference) 775 throws Exception 776 { 777 try { 778 779 loggerRef.debug( 780 oid + "[" + this + "].getReference(" 781 + reference.getName() + ")"); 782 //System.out.println("GETREF: "+loadedReferences+" : "+notloadedReferences); 783 784 if (!loadedReferences.contains(reference.getName())) { 785 OID lOid = (OID) notloadedReferences.get(reference); 786 if (lOid == null) 787 lOid = (OID)oid.getStorage().getField(oid,reference); 788 else 789 notloadedReferences.remove(reference); 790 loggerRef.debug( 791 oid + "." + reference.getName() 792 + " -> " + lOid 793 + " (" + wrappee.getClass().getName() + ")"); 794 Object obj = null; 795 if (lOid != null) { 796 // What the hell is this ??? It bugs if a reference 797 // is initialized by the default constructor 798 //obj=getAC().getObject(lOid,reference.get(wrappee)); 799 obj = getAC().getObject(lOid, null); 800 } 801 attrdef(ATTR_ADDED, "true"); 802 try { 803 reference.set(wrappee, obj); 804 } catch (IllegalArgumentException illegal) { 805 // This may happen if the type of the reference has been changed 806 logger.error( 807 "Incompatible types " 808 + reference.getType() + " and " + obj); 809 } finally { 810 attrdef(ATTR_ADDED, null); 811 } 812 loadedReferences.add(reference.getName()); 813 } else { 814 loggerRef.debug( 815 oid + "." + reference.getName() 816 + " already loaded"); 817 } 818 } catch (Exception e) { 819 logger.error("getReference "+oid+"."+reference.getName(),e); 820 } 821 } 822 823 /** 824 * This method stores the persistent object that is pointed by the 825 * reference into the storage.<p> 826 * 827 * @param reference the reference to store 828 * 829 * @see #getReference(Wrappee,OID,FieldItem) 830 */ 831 protected void setReference(Wrappee wrappee, 832 OID oid, 833 FieldItem reference, 834 Wrappee value) 835 throws Exception 836 { 837 if (value != null) { 838 OID valoid = (OID)Wrapping.invokeRoleMethod( 839 value, 840 "makePersistent", 841 ExtArrays.emptyObjectArray); 842 oid.getStorage().updateField(oid,reference,valoid); 843 } else { 844 oid.getStorage().updateField(oid, reference, null); 845 } 846 // We won't need to load the reference now 847 loadedReferences.add(reference.getName()); 848 notloadedReferences.remove(reference); 849 } 850 851 /** 852 * This method stores the field into the storage.<p> 853 * 854 * @param field the field to store 855 */ 856 protected void setField(Wrappee wrappee, OID oid, FieldItem field) 857 throws Exception 858 { 859 Object value = field.get(wrappee); 860 if (value instanceof Wrappee) { 861 value = Wrapping.invokeRoleMethod( 862 (Wrappee)value, 863 "makePersistent", 864 ExtArrays.emptyObjectArray); 865 866 } 867 oid.getStorage().updateField(oid,field,value); 868 } 869 870 public void initCollections(Wrappee wrappee, OID oid, CollectionItem[] collections) 871 throws Exception 872 { 873 logger.debug("wrappee = " + wrappee.getClass().getName()); 874 logger.debug("collections = " + Arrays.asList(collections)); 875 for (int i=0; i<collections.length; i++) { 876 if (!collections[i].isTransient()) { 877 logger.debug("collections[" + i + "] = " + collections[i]); 878 initCollection(wrappee, oid, collections[i]); 879 } 880 } 881 } 882 883 OID initCollection(Wrappee wrappee, OID oid, CollectionItem collection) 884 throws Exception 885 { 886 logger.debug("Init collection " + collection.getName()); 887 loadedVectors.add(collection.getName()); 888 Storage storage = oid.getStorage(); 889 OID cid = null; 890 if (collection.isList() 891 || collection.isSet() 892 || collection.isArray()) 893 { 894 if (isWrapped(wrappee, collection)) { 895 cid = getOID((Wrappee) collection.get(wrappee)); 896 } else { 897 cid = storage.createObject(collection.getType().getName()); 898 logger.debug(" new id = " + cid); 899 } 900 storage.setField(oid, collection, cid); 901 Collection coll = collection.getActualCollection(wrappee); 902 logger.debug(" Coll value = " + coll); 903 if (coll == null) { 904 logger.warn( 905 "uninitialized collection "+collection.getLongName()+ 906 ". Do you have a constructor with no parameters?"); 907 return cid; 908 } 909 // iterator() is wrapped method, so it triggers the 910 // loading of the collection from the storage, which is bad 911 Iterator it = coll.iterator(); 912 while (it.hasNext()) { 913 Object value = normalizeInput(it.next()); 914 logger.debug(" Coll elt value = " + value); 915 if (value != null) { 916 if (collection.isList() || collection.isArray()) { 917 storage.addToList(cid, value); 918 } else { 919 storage.addToSet(cid, value); 920 } 921 } 922 } 923 } else if (collection.isMap()) { 924 if (isWrapped(wrappee, collection)) { 925 cid = getOID((Wrappee) collection.get(wrappee)); 926 } else { 927 cid = storage.createObject(collection.getType().getName()); 928 } 929 storage.setField(oid, collection, cid); 930 Map map = (Map) collection.get(wrappee); 931 Set entries = map.entrySet(); 932 Iterator it = entries.iterator(); 933 while (it.hasNext()) { 934 Map.Entry entry = (Map.Entry) it.next(); 935 storage.putInMap( 936 cid, 937 normalizeInput(entry.getKey()), 938 normalizeInput(entry.getValue())); 939 } 940 } else { 941 logger.error("unhandled collection type : " + collection.getType(), 942 new Exception()); 943 } 944 logger.debug(" End of init collection " + collection.getName()); 945 return cid; 946 } 947 948 /** 949 * Initialize all fields of an object in the storage. 950 * 951 * <p>This method is called when a new object is made persistent. The 952 * references and collections are also recursively saved into the 953 * storage.<p> 954 * 955 * @param wrappee the initialized object 956 */ 957 public void initAllFields(Wrappee wrappee, OID oid) throws Exception { 958 if (oid==null) 959 throw new InvalidOidException("oid is NULL"); 960 String classID = wrappee.getClass().getName(); 961 logger.debug("initAllfields(" + oid + ") : " + classID); 962 ClassItem cli = cr.getClass(classID); 963 FieldItem[] fields = cli.getPrimitiveFields(); 964 Storage storage = oid.getStorage(); 965 storage.startTransaction(); 966 try { 967 // fields 968 for (int i = 0; i < fields.length; i++) { 969 if (!fields[i].isTransient() 970 && !fields[i].isStatic() 971 && !fields[i].isFinal()) 972 { 973 Object fieldValue = fields[i].get(wrappee); 974 logger.debug("Init field " 975 + fields[i].getName()+ "->" + fieldValue); 976 if (fieldValue != null) { 977 if (fieldValue instanceof Wrappee) 978 storage.setField(oid,fields[i],getOID((Wrappee)fieldValue)); 979 else 980 storage.setField(oid,fields[i],fieldValue); 981 } 982 } 983 } 984 985 FieldItem[] references = cli.getReferences(); 986 987 // references 988 for (int i = 0; i < references.length; i++) { 989 if (!references[i].isTransient() 990 && !references[i].isStatic() 991 && !references[i].isFinal()) { 992 logger.debug("Init reference " + references[i].getName()); 993 Wrappee obj = 994 (Wrappee) references[i].getActualField().get(wrappee); 995 logger.debug("Ref value = " 996 + (obj != null ? obj.getClass().getName() : "null")); 997 998 loadedReferences.add(references[i].getName()); 999 if (obj != null) { 1000 OID objoid = 1001 (OID)Wrapping.invokeRoleMethod( 1002 obj, 1003 "makePersistent", 1004 ExtArrays.emptyObjectArray); 1005 if (objoid == null) { 1006 // this should never happen 1007 logger.error( 1008 "wrapper.oid is NULL in initAllFields, reference = " 1009 + references[i].getName()); 1010 } else { 1011 logger.debug("Ref value = " + objoid); 1012 storage.setField(oid,references[i],objoid); 1013 logger.debug("Ref saved"); 1014 } 1015 } 1016 } 1017 1018 // UNCOMMENT THIS WHEN UNWRAP WILL BE THREAD-SAFE!!! 1019 // unwrap the reference's getter because it won't need to be 1020 // reloaded from the storage 1021 //MethodItem getter = references[i].getGetter(); 1022 //if (getter!=null) { 1023 // Wrapping.unwrap(interaction.wrappee,this,"applyPersistence",getter); 1024 //} 1025 } 1026 1027 initCollections(wrappee, oid, cli.getCollections()); 1028 } catch (Exception e) { 1029 storage.rollback(); 1030 } 1031 storage.commit(); 1032 } 1033 1034 public static class InvalidOidException extends RuntimeException { 1035 public InvalidOidException(String msg) { 1036 super(msg); 1037 } 1038 } 1039 1040 public Object invoke(MethodInvocation invocation) throws Throwable { 1041 return applyPersistence((Interaction) invocation); 1042 } 1043 1044 public Object construct(ConstructorInvocation invocation) 1045 throws Throwable { 1046 return handleStatic((Interaction) invocation); 1047 } 1048 } 1049 1050 // Local Variables: *** 1051 // c-basic-offset:4 *** 1052 // End: ***