You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by da...@apache.org on 2007/04/10 04:01:56 UTC
svn commit: r526994 - in
/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core:
cmp/CmpContainer.java entity/EntityContainer.java
entity/EntityInstanceManager.java entity/EntrancyTracker.java
Author: dain
Date: Mon Apr 9 19:01:55 2007
New Revision: 526994
URL: http://svn.apache.org/viewvc?view=rev&rev=526994
Log:
Implement reentrancy checks
Added:
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntrancyTracker.java
Modified:
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpContainer.java
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityContainer.java
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityInstanceManager.java
Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpContainer.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpContainer.java?view=diff&rev=526994&r1=526993&r2=526994
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpContainer.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/CmpContainer.java Mon Apr 9 19:01:55 2007
@@ -42,6 +42,7 @@
import javax.ejb.FinderException;
import javax.ejb.EJBAccessException;
import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
import org.apache.openejb.ApplicationException;
import org.apache.openejb.DeploymentInfo;
@@ -49,12 +50,14 @@
import org.apache.openejb.ProxyInfo;
import org.apache.openejb.RpcContainer;
import org.apache.openejb.ContainerType;
+import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.core.CoreDeploymentInfo;
import org.apache.openejb.core.Operation;
import org.apache.openejb.core.ThreadContext;
import org.apache.openejb.core.timer.EjbTimerService;
import org.apache.openejb.core.timer.EjbTimerServiceImpl;
import org.apache.openejb.core.entity.EntityContext;
+import org.apache.openejb.core.entity.EntrancyTracker;
import org.apache.openejb.core.transaction.TransactionContainer;
import org.apache.openejb.core.transaction.TransactionContext;
import org.apache.openejb.core.transaction.TransactionPolicy;
@@ -93,6 +96,10 @@
*/
protected final Map<Object, CmpEngine> cmpEngines = new HashMap<Object, CmpEngine>();
+ /**
+ * Tracks entity instances that have been "entered" so we can throw reentrancy exceptions.
+ */
+ protected EntrancyTracker entrancyTracker;
public CmpContainer(Object id, TransactionManager transactionManager, SecurityService securityService, String cmpEngineFactory, String engine, String connectorName) {
this.transactionManager = transactionManager;
@@ -101,6 +108,7 @@
this.cmpEngineFactory = cmpEngineFactory;
this.connectorName = connectorName;
this.engine = engine;
+ entrancyTracker = new EntrancyTracker(SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class));
cmpCallback = new ContainerCmpCallback();
}
@@ -469,6 +477,8 @@
EntityBean bean = null;
Object returnValue = null;
+
+ entrancyTracker.enter(deploymentInfo, callContext.getPrimaryKey());
try {
CmpEngine cmpEngine = getCmpEngine(deploymentInfo);
bean = (EntityBean) cmpEngine.loadBean(callContext, callContext.getPrimaryKey());
@@ -494,6 +504,7 @@
/* System Exception ****************************/
txPolicy.handleSystemException(e, bean, txContext);
} finally {
+ entrancyTracker.exit(deploymentInfo, callContext.getPrimaryKey());
txPolicy.afterInvoke(bean, txContext);
}
Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityContainer.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityContainer.java?view=diff&rev=526994&r1=526993&r2=526994
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityContainer.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityContainer.java Mon Apr 9 19:01:55 2007
@@ -23,6 +23,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Vector;
import javax.ejb.EJBAccessException;
import javax.ejb.EJBHome;
@@ -34,6 +35,7 @@
import javax.ejb.Timer;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
import org.apache.openejb.ApplicationException;
import org.apache.openejb.ContainerType;
@@ -41,6 +43,7 @@
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.ProxyInfo;
import org.apache.openejb.SystemException;
+import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.core.BaseContext;
import org.apache.openejb.core.CoreDeploymentInfo;
import org.apache.openejb.core.Operation;
@@ -68,10 +71,16 @@
private TransactionManager transactionManager;
private SecurityService securityService;
+ /**
+ * Tracks entity instances that have been "entered" so we can throw reentrancy exceptions.
+ */
+ protected EntrancyTracker entrancyTracker;
+
public EntityContainer(Object id, TransactionManager transactionManager, SecurityService securityService, int poolSize) throws OpenEJBException {
this.containerID = id;
this.transactionManager = transactionManager;
this.securityService = securityService;
+ entrancyTracker = new EntrancyTracker(SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class));
instanceManager = new EntityInstanceManager(this, transactionManager, securityService, poolSize);
}
@@ -199,9 +208,8 @@
txPolicy.beforeInvoke(bean, txContext);
Object returnValue = null;
-
+ entrancyTracker.enter(callContext.getDeploymentInfo(), callContext.getPrimaryKey());
try {
-
bean = instanceManager.obtainInstance(callContext);
ejbLoad_If_No_Transaction(callContext, bean);
@@ -233,6 +241,7 @@
*/
txPolicy.handleSystemException(iae, bean, txContext);
} finally {
+ entrancyTracker.exit(callContext.getDeploymentInfo(), callContext.getPrimaryKey());
txPolicy.afterInvoke(bean, txContext);
}
@@ -426,7 +435,7 @@
*/
if (returnValue instanceof java.util.Collection) {
Iterator keys = ((Collection) returnValue).iterator();
- java.util.Vector proxies = new java.util.Vector();
+ Vector<ProxyInfo> proxies = new Vector<ProxyInfo>();
while (keys.hasNext()) {
Object primaryKey = keys.next();
proxies.addElement(new ProxyInfo(deploymentInfo, primaryKey, objectInterface, this));
@@ -434,7 +443,7 @@
returnValue = proxies;
} else if (returnValue instanceof java.util.Enumeration) {
Enumeration keys = (Enumeration) returnValue;
- java.util.Vector proxies = new java.util.Vector();
+ Vector<ProxyInfo> proxies = new Vector<ProxyInfo>();
while (keys.hasMoreElements()) {
Object primaryKey = keys.nextElement();
proxies.addElement(new ProxyInfo(deploymentInfo, primaryKey, objectInterface, this));
@@ -520,5 +529,4 @@
}
}
}
-
}
Modified: incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityInstanceManager.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityInstanceManager.java?view=diff&rev=526994&r1=526993&r2=526994
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityInstanceManager.java (original)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntityInstanceManager.java Mon Apr 9 19:01:55 2007
@@ -18,6 +18,9 @@
import org.apache.openejb.ApplicationException;
import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.SystemException;
+import org.apache.openejb.InvalidateReferenceException;
+import org.apache.openejb.DeploymentInfo;
import org.apache.openejb.spi.SecurityService;
import org.apache.openejb.core.BaseContext;
import org.apache.openejb.core.CoreDeploymentInfo;
@@ -35,9 +38,11 @@
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.Synchronization;
-import javax.transaction.SystemException;
+import javax.transaction.RollbackException;
import java.util.HashMap;
import java.util.Hashtable;
+import java.util.Map;
+import java.rmi.RemoteException;
public class EntityInstanceManager {
@@ -53,12 +58,12 @@
* by using an instance of the inner Key class. The Key class is a compound key composed
* of the tx, deployment, and primary key identifiers.
*/
- protected Hashtable txReadyPool = new Hashtable();
+ protected Hashtable<Object,SyncronizationWrapper> txReadyPool = new Hashtable<Object,SyncronizationWrapper>();
/*
* contains a collection of LinkListStacks indexed by deployment id. Each indexed stack
* represents the method ready pool of for that class.
*/
- protected HashMap poolMap = null;
+ protected Map<Object,LinkedListStack> poolMap = null;
public Logger logger = Logger.getInstance("OpenEJB", "org.apache.openejb.util.resources");
@@ -71,37 +76,37 @@
this.securityService = securityService;
this.poolsize = poolSize;
this.container = container;
- poolMap = new HashMap();// put size in later
+ poolMap = new HashMap<Object,LinkedListStack>();// put size in later
- org.apache.openejb.DeploymentInfo[] deploymentInfos = this.container.deployments();
+ DeploymentInfo[] deploymentInfos = this.container.deployments();
for (int i = 0; i < deploymentInfos.length; i++) {
- org.apache.openejb.DeploymentInfo deploymentInfo = deploymentInfos[i];
+ DeploymentInfo deploymentInfo = deploymentInfos[i];
deploy(deploymentInfo);
}
}
- public void deploy(org.apache.openejb.DeploymentInfo deploymentInfo) {
+ public void deploy(DeploymentInfo deploymentInfo) {
poolMap.put(deploymentInfo.getDeploymentID(), new LinkedListStack(poolsize / 2));
}
- public void undeploy(org.apache.openejb.DeploymentInfo deploymentInfo) {
+ public void undeploy(DeploymentInfo deploymentInfo) {
poolMap.remove(deploymentInfo.getDeploymentID());
}
- public EntityBean obtainInstance(ThreadContext callContext)
- throws OpenEJBException {
- Transaction currentTx = null;
+ public EntityBean obtainInstance(ThreadContext callContext) throws OpenEJBException {
+ Transaction currentTx;
try {
currentTx = getTransactionManager().getTransaction();
} catch (javax.transaction.SystemException se) {
logger.error("Transaction Manager getTransaction() failed.", se);
- throw new org.apache.openejb.SystemException("TransactionManager failure");
+ throw new SystemException("TransactionManager failure");
}
Object primaryKey = callContext.getPrimaryKey();// null if its a servicing a home methods (create, find, ejbHome)
if (currentTx != null && primaryKey != null) {// primkey is null if create operation is called
- Key key = new Key(currentTx, callContext.getDeploymentInfo().getDeploymentID(), primaryKey);
- SyncronizationWrapper wrapper = (SyncronizationWrapper) txReadyPool.get(key);
+ CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
+ Key key = new Key(currentTx, deploymentInfo.getDeploymentID(), primaryKey);
+ SyncronizationWrapper wrapper = txReadyPool.get(key);
if (wrapper != null) {// if true, the requested bean instance is already enrolled in a transaction
@@ -115,7 +120,7 @@
* its likely that the application server would have already made the reference invalid, but this bit of
* code is an extra precaution.
*/
- throw new org.apache.openejb.InvalidateReferenceException(new NoSuchObjectException("Entity not found: " + primaryKey));
+ throw new InvalidateReferenceException(new NoSuchObjectException("Entity not found: " + primaryKey));
} else if (callContext.getCurrentOperation() == Operation.REMOVE) {
/*
* To avoid calling ejbStore( ) on a bean that after its removed, we can not delegate
@@ -129,22 +134,16 @@
return wrapper.getEntityBean();
} else {
- org.apache.openejb.core.CoreDeploymentInfo depInfo = (org.apache.openejb.core.CoreDeploymentInfo) callContext.getDeploymentInfo();
- if (depInfo.isReentrant()) {
- /*
- * If the bean is declared as reentrant then the instance may be accessed
- * by more then one thread at a time. This is one of the reasons that reentrancy
- * is bad. In this case beans must be programmed to be multi threaded. The other reason
- * reentrancy is bad has to do with transaction isolation. Multiple instances writing to
- * the same database records will inevitably cancel out previous writes within the same tx.
- *
- * In the future we may change this to return a new instance of the bean and to
- * link it and its wrapper to the original wrapper, but for now we choose this strategy because
- * its simpler to implement.
- */
- return wrapper.getEntityBean();
- } else
- throw new org.apache.openejb.ApplicationException(new java.rmi.RemoteException("Attempted reentrant access. Bean is not reentrant"));
+ // If the bean is declared as reentrant then the instance may be accessed
+ // by more then one thread at a time. This is one of the reasons that reentrancy
+ // is bad. In this case beans must be programmed to be multi threaded. The other reason
+ // reentrancy is bad has to do with transaction isolation. Multiple instances writing to
+ // the same database records will inevitably cancel out previous writes within the same tx.
+ //
+ // In the future we may change this to return a new instance of the bean and to
+ // link it and its wrapper to the original wrapper, but for now we choose this strategy because
+ // its simpler to implement.
+ return wrapper.getEntityBean();
}
} else {
/*
@@ -169,24 +168,23 @@
try {
currentTx.registerSynchronization(wrapper);
- } catch (javax.transaction.SystemException se) {
- logger.error("Transaction Manager registerSynchronization() failed.", se);
- throw new org.apache.openejb.SystemException(se);
- } catch (javax.transaction.RollbackException re) {
- throw new org.apache.openejb.ApplicationException(new TransactionRolledbackException(re));
+ } catch (javax.transaction.SystemException e) {
+ logger.error("Transaction Manager registerSynchronization() failed.", e);
+ throw new SystemException(e);
+ } catch (RollbackException e) {
+ throw new ApplicationException(new TransactionRolledbackException(e));
}
loadingBean(bean, callContext);
Operation orginalOperation = callContext.getCurrentOperation();
- callContext.setCurrentOperation(org.apache.openejb.core.Operation.LOAD);
- BaseContext.State[] originalStates = callContext.setCurrentAllowedStates(EntityContext.getStates());
+ callContext.setCurrentOperation(Operation.LOAD);
try {
bean.ejbLoad();
} catch (NoSuchEntityException e) {
- throw new org.apache.openejb.InvalidateReferenceException(new NoSuchObjectException("Entity not found: " + primaryKey).initCause(e));
+ throw new InvalidateReferenceException(new NoSuchObjectException("Entity not found: " + primaryKey).initCause(e));
} catch (Exception e) {
logger.error("Exception encountered during ejbLoad():", e);
- throw new org.apache.openejb.OpenEJBException(e);
+ throw new OpenEJBException(e);
} finally {
callContext.setCurrentOperation(orginalOperation);
callContext.setCurrentAllowedStates(EntityContext.getStates());
@@ -195,27 +193,25 @@
return bean;
}
- } else { /*
- If no transaction is associated with the thread or if its a create, find or home method (primaryKey == null), then no synchronized wrapper is needed.
- if bean instance is used for a create method then a syncrhonziation wrapper may be assigned
- when the bean is returned to the pool -- depending on if the tx is a client initiated or container initiated.
- */
+ } else {
+ // If no transaction is associated with the thread or if its a create, find or home method
+ // (primaryKey == null), then no synchronized wrapper is needed. if bean instance is used
+ // for a create method then a syncrhonziation wrapper may be assigned when the bean is
+ // returned to the pool -- depending on if the tx is a client initiated or container initiated.
return getPooledInstance(callContext);
}
}
- protected void loadingBean(javax.ejb.EntityBean bean, org.apache.openejb.core.ThreadContext callContext) throws OpenEJBException {
+ protected void loadingBean(EntityBean bean, ThreadContext callContext) throws OpenEJBException {
}
- protected void reusingBean(javax.ejb.EntityBean bean, org.apache.openejb.core.ThreadContext callContext) throws OpenEJBException {
+ protected void reusingBean(EntityBean bean, ThreadContext callContext) throws OpenEJBException {
}
- protected EntityBean getPooledInstance(ThreadContext callContext)
- throws org.apache.openejb.OpenEJBException {
+ protected EntityBean getPooledInstance(ThreadContext callContext) throws OpenEJBException {
CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
- Stack methodReadyPool = (Stack) poolMap.get(deploymentInfo.getDeploymentID());
- if (methodReadyPool == null)
- throw new org.apache.openejb.SystemException("Invalid deployment id " + deploymentInfo.getDeploymentID() + " for this container");
+ Stack methodReadyPool = poolMap.get(deploymentInfo.getDeploymentID());
+ if (methodReadyPool == null) throw new SystemException("Invalid deployment id " + deploymentInfo.getDeploymentID() + " for this container");
EntityBean bean = (EntityBean) methodReadyPool.pop();
if (bean == null) {
@@ -223,11 +219,11 @@
bean = (EntityBean) deploymentInfo.getBeanClass().newInstance();
} catch (Exception e) {
logger.error("Bean instantiation failed for class " + deploymentInfo.getBeanClass(), e);
- throw new org.apache.openejb.SystemException(e);
+ throw new SystemException(e);
}
Operation currentOp = callContext.getCurrentOperation();
- callContext.setCurrentOperation(org.apache.openejb.core.Operation.SET_CONTEXT);
+ callContext.setCurrentOperation(Operation.SET_CONTEXT);
BaseContext.State[] originalStates = callContext.setCurrentAllowedStates(EntityContext.getStates());
try {
@@ -241,16 +237,15 @@
* we don't want the TransactionScopeHandler commiting the transaction in afterInvoke() which is what it would attempt
* to do.
*/
- CoreDeploymentInfo deploymentInfo1 = callContext.getDeploymentInfo();
bean.setEntityContext(createEntityContext());
- } catch (java.lang.Exception e) {
+ } catch (Exception e) {
/*
* The EJB 1.1 specification does not specify how exceptions thrown by setEntityContext impact the
* transaction, if there is one. In this case we choose the least disruptive operation, throwing an
* application exception and NOT automatically marking the transaciton for rollback.
*/
logger.error("Bean callback method failed ", e);
- throw new org.apache.openejb.ApplicationException(e);
+ throw new ApplicationException(e);
} finally {
callContext.setCurrentOperation(currentOp);
callContext.setCurrentAllowedStates(originalStates);
@@ -259,8 +254,7 @@
reusingBean(bean, callContext);
}
- if ((callContext.getCurrentOperation() == org.apache.openejb.core.Operation.BUSINESS) ||
- (callContext.getCurrentOperation() == org.apache.openejb.core.Operation.REMOVE)) {
+ if ((callContext.getCurrentOperation() == Operation.BUSINESS) || (callContext.getCurrentOperation() == Operation.REMOVE)) {
/*
* When a bean is retrieved from the bean pool to service a client's business method request it must be
* notified that its about to enter service by invoking its ejbActivate( ) method. A bean instance
@@ -272,7 +266,7 @@
*/
Operation currentOp = callContext.getCurrentOperation();
- callContext.setCurrentOperation(org.apache.openejb.core.Operation.ACTIVATE);
+ callContext.setCurrentOperation(Operation.ACTIVATE);
BaseContext.State[] originalStates = callContext.setCurrentAllowedStates(EntityContext.getStates());
try {
/*
@@ -292,9 +286,9 @@
}
} catch (javax.transaction.SystemException se) {
logger.error("Transaction Manager getTransaction() failed.", se);
- throw new org.apache.openejb.SystemException(se);
+ throw new SystemException(se);
}
- throw new ApplicationException(new java.rmi.RemoteException("Exception thrown while attempting to call ejbActivate() on the instance. Exception message = " + e.getMessage()));
+ throw new ApplicationException(new RemoteException("Exception thrown while attempting to call ejbActivate() on the instance. Exception message = " + e.getMessage()));
} finally {
callContext.setCurrentOperation(currentOp);
callContext.setCurrentAllowedStates(originalStates);
@@ -308,10 +302,8 @@
return new EntityContext(transactionManager, securityService);
}
- public void poolInstance(ThreadContext callContext, EntityBean bean)
- throws OpenEJBException {
+ public void poolInstance(ThreadContext callContext, EntityBean bean) throws OpenEJBException {
if (bean == null) {
-
return;
}
Object primaryKey = callContext.getPrimaryKey();// null if servicing a home ejbFind or ejbHome method.
@@ -320,11 +312,11 @@
currentTx = getTransactionManager().getTransaction();
} catch (javax.transaction.SystemException se) {
logger.error("Transaction Manager getTransaction() failed.", se);
- throw new org.apache.openejb.SystemException("TransactionManager failure");
+ throw new SystemException("TransactionManager failure");
}
if (currentTx != null && primaryKey != null) {// primary key is null for find and home methods
Key key = new Key(currentTx, callContext.getDeploymentInfo().getDeploymentID(), primaryKey);
- SyncronizationWrapper wrapper = (SyncronizationWrapper) txReadyPool.get(key);
+ SyncronizationWrapper wrapper = txReadyPool.get(key);
if (wrapper != null) {
if (callContext.getCurrentOperation() == Operation.REMOVE) {
/*
@@ -338,7 +330,7 @@
* If the bean has been removed then the bean instance is no longer needed and can return to the methodReadyPool
* to service another identity.
*/
- Stack methodReadyPool = (Stack) poolMap.get(callContext.getDeploymentInfo().getDeploymentID());
+ Stack methodReadyPool = poolMap.get(callContext.getDeploymentInfo().getDeploymentID());
methodReadyPool.push(bean);
} else
wrapper.setEntityBean(bean);
@@ -356,9 +348,9 @@
currentTx.registerSynchronization(wrapper);
} catch (javax.transaction.SystemException se) {
logger.error("Transaction Manager registerSynchronization() failed.", se);
- throw new org.apache.openejb.SystemException(se);
- } catch (javax.transaction.RollbackException re) {
- throw new org.apache.openejb.ApplicationException(new TransactionRolledbackException(re));
+ throw new SystemException(se);
+ } catch (RollbackException re) {
+ throw new ApplicationException(new TransactionRolledbackException(re));
}
txReadyPool.put(key, wrapper);
@@ -378,7 +370,7 @@
*/
Operation currentOp = callContext.getCurrentOperation();
- callContext.setCurrentOperation(org.apache.openejb.core.Operation.PASSIVATE);
+ callContext.setCurrentOperation(Operation.PASSIVATE);
BaseContext.State[] originalStates = callContext.setCurrentAllowedStates(EntityContext.getStates());
try {
@@ -398,9 +390,9 @@
}
} catch (javax.transaction.SystemException se) {
logger.error("Transaction Manager getTransaction() failed.", se);
- throw new org.apache.openejb.SystemException(se);
+ throw new SystemException(se);
}
- throw new ApplicationException(new java.rmi.RemoteException("Reflection exception thrown while attempting to call ejbPassivate() on the instance. Exception message = " + e.getMessage()));
+ throw new ApplicationException(new RemoteException("Reflection exception thrown while attempting to call ejbPassivate() on the instance. Exception message = " + e.getMessage()));
} finally {
callContext.setCurrentOperation(currentOp);
callContext.setCurrentAllowedStates(originalStates);
@@ -412,19 +404,18 @@
* method and is not still part of a tx. While in the method ready pool the bean instance is not associated with a
* primary key and may be used to service a request for any bean of the same class.
*/
- Stack methodReadyPool = (Stack) poolMap.get(callContext.getDeploymentInfo().getDeploymentID());
+ Stack methodReadyPool = poolMap.get(callContext.getDeploymentInfo().getDeploymentID());
methodReadyPool.push(bean);
}
}
- public void freeInstance(ThreadContext callContext, EntityBean bean)
- throws org.apache.openejb.SystemException {
+ public void freeInstance(ThreadContext callContext, EntityBean bean) throws SystemException {
discardInstance(callContext, bean);
Operation currentOp = callContext.getCurrentOperation();
- callContext.setCurrentOperation(org.apache.openejb.core.Operation.UNSET_CONTEXT);
+ callContext.setCurrentOperation(Operation.UNSET_CONTEXT);
BaseContext.State[] originalStates = callContext.setCurrentAllowedStates(EntityContext.getStates());
try {
@@ -439,7 +430,7 @@
* to do.
*/
bean.unsetEntityContext();
- } catch (java.lang.Exception e) {
+ } catch (Exception e) {
/*
* The EJB 1.1 specification does not specify how exceptions thrown by unsetEntityContext impact the
* transaction, if there is one. In this case we choose to do nothing since the instance is being disposed
@@ -454,14 +445,13 @@
}
- public void discardInstance(ThreadContext callContext, EntityBean bean)
- throws org.apache.openejb.SystemException {
+ public void discardInstance(ThreadContext callContext, EntityBean bean) throws SystemException {
Transaction currentTx = null;
try {
currentTx = getTransactionManager().getTransaction();
} catch (javax.transaction.SystemException se) {
logger.error("Transaction Manager getTransaction() failed.", se);
- throw new org.apache.openejb.SystemException("TransactionManager failure");
+ throw new SystemException("TransactionManager failure");
}
if (currentTx != null) {
if (callContext.getPrimaryKey() == null)
@@ -475,7 +465,7 @@
in the txReadyPool is indicative of an entity bean that has been removed via
ejbRemove() rather than freed because of an error condition as is the case here.
*/
- SyncronizationWrapper wrapper = (SyncronizationWrapper) txReadyPool.remove(key);
+ SyncronizationWrapper wrapper = txReadyPool.remove(key);
if (wrapper != null) {
/*
@@ -554,7 +544,6 @@
private final Key myIndex;
private final CoreDeploymentInfo deploymentInfo;
private final Object primaryKey;
- private final Object securityIdentity;
public SyncronizationWrapper(EntityBean bean, Key key, boolean available, ThreadContext callContext) throws OpenEJBException {
if (bean == null || callContext == null || key == null) {
@@ -566,7 +555,6 @@
isAssociated = true;
deploymentInfo = callContext.getDeploymentInfo();
primaryKey = callContext.getPrimaryKey();
- securityIdentity = null;
}
public void disassociate() {
@@ -611,7 +599,7 @@
TransactionManager transactionManager = getTransactionManager();
try {
transactionManager.setRollbackOnly();
- } catch (SystemException se) {
+ } catch (javax.transaction.SystemException se) {
logger.error("Transaction manager reported error during setRollbackOnly()", se);
}
Added: incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntrancyTracker.java
URL: http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntrancyTracker.java?view=auto&rev=526994
==============================================================================
--- incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntrancyTracker.java (added)
+++ incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/entity/EntrancyTracker.java Mon Apr 9 19:01:55 2007
@@ -0,0 +1,126 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.core.entity;
+
+import org.apache.openejb.DeploymentInfo;
+import org.apache.openejb.ApplicationException;
+
+import javax.transaction.TransactionSynchronizationRegistry;
+import java.util.Set;
+import java.util.HashSet;
+import java.rmi.RemoteException;
+
+public class EntrancyTracker {
+ /**
+ * Thread local used to track the insances in the current call stack so we can determine if an nonreentrant
+ * instance is being reentered.
+ */
+ private final ThreadLocal<Set<InstanceKey>> inCallThreadLocal = new ThreadLocal<Set<InstanceKey>>() {
+ protected Set<InstanceKey> initialValue() {
+ return new HashSet<InstanceKey>();
+ }
+ };
+
+ private final TransactionSynchronizationRegistry synchronizationRegistry;
+
+ public EntrancyTracker(TransactionSynchronizationRegistry synchronizationRegistry) {
+ this.synchronizationRegistry = synchronizationRegistry;
+ }
+
+ public void enter(DeploymentInfo deploymentInfo, Object primaryKey) throws ApplicationException {
+ if (primaryKey == null || deploymentInfo.isReentrant()) {
+ return;
+ }
+
+ Object deploymentId = deploymentInfo.getDeploymentID();
+ InstanceKey key = new InstanceKey(deploymentId, primaryKey);
+
+
+ Set<InstanceKey> inCall;
+ try {
+ //noinspection unchecked
+ inCall = (Set<InstanceKey>) synchronizationRegistry.getResource(EntrancyTracker.class);
+ if (inCall == null) {
+ inCall = new HashSet<InstanceKey>();
+ synchronizationRegistry.putResource(EntrancyTracker.class, inCall);
+ }
+ } catch (IllegalStateException e) {
+ inCall = inCallThreadLocal.get();
+ }
+
+ if (!inCall.add(key)) {
+ ApplicationException exception = new ApplicationException(new RemoteException("Attempted reentrant access. " + "Bean " + deploymentId + " is not reentrant and instance " + primaryKey + " has already been entered : " +inCall));
+ exception.printStackTrace();
+ throw exception;
+ }
+
+ }
+
+ public void exit(DeploymentInfo deploymentInfo, Object primaryKey) throws ApplicationException {
+ if (primaryKey == null || deploymentInfo.isReentrant()) {
+ return;
+ }
+
+ Object deploymentId = deploymentInfo.getDeploymentID();
+ InstanceKey key = new InstanceKey(deploymentId, primaryKey);
+
+ Set<InstanceKey> inCall = null;
+ try {
+ //noinspection unchecked
+ inCall = (Set<InstanceKey>) synchronizationRegistry.getResource(EntrancyTracker.class);
+ } catch (IllegalStateException e) {
+ inCall = inCallThreadLocal.get();
+ }
+
+ if (inCall != null) {
+ inCall.remove(key);
+ }
+ }
+
+ private static class InstanceKey {
+ private final Object deploymentId;
+ private final Object primaryKey;
+
+
+ public InstanceKey(Object deploymentId, Object primaryKey) {
+ this.deploymentId = deploymentId;
+ this.primaryKey = primaryKey;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ InstanceKey that = (InstanceKey) o;
+
+ return deploymentId.equals(that.deploymentId) && primaryKey.equals(that.primaryKey);
+ }
+
+ public int hashCode() {
+ int result;
+ result = deploymentId.hashCode();
+ result = 31 * result + primaryKey.hashCode();
+ return result;
+ }
+
+
+ public String toString() {
+ return deploymentId + ":" + primaryKey;
+ }
+ }
+}