1 17 18 package org.apache.geronimo.transaction.context; 19 20 import java.util.Iterator ; 21 import java.util.Map ; 22 import java.util.ArrayList ; 23 import javax.transaction.SystemException ; 24 import javax.transaction.Status ; 25 import javax.transaction.Transaction ; 26 import javax.transaction.InvalidTransactionException ; 27 import javax.transaction.NotSupportedException ; 28 import javax.transaction.HeuristicMixedException ; 29 import javax.transaction.HeuristicRollbackException ; 30 import javax.transaction.RollbackException ; 31 import javax.transaction.Synchronization ; 32 import javax.transaction.xa.XAResource ; 33 34 import org.apache.geronimo.transaction.ExtendedTransactionManager; 35 import org.apache.geronimo.transaction.ConnectionReleaser; 36 import org.apache.geronimo.transaction.InstanceContext; 37 38 41 abstract class InheritableTransactionContext extends AbstractTransactionContext { 42 private final ExtendedTransactionManager txnManager; 43 private Transaction transaction; 44 private boolean threadAssociated = false; 45 46 protected InheritableTransactionContext(ExtendedTransactionManager txnManager) { 47 this.txnManager = txnManager; 48 } 49 50 protected InheritableTransactionContext(ExtendedTransactionManager txnManager, Transaction transaction) { 51 this.txnManager = txnManager; 52 this.transaction = transaction; 53 } 54 55 void begin(long transactionTimeoutMilliseconds) throws SystemException , NotSupportedException { 56 if (transaction != null) { 57 throw new SystemException ("Context is already associated with a transaction"); 58 } 59 transaction = txnManager.begin(transactionTimeoutMilliseconds); 60 threadAssociated = true; 61 } 62 63 boolean isThreadAssociated() { 64 return threadAssociated; 65 } 66 67 public Transaction getTransaction() { 68 return transaction; 69 } 70 71 public boolean isInheritable() { 72 return true; 73 } 74 75 public boolean isActive() { 76 if (transaction == null) { 77 return false; 78 } 79 try { 80 int status = transaction.getStatus(); 81 return status == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK; 82 } catch (SystemException e) { 83 return false; 84 } 85 } 86 87 public boolean enlistResource(XAResource xaResource) throws RollbackException , SystemException { 88 if (transaction == null) { 89 throw new IllegalStateException ("There is no transaction in progress."); 90 } 91 92 return transaction.enlistResource(xaResource); 93 } 94 95 public boolean delistResource(XAResource xaResource, int flag) throws SystemException { 96 if (transaction == null) { 97 throw new IllegalStateException ("There is no transaction in progress."); 98 } 99 100 return transaction.delistResource(xaResource, flag); 101 } 102 103 public void registerSynchronization(Synchronization synchronization) throws RollbackException , SystemException { 104 if (transaction == null) { 105 throw new IllegalStateException ("There is no transaction in progress."); 106 } 107 108 transaction.registerSynchronization(synchronization); 109 } 110 111 public boolean getRollbackOnly() throws SystemException { 112 if (transaction == null) { 113 throw new IllegalStateException ("There is no transaction in progress."); 114 } 115 116 int status = transaction.getStatus(); 117 return (status == Status.STATUS_MARKED_ROLLBACK || 118 status == Status.STATUS_ROLLEDBACK || 119 status == Status.STATUS_ROLLING_BACK); 120 } 121 122 public void setRollbackOnly() throws IllegalStateException , SystemException { 123 if (transaction == null) { 124 throw new IllegalStateException ("There is no transaction in progress."); 125 } 126 transaction.setRollbackOnly(); 127 } 128 129 public void suspend() throws SystemException { 130 Transaction suspendedTransaction = txnManager.suspend(); 131 if (transaction != suspendedTransaction) { 132 throw new SystemException ("Suspend did not return our transaction: expectedTx=" + transaction + ", suspendedTx=" + suspendedTransaction); 133 } 134 threadAssociated = false; 135 } 136 137 public void resume() throws SystemException , InvalidTransactionException { 138 txnManager.resume(transaction); 139 threadAssociated = true; 140 } 141 142 public boolean commit() throws HeuristicMixedException , HeuristicRollbackException , SystemException , RollbackException { 143 return complete(); 144 } 145 146 public void rollback() throws SystemException { 147 setRollbackOnly(); 148 try { 149 complete(); 150 } catch (SystemException e) { 151 throw e; 152 } catch (RuntimeException e) { 153 throw e; 154 } catch (Error e) { 155 throw e; 156 } catch (Exception e) { 157 throw (SystemException ) new SystemException ("After commit of container transaction failed").initCause(e); 158 } 159 } 160 161 private boolean complete() throws HeuristicMixedException , HeuristicRollbackException , SystemException , RollbackException { 162 if (transaction == null) { 163 throw new IllegalStateException ("There is no transaction in progress."); 164 } 165 166 boolean wasCommitted = false; 167 try { 168 if (isRolledback()) { 169 return false; 170 } 171 172 flushState(); 173 174 if (isRolledback()) { 175 return false; 176 } 177 178 beforeCommit(); 180 181 if (isRolledback()) { 182 return false; 183 } 184 185 Transaction currentTransaction = txnManager.getTransaction(); 189 if (currentTransaction != transaction) { 190 throw new SystemException ("An unknown transaction is currently associated with the thread: expectedTx=" + transaction + ", currentTx=" + currentTransaction); 191 } 192 193 txnManager.commit(); 194 wasCommitted = true; 195 } catch (Throwable t) { 196 rollbackAndThrow("Unable to commit container transaction", t); 197 } finally { 198 transaction = null; 199 try { 200 afterCommit(wasCommitted); 201 } catch (Throwable e) { 202 rollbackAndThrow("After commit of container transaction failed", e); 203 } finally { 204 unassociateAll(); 205 connectorAfterCommit(); 206 threadAssociated = false; 207 } 208 } 209 return wasCommitted; 210 } 211 212 private void beforeCommit() throws Throwable { 213 ArrayList toFlush = getAssociatedContexts(); 215 for (Iterator i = toFlush.iterator(); i.hasNext();) { 216 InstanceContext context = (InstanceContext) i.next(); 217 if (!context.isDead()) { 218 context.beforeCommit(); 219 } 220 } 221 } 222 223 private void afterCommit(boolean status) throws Throwable { 224 Throwable firstThrowable = null; 225 ArrayList toFlush = getAssociatedContexts(); 226 for (Iterator i = toFlush.iterator(); i.hasNext();) { 227 InstanceContext context = (InstanceContext) i.next(); 228 if (!context.isDead()) { 229 try { 230 context.afterCommit(status); 231 } catch (Throwable e) { 232 if (firstThrowable == null) { 233 firstThrowable = e; 234 } 235 } 236 } 237 } 238 239 if (firstThrowable instanceof Error ) { 240 throw (Error ) firstThrowable; 241 } else if (firstThrowable instanceof Exception ) { 242 throw (Exception ) firstThrowable; 243 } else if (firstThrowable != null) { 244 throw (SystemException ) new SystemException ().initCause(firstThrowable); 245 } 246 } 247 248 private void connectorAfterCommit() { 249 if (managedConnections != null) { 250 for (Iterator entries = managedConnections.entrySet().iterator(); entries.hasNext();) { 251 Map.Entry entry = (Map.Entry ) entries.next(); 252 ConnectionReleaser key = (ConnectionReleaser) entry.getKey(); 253 key.afterCompletion(entry.getValue()); 254 } 255 managedConnections.clear(); 258 } 259 } 260 261 private boolean isRolledback() throws SystemException { 262 int status; 263 try { 264 status = transaction.getStatus(); 265 } catch (SystemException e) { 266 transaction.rollback(); 267 throw e; 268 } 269 270 if (status == Status.STATUS_MARKED_ROLLBACK) { 271 Transaction currentTransaction = txnManager.getTransaction(); 275 if (currentTransaction != transaction) { 276 throw new SystemException ("An unknown transaction is currently associated with the thread: expectedTx=" + transaction + ", currentTx=" + currentTransaction); 277 } 278 279 txnManager.rollback(); 281 return true; 282 } else if (status == Status.STATUS_ROLLEDBACK || 283 status == Status.STATUS_ROLLING_BACK) { 284 return true; 286 } 287 return false; 288 } 289 290 private void rollbackAndThrow(String message, Throwable throwable) throws HeuristicMixedException , HeuristicRollbackException , SystemException , RollbackException { 291 try { 292 if (txnManager.getStatus() != Status.STATUS_NO_TRANSACTION) { 293 txnManager.rollback(); 294 } 295 } catch (Throwable t) { 296 log.error("Unable to roll back transaction", t); 297 } 298 299 try { 300 int status = transaction.getStatus(); 303 if (status != Status.STATUS_ROLLEDBACK && 304 status != Status.STATUS_ROLLING_BACK) { 305 transaction.rollback(); 306 } 307 } catch (Throwable t) { 308 log.error("Unable to roll back transaction", t); 309 } 310 311 if (throwable instanceof HeuristicMixedException ) { 312 throw (HeuristicMixedException ) throwable; 313 } else if (throwable instanceof HeuristicRollbackException ) { 314 throw (HeuristicRollbackException ) throwable; 315 } else if (throwable instanceof RollbackException ) { 316 throw (RollbackException ) throwable; 317 } else if (throwable instanceof SystemException ) { 318 throw (SystemException ) throwable; 319 } else if (throwable instanceof Error ) { 320 throw (Error ) throwable; 321 } else if (throwable instanceof RuntimeException ) { 322 throw (RuntimeException ) throwable; 323 } else { 324 throw (SystemException ) new SystemException (message).initCause(throwable); 325 } 326 } 327 } 328 | Popular Tags |