/* */ package org.jboss.ejb.plugins;
/* */
/* */ import java.lang.reflect.Method;
/* */ import java.rmi.RemoteException;
/* */ import java.util.ArrayList;
/* */ import java.util.Iterator;
/* */ import java.util.Map;
/* */ import java.util.Random;
/* */ import javax.ejb.EJBException;
/* */ import javax.ejb.TransactionRequiredLocalException;
/* */ import javax.transaction.HeuristicMixedException;
/* */ import javax.transaction.HeuristicRollbackException;
/* */ import javax.transaction.RollbackException;
/* */ import javax.transaction.SystemException;
/* */ import javax.transaction.Transaction;
/* */ import javax.transaction.TransactionManager;
/* */ import javax.transaction.TransactionRequiredException;
/* */ import javax.transaction.TransactionRolledbackException;
/* */ import org.jboss.ejb.Container;
/* */ import org.jboss.invocation.Invocation;
/* */ import org.jboss.invocation.InvocationType;
/* */ import org.jboss.logging.Logger;
/* */ import org.jboss.metadata.ApplicationMetaData;
/* */ import org.jboss.metadata.BeanMetaData;
/* */ import org.jboss.metadata.MetaData;
/* */ import org.jboss.metadata.XmlLoadable;
/* */ import org.jboss.tm.JBossTransactionRolledbackException;
/* */ import org.jboss.tm.JBossTransactionRolledbackLocalException;
/* */ import org.jboss.tm.TransactionTimeoutConfiguration;
/* */ import org.jboss.util.NestedException;
/* */ import org.jboss.util.deadlock.ApplicationDeadlockException;
/* */ import org.w3c.dom.Element;
/* */
/* */ public class TxInterceptorCMT extends AbstractTxInterceptor
/* */ implements XmlLoadable
/* */ {
/* 71 */ public static int MAX_RETRIES = 5;
/* 72 */ public static Random random = new Random();
/* */
/* 80 */ private boolean exceptionRollback = true;
/* */
/* 82 */ private TxRetryExceptionHandler[] retryHandlers = null;
/* */
/* */ public static ApplicationDeadlockException isADE(Throwable t)
/* */ {
/* 92 */ while (t != null)
/* */ {
/* 94 */ if ((t instanceof ApplicationDeadlockException))
/* */ {
/* 96 */ return (ApplicationDeadlockException)t;
/* */ }
/* 98 */ if ((t instanceof RemoteException))
/* */ {
/* 100 */ t = ((RemoteException)t).detail; continue;
/* */ }
/* 102 */ if ((t instanceof EJBException))
/* */ {
/* 104 */ t = ((EJBException)t).getCausedByException(); continue;
/* */ }
/* */
/* 108 */ return null;
/* */ }
/* */
/* 111 */ return null;
/* */ }
/* */
/* */ public void importXml(Element ielement)
/* */ {
/* */ try
/* */ {
/* 124 */ Element element = MetaData.getOptionalChild(ielement, "retry-handlers");
/* 125 */ if (element == null) return;
/* 126 */ ArrayList list = new ArrayList();
/* 127 */ Iterator handlers = MetaData.getChildrenByTagName(element, "handler");
/* 128 */ while (handlers.hasNext())
/* */ {
/* 130 */ Element handler = (Element)handlers.next();
/* 131 */ String className = MetaData.getElementContent(handler).trim();
/* 132 */ Class clazz = SecurityActions.getContextClassLoader().loadClass(className);
/* 133 */ list.add(clazz.newInstance());
/* */ }
/* 135 */ this.retryHandlers = ((TxRetryExceptionHandler[])(TxRetryExceptionHandler[])list.toArray(new TxRetryExceptionHandler[list.size()]));
/* */ }
/* */ catch (Exception ex)
/* */ {
/* 139 */ this.log.warn("Unable to importXml for the TxInterceptorCMT", ex);
/* */ }
/* */ }
/* */
/* */ public void create()
/* */ throws Exception
/* */ {
/* 147 */ super.create();
/* 148 */ BeanMetaData bmd = getContainer().getBeanMetaData();
/* 149 */ this.exceptionRollback = bmd.getExceptionRollback();
/* 150 */ if (!this.exceptionRollback)
/* 151 */ this.exceptionRollback = bmd.getApplicationMetaData().getExceptionRollback();
/* */ }
/* */
/* */ public Object invokeHome(Invocation invocation) throws Exception
/* */ {
/* 156 */ Transaction oldTransaction = invocation.getTransaction();
/* 157 */ for (int i = 0; i < MAX_RETRIES; i++)
/* */ {
/* */ try
/* */ {
/* 161 */ return runWithTransactions(invocation);
/* */ }
/* */ catch (Exception ex)
/* */ {
/* 165 */ checkRetryable(i, ex, oldTransaction);
/* */ }
/* */ }
/* 168 */ throw new RuntimeException("Unreachable");
/* */ }
/* */
/* */ public Object invoke(Invocation invocation)
/* */ throws Exception
/* */ {
/* 176 */ Transaction oldTransaction = invocation.getTransaction();
/* 177 */ for (int i = 0; i < MAX_RETRIES; i++)
/* */ {
/* */ try
/* */ {
/* 181 */ return runWithTransactions(invocation);
/* */ }
/* */ catch (Exception ex)
/* */ {
/* 185 */ checkRetryable(i, ex, oldTransaction);
/* */ }
/* */ }
/* 188 */ throw new RuntimeException("Unreachable");
/* */ }
/* */
/* */ private void checkRetryable(int i, Exception ex, Transaction oldTransaction)
/* */ throws Exception
/* */ {
/* 195 */ if ((i + 1 >= MAX_RETRIES) || (oldTransaction != null)) throw ex;
/* */
/* 197 */ ApplicationDeadlockException deadlock = isADE(ex);
/* 198 */ if (deadlock != null)
/* */ {
/* 200 */ if (!deadlock.retryable()) throw deadlock;
/* 201 */ this.log.debug(deadlock.getMessage() + " retrying tx " + (i + 1));
/* */ }
/* 203 */ else if (this.retryHandlers != null)
/* */ {
/* 205 */ boolean retryable = false;
/* 206 */ for (int j = 0; j < this.retryHandlers.length; j++)
/* */ {
/* 208 */ retryable = this.retryHandlers[j].retry(ex);
/* 209 */ if (retryable) break;
/* */ }
/* 211 */ if (!retryable) throw ex;
/* 212 */ this.log.debug(ex.getMessage() + " retrying tx " + (i + 1));
/* */ }
/* */ else
/* */ {
/* 216 */ throw ex;
/* */ }
/* 218 */ Thread.sleep(random.nextInt(1 + i), random.nextInt(1000));
/* */ }
/* */
/* */ private void printMethod(Method m, byte type)
/* */ {
/* */ String txName;
/* 226 */ switch (type)
/* */ {
/* */ case 4:
/* 229 */ txName = "TX_MANDATORY";
/* 230 */ break;
/* */ case 5:
/* 232 */ txName = "TX_NEVER";
/* 233 */ break;
/* */ case 0:
/* 235 */ txName = "TX_NOT_SUPPORTED";
/* 236 */ break;
/* */ case 1:
/* 238 */ txName = "TX_REQUIRED";
/* 239 */ break;
/* */ case 3:
/* 241 */ txName = "TX_REQUIRES_NEW";
/* 242 */ break;
/* */ case 2:
/* 244 */ txName = "TX_SUPPORTS";
/* 245 */ break;
/* */ default:
/* 247 */ txName = "TX_UNKNOWN";
/* */ }
/* */ String methodName;
/* */ String methodName;
/* 251 */ if (m != null)
/* 252 */ methodName = m.getName();
/* */ else {
/* 254 */ methodName = "<no method>";
/* */ }
/* 256 */ if (this.log.isTraceEnabled())
/* */ {
/* 258 */ if ((m != null) && ((type == 1) || (type == 3)))
/* 259 */ this.log.trace(txName + " for " + methodName + " timeout=" + this.container.getBeanMetaData().getTransactionTimeout(methodName));
/* */ else
/* 261 */ this.log.trace(txName + " for " + methodName);
/* */ }
/* */ }
/* */
/* */ private Object runWithTransactions(Invocation invocation)
/* */ throws Exception
/* */ {
/* 284 */ Transaction oldTransaction = invocation.getTransaction();
/* */
/* 286 */ Transaction newTransaction = null;
/* */
/* 288 */ boolean trace = this.log.isTraceEnabled();
/* 289 */ if (trace) {
/* 290 */ this.log.trace("Current transaction in MI is " + oldTransaction);
/* */ }
/* 292 */ InvocationType type = invocation.getType();
/* 293 */ byte transType = this.container.getBeanMetaData().getTransactionMethod(invocation.getMethod(), type);
/* */
/* 295 */ if (trace) {
/* 296 */ printMethod(invocation.getMethod(), transType);
/* */ }
/* */
/* 302 */ Transaction threadTx = this.tm.suspend();
/* 303 */ if (trace)
/* 304 */ this.log.trace("Thread came in with tx " + threadTx);
/* */ try
/* */ {
/* */ Object theTransaction;
/* */ Object result;
/* */ Object result;
/* */ Object result;
/* 307 */ switch (transType)
/* */ {
/* */ case 0:
/* */ try
/* */ {
/* 314 */ invocation.setTransaction(null);
/* 315 */ localObject1 = invokeNext(invocation, false);
/* */ }
/* */ finally
/* */ {
/* */ Object localObject1;
/* 319 */ invocation.setTransaction(oldTransaction);
/* */ }
/* */
/* */ case 1:
/* 324 */ int oldTimeout = 0;
/* 325 */ theTransaction = oldTransaction;
/* 326 */ if (oldTransaction == null)
/* */ {
/* 329 */ oldTimeout = startTransaction(invocation);
/* */
/* 332 */ newTransaction = this.tm.getTransaction();
/* 333 */ if (trace) {
/* 334 */ this.log.trace("Starting new tx " + newTransaction);
/* */ }
/* */
/* 337 */ invocation.setTransaction(newTransaction);
/* 338 */ theTransaction = newTransaction;
/* */ }
/* */ else
/* */ {
/* 344 */ this.tm.resume(oldTransaction);
/* */ }
/* */
/* */ try
/* */ {
/* 350 */ result = invokeNext(invocation, oldTransaction != null);
/* 351 */ checkTransactionStatus((Transaction)theTransaction, type);
/* 352 */ localObject4 = result;
/* */ }
/* */ finally
/* */ {
/* */ Object localObject4;
/* 356 */ if (trace) {
/* 357 */ this.log.trace("TxInterceptorCMT: In finally");
/* */ }
/* */
/* 360 */ if (newTransaction != null)
/* 361 */ endTransaction(invocation, newTransaction, oldTransaction, oldTimeout);
/* */ else {
/* 363 */ this.tm.suspend();
/* */ }
/* */
/* */ }
/* */
/* */ case 2:
/* 371 */ if (oldTransaction != null)
/* */ {
/* 373 */ this.tm.resume(oldTransaction);
/* */ }
/* */
/* */ try
/* */ {
/* 378 */ Object result = invokeNext(invocation, oldTransaction != null);
/* 379 */ if (oldTransaction != null)
/* 380 */ checkTransactionStatus(oldTransaction, type);
/* 381 */ theTransaction = result;
/* */ }
/* */ finally
/* */ {
/* 385 */ this.tm.suspend();
/* */ }
/* */
/* */ case 3:
/* 394 */ int oldTimeout = startTransaction(invocation);
/* */
/* 397 */ newTransaction = this.tm.getTransaction();
/* */
/* 400 */ invocation.setTransaction(newTransaction);
/* */ try
/* */ {
/* 404 */ result = invokeNext(invocation, false);
/* 405 */ checkTransactionStatus(newTransaction, type);
/* 406 */ result = result;
/* */ }
/* */ finally
/* */ {
/* 411 */ endTransaction(invocation, newTransaction, oldTransaction, oldTimeout);
/* */ }
/* */
/* */ case 4:
/* 416 */ if (oldTransaction == null)
/* */ {
/* 418 */ if ((type == InvocationType.LOCAL) || (type == InvocationType.LOCALHOME))
/* */ {
/* 421 */ throw new TransactionRequiredLocalException("Transaction Required");
/* */ }
/* */
/* 426 */ throw new TransactionRequiredException("Transaction Required");
/* */ }
/* */
/* 432 */ this.tm.resume(oldTransaction);
/* */ try
/* */ {
/* 435 */ result = invokeNext(invocation, true);
/* 436 */ checkTransactionStatus(oldTransaction, type);
/* 437 */ result = result;
/* */ }
/* */ finally
/* */ {
/* 441 */ this.tm.suspend();
/* */ }
/* */
/* */ case 5:
/* 446 */ if (oldTransaction != null)
/* */ {
/* 448 */ throw new EJBException("Transaction not allowed");
/* */ }
/* 450 */ result = invokeNext(invocation, false); jsr 59;
/* */ }
/* */
/* 453 */ this.log.error("Unknown TX attribute " + transType + " for method" + invocation.getMethod());
/* */ }
/* */ finally
/* */ {
/* 459 */ if (threadTx != null) {
/* 460 */ this.tm.resume(threadTx);
/* */ }
/* */ }
/* 463 */ return null;
/* */ }
/* */
/* */ private int startTransaction(Invocation invocation)
/* */ throws Exception
/* */ {
/* 469 */ int oldTimeout = -1;
/* 470 */ if ((this.tm instanceof TransactionTimeoutConfiguration))
/* */ {
/* 472 */ oldTimeout = ((TransactionTimeoutConfiguration)this.tm).getTransactionTimeout();
/* 473 */ int newTimeout = this.container.getBeanMetaData().getTransactionTimeout(invocation.getMethod());
/* 474 */ this.tm.setTransactionTimeout(newTimeout);
/* */ }
/* 476 */ this.tm.begin();
/* 477 */ return oldTimeout;
/* */ }
/* */
/* */ private void endTransaction(Invocation invocation, Transaction tx, Transaction oldTx, int oldTimeout)
/* */ throws TransactionRolledbackException, SystemException
/* */ {
/* 484 */ Transaction current = this.tm.getTransaction();
/* 485 */ if (((tx == null) && (current != null)) || (!tx.equals(current))) {
/* 486 */ throw new IllegalStateException("Wrong transaction association: expected " + tx + " was " + current);
/* */ }
/* */
/* */ try
/* */ {
/* 491 */ if (tx.getStatus() == 1)
/* */ {
/* 493 */ tx.rollback();
/* */ }
/* */ else
/* */ {
/* 501 */ tx.commit();
/* */ }
/* */ }
/* */ catch (RollbackException e)
/* */ {
/* 506 */ throwJBossException(e, invocation.getType());
/* */ }
/* */ catch (HeuristicMixedException e)
/* */ {
/* 510 */ throwJBossException(e, invocation.getType());
/* */ }
/* */ catch (HeuristicRollbackException e)
/* */ {
/* 514 */ throwJBossException(e, invocation.getType());
/* */ }
/* */ catch (SystemException e)
/* */ {
/* 518 */ throwJBossException(e, invocation.getType());
/* */ }
/* */ catch (IllegalStateException e)
/* */ {
/* 522 */ throwJBossException(e, invocation.getType());
/* */ }
/* */ finally
/* */ {
/* 527 */ invocation.setTransaction(oldTx);
/* */
/* 536 */ this.tm.suspend();
/* */
/* 538 */ if (oldTimeout != -1)
/* 539 */ this.tm.setTransactionTimeout(oldTimeout);
/* */ }
/* */ }
/* */
/* */ protected void throwJBossException(Exception e, InvocationType type)
/* */ throws TransactionRolledbackException
/* */ {
/* 558 */ if ((e instanceof NestedException))
/* */ {
/* 560 */ NestedException rollback = (NestedException)e;
/* 561 */ if ((rollback.getCause() instanceof Exception))
/* */ {
/* 563 */ e = (Exception)rollback.getCause();
/* */ }
/* */ }
/* 566 */ if ((type == InvocationType.LOCAL) || (type == InvocationType.LOCALHOME))
/* */ {
/* 569 */ throw new JBossTransactionRolledbackLocalException(e);
/* */ }
/* */
/* 573 */ throw new JBossTransactionRolledbackException(e);
/* */ }
/* */
/* */ protected void checkTransactionStatus(Transaction tx, InvocationType type)
/* */ throws TransactionRolledbackException
/* */ {
/* 590 */ if (this.exceptionRollback)
/* */ {
/* 592 */ if (this.log.isTraceEnabled())
/* 593 */ this.log.trace("No exception from ejb, checking transaction status: " + tx);
/* 594 */ int status = 5;
/* */ try
/* */ {
/* 597 */ status = tx.getStatus();
/* */ }
/* */ catch (Throwable t)
/* */ {
/* 601 */ this.log.debug("Ignored error trying to retrieve transaction status", t);
/* */ }
/* 603 */ if (status != 0)
/* */ {
/* 605 */ Exception e = new Exception("Transaction cannot be committed (probably transaction timeout): " + tx);
/* 606 */ throwJBossException(e, type);
/* */ }
/* */ }
/* */ }
/* */
/* */ public void sample(Object s)
/* */ {
/* */ }
/* */
/* */ public Map retrieveStatistic()
/* */ {
/* 620 */ return null;
/* */ }
/* */
/* */ public void resetStatistic()
/* */ {
/* */ }
/* */ }
/* Location: /home/mnovotny/projects/EMBEDDED_JBOSS_BETA3_COMMUNITY/embedded/output/lib/embedded-jboss/lib/jboss-embedded-all.jar
* Qualified Name: org.jboss.ejb.plugins.TxInterceptorCMT
* JD-Core Version: 0.6.0
*/