1 package org.apache.ojb.odmg; 2 3 17 18 import javax.transaction.Status ; 19 import java.util.ArrayList ; 20 import java.util.Collection ; 21 import java.util.Enumeration ; 22 import java.util.HashMap ; 23 import java.util.Iterator ; 24 import java.util.List ; 25 26 import org.apache.commons.lang.SystemUtils; 27 import org.apache.ojb.broker.Identity; 28 import org.apache.ojb.broker.OJBRuntimeException; 29 import org.apache.ojb.broker.PBFactoryException; 30 import org.apache.ojb.broker.PersistenceBroker; 31 import org.apache.ojb.broker.PersistenceBrokerException; 32 import org.apache.ojb.broker.PersistenceBrokerInternal; 33 import org.apache.ojb.broker.core.PersistenceBrokerFactoryFactory; 34 import org.apache.ojb.broker.core.proxy.CollectionProxy; 35 import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl; 36 import org.apache.ojb.broker.core.proxy.CollectionProxyListener; 37 import org.apache.ojb.broker.core.proxy.IndirectionHandler; 38 import org.apache.ojb.broker.core.proxy.MaterializationListener; 39 import org.apache.ojb.broker.core.proxy.ProxyHelper; 40 import org.apache.ojb.broker.metadata.ClassDescriptor; 41 import org.apache.ojb.broker.metadata.CollectionDescriptor; 42 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; 43 import org.apache.ojb.broker.util.BrokerHelper; 44 import org.apache.ojb.broker.util.GUID; 45 import org.apache.ojb.broker.util.configuration.Configurable; 46 import org.apache.ojb.broker.util.configuration.Configuration; 47 import org.apache.ojb.broker.util.configuration.ConfigurationException; 48 import org.apache.ojb.broker.util.logging.Logger; 49 import org.apache.ojb.broker.util.logging.LoggerFactory; 50 import org.apache.ojb.odmg.locking.LockManager; 51 import org.odmg.DatabaseClosedException; 52 import org.odmg.LockNotGrantedException; 53 import org.odmg.ODMGRuntimeException; 54 import org.odmg.Transaction; 55 import org.odmg.TransactionAbortedException; 56 import org.odmg.TransactionNotInProgressException; 57 58 69 public class TransactionImpl 70 implements Transaction, MaterializationListener, Configurable, CollectionProxyListener, TransactionExt 71 { 72 private Logger log = LoggerFactory.getLogger(TransactionImpl.class); 73 private boolean impliciteWriteLocks; 74 private boolean implicitLocking; 75 private boolean ordering; 76 77 private String txGUID; 78 protected PersistenceBrokerInternal broker = null; 79 private ArrayList registrationList = new ArrayList (); 80 private ImplementationImpl implementation; 81 private NamedRootsMap namedRootsMap; 82 83 88 private int txStatus = Status.STATUS_NO_TRANSACTION; 89 90 94 protected ObjectEnvelopeTable objectEnvelopeTable = null; 95 96 99 private DatabaseImpl curDB; 100 105 private ArrayList registeredIndirectionHandlers = new ArrayList (); 106 107 111 private ArrayList registeredCollectionProxies = new ArrayList (); 112 113 117 private ArrayList unmaterializedLocks = new ArrayList (); 118 119 123 public TransactionImpl(ImplementationImpl implementation) 124 { 125 this.implementation = implementation; 126 this.impliciteWriteLocks = implementation.isImpliciteWriteLocks(); 127 this.implicitLocking = implementation.isImplicitLocking(); 128 this.ordering = implementation.isOrdering(); 129 131 txGUID = new GUID().toString(); 133 curDB = implementation.getCurrentDatabase(); 134 namedRootsMap = new NamedRootsMap(this); 135 } 136 137 public ImplementationImpl getImplementation() 138 { 139 return implementation; 140 } 141 142 public NamedRootsMap getNamedRootsMap() 143 { 144 return namedRootsMap; 145 } 146 147 150 public DatabaseImpl getAssociatedDatabase() 151 { 152 return this.curDB; 153 } 154 155 protected int getStatus() 156 { 157 return txStatus; 158 } 159 160 protected void setStatus(int status) 161 { 162 this.txStatus = status; 163 } 164 165 private void checkForDB() 166 { 167 if (curDB == null || !curDB.isOpen()) 168 { 169 log.error("Transaction without a associated open Database."); 170 throw new TransactionAbortedExceptionOJB( 171 "No open database found. Open the database before handling transactions"); 172 } 173 } 174 175 181 public boolean isOpen() 182 { 183 return (getStatus() == Status.STATUS_ACTIVE || 184 getStatus() == Status.STATUS_MARKED_ROLLBACK || 185 getStatus() == Status.STATUS_PREPARED || 186 getStatus() == Status.STATUS_PREPARING || 187 getStatus() == Status.STATUS_COMMITTING); 188 } 189 190 private void checkOpen() 191 { 192 if (!isOpen()) 193 { 194 throw new TransactionNotInProgressException( 195 "Transaction was not open, call tx.begin() before perform action, current status is: " + 196 TxUtil.getStatusString(getStatus())); 197 } 198 } 199 200 201 206 public void join() 207 { 208 checkOpen(); 209 implementation.getTxManager().deregisterTx(this); 210 implementation.getTxManager().registerTx(this); 211 } 212 213 224 public void lock(Object obj, int lockMode) throws LockNotGrantedException 225 { 226 if (log.isDebugEnabled()) log.debug("lock object was called on tx " + this + ", object is " + obj.toString()); 227 checkOpen(); 228 RuntimeObject rtObject = new RuntimeObject(obj, this); 229 lockAndRegister(rtObject, lockMode, isImplicitLocking(), getRegistrationList()); 230 } 232 233 236 public ArrayList getRegistrationList() 237 { 238 clearRegistrationList(); 239 return registrationList; 240 } 241 242 245 public void clearRegistrationList() 246 { 247 registrationList.clear(); 248 } 249 250 254 public void lockAndRegister(RuntimeObject rtObject, int lockMode, List registeredObjects) 255 { 256 lockAndRegister(rtObject, lockMode, isImplicitLocking(), registeredObjects); 257 } 258 259 263 public synchronized void lockAndRegister(RuntimeObject rtObject, int lockMode, boolean cascade, List registeredObjects) 264 { 265 if(log.isDebugEnabled()) log.debug("Lock and register called for " + rtObject.getIdentity()); 266 if(!registeredObjects.contains(rtObject.getIdentity())) 269 { 270 if(cascade) 271 { 272 registeredObjects.add(rtObject.getIdentity()); 275 lockAndRegisterReferences(rtObject.getCld(), rtObject.getObjMaterialized(), lockMode, registeredObjects); 280 } 281 try 282 { 283 if(!rtObject.isNew()) 286 { 287 doSingleLock(rtObject.getCld(), rtObject.getObj(), rtObject.getIdentity(), lockMode); 288 } 289 doSingleRegister(rtObject, lockMode); 291 } 292 catch (Throwable t) 293 { 294 implementation.getLockManager().releaseLock(this, rtObject.getIdentity(), rtObject.getObj()); 298 if(t instanceof LockNotGrantedException) 299 { 300 throw (LockNotGrantedException) t; 301 } 302 else 303 { 304 log.error("Unexpected failure while locking", t); 305 throw new LockNotGrantedException("Locking failed for " 306 + rtObject.getIdentity()+ ", nested exception is: [" + t.getClass().getName() 307 + ": " + t.getMessage() + "]"); 308 } 309 } 310 if(cascade) 311 { 312 lockAndRegisterCollections(rtObject.getCld(), rtObject.getObjMaterialized(), lockMode, registeredObjects); 316 } 317 } 318 } 319 320 332 void doSingleLock(ClassDescriptor cld, Object obj, Identity oid, int lockMode) throws LockNotGrantedException 333 { 334 LockManager lm = implementation.getLockManager(); 335 if (cld.isAcceptLocks()) 336 { 337 if (lockMode == Transaction.READ) 338 { 339 if (log.isDebugEnabled()) log.debug("Do READ lock on object: " + oid); 340 if(!lm.readLock(this, oid, obj)) 341 { 342 throw new LockNotGrantedException("Can not lock for READ: " + oid); 343 } 344 } 345 else if (lockMode == Transaction.WRITE) 346 { 347 if (log.isDebugEnabled()) log.debug("Do WRITE lock on object: " + oid); 348 if(!lm.writeLock(this, oid, obj)) 349 { 350 throw new LockNotGrantedException("Can not lock for WRITE: " + oid); 351 } 352 } 353 else if (lockMode == Transaction.UPGRADE) 354 { 355 if (log.isDebugEnabled()) log.debug("Do UPGRADE lock on object: " + oid); 356 if(!lm.upgradeLock(this, oid, obj)) 357 { 358 throw new LockNotGrantedException("Can not lock for UPGRADE: " + oid); 359 } 360 } 361 } 362 else 363 { 364 if (log.isDebugEnabled()) 365 { 366 log.debug("Class '" + cld.getClassNameOfObject() + "' doesn't accept locks" + 367 " (accept-locks=false) when implicite locked, so OJB skip this object: " + oid); 368 } 369 } 370 } 371 372 376 public void leave() 377 { 378 checkOpen(); 379 implementation.getTxManager().deregisterTx(this); 380 } 381 382 387 protected synchronized void doWriteObjects(boolean isFlush) throws TransactionAbortedException, LockNotGrantedException 388 { 389 393 if (!getBroker().isInTransaction()) 394 { 395 if (log.isDebugEnabled()) log.debug("call beginTransaction() on PB instance"); 396 broker.beginTransaction(); 397 } 398 399 performTransactionAwareBeforeCommit(); 401 402 objectEnvelopeTable.writeObjects(isFlush); 404 namedRootsMap.performDeletion(); 406 namedRootsMap.performInsert(); 407 namedRootsMap.afterWriteCleanup(); 408 } 409 410 415 protected synchronized void doAbort() 416 { 417 performTransactionAwareBeforeRollback(); 419 420 objectEnvelopeTable.rollback(); 422 423 performTransactionAwareAfterRollback(); 425 } 426 427 430 protected synchronized void doClose() 431 { 432 try 433 { 434 LockManager lm = getImplementation().getLockManager(); 435 Enumeration en = objectEnvelopeTable.elements(); 436 while (en.hasMoreElements()) 437 { 438 ObjectEnvelope oe = (ObjectEnvelope) en.nextElement(); 439 lm.releaseLock(this, oe.getIdentity(), oe.getObject()); 440 } 441 442 for (Iterator it = unmaterializedLocks.iterator(); it.hasNext();) 444 { 445 lm.releaseLock(this, it.next()); 446 } 447 448 unRegisterFromAllIndirectionHandlers(); 450 unRegisterFromAllCollectionProxies(); 451 } 452 finally 453 { 454 457 if (log.isDebugEnabled()) 458 log.debug("Close Transaction and release current PB " + broker + " on tx " + this); 459 implementation.getTxManager().deregisterTx(this); 462 refresh(); 464 } 465 } 466 467 470 protected void refresh() 471 { 472 if (log.isDebugEnabled()) 473 log.debug("Refresh this transaction for reuse: " + this); 474 try 475 { 476 objectEnvelopeTable.refresh(); 478 } 479 catch (Exception e) 480 { 481 if (log.isDebugEnabled()) 482 { 483 log.debug("error closing object envelope table : " + e.getMessage()); 484 e.printStackTrace(); 485 } 486 } 487 cleanupBroker(); 488 broker = null; 492 clearRegistrationList(); 493 unmaterializedLocks.clear(); 494 txStatus = Status.STATUS_NO_TRANSACTION; 495 } 496 497 504 public void checkpoint() 505 { 506 if (log.isDebugEnabled()) log.debug("Checkpoint was called, commit changes hold locks on tx " + this); 507 try 508 { 509 checkOpen(); 510 doWriteObjects(true); 511 if (hasBroker() && broker.isInTransaction()) broker.commitTransaction(); 513 } 514 catch (Throwable t) 515 { 516 log.error("Checkpoint call failed, do abort transaction", t); 517 txStatus = Status.STATUS_MARKED_ROLLBACK; 518 abort(); 519 if(!(t instanceof ODMGRuntimeException)) 520 { 521 throw new TransactionAbortedExceptionOJB("Can't tx.checkpoint() objects: " + t.getMessage(), t); 522 } 523 else 524 { 525 throw (ODMGRuntimeException) t; 526 } 527 } 528 } 529 530 533 public void flush() 534 { 535 if (log.isDebugEnabled()) 536 { 537 log.debug("Flush was called - write changes to database, do not commit, hold locks on tx " + this); 538 } 539 540 try 541 { 542 checkOpen(); 543 doWriteObjects(true); 544 } 545 catch (Throwable t) 546 { 547 log.error("Calling method 'tx.flush()' failed", t); 548 txStatus = Status.STATUS_MARKED_ROLLBACK; 549 abort(); 550 if(!(t instanceof ODMGRuntimeException)) 551 { 552 throw new TransactionAbortedExceptionOJB("Can't tx.flush() objects: " + t.getMessage(), t); 553 } 554 else 555 { 556 throw (ODMGRuntimeException) t; 557 } 558 } 559 } 560 561 564 public void markDelete(Object anObject) 565 { 566 ObjectEnvelope otw = objectEnvelopeTable.get(anObject, false); 567 otw.setModificationState(otw.getModificationState().markDelete()); 570 } 571 572 public void deletePersistent(RuntimeObject rt) 573 { 574 if(rt.isProxy()) 579 { 580 Object realObj = rt.getHandler().getRealSubject(); 581 rt = new RuntimeObject(realObj, rt.getIdentity(), this, false); 582 } 583 lockAndRegister(rt, Transaction.WRITE, getRegistrationList()); 584 ObjectEnvelope oe = objectEnvelopeTable.getByIdentity(rt.getIdentity()); 585 oe.refreshObjectIfNeeded(rt.getObj()); 588 oe.setModificationState(oe.getModificationState().markDelete()); 589 } 590 591 594 public void markDirty(Object anObject) 595 { 596 ObjectEnvelope otw = objectEnvelopeTable.get(anObject, false); 597 otw.refreshObjectIfNeeded(anObject); 598 otw.setModificationState(otw.getModificationState().markDirty()); 599 } 600 601 void markDirty(RuntimeObject rt) 602 { 603 ObjectEnvelope otw = objectEnvelopeTable.get(rt.getIdentity(), rt.getObj(), rt.isNew()); 604 otw.refreshObjectIfNeeded(rt.getObj()); 605 otw.setModificationState(otw.getModificationState().markDirty()); 606 } 607 608 void markPersistent(RuntimeObject rtObj) 609 { 610 ObjectEnvelope oe = objectEnvelopeTable.getByIdentity(rtObj.getIdentity()); 611 if(oe == null) 612 { 613 oe = objectEnvelopeTable.get(rtObj.getIdentity(), rtObj.getObj(), rtObj.isNew()); 614 } 615 if(oe.needsDelete()) 616 { 617 oe.setModificationState(oe.getModificationState().markNew()); 618 } 619 else 620 { 621 oe.setModificationState(oe.getModificationState().markDirty()); 622 } 623 oe.refreshObjectIfNeeded(rtObj.getObj()); 624 } 625 626 void makePersistent(RuntimeObject rt) 627 { 628 try 629 { 630 lockAndRegister(rt, Transaction.WRITE, getRegistrationList()); 631 markPersistent(rt); 632 } 633 catch (org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException ex) 634 { 635 log.error("Can't persist object: " + rt.getIdentity(), ex); 636 throw new org.odmg.ClassNotPersistenceCapableException(ex.getMessage()); 637 } 638 } 639 640 643 public boolean isDeleted(Identity id) 644 { 645 ObjectEnvelope envelope = objectEnvelopeTable.getByIdentity(id); 646 return (envelope != null && envelope.needsDelete()); 647 } 648 649 659 public boolean tryLock(Object obj, int lockMode) 660 { 661 if (log.isDebugEnabled()) log.debug("Try to lock object was called on tx " + this); 662 checkOpen(); 663 try 664 { 665 lock(obj, lockMode); 666 return true; 667 } 668 catch (LockNotGrantedException ex) 669 { 670 return false; 671 } 672 } 673 674 693 public void commit() 694 { 695 checkOpen(); 696 try 697 { 698 prepareCommit(); 699 checkForCommit(); 700 701 txStatus = Status.STATUS_COMMITTING; 702 if (log.isDebugEnabled()) log.debug("Commit transaction " + this); 703 if(hasBroker()) getBroker().commitTransaction(); 705 706 performTransactionAwareAfterCommit(); 708 709 doClose(); 710 txStatus = Status.STATUS_COMMITTED; 711 } 712 catch(Exception ex) 713 { 714 log.error("Error while commit objects, do abort tx " + this + ", " + ex.getMessage(), ex); 715 txStatus = Status.STATUS_MARKED_ROLLBACK; 716 abort(); 717 if(!(ex instanceof ODMGRuntimeException)) 718 { 719 throw new TransactionAbortedExceptionOJB("Can't commit objects: " + ex.getMessage(), ex); 720 } 721 else 722 { 723 throw (ODMGRuntimeException) ex; 724 } 725 } 726 } 727 728 protected void checkForCommit() 729 { 730 if (txStatus == Status.STATUS_MARKED_ROLLBACK) 732 throw new TransactionAbortedExceptionOJB("Illegal tx-status: tx is already markedRollback"); 733 if (txStatus != Status.STATUS_PREPARED) 735 throw new IllegalStateException ("Illegal tx-status: Do prepare commit before commit"); 736 } 737 738 749 protected void prepareCommit() throws TransactionAbortedException, LockNotGrantedException 750 { 751 if (txStatus == Status.STATUS_MARKED_ROLLBACK) 752 { 753 throw new TransactionAbortedExceptionOJB("Prepare Transaction: tx already marked for rollback"); 754 } 755 if (txStatus != Status.STATUS_ACTIVE) 756 { 757 throw new IllegalStateException ("Prepare Transaction: tx status is not 'active', status is " + TxUtil.getStatusString(txStatus)); 758 } 759 try 760 { 761 txStatus = Status.STATUS_PREPARING; 762 doWriteObjects(false); 763 txStatus = Status.STATUS_PREPARED; 764 } 765 catch (RuntimeException e) 766 { 767 log.error("Could not prepare for commit", e); 768 txStatus = Status.STATUS_MARKED_ROLLBACK; 769 throw e; 770 } 771 } 772 773 778 public void abort() 779 { 780 783 if (txStatus == Status.STATUS_NO_TRANSACTION 784 || txStatus == Status.STATUS_UNKNOWN 785 || txStatus == Status.STATUS_ROLLEDBACK) 786 { 787 log.info("Nothing to abort, tx is not active - status is " + TxUtil.getStatusString(txStatus)); 788 return; 789 } 790 if (txStatus != Status.STATUS_ACTIVE && txStatus != Status.STATUS_PREPARED && 792 txStatus != Status.STATUS_MARKED_ROLLBACK) 793 { 794 throw new IllegalStateException ("Illegal state for abort call, state was '" + TxUtil.getStatusString(txStatus) + "'"); 795 } 796 if(log.isEnabledFor(Logger.INFO)) 797 { 798 log.info("Abort transaction was called on tx " + this); 799 } 800 try 801 { 802 try 803 { 804 doAbort(); 805 } 806 catch(Exception e) 807 { 808 log.error("Error while abort transaction, will be skipped", e); 809 } 810 811 this.implementation.getTxManager().abortExternalTx(this); 813 814 try 815 { 816 if(hasBroker() && getBroker().isInTransaction()) 817 { 818 getBroker().abortTransaction(); 819 } 820 } 821 catch(Exception e) 822 { 823 log.error("Error while do abort used broker instance, will be skipped", e); 824 } 825 } 826 finally 827 { 828 txStatus = Status.STATUS_ROLLEDBACK; 829 doClose(); 831 } 832 } 833 834 844 public synchronized void begin() 845 { 846 checkForBegin(); 847 if (log.isDebugEnabled()) log.debug("Begin transaction was called on tx " + this); 848 objectEnvelopeTable = new ObjectEnvelopeTable(this); 850 implementation.getTxManager().registerTx(this); 852 txStatus = Status.STATUS_ACTIVE; 854 } 855 856 protected void checkForBegin() 857 { 858 861 if ((curDB == null) || !curDB.isOpen()) 862 { 863 throw new DatabaseClosedException("Database is not open. Must have an open DB to begin the Tx."); 864 } 865 if (isOpen()) 866 { 867 log.error("Transaction is already open"); 868 throw new org.odmg.TransactionInProgressException("Impossible to call begin on already opened tx"); 869 } 870 } 871 872 public String getGUID() 873 { 874 return txGUID; 875 } 876 877 884 public Object getObjectByIdentity(Identity id) 885 throws PersistenceBrokerException 886 { 887 checkOpen(); 888 ObjectEnvelope envelope = objectEnvelopeTable.getByIdentity(id); 889 if (envelope != null) 890 { 891 return (envelope.needsDelete() ? null : envelope.getObject()); 892 } 893 else 894 { 895 return getBroker().getObjectByIdentity(id); 896 } 897 } 898 899 903 void doSingleRegister(RuntimeObject rtObject, int lockMode) 904 throws LockNotGrantedException, PersistenceBrokerException 905 { 906 if(log.isDebugEnabled()) log.debug("Register object " + rtObject.getIdentity()); 907 Object objectToRegister = rtObject.getObj(); 908 925 if(rtObject.isProxy()) 926 { 927 IndirectionHandler handler = rtObject.getHandler(); 928 if(handler == null) 929 { 930 throw new OJBRuntimeException("Unexpected error, expect an proxy object as indicated: " + rtObject); 931 } 932 if (handler.alreadyMaterialized()) 933 { 934 objectToRegister = handler.getRealSubject(); 935 } 936 else 937 { 938 registerToIndirectionHandler(handler); 939 registerUnmaterializedLocks(rtObject.getObj()); 940 objectToRegister = null; 942 } 943 } 944 if (objectToRegister != null) 946 { 947 ObjectEnvelope envelope = objectEnvelopeTable.getByIdentity(rtObject.getIdentity()); 948 if ((envelope == null)) 951 { 952 envelope = objectEnvelopeTable.get(rtObject.getIdentity(), objectToRegister, rtObject.isNew()); 954 } 955 else 956 { 957 963 envelope.refreshObjectIfNeeded(objectToRegister); 964 } 965 970 if(lockMode == Transaction.WRITE) 971 { 972 envelope.setWriteLocked(true); 974 } 975 } 976 } 977 978 983 private void lockAndRegisterReferences(ClassDescriptor cld, Object sourceObject, int lockMode, List registeredObjects) throws LockNotGrantedException 984 { 985 if (implicitLocking) 986 { 987 Iterator i = cld.getObjectReferenceDescriptors(true).iterator(); 988 while (i.hasNext()) 989 { 990 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next(); 991 Object refObj = rds.getPersistentField().get(sourceObject); 992 if (refObj != null) 993 { 994 boolean isProxy = ProxyHelper.isProxy(refObj); 995 RuntimeObject rt = isProxy ? new RuntimeObject(refObj, this, false) : new RuntimeObject(refObj, this); 996 if (!registrationList.contains(rt.getIdentity())) 997 { 998 lockAndRegister(rt, lockMode, registeredObjects); 999 } 1000 } 1001 } 1002 } 1003 } 1004 1005 private void lockAndRegisterCollections(ClassDescriptor cld, Object sourceObject, int lockMode, List registeredObjects) throws LockNotGrantedException 1006 { 1007 if (implicitLocking) 1008 { 1009 Iterator i = cld.getCollectionDescriptors(true).iterator(); 1010 while (i.hasNext()) 1011 { 1012 CollectionDescriptor cds = (CollectionDescriptor) i.next(); 1013 Object col = cds.getPersistentField().get(sourceObject); 1014 if (col != null) 1015 { 1016 CollectionProxy proxy = ProxyHelper.getCollectionProxy(col); 1017 if (proxy != null) 1018 { 1019 if (!proxy.isLoaded()) 1020 { 1021 if (log.isDebugEnabled()) log.debug("adding self as listener to collection proxy"); 1022 proxy.addListener(this); 1023 registeredCollectionProxies.add(proxy); 1024 continue; 1025 } 1026 } 1027 Iterator colIterator = BrokerHelper.getCollectionIterator(col); 1028 Object item = null; 1029 try 1030 { 1031 while (colIterator.hasNext()) 1032 { 1033 item = colIterator.next(); 1034 RuntimeObject rt = new RuntimeObject(item, this); 1035 if (rt.isProxy()) 1036 { 1037 IndirectionHandler handler = ProxyHelper.getIndirectionHandler(item); 1038 if (!handler.alreadyMaterialized()) 1039 { 1040 registerToIndirectionHandler(handler); 1041 continue; 1042 } 1043 else 1044 { 1045 item = handler.getRealSubject(); 1048 } 1049 } 1050 if (!registrationList.contains(rt.getIdentity())) 1051 { 1052 lockAndRegister(rt, lockMode, registeredObjects); 1053 } 1054 } 1055 } 1056 catch (LockNotGrantedException e) 1057 { 1058 String eol = SystemUtils.LINE_SEPARATOR; 1059 log.error("Lock not granted, while lock collection references[" + 1060 eol + "current reference descriptor:" + 1061 eol + cds.toXML() + 1062 eol + "object to lock: " + item + 1063 eol + "main object class: " + sourceObject.getClass().getName() + 1064 eol + "]", e); 1065 throw e; 1066 } 1067 } 1068 } 1069 } 1070 } 1071 1072 1078 public void beforeMaterialization(IndirectionHandler handler, Identity oid) 1079 { 1080 } 1082 1083 1091 public void afterMaterialization(IndirectionHandler handler, Object materializedObject) 1092 { 1093 try 1094 { 1095 Identity oid = handler.getIdentity(); 1096 if (log.isDebugEnabled()) 1097 log.debug("deferred registration: " + oid); 1098 if(!isOpen()) 1099 { 1100 log.error("Proxy object materialization outside of a running tx, obj=" + oid); 1101 try{throw new Exception ("Proxy object materialization outside of a running tx, obj=" + oid);}catch(Exception e) 1102 { 1103 e.printStackTrace(); 1104 } 1105 } 1106 ClassDescriptor cld = getBroker().getClassDescriptor(materializedObject.getClass()); 1107 RuntimeObject rt = new RuntimeObject(materializedObject, oid, cld, false, false); 1108 lockAndRegister(rt, Transaction.READ, isImplicitLocking(), getRegistrationList()); 1109 } 1110 catch (Throwable t) 1111 { 1112 log.error("Register materialized object with this tx failed", t); 1113 throw new LockNotGrantedException(t.getMessage()); 1114 } 1115 unregisterFromIndirectionHandler(handler); 1116 } 1117 1118 protected synchronized void unRegisterFromAllIndirectionHandlers() 1119 { 1120 for (int i = registeredIndirectionHandlers.size() - 1; i >= 0; i--) 1123 { 1124 unregisterFromIndirectionHandler((IndirectionHandler) registeredIndirectionHandlers.get(i)); 1125 } 1126 } 1127 1128 protected synchronized void unRegisterFromAllCollectionProxies() 1129 { 1130 for (int i = registeredCollectionProxies.size() - 1; i >= 0; i--) 1131 { 1132 unregisterFromCollectionProxy((CollectionProxy) registeredCollectionProxies.get(i)); 1133 } 1134 } 1135 1136 protected synchronized void unregisterFromCollectionProxy(CollectionProxy handler) 1137 { 1138 handler.removeListener(this); 1139 registeredCollectionProxies.remove(handler); 1140 } 1141 1142 protected synchronized void unregisterFromIndirectionHandler(IndirectionHandler handler) 1143 { 1144 handler.removeListener(this); 1145 registeredIndirectionHandlers.remove(handler); 1146 } 1147 1148 protected synchronized void registerToIndirectionHandler(IndirectionHandler handler) 1149 { 1150 handler.addListener(this); 1151 registeredIndirectionHandlers.add(handler); 1152 } 1153 1154 1158 protected void registerUnmaterializedLocks(Object obj) 1159 { 1160 unmaterializedLocks.add(obj); 1161 } 1162 1163 1174 public PersistenceBrokerInternal getBrokerInternal() 1175 { 1176 if (broker == null || broker.isClosed()) 1177 { 1178 checkOpen(); 1179 try 1180 { 1181 checkForDB(); 1182 broker = PersistenceBrokerFactoryFactory.instance().createPersistenceBroker(curDB.getPBKey()); 1183 } 1184 catch (PBFactoryException e) 1185 { 1186 log.error("Cannot obtain PersistenceBroker from PersistenceBrokerFactory, " + 1187 "found PBKey was " + curDB.getPBKey(), e); 1188 throw new PersistenceBrokerException(e); 1189 } 1190 } 1191 return broker; 1192 } 1193 1194 public PersistenceBroker getBroker() 1195 { 1196 return getBrokerInternal(); 1197 } 1198 1199 1203 protected boolean hasBroker() 1204 { 1205 return broker != null && !broker.isClosed(); 1206 } 1207 1208 protected void cleanupBroker() 1209 { 1210 if(hasBroker()) 1211 { 1212 try 1213 { 1214 if(broker.isInTransaction()) 1215 { 1216 broker.abortTransaction(); 1217 } 1218 } 1219 finally 1220 { 1221 broker.close(); 1222 broker = null; 1223 } 1224 } 1225 } 1226 1227 1230 public void configure(Configuration config) throws ConfigurationException 1231 { 1232 } 1233 1234 1237 public synchronized void setImplicitLocking(boolean value) 1238 { 1239 implicitLocking = value; 1240 } 1241 1242 public boolean isImplicitLocking() 1243 { 1244 return implicitLocking; 1245 } 1246 1247 1250 public void beforeLoading(CollectionProxyDefaultImpl colProxy) 1251 { 1252 } 1254 1255 1259 public void afterLoading(CollectionProxyDefaultImpl colProxy) 1260 { 1261 if (log.isDebugEnabled()) log.debug("loading a proxied collection a collection: " + colProxy); 1262 Collection data = colProxy.getData(); 1263 for (Iterator iterator = data.iterator(); iterator.hasNext();) 1264 { 1265 Object o = iterator.next(); 1266 if(!isOpen()) 1267 { 1268 log.error("Collection proxy materialization outside of a running tx, obj=" + o); 1269 try{throw new Exception ("Collection proxy materialization outside of a running tx, obj=" + o);} 1270 catch(Exception e) 1271 {e.printStackTrace();} 1272 } 1273 else 1274 { 1275 Identity oid = getBroker().serviceIdentity().buildIdentity(o); 1276 ClassDescriptor cld = getBroker().getClassDescriptor(ProxyHelper.getRealClass(o)); 1277 RuntimeObject rt = new RuntimeObject(o, oid, cld, false, ProxyHelper.isProxy(o)); 1278 lockAndRegister(rt, Transaction.READ, isImplicitLocking(), getRegistrationList()); 1279 } 1280 } 1281 unregisterFromCollectionProxy(colProxy); 1282 } 1283 1284 protected void performTransactionAwareBeforeCommit() 1285 { 1286 Enumeration en = objectEnvelopeTable.elements(); 1287 while (en.hasMoreElements()) 1288 { 1289 ((ObjectEnvelope) en.nextElement()).beforeCommit(); 1290 } 1291 } 1292 protected void performTransactionAwareAfterCommit() 1293 { 1294 Enumeration en = objectEnvelopeTable.elements(); 1295 try 1296 { 1297 while (en.hasMoreElements()) 1298 { 1299 ((ObjectEnvelope) en.nextElement()).afterCommit(); 1300 } 1301 } 1302 catch(Exception e) 1303 { 1304 log.error("Unexpected error while perform 'TransactionAware#afterCommit()' listener after commit of objects," + 1305 " after commit you can't rollback - exception will be skipped.", e); 1306 } 1307 } 1308 protected void performTransactionAwareBeforeRollback() 1309 { 1310 Enumeration en = objectEnvelopeTable.elements(); 1311 while (en.hasMoreElements()) 1312 { 1313 try 1314 { 1315 ((ObjectEnvelope) en.nextElement()).beforeAbort(); 1316 } 1317 catch(Exception e) 1318 { 1319 log.error("Unexpected error while perform 'TransactionAware#beforeAbort()' listener before rollback of objects" + 1320 " - exception will be skipped to complete rollback.", e); 1321 } 1322 } 1323 } 1324 protected void performTransactionAwareAfterRollback() 1325 { 1326 Enumeration en = objectEnvelopeTable.elements(); 1327 try 1328 { 1329 while (en.hasMoreElements()) 1330 { 1331 ((ObjectEnvelope) en.nextElement()).afterAbort(); 1332 } 1333 } 1334 catch(Exception e) 1335 { 1336 log.error("Unexpected error while perform 'TransactionAware#afterAbort()' listener after rollback of objects" + 1337 " - exception will be skipped.", e); 1338 } 1339 } 1340 1341 1344 protected boolean isTransient(ClassDescriptor cld, Object obj, Identity oid) 1345 { 1346 boolean isNew = oid != null && oid.isTransient(); 1348 1355 if(!isNew) 1356 { 1357 final PersistenceBroker pb = getBroker(); 1358 if(cld == null) 1359 { 1360 cld = pb.getClassDescriptor(obj.getClass()); 1361 } 1362 isNew = pb.serviceBrokerHelper().hasNullPKField(cld, obj); 1363 if(!isNew) 1364 { 1365 if(oid == null) 1366 { 1367 oid = pb.serviceIdentity().buildIdentity(cld, obj); 1368 } 1369 final ObjectEnvelope mod = objectEnvelopeTable.getByIdentity(oid); 1370 if(mod != null) 1371 { 1372 isNew = mod.needsInsert(); 1374 } 1375 else 1376 { 1377 isNew = pb.serviceObjectCache().lookup(oid) == null 1380 && !pb.serviceBrokerHelper().doesExist(cld, oid, obj); 1381 } 1382 } 1383 } 1384 return isNew; 1385 } 1386 1387 1395 public void setCascadingDelete(Class target, String referenceField, boolean doCascade) 1396 { 1397 ClassDescriptor cld = getBroker().getClassDescriptor(target); 1398 ObjectReferenceDescriptor ord = cld.getObjectReferenceDescriptorByName(referenceField); 1399 if(ord == null) 1400 { 1401 ord = cld.getCollectionDescriptorByName(referenceField); 1402 } 1403 if(ord == null) 1404 { 1405 throw new CascadeSettingException("Invalid reference field name '" + referenceField 1406 + "', can't find 1:1, 1:n or m:n relation with that name in " + target); 1407 } 1408 runtimeCascadeDeleteMap.put(ord, (doCascade ? Boolean.TRUE : Boolean.FALSE)); 1409 } 1410 1411 1420 public void setCascadingDelete(Class target, boolean doCascade) 1421 { 1422 ClassDescriptor cld = getBroker().getClassDescriptor(target); 1423 List extents = cld.getExtentClasses(); 1424 Boolean result = doCascade ? Boolean.TRUE : Boolean.FALSE; 1425 setCascadingDelete(cld, result); 1426 if(extents != null && extents.size() > 0) 1427 { 1428 for(int i = 0; i < extents.size(); i++) 1429 { 1430 Class extent = (Class ) extents.get(i); 1431 ClassDescriptor tmp = getBroker().getClassDescriptor(extent); 1432 setCascadingDelete(tmp, result); 1433 } 1434 } 1435 } 1436 1437 private void setCascadingDelete(ClassDescriptor cld, Boolean cascade) 1438 { 1439 List singleRefs = cld.getObjectReferenceDescriptors(true); 1440 for(int i = 0; i < singleRefs.size(); i++) 1441 { 1442 Object o = singleRefs.get(i); 1443 runtimeCascadeDeleteMap.put(o, cascade); 1444 } 1445 List collectionRefs = cld.getCollectionDescriptors(true); 1446 for(int i = 0; i < collectionRefs.size(); i++) 1447 { 1448 Object o = collectionRefs.get(i); 1449 runtimeCascadeDeleteMap.put(o, cascade); 1450 } 1451 } 1452 1453 private HashMap runtimeCascadeDeleteMap = new HashMap (); 1454 1458 protected boolean cascadeDeleteFor(ObjectReferenceDescriptor ord) 1459 { 1460 boolean result; 1461 Boolean runtimeSetting = (Boolean ) runtimeCascadeDeleteMap.get(ord); 1462 if(runtimeSetting == null) 1463 { 1464 1467 result = ord.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT; 1468 } 1469 else 1470 { 1471 result = runtimeSetting.booleanValue(); 1472 } 1473 return result; 1474 } 1475 1476 int getImpliciteLockType(int parentLockMode) 1477 { 1478 return (parentLockMode == Transaction.WRITE && impliciteWriteLocks) ? Transaction.WRITE : Transaction.READ; 1479 } 1480 1481 1485 public boolean isOrdering() 1486 { 1487 return ordering; 1488 } 1489 1490 1500 public void setOrdering(boolean ordering) 1501 { 1502 this.ordering = ordering; 1503 } 1504 1505 1506 1512 static class CascadeSettingException extends OJBRuntimeException 1513 { 1514 public CascadeSettingException() 1515 { 1516 } 1517 1518 public CascadeSettingException(String msg) 1519 { 1520 super(msg); 1521 } 1522 1523 public CascadeSettingException(Throwable cause) 1524 { 1525 super(cause); 1526 } 1527 1528 public CascadeSettingException(String msg, Throwable cause) 1529 { 1530 super(msg, cause); 1531 } 1532 } 1533} 1534 | Popular Tags |