User: sparre
Date: 01/06/25 12:45:50
Modified: src/main/org/jboss/ejb/plugins TxInterceptorBMT.java
TxInterceptorCMT.java
Added: src/main/org/jboss/ejb/plugins AbstractTxInterceptor.java
AbstractTxInterceptorBMT.java
Log:
Transaction interceptors cleanup and reorganization.
Revision Changes Path
1.18 +49 -369 jboss/src/main/org/jboss/ejb/plugins/TxInterceptorBMT.java
Index: TxInterceptorBMT.java
===================================================================
RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/TxInterceptorBMT.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- TxInterceptorBMT.java 2001/06/18 20:01:23 1.17
+++ TxInterceptorBMT.java 2001/06/25 19:45:49 1.18
@@ -6,384 +6,64 @@
*/
package org.jboss.ejb.plugins;
-import java.lang.reflect.Method;
-import java.rmi.RemoteException;
-import java.rmi.ServerError;
-import java.rmi.ServerException;
-import java.util.*;
-
-import javax.swing.tree.*;
-
-import javax.transaction.Status;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import javax.transaction.RollbackException;
-import javax.transaction.TransactionRequiredException;
-import javax.transaction.SystemException;
-import javax.transaction.UserTransaction;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.Name;
-import javax.naming.Reference;
-import javax.naming.RefAddr;
-import javax.naming.spi.ObjectFactory;
-
-import javax.ejb.EJBException;
-
-import org.jboss.ejb.Container;
-import org.jboss.ejb.EnterpriseContext;
-import org.jboss.ejb.StatefulSessionEnterpriseContext;
-import org.jboss.ejb.StatelessSessionEnterpriseContext;
+
import org.jboss.ejb.MethodInvocation;
-import org.jboss.tm.TxManager;
-import org.jboss.logging.Logger;
-import org.jboss.metadata.MetaData;
-import org.jboss.metadata.BeanMetaData;
import org.jboss.metadata.SessionMetaData;
-import org.jboss.metadata.MethodMetaData;
/**
-* <description>
-*
-* @see <related>
-* @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
-* @author <a href="mailto:[EMAIL PROTECTED]">Sebastien Alborini</a>
-* @author <a href="mailto:[EMAIL PROTECTED]">Peter Antman</a>.
-* @author <a href="mailto:[EMAIL PROTECTED]">Anatoly Akkerman</a>
-* @version $Revision: 1.17 $
-*/
+ * This interceptor handles transactions for session BMT beans.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Sebastien Alborini</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Peter Antman</a>.
+ * @author <a href="mailto:[EMAIL PROTECTED]">Anatoly Akkerman</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a>
+ * @version $Revision: 1.18 $
+ */
public class TxInterceptorBMT
-extends AbstractInterceptor
+ extends AbstractTxInterceptorBMT
{
+
+ // Attributes ----------------------------------------------------
+
+ // Static --------------------------------------------------------
+
+ // Constructors --------------------------------------------------
+
+ // Public --------------------------------------------------------
+
+ // Interceptor implementation --------------------------------------
+
+ public void init()
+ throws Exception
+ {
+ // Do initialization in superclass.
+ super.init();
+
+ // Set the atateless attribute
+ stateless = ((SessionMetaData)container.getBeanMetaData()).isStateless();
+ }
+
+ public Object invokeHome(MethodInvocation mi)
+ throws Exception
+ {
+ if (stateless)
+ // stateless: no context, no transaction, no call to the instance
+ return getNext().invokeHome(mi);
+ else
+ return invokeNext(false, mi);
+ }
+
+ public Object invoke(MethodInvocation mi)
+ throws Exception
+ {
+ return invokeNext(true, mi);
+ }
- // Attributes ----------------------------------------------------
- // Protected to be able to inherit, pra
- protected TxManager tm;
-
- // lookup on java:comp/UserTransaction should be redirected to
- // sessionContext.getUserTransaction()
- // The ThreadLocal associates the thread to the UserTransaction
- ThreadLocal userTransaction = new ThreadLocal();
-
- protected Container container;
-
- // Static --------------------------------------------------------
-
- // Constructors --------------------------------------------------
-
- // Public --------------------------------------------------------
- public void setContainer(Container container)
- {
- this.container = container;
- }
-
- public Container getContainer()
- {
- return container;
- }
-
- // Interceptor implementation --------------------------------------
- public void init()
- throws Exception
- {
- // Store TM reference locally
- tm = (TxManager) getContainer().getTransactionManager();
-
- // bind java:comp/UserTransaction
- RefAddr refAddr = new RefAddr("userTransaction") {
- public Object getContent() {
- return userTransaction;
- }
- };
-
- Reference ref = new Reference("javax.transaction.UserTransaction",
- refAddr,
- new UserTxFactory().getClass().getName(),
- null);
- ((Context)new
InitialContext().lookup("java:comp/")).bind("UserTransaction", ref);
-
- }
-
- public void stop()
- {
- try
- {
- ((Context)new
InitialContext().lookup("java:comp/")).unbind("UserTransaction");
- }
- catch (Exception e)
- {
- //ignore
- }
- }
-
- public Object invokeHome(MethodInvocation mi)
- throws Exception
- {
- // set the threadlocal to the userTransaction of the instance
- // (mi has the sessioncontext from the previous interceptor)
- if (((SessionMetaData)container.getBeanMetaData()).isStateful()) {
-
- // Save old userTx
- Object oldUserTx = userTransaction.get();
-
- // retrieve the real userTransaction
-
userTransaction.set(((StatefulSessionEnterpriseContext)mi.getEnterpriseContext()).getSessionContext().getUserTransaction());
-
- // t1 refers to the client transaction (spec ejb1.1, 11.6.1, p174)
- // this is necessary for optimized (inVM) calls: threads come
associated with the client transaction
- Transaction t1 = tm.getTransaction();
-
- // t2 refers to the instance transaction (spec ejb1.1, 11.6.1, p174)
- Transaction t2 = mi.getEnterpriseContext().getTransaction();
-
- try {
-
- if (t2 == null) {
- tm.suspend();
- }
- else if (! t2.equals(t1) ){
- tm.suspend();
- // associate the transaction to the thread
- tm.resume(t2);
-
- } // else we are in the proper tx context
-
- return getNext().invokeHome(mi);
-
- } catch (RuntimeException e)
- {
- // EJB 2.0 17.3, table 16
- if (mi.getEnterpriseContext().getTransaction() != null) {
- try {
-
mi.getEnterpriseContext().getTransaction().setRollbackOnly();
- } catch (IllegalStateException ex) {
- }
- }
-
- if (e instanceof EJBException) {
- throw new ServerException("Transaction rolled back",
- ((EJBException)
e).getCausedByException());
- } else {
- throw new ServerException("Transaction rolled back", e);
- }
- } catch (RemoteException e)
- {
- // EJB 2.0 17.3, table 16
- if (mi.getEnterpriseContext().getTransaction() != null) {
- try {
-
mi.getEnterpriseContext().getTransaction().setRollbackOnly();
- } catch (IllegalStateException ex) {
- }
- }
-
- throw new ServerException("Transaction rolled back", e);
- } catch (Error e)
- {
- // EJB 2.0 17.3, table 16
- if (mi.getEnterpriseContext().getTransaction() != null) {
- try {
-
mi.getEnterpriseContext().getTransaction().setRollbackOnly();
- } catch (IllegalStateException ex) {
- }
- }
-
- throw new ServerException("Transaction rolled
back:"+e.getMessage());
- } finally {
-
- // Reset user Tx
- userTransaction.set(oldUserTx);
-
- Transaction currentTx = tm.getTransaction();
- if (t1 == null) {
- tm.suspend();
- }
- else if (! t1.equals(currentTx)) {
-
- tm.suspend();
- // reassociate the previous transaction before returning
- tm.resume(t1);
- } // else we are in the right tx context, do nothing
- }
- } else {
-
- // stateless: no context, no transaction, no call to the instance
-
- return getNext().invokeHome(mi);
- }
-
-
- }
-
- /**
- * This method does invocation interpositioning of tx management
- *
- * @param id
- * @param m
- * @param args
- * @return
- * @exception Exception
- */
- public Object invoke(MethodInvocation mi) throws Exception {
-
- // Store old UserTX
- Object oldUserTx = userTransaction.get();
-
- // set the threadlocal to the userTransaction of the instance
- // (mi has the sessioncontext from the previous interceptor)
- if (((SessionMetaData)container.getBeanMetaData()).isStateful()) {
-
- // retrieve the real userTransaction
-
userTransaction.set(((StatefulSessionEnterpriseContext)mi.getEnterpriseContext()).getSessionContext().getUserTransaction());
-
- } else {
-
- // retrieve the real userTransaction
-
userTransaction.set(((StatelessSessionEnterpriseContext)mi.getEnterpriseContext()).getSessionContext().getUserTransaction());
- }
-
-
- // t1 refers to the client transaction (spec ejb1.1, 11.6.1, p174)
- // this is necessary for optimized (inVM) calls: threads come associated
with the client transaction
- Transaction t1 = tm.getTransaction();
-
-//DEBUG Logger.debug("TxInterceptorBMT disassociate" + ((t1==null) ? "null":
Integer.toString(t1.hashCode())));
-
- // t2 refers to the instance transaction (spec ejb1.1, 11.6.1, p174)
- Transaction t2 = mi.getEnterpriseContext().getTransaction();
-
- // This is BMT so the transaction is dictated by the Bean, the
MethodInvocation follows
- mi.setTransaction(t2);
-
-//DEBUG Logger.debug("TxInterceptorBMT t2 in context" + ((t2==null) ? "null":
Integer.toString(t2.hashCode())));
-
- try {
-
- if (t2 == null) {
-
- tm.suspend();
- }
- else if ( ! t2.equals(t1) ) {
-
- tm.suspend();
- // associate the transaction to the thread
- tm.resume(t2);
-
- }
- // else we are in the right tx context
-
- return getNext().invoke(mi);
-
- } catch (RuntimeException e)
- {
- // EJB 2.0 17.3, table 16
- if (mi.getEnterpriseContext().getTransaction() != null) {
- try {
- mi.getEnterpriseContext().getTransaction().setRollbackOnly();
- } catch (IllegalStateException ex) {
- }
- }
-
- if (e instanceof EJBException) {
- throw new ServerException("Transaction rolled back",
- ((EJBException)
e).getCausedByException());
- } else {
- throw new ServerException("Transaction rolled back", e);
- }
- } catch (RemoteException e)
- {
- // EJB 2.0 17.3, table 16
- if (mi.getEnterpriseContext().getTransaction() != null) {
- try {
- mi.getEnterpriseContext().getTransaction().setRollbackOnly();
- } catch (IllegalStateException ex) {
- }
- }
-
- throw new ServerException("Transaction rolled back", e);
- } catch (Error e)
- {
- // EJB 2.0 17.3, table 16
- if (mi.getEnterpriseContext().getTransaction() != null) {
- try {
- mi.getEnterpriseContext().getTransaction().setRollbackOnly();
- } catch (IllegalStateException ex) {
- }
- }
-
- throw new ServerError("Transaction rolled back", e);
- } finally {
-
- // Reset user Tx
- userTransaction.set(oldUserTx);
-
-//DEBUG Logger.debug("TxInterceptorBMT reassociating client tx " +
-//DEBUG (t1==null?"null":String.valueOf(t1.hashCode())));
-
-
- Transaction currentTx = tm.getTransaction();
- if (t1 == null) {
-
- tm.suspend();
- }
- else if (! t1.equals(currentTx)) {
-
- tm.suspend();
- // reassociate the previous transaction before returning
- tm.resume(t1);
- } // else we are in the right tx context, do nothing
-
- if (((SessionMetaData)container.getBeanMetaData()).isStateless()) {
-
- // t3 is the transaction associated with the context at the end of
the call
- Transaction t3 = mi.getEnterpriseContext().getTransaction();
-
-//DEBUG Logger.debug("in TxIntBMT " + t3);
-
- // for a stateless sessionbean the transaction should be completed
at the end of the call
- if (t3 != null) switch (t3.getStatus()) {
- case Status.STATUS_ACTIVE:
- case Status.STATUS_COMMITTING:
- case Status.STATUS_MARKED_ROLLBACK:
- case Status.STATUS_PREPARING:
- case Status.STATUS_ROLLING_BACK:
-
- t3.rollback();
-
- case Status.STATUS_PREPARED:
-
- // cf ejb1.1 11.6.1
- Logger.error("Application error: BMT stateless bean " +
container.getBeanMetaData().getEjbName() + " should complete transactions before
returning (ejb1.1 spec, 11.6.1)");
-
- // the instance interceptor will discard the instance
- throw new RemoteException("Application error: BMT stateless
bean " + container.getBeanMetaData().getEjbName() + " should complete transactions
before returning (ejb1.1 spec, 11.6.1)");
- }
- }
- }
- }
-
- // Protected ----------------------------------------------------
-
- // Inner classes -------------------------------------------------
-
- public static class UserTxFactory implements ObjectFactory {
- public Object getObjectInstance(Object ref,
- Name name,
- Context nameCtx,
- Hashtable environment)
- throws Exception
- {
-
- // the ref is a list with only one refAddr whose content is the
threadlocal
- ThreadLocal threadLocal =
(ThreadLocal)((Reference)ref).get(0).getContent();
-
- // the threadlocal holds the UserTransaction
- // we can now return the userTx, calls on it will indirect on the right
context
- return threadLocal.get();
+ // Protected ----------------------------------------------------
- }
- }
+ // Inner classes -------------------------------------------------
}
1.13 +5 -132 jboss/src/main/org/jboss/ejb/plugins/TxInterceptorCMT.java
Index: TxInterceptorCMT.java
===================================================================
RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/TxInterceptorCMT.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- TxInterceptorCMT.java 2001/06/20 05:56:11 1.12
+++ TxInterceptorCMT.java 2001/06/25 19:45:49 1.13
@@ -8,29 +8,17 @@
import java.lang.reflect.Method;
import java.rmi.RemoteException;
-import java.rmi.ServerException;
-import java.rmi.NoSuchObjectException;
import java.util.HashMap;
import javax.transaction.Status;
import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import javax.transaction.RollbackException;
import javax.transaction.TransactionRequiredException;
-import javax.transaction.TransactionRolledbackException;
-import javax.transaction.SystemException;
-import javax.ejb.EJBException;
-import javax.ejb.NoSuchEntityException;
-
-import org.jboss.ejb.Container;
-import org.jboss.ejb.EnterpriseContext;
import org.jboss.ejb.MethodInvocation;
import org.jboss.logging.Logger;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.BeanMetaData;
-import org.jboss.metadata.MethodMetaData;
/**
* This interceptor handles transactions for CMT beans.
@@ -40,58 +28,25 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Sebastien Alborini</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Anatoly Akkerman</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a>
- * @version $Revision: 1.12 $
+ * @version $Revision: 1.13 $
*/
public class TxInterceptorCMT
-extends AbstractInterceptor
+ extends AbstractTxInterceptor
{
// Attributes ----------------------------------------------------
- /** Local reference to the container's TransactionManager. */
- private TransactionManager tm;
-
/** A cache mapping methods to transaction attributes. */
private HashMap methodTx = new HashMap();
- /** The container that we manage transactions for. */
- protected Container container;
-
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
- /**
- * Set the container that we manage transactions for.
- */
- public void setContainer(Container container)
- {
- this.container = container;
- }
-
- /**
- * Set the container that we manage transactions for.
- */
- public Container getContainer()
- {
- return container;
- }
-
// Interceptor implementation --------------------------------------
- public void init()
- throws Exception
- {
- // Store TM reference locally
- tm = (TransactionManager) getContainer().getTransactionManager();
- // Find out method->tx-type mappings from meta-info
- // EnterpriseBean eb = getContainer.getMetaData();
- // eb.getBeanContext()
-
- }
-
public Object invokeHome(MethodInvocation mi)
throws Exception
{
@@ -107,6 +62,8 @@
return runWithTransactions(true, mi);
}
+ // Private ------------------------------------------------------
+
private void printMethod(Method m, byte type) {
String name;
switch(type) {
@@ -135,90 +92,6 @@
}
/*
- * This method calls the next interceptor in the chain.
- *
- * Throwables <code>Error</code>, <code>RemoteException</code> and
- * <code>RuntimeException</code> are caught and result in the transaction
- * being marked for rollback only. If such a non-application exception
- * happens with a transaction that was not started locally, it is wrapped
- * in a <code>TransactionRolledbackException</code>.
- *
- * @param remoteInvocation If <code>true</code> this is an invocation
- * of a method in the remote interface, otherwise
- * it is an invocation of a method in the home
- * interface.
- * @param mi The <code>MethodInvocation</code> of this call.
- * @param newTx If <code>true</code> the transaction has just been
- * started in this interceptor.
- */
- private Object invokeNext(boolean remoteInvocation, MethodInvocation mi,
boolean newTx)
- throws Exception
- {
- try {
- if (remoteInvocation)
- return getNext().invoke(mi);
- else
- return getNext().invokeHome(mi);
- } catch (RuntimeException e) {
- try {
- mi.getTransaction().setRollbackOnly();
- } catch (SystemException ex) {
- Logger.exception(ex);
- } catch (IllegalStateException ex) {
- Logger.exception(ex);
- }
- RemoteException ex;
- if (newTx) {
- if (e instanceof NoSuchEntityException) {
- // Convert NoSuchEntityException to a NoSuchObjectException
- // with the same detail.
- ex = new NoSuchObjectException(e.getMessage());
- ex.detail = ((NoSuchEntityException)e).getCausedByException();
- throw ex;
- }
- // OSH: Should this be wrapped?
- ex = new ServerException(e.getMessage());
- } else
- // We inherited tx: Tell caller that we marked for rollback only.
- ex = new TransactionRolledbackException(e.getMessage());
- ex.detail = e;
- throw ex;
- } catch (RemoteException e) {
- try {
- mi.getTransaction().setRollbackOnly();
- } catch (SystemException ex) {
- Logger.exception(ex);
- } catch (IllegalStateException ex) {
- Logger.exception(ex);
- }
- RemoteException ex;
- if (newTx) {
- if (e instanceof NoSuchObjectException)
- throw e; // Do not wrap this.
- // OSH: Should this be wrapped?
- ex = new ServerException(e.getMessage());
- } else
- ex = new TransactionRolledbackException(e.getMessage());
- ex.detail = e;
- throw ex;
- } catch (Error e) {
- if (mi.getTransaction() != null) {
- try {
- mi.getTransaction().setRollbackOnly();
- } catch (IllegalStateException ex) {
- }
- RemoteException tre = new
TransactionRolledbackException(e.getMessage());
- tre.detail = e;
- throw tre;
- } else {
- // This exception will be transformed into a RemoteException
- // by the LogInterceptor
- throw e;
- }
- }
- }
-
- /*
* This method does invocation interpositioning of tx management.
*
* This is where the meat is. We define what to do with the Tx based
@@ -246,7 +119,7 @@
//DEBUG Logger.debug("Current transaction in MI is
"+mi.getTransaction());
//DEBUG Logger.debug("Current method "+mi.getMethod());
byte transType = getTransactionMethod(mi.getMethod(), remoteInvocation);
- printMethod(mi.getMethod(), transType);
+ // printMethod(mi.getMethod(), transType);
// Thread arriving must be clean (jboss doesn't set the thread
// previously). However optimized calls come with associated
1.1 jboss/src/main/org/jboss/ejb/plugins/AbstractTxInterceptor.java
Index: AbstractTxInterceptor.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.ejb.plugins;
import java.rmi.RemoteException;
import java.rmi.ServerException;
import java.rmi.NoSuchObjectException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionRolledbackException;
import javax.transaction.SystemException;
import javax.ejb.NoSuchEntityException;
import org.jboss.ejb.Container;
import org.jboss.ejb.MethodInvocation;
import org.jboss.logging.Logger;
/**
* A common superclass for the transaction interceptors.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a>
* @version $Revision: 1.1 $
*/
abstract class AbstractTxInterceptor
extends AbstractInterceptor
{
// Attributes ----------------------------------------------------
/** Local reference to the container's TransactionManager. */
protected TransactionManager tm;
/** The container that we manage transactions for. */
protected Container container;
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
/**
* Set the container that we manage transactions for.
*/
public void setContainer(Container container)
{
this.container = container;
}
/**
* Get the container that we manage transactions for.
*/
public Container getContainer()
{
return container;
}
// Interceptor implementation --------------------------------------
public void init()
throws Exception
{
tm = (TransactionManager) getContainer().getTransactionManager();
}
// Protected ----------------------------------------------------
/**
* This method calls the next interceptor in the chain.
*
* Throwables <code>Error</code>, <code>RemoteException</code> and
* <code>RuntimeException</code> are caught and result in the transaction
* being marked for rollback only. If such a non-application exception
* happens with a transaction that was not started locally, it is wrapped
* in a <code>TransactionRolledbackException</code>.
*
* @param remoteInvocation If <code>true</code> this is an invocation
* of a method in the remote interface, otherwise
* it is an invocation of a method in the home
* interface.
* @param mi The <code>MethodInvocation</code> of this call.
* @param newTx If <code>true</code> the transaction has just been
* started in this interceptor.
*/
protected Object invokeNext(boolean remoteInvocation, MethodInvocation mi,
boolean newTx)
throws Exception
{
try {
if (remoteInvocation)
return getNext().invoke(mi);
else
return getNext().invokeHome(mi);
} catch (RuntimeException e) {
try {
mi.getTransaction().setRollbackOnly();
} catch (SystemException ex) {
Logger.exception(ex);
} catch (IllegalStateException ex) {
Logger.exception(ex);
}
RemoteException ex;
if (newTx) {
if (e instanceof NoSuchEntityException) {
// Convert NoSuchEntityException to a NoSuchObjectException
// with the same detail.
ex = new NoSuchObjectException(e.getMessage());
ex.detail = ((NoSuchEntityException)e).getCausedByException();
throw ex;
}
// OSH: Should this be wrapped?
ex = new ServerException(e.getMessage());
} else
// We inherited tx: Tell caller we marked for rollback only.
ex = new TransactionRolledbackException(e.getMessage());
ex.detail = e;
throw ex;
} catch (RemoteException e) {
try {
mi.getTransaction().setRollbackOnly();
} catch (SystemException ex) {
Logger.exception(ex);
} catch (IllegalStateException ex) {
Logger.exception(ex);
}
RemoteException ex;
if (newTx) {
if (e instanceof NoSuchObjectException)
throw e; // Do not wrap this.
// OSH: Should this be wrapped?
ex = new ServerException(e.getMessage());
} else
ex = new TransactionRolledbackException(e.getMessage());
ex.detail = e;
throw ex;
} catch (Error e) {
if (mi.getTransaction() != null) {
try {
mi.getTransaction().setRollbackOnly();
} catch (IllegalStateException ex) {
}
RemoteException tre = new
TransactionRolledbackException(e.getMessage());
tre.detail = e;
throw tre;
} else {
// This exception will be transformed into a RemoteException
// by the LogInterceptor
throw e;
}
}
}
// Inner classes -------------------------------------------------
}
1.1
jboss/src/main/org/jboss/ejb/plugins/AbstractTxInterceptorBMT.java
Index: AbstractTxInterceptorBMT.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.ejb.plugins;
import java.util.Hashtable;
import java.rmi.RemoteException;
import javax.transaction.Transaction;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.Reference;
import javax.naming.RefAddr;
import javax.naming.spi.ObjectFactory;
import org.jboss.ejb.EnterpriseContext;
import org.jboss.ejb.MethodInvocation;
import org.jboss.logging.Logger;
/**
* A common superclass for the BMT transaction interceptors.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a>
* @version $Revision: 1.1 $
*/
abstract class AbstractTxInterceptorBMT
extends AbstractTxInterceptor
{
// Attributes ----------------------------------------------------
/**
* This associates the thread to the UserTransaction.
*
* It is used to redirect lookups on java:comp/UserTransaction to
* the <code>getUserTransaction()</code> method of the context.
*/
private ThreadLocal userTransaction = new ThreadLocal();
/**
* If <code>false</code>, transactions may live across bean instance
* invocations, otherwise the bean instance should terminate any
* transaction before returning from the invocation.
* This attribute defaults to <code>true</code>.
*/
protected boolean stateless = true;
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
// Interceptor implementation --------------------------------------
public void init()
throws Exception
{
// Do initialization in superclass.
super.init();
// bind java:comp/UserTransaction
RefAddr refAddr = new RefAddr("userTransaction") {
public Object getContent() {
return userTransaction;
}
};
Reference ref = new Reference("javax.transaction.UserTransaction",
refAddr,
new UserTxFactory().getClass().getName(),
null);
((Context)new InitialContext().lookup("java:comp/")).bind("UserTransaction",
ref);
}
public void stop()
{
// bind java:comp/UserTransaction
try {
((Context)new
InitialContext().lookup("java:comp/")).unbind("UserTransaction");
} catch (Exception e) {
//ignore
}
}
// Protected ----------------------------------------------------
/*
* This method calls the next interceptor in the chain.
*
* It handles the suspension of any client transaction, and the
* association of the calling thread with the instance transaction.
* And it takes care that any lookup of
* <code>java:comp/UserTransaction</code> will return the right
* UserTransaction for the bean instance.
*
* @param remoteInvocation If <code>true</code> this is an invocation
* of a method in the remote interface, otherwise
* it is an invocation of a method in the home
* interface.
* @param mi The <code>MethodInvocation</code> of this call.
*/
protected Object invokeNext(boolean remoteInvocation, MethodInvocation mi)
throws Exception
{
// Save the transaction that comes with the MI
Transaction oldTransaction = mi.getTransaction();
// Get old threadlocal: It may be non-null if one BMT bean does a local
// call to another.
Object oldUserTx = userTransaction.get();
// Suspend any transaction associated with the thread: It may be
// non-null on optimized local calls.
Transaction threadTx = tm.suspend();
try {
EnterpriseContext ctx = mi.getEnterpriseContext();
// Set the threadlocal to the userTransaction of the instance
userTransaction.set(ctx.getEJBContext().getUserTransaction());
// Get the bean instance transaction
Transaction beanTx = ctx.getTransaction();
// Resume the bean instance transaction
tm.resume(beanTx);
// Let the MI know about our new transaction
mi.setTransaction(beanTx);
try {
// Let the superclass call next interceptor and do the exception
// handling
return super.invokeNext(remoteInvocation, mi, true);
} finally {
try {
if (stateless)
checkStatelessDone();
} finally {
tm.suspend();
}
}
} finally {
// Reset threadlocal to its old value
userTransaction.set(oldUserTx);
// Restore old MI transaction
// OSH: Why ???
mi.setTransaction(oldTransaction);
// If we had a Tx associated with the thread reassociate
if (threadTx != null)
tm.resume(threadTx);
}
}
private void checkStatelessDone()
throws RemoteException
{
int status = Status.STATUS_NO_TRANSACTION;
try {
status = tm.getStatus();
} catch (SystemException ex) {
Logger.exception(ex);
}
switch (status) {
case Status.STATUS_ACTIVE:
case Status.STATUS_COMMITTING:
case Status.STATUS_MARKED_ROLLBACK:
case Status.STATUS_PREPARING:
case Status.STATUS_ROLLING_BACK:
try {
tm.rollback();
} catch (Exception ex) {
Logger.exception(ex);
}
// fall through...
case Status.STATUS_PREPARED:
String msg = "Application error: BMT stateless bean " +
container.getBeanMetaData().getEjbName() +
" should complete transactions before" +
" returning (ejb1.1 spec, 11.6.1)";
Logger.error(msg);
// the instance interceptor will discard the instance
throw new RemoteException(msg);
}
}
// Inner classes -------------------------------------------------
public static class UserTxFactory
implements ObjectFactory
{
public Object getObjectInstance(Object ref, Name name,
Context nameCtx, Hashtable environment)
throws Exception
{
// The ref is a list with only one RefAddr ...
RefAddr refAddr = ((Reference)ref).get(0);
// ... whose content is the threadlocal
ThreadLocal threadLocal = (ThreadLocal)refAddr.getContent();
// The threadlocal holds the right UserTransaction
return threadLocal.get();
}
}
}
_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development