Author: jlmonteiro
Date: Tue Jul 12 10:01:47 2011
New Revision: 1145516

URL: http://svn.apache.org/viewvc?rev=1145516&view=rev
Log:
OPENEJB-1628 Calling a @Remove method must also close persistence contexts
Second try dealing with Inherited Extended Persistence Contexts

Modified:
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/Instance.java
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Instance.java
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/persistence/JtaEntityManagerRegistry.java
    
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/EntityManagerPropogationTest.java

Modified: 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/Instance.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/Instance.java?rev=1145516&r1=1145515&r2=1145516&view=diff
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/Instance.java
 (original)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/Instance.java
 Tue Jul 12 10:01:47 2011
@@ -17,24 +17,25 @@
  */
 package org.apache.openejb.core.managed;
 
-import java.io.Serializable;
-import java.io.ObjectStreamException;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Stack;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.EntityManager;
-import javax.transaction.Transaction;
-
 import org.apache.openejb.BeanContext;
 import 
org.apache.openejb.core.transaction.BeanTransactionPolicy.SuspendedTransaction;
 import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.persistence.JtaEntityManagerRegistry;
 import org.apache.openejb.spi.ContainerSystem;
+import org.apache.openejb.util.Duration;
 import org.apache.openejb.util.Index;
 import org.apache.openejb.util.PojoSerialization;
 
+import javax.persistence.EntityManagerFactory;
+import javax.transaction.Transaction;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
 public class Instance implements Serializable {
     private static final long serialVersionUID = 2862563626506556542L;
     public final BeanContext beanContext;
@@ -45,15 +46,15 @@ public class Instance implements Seriali
     private boolean inUse;
     private SuspendedTransaction beanTransaction;
     private Stack<Transaction> transaction = new Stack<Transaction>();
-    private final Lock lock = new ReentrantLock();
+    private final ReentrantLock lock = new ReentrantLock();
 
     // todo if we keyed by an entity manager factory id we would not have to 
make this transient and rebuild the index below
     // This would require that we crete an id and that we track it
     // alternatively, we could use ImmutableArtifact with some read/write 
replace magic
-    private Map<EntityManagerFactory, EntityManager> entityManagers;
-    private final EntityManager[] entityManagerArray;
+    private Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers;
+    private final JtaEntityManagerRegistry.EntityManagerTracker[] 
entityManagerArray;
 
-    public Instance(BeanContext beanContext, Object primaryKey, Object bean, 
Map<String, Object> interceptors, Map<EntityManagerFactory, EntityManager> 
entityManagers) {
+    public Instance(BeanContext beanContext, Object primaryKey, Object bean, 
Map<String, Object> interceptors, Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers) {
         this.beanContext = beanContext;
         this.primaryKey = primaryKey;
         this.bean = bean;
@@ -62,7 +63,7 @@ public class Instance implements Seriali
         this.entityManagerArray = null;
     }
 
-    public Instance(Object deploymentId, Object primaryKey, Object bean, 
Map<String, Object> interceptors, EntityManager[] entityManagerArray) {
+    public Instance(Object deploymentId, Object primaryKey, Object bean, 
Map<String, Object> interceptors, 
JtaEntityManagerRegistry.EntityManagerTracker[] entityManagerArray) {
         this.beanContext = 
SystemInstance.get().getComponent(ContainerSystem.class).getBeanContext(deploymentId);
         if (beanContext == null) {
             throw new IllegalArgumentException("Unknown deployment " + 
deploymentId);
@@ -73,6 +74,10 @@ public class Instance implements Seriali
         this.entityManagerArray = entityManagerArray;
     }
 
+    public Duration getTimeOut() {
+        return beanContext.getStatefulTimeout();
+    }
+
     public synchronized boolean isInUse() {
         return inUse;
     }
@@ -107,15 +112,20 @@ public class Instance implements Seriali
         } else if (transaction != null){
             this.transaction.push(transaction);
         }
+    }
 
+    public synchronized void releaseLock() {
+        if (lock.isHeldByCurrentThread()) {
+            lock.unlock();
+        }
     }
 
-    public synchronized Map<EntityManagerFactory, EntityManager> 
getEntityManagers(Index<EntityManagerFactory, Map> factories) {
+    public synchronized Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> 
getEntityManagers(Index<EntityManagerFactory, Map> factories) {
         if (entityManagers == null && entityManagerArray != null) {
-            entityManagers = new HashMap<EntityManagerFactory, 
EntityManager>();
+            entityManagers = new HashMap<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker>();
             for (int i = 0; i < entityManagerArray.length; i++) {
                 EntityManagerFactory entityManagerFactory = 
factories.getKey(i);
-                EntityManager entityManager = entityManagerArray[i];
+                JtaEntityManagerRegistry.EntityManagerTracker entityManager = 
entityManagerArray[i];
                 entityManagers.put(entityManagerFactory, entityManager);
             }
         }
@@ -138,36 +148,40 @@ public class Instance implements Seriali
         public final Object primaryKey;
         public final Object bean;
         public final Map<String, Object> interceptors;
-        public final EntityManager[] entityManagerArray;
+        public final JtaEntityManagerRegistry.EntityManagerTracker[] 
entityManagerArray;
 
         public Serialization(Instance i) {
             deploymentId = i.beanContext.getDeploymentID();
             primaryKey = i.primaryKey;
-            if (i.bean instanceof Serializable) {
-                bean = i.bean;
-            } else {
-                bean = new PojoSerialization(i.bean);
-            }
+            bean = toSerializable(i.bean);
 
-            interceptors = new HashMap(i.interceptors.size());
+            interceptors = new HashMap<String, Object>(i.interceptors.size());
             for (Map.Entry<String, Object> e : i.interceptors.entrySet()) {
                 if (e.getValue() == i.bean) {
                     // need to use the same wrapped reference or well get two 
copies.
                     interceptors.put(e.getKey(), bean);
-                } else if (!(e.getValue() instanceof Serializable)) {
-                    interceptors.put(e.getKey(), new 
PojoSerialization(e.getValue()));
+                } else {
+                    interceptors.put(e.getKey(), toSerializable(e.getValue()));
                 }
             }
 
             if (i.entityManagerArray != null) {
                 entityManagerArray = i.entityManagerArray;
             } else if (i.entityManagers != null) {
-                entityManagerArray = i.entityManagers.values().toArray(new 
EntityManager[i.entityManagers.values().size()]);
+                entityManagerArray = i.entityManagers.values().toArray(new 
JtaEntityManagerRegistry.EntityManagerTracker[i.entityManagers.values().size()]);
             } else {
                 entityManagerArray = null;
             }
         }
 
+        private static Object toSerializable(Object obj) {
+            if (obj instanceof Serializable) {
+                return obj;
+            } else {
+                return new PojoSerialization(obj);
+            }
+        }
+
         protected Object readResolve() throws ObjectStreamException {
             // Anything wrapped with PojoSerialization will have been 
automatically
             // unwrapped via it's own readResolve so passing in the raw bean

Modified: 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java?rev=1145516&r1=1145515&r2=1145516&view=diff
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java
 (original)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java
 Tue Jul 12 10:01:47 2011
@@ -16,32 +16,6 @@
  */
 package org.apache.openejb.core.managed;
 
-import java.lang.reflect.Method;
-import java.lang.management.ManagementFactory;
-import java.rmi.NoSuchObjectException;
-import java.rmi.RemoteException;
-import java.rmi.dgc.VMID;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import javax.ejb.EJBAccessException;
-import javax.ejb.EJBContext;
-import javax.ejb.EJBException;
-import javax.ejb.EJBHome;
-import javax.ejb.EJBLocalHome;
-import javax.ejb.RemoveException;
-import javax.ejb.SessionBean;
-import javax.ejb.SessionContext;
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.transaction.Transaction;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
 import org.apache.openejb.ApplicationException;
 import org.apache.openejb.BeanContext;
 import org.apache.openejb.ContainerType;
@@ -51,15 +25,10 @@ import org.apache.openejb.OpenEJBExcepti
 import org.apache.openejb.ProxyInfo;
 import org.apache.openejb.RpcContainer;
 import org.apache.openejb.SystemException;
-import org.apache.openejb.monitoring.StatsInterceptor;
-import org.apache.openejb.monitoring.ObjectNameBuilder;
-import org.apache.openejb.monitoring.ManagedMBean;
 import org.apache.openejb.core.ExceptionType;
-import static org.apache.openejb.core.ExceptionType.APPLICATION_ROLLBACK;
-import static org.apache.openejb.core.ExceptionType.SYSTEM;
+import org.apache.openejb.core.InstanceContext;
 import org.apache.openejb.core.Operation;
 import org.apache.openejb.core.ThreadContext;
-import org.apache.openejb.core.InstanceContext;
 import org.apache.openejb.core.interceptor.InterceptorData;
 import org.apache.openejb.core.interceptor.InterceptorStack;
 import org.apache.openejb.core.managed.Cache.CacheFilter;
@@ -67,21 +36,53 @@ import org.apache.openejb.core.managed.C
 import org.apache.openejb.core.transaction.BeanTransactionPolicy;
 import 
org.apache.openejb.core.transaction.BeanTransactionPolicy.SuspendedTransaction;
 import org.apache.openejb.core.transaction.EjbTransactionUtil;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleApplicationException;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException;
 import org.apache.openejb.core.transaction.EjbUserTransaction;
-import org.apache.openejb.core.transaction.TransactionPolicy;
 import org.apache.openejb.core.transaction.JtaTransactionPolicy;
+import org.apache.openejb.core.transaction.TransactionPolicy;
 import 
org.apache.openejb.core.transaction.TransactionPolicy.TransactionSynchronization;
 import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.monitoring.ManagedMBean;
+import org.apache.openejb.monitoring.ObjectNameBuilder;
+import org.apache.openejb.monitoring.StatsInterceptor;
 import org.apache.openejb.persistence.EntityManagerAlreadyRegisteredException;
 import org.apache.openejb.persistence.JtaEntityManagerRegistry;
 import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.util.Duration;
 import org.apache.openejb.util.Index;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
-import org.apache.openejb.util.Duration;
+
+import javax.ejb.EJBAccessException;
+import javax.ejb.EJBContext;
+import javax.ejb.EJBException;
+import javax.ejb.EJBHome;
+import javax.ejb.EJBLocalHome;
+import javax.ejb.RemoveException;
+import javax.ejb.SessionBean;
+import javax.ejb.SessionContext;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.transaction.Transaction;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.rmi.NoSuchObjectException;
+import java.rmi.RemoteException;
+import java.rmi.dgc.VMID;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.openejb.core.ExceptionType.APPLICATION_ROLLBACK;
+import static org.apache.openejb.core.ExceptionType.SYSTEM;
+import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
+import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleApplicationException;
+import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException;
 
 public class ManagedContainer implements RpcContainer {
     private static final Logger logger = 
Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources");
@@ -343,7 +344,7 @@ public class ManagedContainer implements
             checkAuthorization(callMethod, interfaceType);
 
             // Create the extended entity managers for this instance
-            Index<EntityManagerFactory, EntityManager> entityManagers = 
createEntityManagers(beanContext);
+            Index<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = 
createEntityManagers(beanContext);
 
             // Register the newly created entity managers
             if (entityManagers != null) {
@@ -738,29 +739,33 @@ public class ManagedContainer implements
         }
     }
 
-    private Index<EntityManagerFactory, EntityManager> 
createEntityManagers(BeanContext beanContext) {
+    private Index<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> createEntityManagers(BeanContext 
beanContext) {
         // create the extended entity managers
         Index<EntityManagerFactory, Map> factories = 
beanContext.getExtendedEntityManagerFactories();
-        Index<EntityManagerFactory, EntityManager> entityManagers = null;
+        Index<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = null;
         if (factories != null && factories.size() > 0) {
-            entityManagers = new Index<EntityManagerFactory, 
EntityManager>(new ArrayList<EntityManagerFactory>(factories.keySet()));
+            entityManagers  = new Index<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker>(new 
ArrayList<EntityManagerFactory>(factories.keySet()));
             for (Map.Entry<EntityManagerFactory, Map> entry : 
factories.entrySet()) {
                 EntityManagerFactory entityManagerFactory = entry.getKey();
                 Map properties = entry.getValue();
 
 
-                EntityManager entityManager = 
entityManagerRegistry.getInheritedEntityManager(entityManagerFactory);
-                if (entityManager == null) {
+                JtaEntityManagerRegistry.EntityManagerTracker 
entityManagerTracker = 
entityManagerRegistry.getInheritedEntityManager(entityManagerFactory);
+                EntityManager entityManager;
+                if (entityManagerTracker == null) {
                     if (properties != null) {
                         entityManager = 
entityManagerFactory.createEntityManager(properties);
                     } else {
                         entityManager = 
entityManagerFactory.createEntityManager();
                     }
+                    entityManagerTracker = new 
JtaEntityManagerRegistry.EntityManagerTracker(entityManager);
+                } else {
+                    entityManagerTracker.incCounter();
                 }
-                entityManagers.put(entityManagerFactory, entityManager);
+                entityManagers .put(entityManagerFactory, 
entityManagerTracker);
             }
         }
-        return entityManagers;
+        return entityManagers ;
     }
 
     private void registerEntityManagers(Instance instance, ThreadContext 
callContext) throws OpenEJBException {
@@ -773,7 +778,7 @@ public class ManagedContainer implements
         if (factories == null) return;
 
         // get the managers for the factories
-        Map<EntityManagerFactory, EntityManager> entityManagers = 
instance.getEntityManagers(factories);
+        Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = 
instance.getEntityManagers(factories);
         if (entityManagers == null) return;
 
         // register them

Modified: 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Instance.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Instance.java?rev=1145516&r1=1145515&r2=1145516&view=diff
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Instance.java
 (original)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/Instance.java
 Tue Jul 12 10:01:47 2011
@@ -17,25 +17,25 @@
  */
 package org.apache.openejb.core.stateful;
 
-import java.io.Serializable;
-import java.io.ObjectStreamException;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Stack;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import javax.persistence.EntityManagerFactory;
-import javax.persistence.EntityManager;
-import javax.transaction.Transaction;
-
 import org.apache.openejb.BeanContext;
 import 
org.apache.openejb.core.transaction.BeanTransactionPolicy.SuspendedTransaction;
 import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.persistence.JtaEntityManagerRegistry;
 import org.apache.openejb.spi.ContainerSystem;
 import org.apache.openejb.util.Duration;
 import org.apache.openejb.util.Index;
 import org.apache.openejb.util.PojoSerialization;
 
+import javax.persistence.EntityManagerFactory;
+import javax.transaction.Transaction;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
 public class Instance implements Serializable, Cache.TimeOut {
     private static final long serialVersionUID = 2862563626506556542L;
     public final BeanContext beanContext;
@@ -51,10 +51,10 @@ public class Instance implements Seriali
     // todo if we keyed by an entity manager factory id we would not have to 
make this transient and rebuild the index below
     // This would require that we crete an id and that we track it
     // alternatively, we could use ImmutableArtifact with some read/write 
replace magic
-    private Map<EntityManagerFactory, EntityManager> entityManagers;
-    private final EntityManager[] entityManagerArray;
+    private Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers;
+    private final JtaEntityManagerRegistry.EntityManagerTracker[] 
entityManagerArray;
 
-    public Instance(BeanContext beanContext, Object primaryKey, Object bean, 
Map<String, Object> interceptors, Map<EntityManagerFactory, EntityManager> 
entityManagers) {
+    public Instance(BeanContext beanContext, Object primaryKey, Object bean, 
Map<String, Object> interceptors, Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers) {
         this.beanContext = beanContext;
         this.primaryKey = primaryKey;
         this.bean = bean;
@@ -63,7 +63,7 @@ public class Instance implements Seriali
         this.entityManagerArray = null;
     }
 
-    public Instance(Object deploymentId, Object primaryKey, Object bean, 
Map<String, Object> interceptors, EntityManager[] entityManagerArray) {
+    public Instance(Object deploymentId, Object primaryKey, Object bean, 
Map<String, Object> interceptors, 
JtaEntityManagerRegistry.EntityManagerTracker[] entityManagerArray) {
         this.beanContext = 
SystemInstance.get().getComponent(ContainerSystem.class).getBeanContext(deploymentId);
         if (beanContext == null) {
             throw new IllegalArgumentException("Unknown deployment " + 
deploymentId);
@@ -120,12 +120,12 @@ public class Instance implements Seriali
         }
     }
     
-    public synchronized Map<EntityManagerFactory, EntityManager> 
getEntityManagers(Index<EntityManagerFactory, Map> factories) {
+    public synchronized Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> 
getEntityManagers(Index<EntityManagerFactory, Map> factories) {
         if (entityManagers == null && entityManagerArray != null) {
-            entityManagers = new HashMap<EntityManagerFactory, 
EntityManager>();
+            entityManagers = new HashMap<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker>();
             for (int i = 0; i < entityManagerArray.length; i++) {
                 EntityManagerFactory entityManagerFactory = 
factories.getKey(i);
-                EntityManager entityManager = entityManagerArray[i];
+                JtaEntityManagerRegistry.EntityManagerTracker entityManager = 
entityManagerArray[i];
                 entityManagers.put(entityManagerFactory, entityManager);
             }
         }
@@ -148,7 +148,7 @@ public class Instance implements Seriali
         public final Object primaryKey;
         public final Object bean;
         public final Map<String, Object> interceptors;
-        public final EntityManager[] entityManagerArray;
+        public final JtaEntityManagerRegistry.EntityManagerTracker[] 
entityManagerArray;
 
         public Serialization(Instance i) {
             deploymentId = i.beanContext.getDeploymentID();
@@ -168,7 +168,7 @@ public class Instance implements Seriali
             if (i.entityManagerArray != null) {
                 entityManagerArray = i.entityManagerArray;
             } else if (i.entityManagers != null) {
-                entityManagerArray = i.entityManagers.values().toArray(new 
EntityManager[i.entityManagers.values().size()]);
+                entityManagerArray = i.entityManagers.values().toArray(new 
JtaEntityManagerRegistry.EntityManagerTracker[i.entityManagers.values().size()]);
             } else {
                 entityManagerArray = null;
             }

Modified: 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java?rev=1145516&r1=1145515&r2=1145516&view=diff
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java
 (original)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java
 Tue Jul 12 10:01:47 2011
@@ -16,37 +16,6 @@
  */
 package org.apache.openejb.core.stateful;
 
-import java.lang.reflect.Method;
-import java.lang.management.ManagementFactory;
-import java.rmi.NoSuchObjectException;
-import java.rmi.RemoteException;
-import java.rmi.dgc.VMID;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import javax.ejb.EJBAccessException;
-import javax.ejb.EJBContext;
-import javax.ejb.EJBException;
-import javax.ejb.EJBHome;
-import javax.ejb.EJBLocalHome;
-import javax.ejb.RemoveException;
-import javax.ejb.SessionBean;
-import javax.ejb.SessionContext;
-import javax.ejb.ConcurrentAccessTimeoutException;
-import javax.enterprise.context.Dependent;
-import javax.enterprise.inject.spi.Bean;
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
-import javax.transaction.Transaction;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
 import org.apache.openejb.ApplicationException;
 import org.apache.openejb.BeanContext;
 import org.apache.openejb.ContainerType;
@@ -57,17 +26,10 @@ import org.apache.openejb.ProxyInfo;
 import org.apache.openejb.RpcContainer;
 import org.apache.openejb.SystemException;
 import org.apache.openejb.cdi.CdiEjbBean;
-import org.apache.openejb.config.rules.CheckDependsOn;
-import org.apache.openejb.monitoring.StatsInterceptor;
-import org.apache.openejb.monitoring.ObjectNameBuilder;
-import org.apache.openejb.monitoring.ManagedMBean;
 import org.apache.openejb.core.ExceptionType;
-import static org.apache.openejb.core.ExceptionType.APPLICATION_ROLLBACK;
-import static org.apache.openejb.core.ExceptionType.SYSTEM;
-
+import org.apache.openejb.core.InstanceContext;
 import org.apache.openejb.core.Operation;
 import org.apache.openejb.core.ThreadContext;
-import org.apache.openejb.core.InstanceContext;
 import org.apache.openejb.core.interceptor.InterceptorData;
 import org.apache.openejb.core.interceptor.InterceptorStack;
 import org.apache.openejb.core.stateful.Cache.CacheFilter;
@@ -75,21 +37,57 @@ import org.apache.openejb.core.stateful.
 import org.apache.openejb.core.transaction.BeanTransactionPolicy;
 import 
org.apache.openejb.core.transaction.BeanTransactionPolicy.SuspendedTransaction;
 import org.apache.openejb.core.transaction.EjbTransactionUtil;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleApplicationException;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException;
 import org.apache.openejb.core.transaction.EjbUserTransaction;
-import org.apache.openejb.core.transaction.TransactionPolicy;
 import org.apache.openejb.core.transaction.JtaTransactionPolicy;
+import org.apache.openejb.core.transaction.TransactionPolicy;
 import 
org.apache.openejb.core.transaction.TransactionPolicy.TransactionSynchronization;
 import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.monitoring.ManagedMBean;
+import org.apache.openejb.monitoring.ObjectNameBuilder;
+import org.apache.openejb.monitoring.StatsInterceptor;
 import org.apache.openejb.persistence.EntityManagerAlreadyRegisteredException;
 import org.apache.openejb.persistence.JtaEntityManagerRegistry;
 import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.util.Duration;
 import org.apache.openejb.util.Index;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
-import org.apache.openejb.util.Duration;
+
+import javax.ejb.ConcurrentAccessTimeoutException;
+import javax.ejb.EJBAccessException;
+import javax.ejb.EJBContext;
+import javax.ejb.EJBException;
+import javax.ejb.EJBHome;
+import javax.ejb.EJBLocalHome;
+import javax.ejb.RemoveException;
+import javax.ejb.SessionBean;
+import javax.ejb.SessionContext;
+import javax.enterprise.context.Dependent;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.transaction.Transaction;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.rmi.NoSuchObjectException;
+import java.rmi.RemoteException;
+import java.rmi.dgc.VMID;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+import static org.apache.openejb.core.ExceptionType.APPLICATION_ROLLBACK;
+import static org.apache.openejb.core.ExceptionType.SYSTEM;
+import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
+import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleApplicationException;
+import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException;
 
 public class StatefulContainer implements RpcContainer {
     private static final Logger logger = 
Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources");
@@ -363,7 +361,7 @@ public class StatefulContainer implement
             checkAuthorization(callMethod, interfaceType);
 
             // Create the extended entity managers for this instance
-            Index<EntityManagerFactory, EntityManager> entityManagers = 
createEntityManagers(beanContext);
+            Index<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = 
createEntityManagers(beanContext);
 
             // Register the newly created entity managers
             if (entityManagers != null) {
@@ -427,6 +425,9 @@ public class StatefulContainer implement
             } catch (Throwable e) {
                 handleException(createContext, txPolicy, e);
             } finally {
+                // un register EntityManager
+                unregisterEntityManagers(instance, createContext);
+
                 afterInvoke(createContext, txPolicy, instance);
             }
 
@@ -558,12 +559,27 @@ public class StatefulContainer implement
                         callContext.setCurrentOperation(Operation.REMOVE);
                     }
 
-                    // todo destroy extended persistence contexts
                     discardInstance(callContext);
                 }
 
+                // un register EntityManager
+                Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> unregisteredEntityManagers = 
unregisterEntityManagers(instance, callContext);
+
                 // Commit transaction
                 afterInvoke(callContext, txPolicy, instance);
+
+                // Un register and close extended persistence contexts
+                /*
+                7.6.2 Container-managed Extended Persistence Context
+                A container-managed extended persistence context can only be 
initiated within the scope of a stateful
+                session bean. It exists from the point at which the stateful 
session bean that declares a dependency on an
+                entity manager of type PersistenceContextType.EXTENDED is 
created, and is said to be bound
+                to the stateful session bean. The dependency on the extended 
persistence context is declared by means
+                of the PersistenceContext annotation or 
persistence-context-ref deployment descriptor element.
+                The persistence context is closed by the container when the 
@Remove method of the stateful session
+                bean completes (or the stateful session bean instance is 
otherwise destroyed).
+                */
+                closeEntityManagers(unregisteredEntityManagers);
             }
 
             return returnValue;
@@ -600,6 +616,7 @@ public class StatefulContainer implement
 
                 // Register the entity managers
                 registerEntityManagers(instance, callContext);
+
                 // Register for synchronization callbacks
                 registerSessionSynchronization(instance, callContext);
 
@@ -619,6 +636,9 @@ public class StatefulContainer implement
             } catch (Throwable e) {
                 handleException(callContext, txPolicy, e);
             } finally {
+                // un register EntityManager
+                unregisterEntityManagers(instance, callContext);
+
                 // Commit transaction
                 afterInvoke(callContext, txPolicy, instance);
             }
@@ -777,7 +797,6 @@ public class StatefulContainer implement
 
     private void afterInvoke(ThreadContext callContext, TransactionPolicy 
txPolicy, Instance instance) throws OpenEJBException {
         try {
-            unregisterEntityManagers(instance, callContext);
             if (instance != null && txPolicy instanceof BeanTransactionPolicy) 
{
                 // suspend the currently running transaction if any
                 SuspendedTransaction suspendedTransaction = null;
@@ -801,26 +820,30 @@ public class StatefulContainer implement
         }
     }
 
-    private Index<EntityManagerFactory, EntityManager> 
createEntityManagers(BeanContext beanContext) {
+    private Index<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> createEntityManagers(BeanContext 
beanContext) {
         // create the extended entity managers
         Index<EntityManagerFactory, Map> factories = 
beanContext.getExtendedEntityManagerFactories();
-        Index<EntityManagerFactory, EntityManager> entityManagers = null;
+        Index<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = null;
         if (factories != null && factories.size() > 0) {
-            entityManagers = new Index<EntityManagerFactory, 
EntityManager>(new ArrayList<EntityManagerFactory>(factories.keySet()));
+            entityManagers = new Index<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker>(new 
ArrayList<EntityManagerFactory>(factories.keySet()));
             for (Map.Entry<EntityManagerFactory, Map> entry : 
factories.entrySet()) {
                 EntityManagerFactory entityManagerFactory = entry.getKey();
                 Map properties = entry.getValue();
 
 
-                EntityManager entityManager = 
entityManagerRegistry.getInheritedEntityManager(entityManagerFactory);
-                if (entityManager == null) {
+                JtaEntityManagerRegistry.EntityManagerTracker 
entityManagerTracker = 
entityManagerRegistry.getInheritedEntityManager(entityManagerFactory);
+                EntityManager entityManager;
+                if (entityManagerTracker == null) {
                     if (properties != null) {
                         entityManager = 
entityManagerFactory.createEntityManager(properties);
                     } else {
                         entityManager = 
entityManagerFactory.createEntityManager();
                     }
+                    entityManagerTracker = new 
JtaEntityManagerRegistry.EntityManagerTracker(entityManager);
+                } else {
+                    entityManagerTracker.incCounter();
                 }
-                entityManagers.put(entityManagerFactory, entityManager);
+                entityManagers.put(entityManagerFactory, entityManagerTracker);
             }
         }
         return entityManagers;
@@ -836,7 +859,7 @@ public class StatefulContainer implement
         if (factories == null) return;
 
         // get the managers for the factories
-        Map<EntityManagerFactory, EntityManager> entityManagers = 
instance.getEntityManagers(factories);
+        Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = 
instance.getEntityManagers(factories);
         if (entityManagers == null) return;
 
         // register them
@@ -847,16 +870,26 @@ public class StatefulContainer implement
         }
     }
 
-    private void unregisterEntityManagers(Instance instance, ThreadContext 
callContext) {
-        if (entityManagerRegistry == null) return;
-        if (instance == null) return;
+    private Map<EntityManagerFactory, 
JtaEntityManagerRegistry.EntityManagerTracker> 
unregisterEntityManagers(Instance instance, ThreadContext callContext) {
+        if (entityManagerRegistry == null) return null;
+        if (instance == null) return null;
 
         BeanContext beanContext = callContext.getBeanContext();
 
         // register them
-        entityManagerRegistry.removeEntityManagers((String) 
beanContext.getDeploymentID(), instance.primaryKey);
+        return entityManagerRegistry.removeEntityManagers((String) 
beanContext.getDeploymentID(), instance.primaryKey);
     }
 
+    private void 
closeEntityManagers(Map<EntityManagerFactory,JtaEntityManagerRegistry.EntityManagerTracker>
 unregisteredEntityManagers) {
+        if (unregisteredEntityManagers == null) return;
+
+        // iterate throughout all EM to close EntityManager
+        for (JtaEntityManagerRegistry.EntityManagerTracker 
entityManagerTracker : unregisteredEntityManagers.values()) {
+            if(entityManagerTracker.decCounter() == 0) {
+                entityManagerTracker.getEntityManager().close();
+            }
+        }
+    }
 
     private void registerSessionSynchronization(Instance instance, 
ThreadContext callContext)  {
         TransactionPolicy txPolicy = callContext.getTransactionPolicy();

Modified: 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/persistence/JtaEntityManagerRegistry.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/persistence/JtaEntityManagerRegistry.java?rev=1145516&r1=1145515&r2=1145516&view=diff
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/persistence/JtaEntityManagerRegistry.java
 (original)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/persistence/JtaEntityManagerRegistry.java
 Tue Jul 12 10:01:47 2011
@@ -95,10 +95,11 @@ public class JtaEntityManagerRegistry {
 
         // if extended context, there must be an entity manager already 
registered with the tx
         if (extended) {
-            EntityManager entityManager = 
getInheritedEntityManager(entityManagerFactory);
-            if (entityManager == null) {
+            EntityManagerTracker entityManagerTracker = 
getInheritedEntityManager(entityManagerFactory);
+            if (entityManagerTracker == null || 
entityManagerTracker.getEntityManager() == null) {
                 throw new IllegalStateException("InternalError: an entity 
manager should already be registered for this extended persistence unit");
             }
+            EntityManager entityManager = 
entityManagerTracker.getEntityManager();
 
             // if transaction is active, we need to register the entity 
manager with the transaction manager
             if (transactionActive) {
@@ -137,16 +138,17 @@ public class JtaEntityManagerRegistry {
      * @throws EntityManagerAlreadyRegisteredException if an entity manager is 
already registered with the transaction
      * for one of the supplied entity manager factories; for EJBs this should 
be caught and rethown as an EJBException
      */
-    public void addEntityManagers(String deploymentId, Object primaryKey, 
Map<EntityManagerFactory, EntityManager> entityManagers) throws 
EntityManagerAlreadyRegisteredException {
+    public void addEntityManagers(String deploymentId, Object primaryKey, 
Map<EntityManagerFactory, EntityManagerTracker> entityManagers) throws 
EntityManagerAlreadyRegisteredException {
         extendedRegistry.get().addEntityManagers(new InstanceId(deploymentId, 
primaryKey), entityManagers);
     }
 
     /**
      * Removed the registered entity managers for the specified component.
      * @param deploymentId the id of the component
+     * @return EntityManager map we are removing
      */
-    public void removeEntityManagers(String deploymentId, Object primaryKey) {
-        extendedRegistry.get().removeEntityManagers(new 
InstanceId(deploymentId, primaryKey));
+    public Map<EntityManagerFactory, EntityManagerTracker> 
removeEntityManagers(String deploymentId, Object primaryKey) {
+        return extendedRegistry.get().removeEntityManagers(new 
InstanceId(deploymentId, primaryKey));
     }
 
     /**
@@ -154,7 +156,7 @@ public class JtaEntityManagerRegistry {
      * @param entityManagerFactory the entity manager factory from which an 
entity manager is needed
      * @return the existing entity manager or null if one is not found
      */
-    public EntityManager getInheritedEntityManager(EntityManagerFactory 
entityManagerFactory) {
+    public EntityManagerTracker getInheritedEntityManager(EntityManagerFactory 
entityManagerFactory) {
         return 
extendedRegistry.get().getInheritedEntityManager(entityManagerFactory);
     }
 
@@ -179,10 +181,11 @@ public class JtaEntityManagerRegistry {
     }
 
     private class ExtendedRegistry {
-        private final Map<InstanceId, Map<EntityManagerFactory, 
EntityManager>> entityManagersByDeploymentId =
-                new HashMap<InstanceId, Map<EntityManagerFactory, 
EntityManager>>();
+        private final Map<InstanceId, Map<EntityManagerFactory, 
EntityManagerTracker>> entityManagersByDeploymentId =
+                new HashMap<InstanceId, Map<EntityManagerFactory, 
EntityManagerTracker>>();
 
-        private void addEntityManagers(InstanceId instanceId, 
Map<EntityManagerFactory, EntityManager> entityManagers) throws 
EntityManagerAlreadyRegisteredException {
+        private void addEntityManagers(InstanceId instanceId, 
Map<EntityManagerFactory, EntityManagerTracker> entityManagers)
+                throws EntityManagerAlreadyRegisteredException {
             if (instanceId == null) {
                 throw new NullPointerException("instanceId is null");
             }
@@ -191,9 +194,9 @@ public class JtaEntityManagerRegistry {
             }
 
             if (isTransactionActive()) {
-                for (Map.Entry<EntityManagerFactory, EntityManager> entry : 
entityManagers.entrySet()) {
+                for (Map.Entry<EntityManagerFactory, EntityManagerTracker> 
entry : entityManagers.entrySet()) {
                     EntityManagerFactory entityManagerFactory = entry.getKey();
-                    EntityManager entityManager = entry.getValue();
+                    EntityManager entityManager = 
entry.getValue().getEntityManager();
                     EntityManagerTxKey txKey = new 
EntityManagerTxKey(entityManagerFactory);
                     EntityManager oldEntityManager = (EntityManager) 
transactionRegistry.getResource(txKey);
                     if (entityManager == oldEntityManager) {
@@ -210,23 +213,23 @@ public class JtaEntityManagerRegistry {
             entityManagersByDeploymentId.put(instanceId, entityManagers);
         }
 
-        private void removeEntityManagers(InstanceId instanceId) {
+        private Map<EntityManagerFactory, EntityManagerTracker> 
removeEntityManagers(InstanceId instanceId) {
             if (instanceId == null) {
                 throw new NullPointerException("InstanceId is null");
             }
 
-            entityManagersByDeploymentId.remove(instanceId);
+            return entityManagersByDeploymentId.remove(instanceId);
         }
 
-        private EntityManager getInheritedEntityManager(EntityManagerFactory 
entityManagerFactory) {
+        private EntityManagerTracker 
getInheritedEntityManager(EntityManagerFactory entityManagerFactory) {
             if (entityManagerFactory == null) {
                 throw new NullPointerException("entityManagerFactory is null");
             }
 
-            for (Map<EntityManagerFactory, EntityManager> entityManagers : 
entityManagersByDeploymentId.values()) {
-                EntityManager entityManager = 
entityManagers.get(entityManagerFactory);
-                if (entityManager != null) {
-                    return entityManager;
+            for (Map<EntityManagerFactory, EntityManagerTracker> 
entityManagers : entityManagersByDeploymentId.values()) {
+                EntityManagerTracker entityManagerTracker = 
entityManagers.get(entityManagerFactory);
+                if (entityManagerTracker != null) {
+                    return entityManagerTracker;
                 }
             }
             return null;
@@ -240,14 +243,14 @@ public class JtaEntityManagerRegistry {
                 throw new TransactionRequiredException();
             }
 
-            Map<EntityManagerFactory, EntityManager> entityManagers = 
entityManagersByDeploymentId.get(instanceId);
+            Map<EntityManagerFactory, EntityManagerTracker> entityManagers = 
entityManagersByDeploymentId.get(instanceId);
             if (entityManagers == null) {
                 return;
             }
 
-            for (Map.Entry<EntityManagerFactory, EntityManager> entry : 
entityManagers.entrySet()) {
+            for (Map.Entry<EntityManagerFactory, EntityManagerTracker> entry : 
entityManagers.entrySet()) {
                 EntityManagerFactory entityManagerFactory = entry.getKey();
-                EntityManager entityManager = entry.getValue();
+                EntityManager entityManager = 
entry.getValue().getEntityManager();
                 entityManager.joinTransaction();
                 EntityManagerTxKey txKey = new 
EntityManagerTxKey(entityManagerFactory);
                 transactionRegistry.putResource(txKey, entityManager);
@@ -292,6 +295,36 @@ public class JtaEntityManagerRegistry {
         }
     }
 
+    /**
+     * This object is used track all EntityManagers inherited in order
+     * to effectively close it when the latest Extended persistence context
+     * is no more accessed.
+     */
+    public static class EntityManagerTracker {
+        // must take care of the first inheritance level
+        private transient int counter;
+        private EntityManager entityManager;
+
+        public EntityManagerTracker(EntityManager entityManager) {
+            if (entityManager == null) throw new 
NullPointerException("entityManager is null.");
+
+            this.counter = 0;
+            this.entityManager = entityManager;
+        }
+
+        public int incCounter() {
+            return counter++;
+        }
+
+        public int decCounter() {
+            return counter--;
+        }
+
+        public EntityManager getEntityManager() {
+            return entityManager;
+        }
+    }
+
     private static class CloseEntityManager implements Synchronization {
         private final EntityManager entityManager;
         private String unitName;

Modified: 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/EntityManagerPropogationTest.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/EntityManagerPropogationTest.java?rev=1145516&r1=1145515&r2=1145516&view=diff
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/EntityManagerPropogationTest.java
 (original)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/EntityManagerPropogationTest.java
 Tue Jul 12 10:01:47 2011
@@ -39,28 +39,53 @@ import org.apache.openjpa.persistence.Ar
 import javax.ejb.EJB;
 import javax.ejb.EJBException;
 import javax.ejb.Local;
-import javax.ejb.Remove;
 import javax.ejb.NoSuchEJBException;
+import javax.ejb.Remove;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
 import javax.persistence.Entity;
 import javax.persistence.EntityManager;
 import javax.persistence.Id;
 import javax.persistence.PersistenceContext;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
 import static javax.persistence.PersistenceContextType.EXTENDED;
 import static javax.persistence.PersistenceContextType.TRANSACTION;
-import java.io.IOException;
 
 public class EntityManagerPropogationTest extends TestCase {
 
     public void test() throws Exception {
+        _testEMClose();
         _testExtended();
         _testExtendedRemove();
+        _testExtendedRandomRemove();
         _testNotTooExtended();
         _testTransaction();
-       _testSFTr2SFEx();
-       _testSFEx2SLTr2SFEx();
-       _testSLTr2SFEx();
+        _testSFTr2SFEx();
+        _testSFEx2SLTr2SFEx();
+        _testSLTr2SFEx();
+    }
+
+    private void _testEMClose() throws Exception {
+        InitialContext ctx = new InitialContext();
+
+        PleaseCloseMyExtendedEmBean checkExtendedWorks = 
(PleaseCloseMyExtendedEmBean) ctx.lookup("PleaseCloseMyExtendedEmLocalBean");
+        EntityManager savedReference = checkExtendedWorks.getDelegate();
+        checkExtendedWorks.remove();
+        assertFalse(savedReference.isOpen());
+
+        PleaseCloseMyEmBean please = (PleaseCloseMyEmBean) 
ctx.lookup("PleaseCloseMyEmLocalBean");
+        savedReference = please.getDelegate();
+        please.remove();
+        assertFalse(savedReference.isOpen());
+
+        PleaseCloseMyEmBean statelessIsEasier = (PleaseCloseMyEmBean) 
ctx.lookup("PleaseCloseMyLessEmLocalBean");
+        savedReference = statelessIsEasier.getDelegate();
+        statelessIsEasier.remove();
+        assertFalse(savedReference.isOpen());
     }
 
     public void _testExtended() throws Exception {
@@ -117,6 +142,42 @@ public class EntityManagerPropogationTes
 
     }
 
+    public void _testExtendedRandomRemove() throws Exception {
+
+        InitialContext ctx = new InitialContext();
+        int size;
+        Random rdm = new Random();
+
+        for (int l = 0 ; l < 10 ; l++) { // because Romain is not sure of the 
Random ;-)
+            Node node = (Node) ctx.lookup("ExtendedLocalBean");
+            List<Node> nodes = new ArrayList<Node>();
+            List<EntityManager> delegates = new ArrayList<EntityManager>();
+
+            while (node.getChild() != null) {
+                nodes.add(node);
+                delegates.add(node.getDelegateEntityManager());
+                node = node.getChild();
+            }
+
+            // random remove all stateful
+            do {
+                size = nodes.size();
+                int i = rdm.nextInt(size);
+                Node n = nodes.remove(i);
+                EntityManager entityManager = delegates.remove(i);
+
+                n.remove();
+
+                if (--size == 0) {
+                    assertFalse(entityManager.isOpen());
+                } else {
+                    assertTrue(entityManager.isOpen());
+                }
+
+            } while (size > 0);
+        }
+    }
+
     /**
      * Test that two Stateful session bean siblings
      * do not share the same extended persistence context
@@ -217,7 +278,7 @@ public class EntityManagerPropogationTes
            node.createUntilLeaf(8, "Yellow");
            
            fail("5.6.3.1 Requirements for Persistence Context Propagation 
(persistence spec)" +
-                       "\n\t--> we cannot have two persistence contexts 
associated with the transaction");
+                "\n\t--> we cannot have two persistence contexts associated 
with the transaction");
            
        } catch (EJBException e) {
            // OK
@@ -241,6 +302,10 @@ public class EntityManagerPropogationTes
         // Create an ejb-jar.xml for this app
         EjbJar ejbJar = new EjbJar();
 
+        ejbJar.addEnterpriseBean(new StatefulBean("PleaseCloseMyExtendedEm", 
PleaseCloseMyExtendedEmBean.class));
+        ejbJar.addEnterpriseBean(new StatefulBean("PleaseCloseMyEm", 
PleaseCloseMyEmBean.class));
+        ejbJar.addEnterpriseBean(new StatelessBean("PleaseCloseMyLessEm", 
PleaseCloseMyEmBean.class));
+
         // Add six beans and link them all in a chain
         addStatefulBean(ejbJar, ExtendedContextBean.class, "Extended", 
"Extendedx2");
         addStatefulBean(ejbJar, ExtendedContextBean.class, "Extendedx2", 
"Extendedx3");
@@ -349,9 +414,35 @@ public class EntityManagerPropogationTes
         Node getChild();
         
         String getDelegateEntityManagerReference();
-        
+
+        EntityManager getDelegateEntityManager();
+    }
+
+    public static class PleaseCloseMyExtendedEmBean {
+
+        @PersistenceContext(unitName = "testUnit", type = EXTENDED)
+        protected EntityManager context;
+
+        public EntityManager getDelegate() {
+            return (EntityManager) context.getDelegate();
+        }
+
+        @Remove
+        public void remove(){}
     }
 
+    public static class PleaseCloseMyEmBean {
+
+        @PersistenceContext(unitName = "testUnit", type = TRANSACTION)
+        protected EntityManager context;
+
+        public EntityManager getDelegate() {
+            return (EntityManager) context.getDelegate();
+        }
+
+        @Remove
+        public void remove(){}
+    }
 
     /**
      * The root stateful session bean is essentially the "owner"
@@ -371,6 +462,10 @@ public class EntityManagerPropogationTes
         protected EntityManager getEntityManager() {
             return context;
         }
+
+        public EntityManager getDelegateEntityManager() {
+            return (EntityManager) context.getDelegate();
+        }
     }
 
     public static class TransactionContextBean extends NodeBean {
@@ -381,6 +476,10 @@ public class EntityManagerPropogationTes
         protected EntityManager getEntityManager() {
             return context;
         }
+
+        public EntityManager getDelegateEntityManager() {
+            return (EntityManager) context.getDelegate();
+        }
     }
 
     public static abstract class NodeBean implements Node {
@@ -444,6 +543,10 @@ public class EntityManagerPropogationTes
             return null;
         }
 
+        public EntityManager getDelegateEntityManager() {
+            return null;
+        }
+
         @Remove
         public void remove(){}
 


Reply via email to