1 package org.apache.ojb.otm.core; 2 3 17 18 import java.lang.reflect.Array ; 19 import java.math.BigDecimal ; 20 import java.util.ArrayList ; 21 import java.util.Arrays ; 22 import java.util.Collection ; 23 import java.util.Comparator ; 24 import java.util.Iterator ; 25 import java.util.HashMap ; 26 import java.util.HashSet ; 27 import java.util.Date ; 28 import java.util.List ; 29 import java.util.Set ; 30 import java.util.Stack ; 31 32 import org.apache.commons.collections.iterators.ArrayIterator; 33 import org.apache.ojb.broker.Identity; 34 import org.apache.ojb.broker.OJBRuntimeException; 35 import org.apache.ojb.broker.PBKey; 36 import org.apache.ojb.broker.PersistenceBroker; 37 import org.apache.ojb.broker.accesslayer.ConnectionManagerIF; 38 import org.apache.ojb.broker.cache.ObjectCache; 39 import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl; 40 import org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl; 41 import org.apache.ojb.broker.core.proxy.SetProxyDefaultImpl; 42 import org.apache.ojb.broker.core.proxy.CollectionProxyListener; 43 import org.apache.ojb.broker.core.proxy.IndirectionHandler; 44 import org.apache.ojb.broker.core.proxy.MaterializationListener; 45 import org.apache.ojb.broker.core.proxy.ProxyHelper; 46 import org.apache.ojb.broker.metadata.ClassDescriptor; 47 import org.apache.ojb.broker.metadata.CollectionDescriptor; 48 import org.apache.ojb.broker.metadata.FieldDescriptor; 49 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; 50 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField; 51 52 import org.apache.ojb.otm.EditingContext; 53 import org.apache.ojb.otm.OTMKit; 54 import org.apache.ojb.otm.copy.ObjectCopyStrategy; 55 import org.apache.ojb.otm.lock.LockManager; 56 import org.apache.ojb.otm.lock.LockType; 57 import org.apache.ojb.otm.lock.LockingException; 58 import org.apache.ojb.otm.states.State; 59 import org.apache.ojb.otm.swizzle.Swizzling; 60 61 69 public class ConcreteEditingContext 70 implements EditingContext, MaterializationListener, ObjectCache 71 { 72 private static HashMap _withBidirAsscMap = new HashMap (); 76 private static HashMap _withoutBidirAsscMap = new HashMap (); 77 78 private HashSet _withBidirAssc; 79 private HashSet _withoutBidirAssc; 80 81 private HashMap _objects; 82 private ArrayList _order; 83 private Transaction _tx; 84 private PersistenceBroker _pb; 85 private HashMap _original; 86 private HashMap _checkpointed; 87 private HashMap _colProxyListeners; 88 89 93 public ConcreteEditingContext(Transaction tx, PersistenceBroker pb) 94 { 95 PBKey pbkey; 96 97 _tx = tx; 98 _pb = pb; 99 _objects = new HashMap (); 100 _order = new ArrayList (); 101 _original = new HashMap (); 102 _checkpointed = _original; 103 pbkey = _pb.getPBKey(); 104 _withoutBidirAssc = (HashSet ) _withoutBidirAsscMap.get(pbkey); 105 if (_withoutBidirAssc != null) 106 { 107 _withBidirAssc = (HashSet ) _withBidirAsscMap.get(pbkey); 108 } 109 else 110 { 111 _withoutBidirAssc = new HashSet (); 112 _withoutBidirAsscMap.put(pbkey, _withoutBidirAssc); 113 _withBidirAssc = new HashSet (); 114 _withBidirAsscMap.put(pbkey, _withBidirAssc); 115 } 116 } 117 118 122 125 public void insert(Identity oid, Object userObject, int lock) 126 throws LockingException 127 { 128 ContextEntry entry; 129 130 entry = insertInternal(oid, userObject, lock, true, null, new Stack ()); 131 if ((entry != null) && entry.state.needsDelete()) { 132 entry.state = State.PERSISTENT_CLEAN; 134 } 135 } 136 137 private ContextEntry insertInternal(Identity oid, Object userObject, 138 int lock, boolean canCreate, Identity insertBeforeThis, Stack stack) 139 throws LockingException 140 { 141 ContextEntry entry; 142 LockManager lockManager; 143 Swizzling swizzlingStrategy; 144 IndirectionHandler handler = null; 145 OTMKit kit = _tx.getKit(); 146 boolean buildingObject = false; 150 boolean lazySwizzle = false; 151 152 if (lock == LockType.NO_LOCK) 153 { 154 return null; 155 } 156 157 entry = (ContextEntry) _objects.get(oid); 158 159 if (userObject == null) 160 { 161 _original.remove(oid); 163 _checkpointed.remove(oid); 164 if (entry != null) 165 { 166 entry.userObject = null; 167 entry.cacheObject = null; 168 } 169 return entry; 170 } 171 172 lockManager = LockManager.getInstance(); 173 swizzlingStrategy = kit.getSwizzlingStrategy(); 174 175 handler = ProxyHelper.getIndirectionHandler(userObject); 176 if ((handler != null) && handler.alreadyMaterialized()) 177 { 178 userObject = handler.getRealSubject(); 179 handler = null; 180 } 181 182 if ((entry == null) || (entry.userObject == null)) 183 { 184 Object swizzledObject = swizzlingStrategy.swizzle(userObject, null, _pb, this); 186 entry = new ContextEntry(swizzledObject); 187 if (entry.handler != null) 188 { 189 ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid); 190 entry.cacheObject = copyStrategy.copy(userObject, _pb); 191 _objects.put(oid, entry); 193 lockManager.ensureLock(oid, _tx, lock, _pb); entry.handler.addListener(this); 195 } 196 else 197 { 198 Object origCacheObj = _pb.getObjectByIdentity(oid); 199 200 if ((origCacheObj == null) && !canCreate) 201 { 202 throw new IllegalStateException ("Related object is neither persistent, nor otm-depentent: " + oid); 204 } 205 if (origCacheObj != null) 206 { 207 entry.cacheObject = origCacheObj; 208 } 209 buildingObject = true; 210 _objects.put(oid, entry); 211 lockManager.ensureLock(oid, _tx, lock, _pb); 213 if (userObject != null) 214 { 215 if ((origCacheObj == null) && canCreate) 216 { 217 ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid); 218 entry.cacheObject = copyStrategy.copy(userObject, _pb); 219 entry.state = State.PERSISTENT_NEW; 220 if (kit.isEagerInsert(userObject) 221 || hasBidirectionalAssociation(userObject.getClass())) 222 { 223 _pb.store(entry.cacheObject, entry.state); 224 entry.state = State.PERSISTENT_CLEAN; 225 origCacheObj = entry.cacheObject; 226 } 227 } 228 229 if (origCacheObj != null) 230 { 231 _original.put(oid, getFields(userObject, false, true)); 232 } 233 } 234 } 235 if (insertBeforeThis != null) 236 { 237 int insertIndex = _order.indexOf(insertBeforeThis); 238 _order.add(insertIndex, oid); 239 } 240 else 241 { 242 _order.add(oid); 243 } 244 } 245 else 246 { 247 lockManager.ensureLock(oid, _tx, lock, _pb); 250 251 if (handler == null) 252 { 253 if (!swizzlingStrategy.isSameInstance(entry.userObject, userObject)) 254 { 255 if (entry.handler != null) 257 { 258 entry.userObject = entry.handler.getRealSubject(); 262 entry.handler = null; 263 } 264 lazySwizzle = true; 267 } 268 } 269 } 270 271 if ((handler == null) && !stack.contains(userObject)) 274 { 275 stack.push(userObject); 276 lockReachableObjects(oid, userObject, entry.cacheObject, lock, stack, buildingObject); 277 stack.pop(); 278 if (lazySwizzle) 279 { 280 entry.userObject = swizzlingStrategy.swizzle(userObject, entry.userObject, _pb, this); 281 } 282 } 283 284 return entry; 285 } 286 287 291 private void lockReachableObjects(Identity oid, Object userObject, 292 Object cacheObject, int lock, Stack stack, boolean buildingObject) 293 throws LockingException 294 { 295 ContextEntry entry; 296 boolean onlyDependants = !_tx.getKit().isImplicitLockingUsed(); 297 ClassDescriptor mif = _pb.getClassDescriptor(userObject.getClass()); 298 299 Iterator iter = mif.getObjectReferenceDescriptors().iterator(); 301 ObjectReferenceDescriptor rds = null; 302 PersistentField f; 303 Object relUserObj; 304 Identity relOid; 305 boolean isDependent; 306 307 while (iter.hasNext()) 308 { 309 rds = (ObjectReferenceDescriptor) iter.next(); 310 isDependent = rds.getOtmDependent(); 311 if (onlyDependants && !isDependent) 312 { 313 continue; 314 } 315 f = rds.getPersistentField(); 316 relUserObj = f.get(userObject); 317 if (relUserObj != null) 318 { 319 relOid = new Identity(relUserObj, _pb); 320 entry = (ContextEntry) _objects.get(relOid); 321 if ((entry == null) || (entry.userObject != relUserObj)) 322 { 323 entry = insertInternal(relOid, relUserObj, lock, isDependent, 324 oid, stack); 325 if (buildingObject && (entry != null)) 326 { 327 f.set(userObject, entry.userObject); 328 f.set(cacheObject, entry.cacheObject); 329 } 330 } 331 } 332 } 333 334 Iterator collections = mif.getCollectionDescriptors().iterator(); 336 CollectionDescriptor cds; 337 Object userCol; 338 Iterator userColIterator; 339 Class type; 340 ArrayList newUserCol = null; 341 ArrayList newCacheCol = null; 342 343 while (collections.hasNext()) 344 { 345 cds = (CollectionDescriptor) collections.next(); 346 f = cds.getPersistentField(); 347 type = f.getType(); 348 isDependent = cds.getOtmDependent(); 349 if (onlyDependants && !isDependent) 350 { 351 continue; 352 } 353 userCol = f.get(userObject); 354 if (userCol != null) 355 { 356 if ((userCol instanceof CollectionProxyDefaultImpl) 357 && !((CollectionProxyDefaultImpl) userCol).isLoaded()) 358 { 359 continue; 360 } 361 362 if (buildingObject) 363 { 364 newUserCol = new ArrayList (); 365 newCacheCol = new ArrayList (); 366 } 367 368 if (Collection .class.isAssignableFrom(type)) 369 { 370 userColIterator = ((Collection ) userCol).iterator(); 371 } 372 else if (type.isArray()) 373 { 374 userColIterator = new ArrayIterator(userCol); 375 } 376 else 377 { 378 throw new OJBRuntimeException( 379 userCol.getClass() 380 + " can not be managed by OJB OTM, use Array or Collection instead !"); 381 } 382 383 while (userColIterator.hasNext()) 384 { 385 relUserObj = userColIterator.next(); 386 relOid = new Identity(relUserObj, _pb); 387 entry = (ContextEntry) _objects.get(relOid); 388 if ((entry == null) || (entry.userObject != relUserObj)) 389 { 390 entry = insertInternal(relOid, relUserObj, lock, 391 isDependent, null, stack); 392 } 393 if (buildingObject && (entry != null)) 394 { 395 newUserCol.add(entry.userObject); 396 newCacheCol.add(entry.cacheObject); 397 } 398 } 399 if (buildingObject) 400 { 401 setCollectionField(userObject, f, newUserCol); 402 setCollectionField(cacheObject, f, newCacheCol); 403 } 404 } 405 } 406 } 407 408 411 public void remove(Identity oid) 412 { 413 _objects.remove(oid); 414 _order.remove(oid); 415 LockManager.getInstance().releaseLock(oid, _tx); 416 } 417 418 419 public void deletePersistent(Identity oid, Object userObject) 420 throws LockingException 421 { 422 ContextEntry entry; 423 424 entry = insertInternal(oid, userObject, LockType.WRITE_LOCK, true, null, 425 new Stack ()); 426 if (entry != null) 427 { 428 entry.state = entry.state.deletePersistent(); 429 } 430 _order.remove(oid); 431 _order.add(oid); 432 } 433 434 437 public Object lookup(Identity oid) 438 { 439 ContextEntry entry = (ContextEntry) _objects.get(oid); 440 return (entry == null ? null : entry.userObject); 441 } 442 443 public boolean contains(Identity oid) 444 { 445 return lookup(oid) != null; 446 } 447 448 451 public State lookupState(Identity oid) 452 throws LockingException 453 { 454 State retval = null; 455 ContextEntry entry = (ContextEntry) _objects.get(oid); 456 if (entry != null) 457 { 458 461 retval = entry.state; 462 } 463 return retval; 464 } 465 466 469 public void setState(Identity oid, State state) 470 { 471 ContextEntry entry = (ContextEntry) _objects.get(oid); 472 entry.state = state; 473 } 474 475 public Collection getAllObjectsInContext() 476 { 477 return _objects.values(); 478 } 479 480 484 public void beforeMaterialization(IndirectionHandler handler, Identity oid) 485 { 486 } 488 489 public void afterMaterialization(IndirectionHandler handler, Object cacheObject) 490 { 491 Identity oid = handler.getIdentity(); 492 ContextEntry entry = (ContextEntry) _objects.get(oid); 493 494 if (entry == null) 495 { 496 return; 497 } 498 499 int lock = LockManager.getInstance().getLockHeld(oid, _tx); 500 ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid); 501 Object userObject = copyStrategy.copy(cacheObject, _pb); 502 handler.setRealSubject(userObject); 503 _original.put(oid, getFields(userObject, false, true)); 504 505 entry.userObject = userObject; 507 entry.cacheObject = cacheObject; 508 entry.handler.removeListener(this); 509 entry.handler = null; 510 511 try 514 { 515 lockReachableObjects(oid, userObject, cacheObject, lock, new Stack (), true); 516 } 517 catch (LockingException ex) 518 { 519 throw new LockingPassthruException(ex); 520 } 521 } 522 523 524 525 529 535 public void commit() throws TransactionAbortedException 536 { 537 checkpointInternal(true); 538 releaseLocksAndClear(); 539 } 540 541 private void releaseLocksAndClear() 542 { 543 releaseLocks(); 544 removeMaterializationListener(); 545 _objects.clear(); 546 _order.clear(); 547 _original.clear(); 548 if (_checkpointed != _original) 549 { 550 _checkpointed.clear(); 551 } 552 } 553 554 559 public void checkpoint() throws TransactionAbortedException 560 { 561 checkpointInternal(false); 562 _checkpointed = new HashMap (); 563 for (Iterator iterator = _order.iterator(); iterator.hasNext();) 564 { 565 Identity oid = (Identity) iterator.next(); 566 ContextEntry entry = (ContextEntry) _objects.get(oid); 567 if (entry.handler == null) 568 { 569 _checkpointed.put(oid, getFields(entry.userObject, false, true)); 570 } 571 } 572 } 573 574 579 private void checkpointInternal(boolean isCommit) 580 throws TransactionAbortedException 581 { 582 if (_order.size() == 0) 583 { 584 return; 585 } 586 587 removeCollectionProxyListeners(); 588 589 ConnectionManagerIF connMan = _pb.serviceConnectionManager(); 590 boolean saveBatchMode = connMan.isBatchMode(); 591 Swizzling swizzlingStrategy = _tx.getKit().getSwizzlingStrategy(); 592 LockManager lockManager = LockManager.getInstance(); 593 Identity[] lockOrder = (Identity[]) _order.toArray(new Identity[_order.size()]); 594 ObjectCache cache = _pb.serviceObjectCache(); 595 boolean isInsertVerified = _tx.getKit().isInsertVerified(); 596 ArrayList changedCollections = new ArrayList (); 597 598 Arrays.sort(lockOrder, new Comparator () 600 { 601 public int compare(Object o1, Object o2) 602 { 603 return o1.hashCode() - o2.hashCode(); 604 } 605 606 public boolean equals(Object obj) 607 { 608 return false; 609 } 610 }); 611 612 try { 613 ArrayList newObjects = new ArrayList (); 617 int countNewObjects; 618 do 619 { 620 newObjects.clear(); 621 countNewObjects = 0; 622 for (int i = 0; i < lockOrder.length; i++) 623 { 624 Identity oid = lockOrder[i]; 625 ContextEntry entry = (ContextEntry) _objects.get(oid); 626 State state = entry.state; 627 628 if (entry.userObject == null) { 630 continue; 631 } 632 633 if (entry.handler == null) { 635 if (!state.isDeleted()) 636 { 637 Object [][] origFields = (Object [][]) _checkpointed.get(oid); 638 Object [][] newFields = getFields(entry.userObject, true, !isCommit); 639 640 if (origFields == null) 641 { 642 entry.needsCacheSwizzle = true; 643 newObjects.addAll( 644 handleDependentReferences(oid, entry.userObject, 645 null, newFields[0], newFields[2])); 646 newObjects.addAll( 647 handleDependentCollections(oid, entry.userObject, 648 null, newFields[1], newFields[3])); 649 } 650 else 651 { 652 if (isModified(origFields[0], newFields[0])) 653 { 654 entry.state = state.markDirty(); 655 entry.needsCacheSwizzle = true; 656 lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb); 657 newObjects.addAll( 658 handleDependentReferences(oid, entry.userObject, 659 origFields[0], newFields[0], newFields[2])); 660 } 661 662 if (isModified(origFields[1], newFields[1])) 663 { 664 entry.needsCacheSwizzle = true; 667 lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb); 668 newObjects.addAll( 669 handleDependentCollections(oid, entry.userObject, 670 origFields[1], newFields[1], newFields[3])); 671 changedCollections.add(oid); 672 } 673 } 674 } 675 } 676 } 677 countNewObjects = newObjects.size(); 678 if (countNewObjects > 0) 679 { 680 lockOrder = (Identity[]) newObjects.toArray( 682 new Identity[countNewObjects]); 683 } 684 } 685 while (countNewObjects > 0); 686 687 for (Iterator it = _order.iterator(); it.hasNext(); ) 689 { 690 Identity oid = (Identity) it.next(); 691 ContextEntry entry = (ContextEntry) _objects.get(oid); 692 693 if (entry.needsCacheSwizzle) 694 { 695 entry.userObject = swizzlingStrategy.getRealTarget(entry.userObject); 696 entry.cacheObject = swizzlingStrategy.swizzle( 697 entry.userObject, entry.cacheObject, _pb, new ObjectCache() 700 { 701 public Object lookup(Identity anOid) 702 { 703 ContextEntry ent = (ContextEntry) _objects.get(anOid); 704 return (ent == null ? null : ent.cacheObject); 705 } 706 707 public boolean contains(Identity oid) 708 { 709 return lookup(oid) != null; 710 } 711 712 public void cache(Identity anOid, Object obj) 713 { 714 } 716 717 public boolean cacheIfNew(Identity oid, Object obj) 718 { 719 return false; 720 } 721 722 public void clear() 723 { 724 } 726 727 public void remove(Identity anOid) 728 { 729 } 731 }); 732 } 733 } 734 735 int countCascadeDeleted; 737 do 738 { 739 countCascadeDeleted = 0; 740 for (Iterator it = (new ArrayList (_order)).iterator(); it.hasNext(); ) 743 { 744 Identity oid = (Identity) it.next(); 745 ContextEntry entry = (ContextEntry) _objects.get(oid); 746 747 if (entry.state.isDeleted()) 748 { 749 countCascadeDeleted += doCascadeDelete(oid, entry.userObject); 750 } 751 } 752 } 753 while (countCascadeDeleted > 0); 754 755 connMan.setBatchMode(true); 757 try 758 { 759 for (Iterator it = _order.iterator(); it.hasNext(); ) 760 { 761 Identity oid = (Identity) it.next(); 762 ContextEntry entry = (ContextEntry) _objects.get(oid); 763 State state = entry.state; 764 765 if (!state.needsInsert() && !state.needsUpdate() 766 && !state.needsDelete()) 767 { 768 if (changedCollections.contains(oid)) { 769 _pb.store(entry.cacheObject, state); 770 } 771 continue; 772 } 773 774 if (state.needsInsert()) 775 { 776 if (isInsertVerified) 777 { 778 _pb.store(entry.cacheObject); 780 } 781 else 782 { 783 if (cache.lookup(oid) == null) { 785 _pb.store(entry.cacheObject, state); 786 } 787 } 788 789 } 790 else if (state.needsUpdate()) 791 { 792 _pb.store(entry.cacheObject, state); 793 } 794 else if (state.needsDelete()) 795 { 796 _pb.delete(entry.cacheObject); 797 } 798 entry.state = state.commit(); 799 } 800 connMan.executeBatch(); 801 } 802 finally 803 { 804 connMan.setBatchMode(saveBatchMode); 805 } 806 } catch (Throwable ex) { 807 ex.printStackTrace(); 808 throw new TransactionAbortedException(ex); 809 } 810 } 811 812 818 public void rollback() 819 { 820 for (Iterator iterator = _order.iterator(); iterator.hasNext();) 821 { 822 Identity oid = (Identity) iterator.next(); 823 ContextEntry entry = (ContextEntry) _objects.get(oid); 824 entry.state = entry.state.rollback(); 825 Object [][] origFields = (Object [][]) _original.get(oid); 826 if (origFields != null) 827 { 828 setFields(entry.userObject, origFields); 829 setFields(entry.cacheObject, origFields); 830 } 831 } 832 releaseLocksAndClear(); 833 } 834 835 840 public void refresh(Identity oid, Object object) 841 { 842 ContextEntry entry = (ContextEntry) _objects.get(oid); 843 Object [][] origFields = (Object [][]) _original.get(oid); 844 if (origFields != null) 845 { 846 setFields(entry.userObject, origFields); 847 if (object != entry.userObject) 848 { 849 setFields(object, origFields); 850 } 851 } 852 entry.state = entry.state.refresh(); 853 } 854 855 private void removeMaterializationListener() 856 { 857 for (Iterator it = _order.iterator(); it.hasNext();) 858 { 859 Identity oid = (Identity) it.next(); 860 ContextEntry entry = (ContextEntry) _objects.get(oid); 861 if (entry.handler != null) 862 { 863 entry.handler.removeListener(this); 864 } 865 } 866 } 867 868 private void removeCollectionProxyListeners() 869 { 870 if (_colProxyListeners != null) 871 { 872 for (Iterator it = _colProxyListeners.keySet().iterator(); it.hasNext();) 873 { 874 CollectionProxyListener listener = (CollectionProxyListener) it.next(); 875 CollectionProxyDefaultImpl colProxy = (CollectionProxyDefaultImpl) _colProxyListeners.get(listener); 876 colProxy.removeListener(listener); 877 } 878 _colProxyListeners.clear(); 879 } 880 } 881 882 private void releaseLocks() 883 { 884 LockManager lockManager = LockManager.getInstance(); 885 886 for (Iterator it = _objects.keySet().iterator(); it.hasNext(); ) 887 { 888 Identity oid = (Identity) it.next(); 889 lockManager.releaseLock(oid, _tx); 890 } 891 _tx.getKit().getLockMap().gc(); 892 } 893 894 898 private boolean isEqual(Object fld1, Object fld2) 899 { 900 if (fld1 == null || fld2 == null) 901 { 902 return (fld1 == fld2); 903 } 904 else if ((fld1 instanceof BigDecimal ) && (fld2 instanceof BigDecimal )) 905 { 906 return (((BigDecimal ) fld1).compareTo((BigDecimal ) fld2) == 0); 907 } 908 else if ((fld1 instanceof Date ) && (fld2 instanceof Date )) 909 { 910 return (((Date ) fld1).getTime() == ((Date ) fld2).getTime()); 911 } 912 else 913 { 914 return fld1.equals(fld2); 915 } 916 } 917 918 private boolean isModified(Object [] newFields, Object [] oldFields) 919 { 920 if (newFields.length != oldFields.length) 921 { 922 return true; 923 } 924 925 for (int i = 0; i < newFields.length; i++) 926 { 927 if (!isEqual(newFields[i], oldFields[i])) 928 { 929 return true; 930 } 931 } 932 933 return false; 934 } 935 936 946 private Object [][] getFields(Object obj, boolean withObjects, boolean addListeners) 947 { 948 ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass()); 949 FieldDescriptor[] fieldDescs = mif.getFieldDescriptions(); 950 Collection refDescs = mif.getObjectReferenceDescriptors(); 951 Collection colDescs = mif.getCollectionDescriptors(); 952 int count = 0; 953 Object [] fields = new Object [1 + fieldDescs.length + refDescs.size()]; 954 ArrayList [] collections = new ArrayList [colDescs.size()]; 955 Object [] references = null; 956 ArrayList [] collectionsOfObjects = null; 957 int lockForListeners = LockType.NO_LOCK; 958 959 if (withObjects) 960 { 961 references = new Object [refDescs.size()]; 962 collectionsOfObjects = new ArrayList [colDescs.size()]; 963 } 964 965 if (addListeners) 966 { 967 lockForListeners = LockManager.getInstance().getLockHeld( 968 new Identity(obj, _pb), _tx); 969 } 970 971 fields[0] = obj.getClass(); count++; 973 974 for (int i = 0; i < fieldDescs.length; i++) 975 { 976 FieldDescriptor fd = fieldDescs[i]; 977 PersistentField f = fd.getPersistentField(); 978 fields[count] = f.get(obj); 979 count++; 980 } 981 982 int countRefs = 0; 983 for (Iterator it = refDescs.iterator(); it.hasNext(); count++, countRefs++) 984 { 985 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next(); 986 PersistentField f = rds.getPersistentField(); 987 Object relObj = f.get(obj); 988 if (relObj != null) 989 { 990 fields[count] = new Identity(relObj, _pb); 991 if (withObjects) 992 { 993 references[countRefs] = relObj; 994 } 995 } 996 } 997 998 count = 0; 999 for (Iterator it = colDescs.iterator(); it.hasNext(); count++) 1000 { 1001 CollectionDescriptor cds = (CollectionDescriptor) it.next(); 1002 PersistentField f = cds.getPersistentField(); 1003 Class type = f.getType(); 1004 Object col = f.get(obj); 1005 1006 if ((col != null) && (col instanceof CollectionProxyDefaultImpl) 1007 && !((CollectionProxyDefaultImpl) col).isLoaded()) 1008 { 1009 if (addListeners) 1010 { 1011 OTMCollectionProxyListener listener = 1012 new OTMCollectionProxyListener(cds, collections, 1013 count, lockForListeners); 1014 1015 ((CollectionProxyDefaultImpl) col).addListener(listener); 1016 if (_colProxyListeners == null) 1017 { 1018 _colProxyListeners = new HashMap (); 1019 } 1020 _colProxyListeners.put(listener, col); 1021 } 1022 continue; 1023 } 1024 1025 if (col != null) 1026 { 1027 ArrayList list = new ArrayList (); 1028 ArrayList listOfObjects = null; 1029 Iterator colIterator; 1030 1031 collections[count] = list; 1032 if (withObjects) 1033 { 1034 listOfObjects = new ArrayList (); 1035 collectionsOfObjects[count] = listOfObjects; 1036 } 1037 1038 if (Collection .class.isAssignableFrom(type)) 1039 { 1040 colIterator = ((Collection ) col).iterator(); 1041 } 1042 else if (type.isArray()) 1043 { 1044 colIterator = new ArrayIterator(col); 1045 } 1046 else 1047 { 1048 continue; 1049 } 1050 1051 while (colIterator.hasNext()) 1052 { 1053 Object relObj = colIterator.next(); 1054 list.add(new Identity(relObj, _pb)); 1055 if (withObjects) 1056 { 1057 listOfObjects.add(relObj); 1058 } 1059 } 1060 } 1061 } 1062 1063 return new Object [][] {fields, collections, references, collectionsOfObjects}; 1064 } 1065 1066 private void setFields(Object obj, Object [][] fieldsAndCollections) 1067 { 1068 ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass()); 1069 FieldDescriptor[] fieldDescs = mif.getFieldDescriptions(); 1070 Collection refDescs = mif.getObjectReferenceDescriptors(); 1071 Collection colDescs = mif.getCollectionDescriptors(); 1072 Object [] fields = fieldsAndCollections[0]; 1073 ArrayList [] collections = (ArrayList []) fieldsAndCollections[1]; 1074 int count = 0; 1075 1076 if (!fields[0].equals(obj.getClass())) 1077 { 1078 System.err.println("Can't restore the object fields " 1079 + "since its class changed during transaction from " 1080 + fields[0] + " to " + obj.getClass()); 1081 return; 1082 } 1083 count++; 1084 1085 for (int i = 0; i < fieldDescs.length; i++) 1086 { 1087 FieldDescriptor fd = fieldDescs[i]; 1088 PersistentField f = fd.getPersistentField(); 1089 f.set(obj, fields[count]); 1090 count++; 1091 } 1092 1093 for (Iterator it = refDescs.iterator(); it.hasNext(); count++) 1094 { 1095 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next(); 1096 PersistentField f = rds.getPersistentField(); 1097 Identity oid = (Identity) fields[count]; 1098 Object relObj; 1099 if (oid == null) 1100 { 1101 relObj = null; 1102 } 1103 else 1104 { 1105 relObj = _pb.getObjectByIdentity(oid); 1106 } 1107 f.set(obj, relObj); 1108 } 1109 1110 count = 0; 1111 for (Iterator it = colDescs.iterator(); it.hasNext(); count++) 1112 { 1113 CollectionDescriptor cds = (CollectionDescriptor) it.next(); 1114 PersistentField f = cds.getPersistentField(); 1115 ArrayList list = collections[count]; 1116 ArrayList newCol; 1117 1118 if (list == null) 1119 { 1120 f.set(obj, null); 1121 } 1122 else 1123 { 1124 newCol = new ArrayList (); 1125 for (Iterator it2 = list.iterator(); it2.hasNext(); ) 1126 { 1127 Identity relOid = (Identity) it2.next(); 1128 Object relObj = _pb.getObjectByIdentity(relOid); 1129 1130 if (relObj != null) 1131 { 1132 newCol.add(relObj); 1133 } 1134 } 1135 setCollectionField(obj, f, newCol); 1136 } 1137 } 1138 } 1139 1140 private void setCollectionField(Object obj, PersistentField f, List newCol) 1141 { 1142 Class type = f.getType(); 1143 1144 if (Collection .class.isAssignableFrom(type)) 1145 { 1146 Collection col = (Collection ) f.get(obj); 1147 1148 if (col == null) 1149 { 1150 if (type == List .class || type == Collection .class) 1151 { 1152 col = new ArrayList (); 1153 } 1154 else if (type == Set .class) 1155 { 1156 col = new HashSet (); 1157 } 1158 else 1159 { 1160 try 1161 { 1162 col = (Collection ) type.newInstance(); 1163 } 1164 catch (Throwable ex) 1165 { 1166 System.err.println("Cannot instantiate collection field: " + f); 1167 ex.printStackTrace(); 1168 return; 1169 } 1170 } 1171 } 1172 else 1173 { 1174 if (col instanceof CollectionProxyDefaultImpl) 1175 { 1176 CollectionProxyDefaultImpl cp = (CollectionProxyDefaultImpl) col; 1177 if (col instanceof List ) 1178 { 1179 col = new ListProxyDefaultImpl(_pb.getPBKey(), cp.getData().getClass(), null); 1180 } 1181 else if (col instanceof Set ) 1182 { 1183 col = new SetProxyDefaultImpl(_pb.getPBKey(), cp.getData().getClass(), null); 1184 } 1185 else 1186 { 1187 col = new CollectionProxyDefaultImpl(_pb.getPBKey(), cp.getData().getClass(), null); 1188 } 1189 col.clear(); 1190 } 1191 else 1192 { 1193 try 1194 { 1195 col = (Collection ) col.getClass().newInstance(); 1196 } 1197 catch (Exception ex) 1198 { 1199 System.err.println("Cannot instantiate collection field: " + f); 1200 ex.printStackTrace(); 1201 return; 1202 } 1203 } 1204 } 1205 col.addAll(newCol); 1206 f.set(obj, col); 1207 } 1208 else if (type.isArray()) 1209 { 1210 int length = newCol.size(); 1211 Object array = Array.newInstance(type.getComponentType(), length); 1212 1213 for (int i = 0; i < length; i++) 1214 { 1215 Array.set(array, i, newCol.get(i)); 1216 } 1217 f.set(obj, array); 1218 } 1219 } 1220 1221 1225 private boolean hasBidirectionalAssociation(Class clazz) 1226 { 1227 ClassDescriptor cdesc; 1228 Collection refs; 1229 boolean hasBidirAssc; 1230 1231 if (_withoutBidirAssc.contains(clazz)) 1232 { 1233 return false; 1234 } 1235 1236 if (_withBidirAssc.contains(clazz)) 1237 { 1238 return true; 1239 } 1240 1241 cdesc = _pb.getClassDescriptor(clazz); 1243 refs = cdesc.getObjectReferenceDescriptors(); 1244 hasBidirAssc = false; 1245 REFS_CYCLE: 1246 for (Iterator it = refs.iterator(); it.hasNext(); ) 1247 { 1248 ObjectReferenceDescriptor ord; 1249 ClassDescriptor relCDesc; 1250 Collection relRefs; 1251 1252 ord = (ObjectReferenceDescriptor) it.next(); 1253 relCDesc = _pb.getClassDescriptor(ord.getItemClass()); 1254 relRefs = relCDesc.getObjectReferenceDescriptors(); 1255 for (Iterator relIt = relRefs.iterator(); relIt.hasNext(); ) 1256 { 1257 ObjectReferenceDescriptor relOrd; 1258 1259 relOrd = (ObjectReferenceDescriptor) relIt.next(); 1260 if (relOrd.getItemClass().equals(clazz)) 1261 { 1262 hasBidirAssc = true; 1263 break REFS_CYCLE; 1264 } 1265 } 1266 } 1267 if (hasBidirAssc) 1268 { 1269 _withBidirAssc.add(clazz); 1270 } 1271 else 1272 { 1273 _withoutBidirAssc.add(clazz); 1274 } 1275 1276 return hasBidirAssc; 1277 } 1278 1279 1282 private int markDelete(Identity oid, Identity mainOid, boolean isCollection) 1283 { 1284 ContextEntry entry = (ContextEntry) _objects.get(oid); 1285 1286 if (entry == null) 1287 { 1288 throw new IllegalStateException ("markDelete failed: the dependent object " 1289 + oid + " is not in the editing context"); 1290 } 1291 1292 if (entry.state.isDeleted()) 1293 { 1294 return 0; 1295 } 1296 else 1297 { 1298 entry.state = entry.state.deletePersistent(); 1299 if (mainOid != null) 1300 { 1301 int dependentIndex = _order.indexOf(oid); 1302 int mainIndex = _order.indexOf(mainOid); 1303 1304 if (isCollection) { 1306 if (dependentIndex > mainIndex) 1307 { 1308 _order.remove(dependentIndex); 1309 _order.add(mainIndex, oid); 1310 } 1311 } 1312 else { 1314 if (dependentIndex < mainIndex) 1315 { 1316 _order.remove(dependentIndex); _order.add(mainIndex, oid); 1318 } 1319 } 1320 1321 } 1322 return 1; 1323 } 1324 } 1325 1326 1331 private ArrayList handleDependentReferences(Identity oid, Object userObject, 1332 Object [] origFields, Object [] newFields, Object [] newRefs) 1333 throws LockingException 1334 { 1335 ClassDescriptor mif = _pb.getClassDescriptor(userObject.getClass()); 1336 FieldDescriptor[] fieldDescs = mif.getFieldDescriptions(); 1337 Collection refDescs = mif.getObjectReferenceDescriptors(); 1338 int count = 1 + fieldDescs.length; 1339 ArrayList newObjects = new ArrayList (); 1340 int countRefs = 0; 1341 1342 for (Iterator it = refDescs.iterator(); it.hasNext(); count++, countRefs++) 1343 { 1344 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next(); 1345 Identity origOid = (origFields == null ? null : (Identity) origFields[count]); 1346 Identity newOid = (Identity) newFields[count]; 1347 1348 if (rds.getOtmDependent()) 1349 { 1350 if ((origOid == null) && (newOid != null)) 1351 { 1352 ContextEntry entry = (ContextEntry) _objects.get(newOid); 1353 1354 if (entry == null) 1355 { 1356 Object relObj = newRefs[countRefs]; 1357 insertInternal(newOid, relObj, LockType.WRITE_LOCK, 1358 true, oid, new Stack ()); 1359 newObjects.add(newOid); 1360 } 1361 } 1362 else if ((origOid != null) && 1363 ((newOid == null) || !newOid.equals(origOid))) 1364 { 1365 markDelete(origOid, oid, false); 1366 } 1367 } 1368 } 1369 1370 return newObjects; 1371 } 1372 1373 1377 private ArrayList handleDependentCollections(Identity oid, Object obj, 1378 Object [] origCollections, Object [] newCollections, 1379 Object [] newCollectionsOfObjects) 1380 throws LockingException 1381 { 1382 ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass()); 1383 Collection colDescs = mif.getCollectionDescriptors(); 1384 ArrayList newObjects = new ArrayList (); 1385 int count = 0; 1386 1387 for (Iterator it = colDescs.iterator(); it.hasNext(); count++) 1388 { 1389 CollectionDescriptor cds = (CollectionDescriptor) it.next(); 1390 1391 if (cds.getOtmDependent()) 1392 { 1393 ArrayList origList = (origCollections == null ? null 1394 : (ArrayList ) origCollections[count]); 1395 ArrayList newList = (ArrayList ) newCollections[count]; 1396 1397 if (origList != null) 1398 { 1399 for (Iterator it2 = origList.iterator(); it2.hasNext(); ) 1400 { 1401 Identity origOid = (Identity) it2.next(); 1402 1403 if ((newList == null) || !newList.contains(origOid)) 1404 { 1405 markDelete(origOid, oid, true); 1406 } 1407 } 1408 } 1409 1410 if (newList != null) 1411 { 1412 int countElem = 0; 1413 for (Iterator it2 = newList.iterator(); it2.hasNext(); countElem++) 1414 { 1415 Identity newOid = (Identity) it2.next(); 1416 1417 if ((origList == null) || !origList.contains(newOid)) 1418 { 1419 ContextEntry entry = (ContextEntry) _objects.get(newOid); 1420 1421 if (entry == null) 1422 { 1423 ArrayList relCol = (ArrayList ) 1424 newCollectionsOfObjects[count]; 1425 Object relObj = relCol.get(countElem); 1426 insertInternal(newOid, relObj, LockType.WRITE_LOCK, 1427 true, null, new Stack ()); 1428 newObjects.add(newOid); 1429 } 1430 } 1431 } 1432 } 1433 } 1434 } 1435 1436 return newObjects; 1437 } 1438 1439 1443 private int doCascadeDelete(Identity oid, Object obj) 1444 { 1445 ClassDescriptor mif = _pb.getClassDescriptor(ProxyHelper.getRealClass(obj)); 1446 Collection refDescs = mif.getObjectReferenceDescriptors(); 1447 Collection colDescs = mif.getCollectionDescriptors(); 1448 int countCascadeDeleted = 0; 1449 1450 for (Iterator it = refDescs.iterator(); it.hasNext(); ) 1451 { 1452 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next(); 1453 1454 if (rds.getOtmDependent()) 1455 { 1456 PersistentField f = rds.getPersistentField(); 1457 Object relObj = f.get(obj); 1458 1459 if (relObj != null) 1460 { 1461 countCascadeDeleted += 1462 markDelete(new Identity(relObj, _pb), oid, false); 1463 } 1464 } 1465 } 1466 1467 for (Iterator it = colDescs.iterator(); it.hasNext(); ) 1468 { 1469 CollectionDescriptor cds = (CollectionDescriptor) it.next(); 1470 1471 if (cds.getOtmDependent()) 1472 { 1473 PersistentField f = cds.getPersistentField(); 1474 Class type = f.getType(); 1475 Object col = f.get(obj); 1476 1477 if (col != null) 1478 { 1479 Iterator colIterator; 1480 1481 if (Collection .class.isAssignableFrom(type)) 1482 { 1483 colIterator = ((Collection ) col).iterator(); 1484 } 1485 else if (type.isArray()) 1486 { 1487 colIterator = new ArrayIterator(col); 1488 } 1489 else 1490 { 1491 continue; 1492 } 1493 1494 while (colIterator.hasNext()) 1495 { 1496 1497 countCascadeDeleted += 1498 markDelete(new Identity(colIterator.next(), _pb), oid, true); 1499 } 1500 } 1501 } 1502 } 1503 1504 return countCascadeDeleted; 1505 } 1506 1507 1514 public void cache(Identity oid, Object obj) 1515 { 1516 throw new UnsupportedOperationException (); 1517 } 1518 1519 public boolean cacheIfNew(Identity oid, Object obj) 1520 { 1521 throw new UnsupportedOperationException ("Not implemented"); 1523 } 1524 1525 public void clear() 1526 { 1527 throw new UnsupportedOperationException (); 1528 } 1529 1530 1531 1535 private static class ContextEntry 1536 { 1537 Object userObject; 1538 Object cacheObject; 1539 State state = State.PERSISTENT_CLEAN; 1540 1541 1544 IndirectionHandler handler; 1545 1546 1549 boolean needsCacheSwizzle; 1550 1551 ContextEntry(Object theUserObject) 1552 { 1553 userObject = theUserObject; 1554 if (userObject != null) 1555 { 1556 handler = ProxyHelper.getIndirectionHandler(userObject); 1557 if ((handler != null) && handler.alreadyMaterialized()) 1558 { 1559 userObject = handler.getRealSubject(); 1560 handler = null; 1561 } 1562 } 1563 } 1564 } 1565 1566 private class OTMCollectionProxyListener implements CollectionProxyListener 1567 { 1568 private final CollectionDescriptor _cds; 1569 private final ArrayList [] _collections; 1570 private final int _index; 1571 private final int _lock; 1572 1573 OTMCollectionProxyListener(CollectionDescriptor cds, 1574 ArrayList [] collections, int index, int lock) 1575 { 1576 _cds = cds; 1577 _collections = collections; 1578 _index = index; 1579 _lock = lock; 1580 } 1581 1582 public void beforeLoading(CollectionProxyDefaultImpl colProxy) 1583 { 1584 } 1586 1587 1591 public void afterLoading(CollectionProxyDefaultImpl colProxy) 1592 { 1593 ArrayList list = new ArrayList (); 1594 ArrayList newUserCol = new ArrayList (); 1595 LockManager lockManager = LockManager.getInstance(); 1596 _collections[_index] = list; 1597 1598 for (Iterator it = colProxy.iterator(); it.hasNext(); ) 1599 { 1600 Object relUserObj; 1601 Object relCacheObj = it.next(); 1602 Identity relOid = new Identity(relCacheObj, _pb); 1603 ContextEntry entry; 1604 1605 list.add(relOid); 1606 entry = (ContextEntry) _objects.get(relOid); 1607 if (entry != null) 1608 { 1609 relUserObj = entry.userObject; 1610 } 1611 else 1612 { 1613 ObjectCopyStrategy copyStrategy; 1614 1615 copyStrategy = _tx.getKit().getCopyStrategy(relOid); 1616 relUserObj = copyStrategy.copy(relCacheObj, _pb); 1617 try 1618 { 1619 entry = insertInternal(relOid, relUserObj, _lock, 1620 _cds.getOtmDependent(), null, new Stack ()); 1621 if (entry != null) 1622 { 1623 relUserObj = entry.userObject; 1624 } 1625 } 1626 catch (LockingException ex) 1627 { 1628 throw new LockingPassthruException(ex); 1629 } 1630 } 1631 newUserCol.add(relUserObj); 1632 } 1633 colProxy.clear(); 1634 colProxy.addAll(newUserCol); 1635 } 1636 } 1637} 1638 | Popular Tags |