1 17 18 package org.apache.geronimo.transaction.context; 19 20 import java.util.HashMap ; 21 import java.util.Iterator ; 22 import java.util.Map ; 23 import javax.resource.spi.XATerminator ; 24 import javax.transaction.InvalidTransactionException ; 25 import javax.transaction.NotSupportedException ; 26 import javax.transaction.Status ; 27 import javax.transaction.SystemException ; 28 import javax.transaction.Transaction ; 29 import javax.transaction.TransactionManager ; 30 import javax.transaction.xa.XAException ; 31 import javax.transaction.xa.XAResource ; 32 import javax.transaction.xa.Xid ; 33 34 import org.apache.geronimo.gbean.GBeanInfo; 35 import org.apache.geronimo.gbean.GBeanInfoBuilder; 36 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 37 import org.apache.geronimo.transaction.ExtendedTransactionManager; 38 import org.apache.geronimo.transaction.ImportedTransactionActiveException; 39 import org.apache.geronimo.transaction.XAWork; 40 import org.apache.geronimo.transaction.manager.XidImporter; 41 import org.apache.commons.logging.Log; 42 import org.apache.commons.logging.LogFactory; 43 44 47 public class TransactionContextManager implements XATerminator , XAWork { 48 private static final Log log = LogFactory.getLog(TransactionContextManager.class); 49 private static final boolean NOT_IN_RECOVERY = false; 50 private static final boolean IN_RECOVERY = true; 51 52 private ThreadLocal CONTEXT = new ThreadLocal (); 53 private final ExtendedTransactionManager transactionManager; 54 private final XidImporter importer; 55 private final Map importedTransactions = new HashMap (); 56 57 private boolean recoveryState = NOT_IN_RECOVERY; 58 59 public TransactionContextManager() { 61 this(null, null); 62 } 63 64 public TransactionContextManager(ExtendedTransactionManager transactionManager, XidImporter importer) { 65 this.transactionManager = transactionManager; 66 this.importer = importer; 67 } 68 69 public TransactionManager getTransactionManager() { 70 return transactionManager; 71 } 72 73 public void setTransactionTimeout(int timeoutSeconds) throws SystemException { 74 transactionManager.setTransactionTimeout(timeoutSeconds); 75 } 76 77 public TransactionContext getContext() { 78 return (TransactionContext) CONTEXT.get(); 79 } 80 81 public void setContext(TransactionContext transactionContext) { 82 CONTEXT.set(transactionContext); 83 } 84 85 public TransactionContext newContainerTransactionContext() throws NotSupportedException , SystemException { 86 ContainerTransactionContext transactionContext = new ContainerTransactionContext(transactionManager); 87 setContext(transactionContext); 88 return transactionContext; 89 } 90 91 public TransactionContext newBeanTransactionContext(long transactionTimeoutMilliseconds) throws NotSupportedException , SystemException { 92 TransactionContext ctx = getContext(); 93 if (ctx instanceof UnspecifiedTransactionContext == false) { 94 throw new NotSupportedException ("Previous Transaction has not been committed"); 95 } 96 UnspecifiedTransactionContext oldContext = (UnspecifiedTransactionContext) ctx; 97 BeanTransactionContext transactionContext = new BeanTransactionContext(transactionManager, oldContext); 98 oldContext.suspend(); 99 try { 100 transactionContext.begin(transactionTimeoutMilliseconds); 101 } catch (SystemException e) { 102 oldContext.resume(); 103 throw e; 104 } catch (NotSupportedException e) { 105 oldContext.resume(); 106 throw e; 107 } 108 setContext(transactionContext); 109 return transactionContext; 110 } 111 112 public TransactionContext newUnspecifiedTransactionContext() { 113 UnspecifiedTransactionContext transactionContext = new UnspecifiedTransactionContext(); 114 setContext(transactionContext); 115 return transactionContext; 116 } 117 118 public TransactionContext suspendBeanTransactionContext() throws SystemException { 119 TransactionContext callerContext = getContext(); 121 if (!(callerContext instanceof BeanTransactionContext)) { 122 throw new SystemException ("Caller context is not a bean managed transaction context"); 123 } 124 BeanTransactionContext beanContext = ((BeanTransactionContext) callerContext); 125 126 UnspecifiedTransactionContext oldContext = beanContext.getOldContext(); 128 beanContext.setOldContext(null); 129 130 try { 132 beanContext.suspend(); 133 return beanContext; 134 } catch (SystemException e) { 135 if (beanContext.isActive()) { 136 try { 137 beanContext.rollback(); 138 } catch (SystemException e1) { 139 log.warn("Unable to rollback transaction", e); 140 } 141 } 142 throw e; 143 } finally { 144 setContext(oldContext); 146 oldContext.resume(); 147 setContext(oldContext); 148 } 149 } 150 151 public void resumeBeanTransactionContext(TransactionContext context) throws SystemException , InvalidTransactionException { 152 if (!(context instanceof BeanTransactionContext)) { 153 throw new InvalidTransactionException ("Context is not a bean managed transaction context"); 154 } 155 if (!context.isActive()) { 156 throw new InvalidTransactionException ("Context is not active"); 157 } 158 BeanTransactionContext beanContext = ((BeanTransactionContext) context); 159 160 TransactionContext callerContext = getContext(); 162 if (!(callerContext instanceof UnspecifiedTransactionContext)) { 163 throw new InvalidTransactionException ("Caller context is not an unspecified transaction context"); 164 } 165 callerContext.suspend(); 166 167 try { 168 beanContext.setOldContext((UnspecifiedTransactionContext) callerContext); 169 context.resume(); 170 setContext(context); 171 } catch (SystemException e) { 172 if (beanContext.isActive()) { 173 try { 174 beanContext.rollback(); 175 } catch (SystemException e1) { 176 log.warn("Unable to rollback transaction", e); 177 } 178 } 179 beanContext.setOldContext(null); 180 callerContext.resume(); 181 throw e; 182 } catch (InvalidTransactionException e) { 183 if (beanContext.isActive()) { 184 try { 185 beanContext.rollback(); 186 } catch (SystemException e1) { 187 log.warn("Unable to rollback transaction", e); 188 } 189 } 190 beanContext.setOldContext(null); 191 callerContext.resume(); 192 throw e; 193 } 194 } 195 196 public int getStatus() throws SystemException { 197 return transactionManager.getStatus(); 198 } 199 200 public void setRollbackOnly() throws SystemException { 201 transactionManager.setRollbackOnly(); 202 } 203 204 205 208 public void commit(Xid xid, boolean onePhase) throws XAException { 209 ContainerTransactionContext containerTransactionContext; 210 synchronized (importedTransactions) { 211 containerTransactionContext = (ContainerTransactionContext) importedTransactions.remove(xid); 212 } 213 if (containerTransactionContext == null) { 214 throw new XAException ("No imported transaction for xid: " + xid); 215 } 216 217 try { 218 int status = containerTransactionContext.getTransaction().getStatus(); 219 assert status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARED: "invalid status: " + status; 220 } catch (SystemException e) { 221 throw new XAException (); 222 } 223 importer.commit(containerTransactionContext.getTransaction(), onePhase); 224 } 225 226 229 public void forget(Xid xid) throws XAException { 230 ContainerTransactionContext containerTransactionContext; 231 synchronized (importedTransactions) { 232 containerTransactionContext = (ContainerTransactionContext) importedTransactions.remove(xid); 233 } 234 if (containerTransactionContext == null) { 235 throw new XAException ("No imported transaction for xid: " + xid); 236 } 237 importer.forget(containerTransactionContext.getTransaction()); 245 } 246 247 250 public int prepare(Xid xid) throws XAException { 251 ContainerTransactionContext containerTransactionContext; 252 synchronized (importedTransactions) { 253 containerTransactionContext = (ContainerTransactionContext) importedTransactions.get(xid); 254 } 255 if (containerTransactionContext == null) { 256 throw new XAException ("No imported transaction for xid: " + xid); 257 } 258 Transaction tx = containerTransactionContext.getTransaction(); 259 try { 260 int status = tx.getStatus(); 261 assert status == Status.STATUS_ACTIVE; 262 } catch (SystemException e) { 263 throw new XAException (); 264 } 265 return importer.prepare(tx); 266 } 267 268 271 public Xid [] recover(int flag) throws XAException { 272 if (recoveryState == NOT_IN_RECOVERY) { 273 if ((flag & XAResource.TMSTARTRSCAN) == 0) { 274 throw new XAException (XAException.XAER_PROTO); 275 } 276 recoveryState = IN_RECOVERY; 277 } 278 if ((flag & XAResource.TMENDRSCAN) != 0) { 279 recoveryState = NOT_IN_RECOVERY; 280 } 281 if ((flag & XAResource.TMSTARTRSCAN) != 0) { 284 Map recoveredXidMap = transactionManager.getExternalXids(); 285 Xid [] recoveredXids = new Xid [recoveredXidMap.size()]; 286 int i = 0; 287 synchronized (importedTransactions) { 288 for (Iterator iterator = recoveredXidMap.entrySet().iterator(); iterator.hasNext();) { 289 Map.Entry entry = (Map.Entry ) iterator.next(); 290 Xid xid = (Xid ) entry.getKey(); 291 recoveredXids[i++] = xid; 292 ContainerTransactionContext containerTransactionContext = new ContainerTransactionContext(transactionManager, (Transaction ) entry.getValue()); 293 importedTransactions.put(xid, containerTransactionContext); 294 } 295 } 296 return recoveredXids; 297 } else { 298 return new Xid [0]; 299 } 300 } 301 302 305 public void rollback(Xid xid) throws XAException { 306 ContainerTransactionContext containerTransactionContext; 307 synchronized (importedTransactions) { 308 containerTransactionContext = (ContainerTransactionContext) importedTransactions.remove(xid); 309 } 310 if (containerTransactionContext == null) { 311 throw new XAException ("No imported transaction for xid: " + xid); 312 } 313 Transaction tx = containerTransactionContext.getTransaction(); 314 315 try { 316 int status = tx.getStatus(); 317 assert status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARED; 318 } catch (SystemException e) { 319 throw new XAException (); 320 } 321 importer.rollback(tx); 322 } 323 324 325 public void begin(Xid xid, long txTimeoutMillis) throws XAException , InvalidTransactionException , SystemException , ImportedTransactionActiveException { 327 ContainerTransactionContext containerTransactionContext; 328 synchronized (importedTransactions) { 329 containerTransactionContext = (ContainerTransactionContext) importedTransactions.get(xid); 330 if (containerTransactionContext == null) { 331 Transaction transaction = importer.importXid(xid, txTimeoutMillis); 333 containerTransactionContext = new ContainerTransactionContext(transactionManager, transaction); 334 importedTransactions.put(xid, containerTransactionContext); 335 } else { 336 if (containerTransactionContext.isThreadAssociated()) { 337 throw new ImportedTransactionActiveException(xid); 338 } 339 } 340 containerTransactionContext.resume(); 341 } 342 setContext(containerTransactionContext); 343 } 344 345 public void end(Xid xid) throws XAException , SystemException { 346 setContext(null); 347 synchronized (importedTransactions) { 348 ContainerTransactionContext containerTransactionContext = (ContainerTransactionContext) importedTransactions.get(xid); 349 if (containerTransactionContext == null) { 350 throw new XAException ("No imported transaction for xid: " + xid); 351 } 352 if (!containerTransactionContext.isThreadAssociated()) { 353 throw new XAException ("tx not active for containerTransactionContext: " + containerTransactionContext + ", xid: " + xid); 354 } 355 containerTransactionContext.suspend(); 356 } 357 } 358 359 360 public static final GBeanInfo GBEAN_INFO; 361 362 static { 363 GBeanInfoBuilder infoFactory = new GBeanInfoBuilder(TransactionContextManager.class, NameFactory.JTA_RESOURCE); 364 365 infoFactory.addOperation("getTransactionManager"); 366 infoFactory.addOperation("getContext"); 367 infoFactory.addOperation("setContext", new Class []{TransactionContext.class}); 368 infoFactory.addOperation("newContainerTransactionContext"); 369 infoFactory.addOperation("newBeanTransactionContext", new Class [] {long.class}); 370 infoFactory.addOperation("newUnspecifiedTransactionContext"); 371 infoFactory.addOperation("resumeBeanTransactionContext", new Class [] {TransactionContext.class}); 372 infoFactory.addOperation("suspendBeanTransactionContext"); 373 infoFactory.addOperation("getStatus"); 374 infoFactory.addOperation("setRollbackOnly"); 375 infoFactory.addOperation("setTransactionTimeout", new Class [] {int.class}); 376 377 infoFactory.addReference("TransactionManager", ExtendedTransactionManager.class, NameFactory.JTA_RESOURCE); 378 infoFactory.addReference("XidImporter", XidImporter.class, NameFactory.JTA_RESOURCE); 379 380 infoFactory.addInterface(XATerminator .class); 381 infoFactory.addInterface(XAWork.class); 382 383 infoFactory.setConstructor(new String []{"TransactionManager", "XidImporter"}); 384 GBEAN_INFO = infoFactory.getBeanInfo(); 385 } 386 387 public static GBeanInfo getGBeanInfo() { 388 return GBEAN_INFO; 389 } 390 391 } 392 | Popular Tags |