Repository: tomee
Updated Branches:
  refs/heads/master eb0c2da70 -> 1a3f66df2


TOMEE-1702 dont store cmp reference globally


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/dac78206
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/dac78206
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/dac78206

Branch: refs/heads/master
Commit: dac782064fa1b356686a845f385eca1c2a5534fa
Parents: eb0c2da
Author: Romain manni-Bucau <rmannibu...@gmail.com>
Authored: Tue Feb 2 12:25:55 2016 +0100
Committer: Romain manni-Bucau <rmannibu...@gmail.com>
Committed: Tue Feb 2 12:25:55 2016 +0100

----------------------------------------------------------------------
 .../openejb/core/ivm/BaseEjbProxyHandler.java   | 104 ++++++--
 .../openejb/core/cmp/jpa/SimpleCmpTest.java     | 244 +++++++++++++++++++
 2 files changed, 333 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/dac78206/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/BaseEjbProxyHandler.java
----------------------------------------------------------------------
diff --git 
a/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/BaseEjbProxyHandler.java
 
b/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/BaseEjbProxyHandler.java
index ac0e1dd..309b359 100644
--- 
a/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/BaseEjbProxyHandler.java
+++ 
b/container/openejb-core/src/main/java/org/apache/openejb/core/ivm/BaseEjbProxyHandler.java
@@ -23,12 +23,31 @@ import org.apache.openejb.InterfaceType;
 import org.apache.openejb.OpenEJBException;
 import org.apache.openejb.ProxyInfo;
 import org.apache.openejb.RpcContainer;
+import org.apache.openejb.core.Operation;
 import org.apache.openejb.core.ThreadContext;
+import org.apache.openejb.core.ThreadContextListener;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.spi.ContainerSystem;
 import org.apache.openejb.spi.SecurityService;
 import org.apache.openejb.util.proxy.LocalBeanProxyFactory;
 
+import javax.ejb.AccessLocalException;
+import javax.ejb.EJBException;
+import javax.ejb.EJBTransactionRequiredException;
+import javax.ejb.EJBTransactionRolledbackException;
+import javax.ejb.NoSuchEJBException;
+import javax.ejb.NoSuchObjectLocalException;
+import javax.ejb.TransactionRequiredLocalException;
+import javax.ejb.TransactionRolledbackLocalException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.TransactionRequiredException;
+import javax.transaction.TransactionRolledbackException;
+import javax.transaction.TransactionSynchronizationRegistry;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -54,16 +73,6 @@ import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.locks.ReentrantLock;
-import javax.ejb.AccessLocalException;
-import javax.ejb.EJBException;
-import javax.ejb.EJBTransactionRequiredException;
-import javax.ejb.EJBTransactionRolledbackException;
-import javax.ejb.NoSuchEJBException;
-import javax.ejb.NoSuchObjectLocalException;
-import javax.ejb.TransactionRequiredLocalException;
-import javax.ejb.TransactionRolledbackLocalException;
-import javax.transaction.TransactionRequiredException;
-import javax.transaction.TransactionRolledbackException;
 
 import static 
org.apache.openejb.core.ivm.IntraVmCopyMonitor.State.CLASSLOADER_COPY;
 import static org.apache.openejb.core.ivm.IntraVmCopyMonitor.State.COPY;
@@ -74,6 +83,25 @@ public abstract class BaseEjbProxyHandler implements 
InvocationHandler, Serializ
 
     private static final String OPENEJB_LOCALCOPY = "openejb.localcopy";
     private static final boolean REMOTE_COPY_ENABLED = 
parseRemoteCopySetting();
+    static {
+        ThreadContext.addThreadContextListener(new ThreadContextListener() {
+            @Override
+            public void contextEntered(final ThreadContext oldContext, final 
ThreadContext newContext) {
+                // no-op
+            }
+
+            @Override
+            public void contextExited(final ThreadContext exitedContext, final 
ThreadContext reenteredContext) {
+                if (exitedContext != null) {
+                    final ProxyRegistry proxyRegistry = 
exitedContext.get(ProxyRegistry.class);
+                    if (proxyRegistry != null) {
+                        proxyRegistry.liveHandleRegistry.clear();
+                    }
+                }
+            }
+        });
+    }
+
     public final Object deploymentID;
     public final Object primaryKey;
     protected final InterfaceType interfaceType;
@@ -640,12 +668,58 @@ public abstract class BaseEjbProxyHandler implements 
InvocationHandler, Serializ
 
     public ConcurrentMap getLiveHandleRegistry() {
         final BeanContext beanContext = getBeanContext();
-        ProxyRegistry proxyRegistry = beanContext.get(ProxyRegistry.class);
-        if (proxyRegistry == null) {
-            proxyRegistry = new ProxyRegistry();
-            beanContext.set(ProxyRegistry.class, proxyRegistry);
+
+        final ThreadContext tc = ThreadContext.getThreadContext();
+        if (tc != null && tc.getBeanContext() != beanContext /* parent bean */ 
&& tc.getCurrentOperation() == Operation.BUSINESS) {
+            ProxyRegistry registry = tc.get(ProxyRegistry.class);
+            if (registry == null) {
+                registry = new ProxyRegistry();
+                tc.set(ProxyRegistry.class, registry);
+            }
+            return registry.liveHandleRegistry;
+        } else { // use the tx if there
+            final SystemInstance systemInstance = SystemInstance.get();
+            final TransactionManager txMgr = 
systemInstance.getComponent(TransactionManager.class);
+            try {
+                final Transaction tx = txMgr.getTransaction();
+                if (tx != null && tx.getStatus() == Status.STATUS_ACTIVE) {
+                    final TransactionSynchronizationRegistry registry = 
systemInstance.getComponent(TransactionSynchronizationRegistry.class);
+                    final String resourceKey = ProxyRegistry.class.getName();
+                    ConcurrentMap map = 
ConcurrentMap.class.cast(registry.getResource(resourceKey));
+                    if (map == null) {
+                        map = new ConcurrentHashMap();
+                        registry.putResource(resourceKey, map);
+                        try {
+                            final ConcurrentMap tmp = map;
+                            tx.registerSynchronization(new Synchronization() {
+                                @Override
+                                public void beforeCompletion() {
+                                    // no-op
+                                }
+
+                                @Override
+                                public void afterCompletion(final int status) {
+                                    tmp.clear();
+                                }
+                            });
+                        } catch (final RollbackException e) { // not really 
possible since we check the status
+                            // let it go to default
+                        }
+                    }
+                    return map;
+                }
+            } catch (final SystemException e) {
+                // let it go to default
+            }
+
+            // back to default but it doesnt release the memory
+            ProxyRegistry proxyRegistry = beanContext.get(ProxyRegistry.class);
+            if (proxyRegistry == null) {
+                proxyRegistry = new ProxyRegistry();
+                beanContext.set(ProxyRegistry.class, proxyRegistry);
+            }
+            return proxyRegistry.liveHandleRegistry;
         }
-        return proxyRegistry.liveHandleRegistry;
     }
 
     private void writeObject(final ObjectOutputStream out) throws IOException {

http://git-wip-us.apache.org/repos/asf/tomee/blob/dac78206/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SimpleCmpTest.java
----------------------------------------------------------------------
diff --git 
a/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SimpleCmpTest.java
 
b/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SimpleCmpTest.java
new file mode 100644
index 0000000..9ff4557
--- /dev/null
+++ 
b/container/openejb-core/src/test/java/org/apache/openejb/core/cmp/jpa/SimpleCmpTest.java
@@ -0,0 +1,244 @@
+/*
+ * 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.cmp.jpa;
+
+import org.apache.activemq.util.ByteArrayInputStream;
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.config.ReadDescriptors;
+import org.apache.openejb.core.entity.EntityContext;
+import org.apache.openejb.core.entity.EntityEjbHomeHandler;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.testing.AppResource;
+import org.apache.openejb.testing.Module;
+import org.apache.openejb.testing.SimpleLog;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.ejb.CreateException;
+import javax.ejb.EJBException;
+import javax.ejb.EJBLocalObject;
+import javax.ejb.EntityBean;
+import javax.ejb.RemoveException;
+import javax.ejb.SessionBean;
+import javax.ejb.SessionContext;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import java.lang.reflect.Proxy;
+import java.rmi.RemoteException;
+
+import static org.junit.Assert.assertNotNull;
+
+@SimpleLog
+@RunWith(ApplicationComposer.class)
+public class SimpleCmpTest {
+    @AppResource
+    private Context ctx;
+
+    @Test
+    public void checkNoLeak() throws NamingException, RemoteException {
+        TestBeanEJBHome home = (TestBeanEJBHome) 
ctx.lookup("TestBeanRemoteHome");
+        TestBeanEJBObject bean = home.create();
+
+        bean.check(bean.createHotelBean(0)); // the bean has the asserts
+    }
+
+    @Module
+    public EjbJar jar() throws OpenEJBException {
+        return ReadDescriptors.readEjbJar(new ByteArrayInputStream(
+                ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                        "<ejb-jar xsi:schemaLocation=\"" +
+                        "http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd\"; " +
+                        
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"; " +
+                        "xmlns=\"http://java.sun.com/xml/ns/j2ee\"; 
version=\"2.1\" id=\"ejb-jar_ID\">\n" +
+                        "<display-name>OMEApp</display-name>\n" +
+                        "<enterprise-beans>\n" +
+                        "<entity id=\"ContainerManagedEntity_1\">\n" +
+                        "<ejb-name>HotelBean</ejb-name>\n" +
+                        "<local-home>" + HotelEJBLocalHome.class.getName() + 
"</local-home>\n" +
+                        "<local>" + HotelEJBLocalObject.class.getName() + 
"</local>\n" +
+                        "<ejb-class>" + HotelBean.class.getName() + 
"</ejb-class>\n" +
+                        "<persistence-type>Container</persistence-type>\n" +
+                        "<prim-key-class>java.lang.String</prim-key-class>\n" +
+                        "<reentrant>false</reentrant>\n" +
+                        "<cmp-version>2.x</cmp-version>\n" +
+                        
"<abstract-schema-name>HotelBean</abstract-schema-name>\n" +
+                        "<cmp-field id=\"HotelBean_primKey\">\n" +
+                        "<field-name>hotelId</field-name>\n" +
+                        "</cmp-field>\n" +
+                        "<cmp-field id=\"HotelBean_name\">\n" +
+                        "<field-name>hotelname</field-name>\n" +
+                        "</cmp-field>\n" +
+                        "<primkey-field>hotelId</primkey-field>\n" +
+                        "</entity>\n" +
+                        "<session>\n" +
+                        "<ejb-name>TestBean</ejb-name>\n" +
+                        "<home>" + TestBeanEJBHome.class.getName() + 
"</home>\n" +
+                        "<remote>" + TestBeanEJBObject.class.getName() + 
"</remote>\n" +
+                        "<local-home>" + TestBeanEJBLocalHome.class.getName() 
+ "</local-home>\n" +
+                        "<local>" + TestBeanEJBLocalObject.class.getName() + 
"</local>\n" +
+                        "<ejb-class>" + TestBean.class.getName() + 
"</ejb-class>\n" +
+                        "<session-type>Stateless</session-type>\n" +
+                        "<transaction-type>Container</transaction-type>\n" +
+                        "<ejb-local-ref>\n" +
+                        "<ejb-ref-name>ejb/HotelEJBLocalHome</ejb-ref-name>\n" 
+
+                        "<ejb-ref-type>Entity</ejb-ref-type>\n" +
+                        "<local-home>" + HotelEJBLocalHome.class.getName() + 
"</local-home>\n" +
+                        "<local>" + HotelEJBLocalObject.class.getName() + 
"</local>\n" +
+                        "</ejb-local-ref>\n" +
+                        "</session>\n" +
+                        "</enterprise-beans>\n" +
+                        "</ejb-jar>").getBytes()));
+    }
+
+    public interface HotelEJBLocalHome extends javax.ejb.EJBLocalHome {
+        HotelEJBLocalObject create(String id, String name) throws 
CreateException;
+        HotelEJBLocalObject findByPrimaryKey(String id);
+    }
+
+    public interface TestBeanEJBHome extends javax.ejb.EJBHome {
+        TestBeanEJBObject create() throws RemoteException;
+    }
+
+    public interface TestBeanEJBLocalHome extends javax.ejb.EJBLocalHome {
+
+        TestBeanEJBLocalObject create();
+    }
+
+    public interface TestBeanEJBLocalObject extends javax.ejb.EJBLocalObject {
+        void createHotelBean(int num) throws CreateException;
+    }
+
+    public static class TestBean implements SessionBean {
+
+        private static final long serialVersionUID = 1L;
+        protected SessionContext sessionContext;
+        private HotelEJBLocalHome hotel;
+
+        public void ejbCreate() {
+        }
+
+        public void ejbPassivate() throws EJBException, RemoteException {
+        }
+
+        public void ejbRemove() throws EJBException, RemoteException {
+        }
+
+        public void setSessionContext(SessionContext arg0) throws EJBException,
+                RemoteException {
+            this.sessionContext = arg0;
+        }
+
+        public void ejbActivate() throws EJBException, RemoteException {
+        }
+
+        public Object createHotelBean(int num) throws CreateException {
+            hotel = (HotelEJBLocalHome) 
this.sessionContext.lookup("ejb/HotelEJBLocalHome");
+            final String pk = hotel.create(String.valueOf(num), "Some 
Hotel").getPrimaryKey().toString();
+            assertNotNull(hotel.findByPrimaryKey(pk));
+            return pk;
+        }
+
+        public void check(final String pk) {
+            hotel = (HotelEJBLocalHome) 
this.sessionContext.lookup("ejb/HotelEJBLocalHome");
+
+            // main part of the test is there
+            final EntityEjbHomeHandler handler = 
EntityEjbHomeHandler.class.cast(Proxy.getInvocationHandler(hotel));
+            try {
+                final Object registry = handler.getBeanContext().get(
+                        Thread.currentThread().getContextClassLoader() // 
private so use reflection
+                                
.loadClass("org.apache.openejb.core.ivm.BaseEjbProxyHandler$ProxyRegistry"));
+                assertNotNull(registry); // not even instantiated since we 
have a wrapper (stateless)
+            } catch (final ClassNotFoundException e) {
+                throw new IllegalStateException(e);
+            }
+
+            // ensure we didn't deleted the entry
+            assertNotNull(hotel.findByPrimaryKey(pk));
+        }
+    }
+
+    public interface HotelEJBLocalObject extends EJBLocalObject {
+
+        java.lang.String getHotelId();
+
+        void setHotelId(java.lang.String hotelId);
+
+        String getHotelname();
+
+        void setHotelname(String hotelname);
+    }
+
+    public interface TestBeanEJBObject extends javax.ejb.EJBObject {
+        String createHotelBean(int num) throws RemoteException;
+        void check(String pk) throws RemoteException;
+    }
+
+    public static abstract class HotelBean implements EntityBean {
+        private static final long serialVersionUID = -1740314851444302078L;
+
+
+        public String ejbCreate(String id, String name) throws CreateException 
{
+            this.setHotelId(id);
+            this.setHotelname(name);
+            return null;
+        }
+
+        public abstract java.lang.String getHotelId();
+
+        public abstract void setHotelId(java.lang.String hotelId);
+
+        public abstract String getHotelname();
+
+        public abstract void setHotelname(String hotelname);
+
+        public void ejbPostCreate(String str1, String str2)
+                throws CreateException {
+        }
+
+
+        public void ejbRemove() throws RemoveException, EJBException,
+                RemoteException {
+            // no-op
+        }
+
+        public void ejbActivate() throws EJBException, RemoteException {
+            // no-op
+        }
+
+        public void ejbLoad() throws EJBException, RemoteException {
+            // no-op
+        }
+
+        public void ejbPassivate() throws EJBException, RemoteException {
+            // no-op
+        }
+
+        public void ejbStore() throws EJBException, RemoteException {
+            // no-op
+        }
+
+        public void setEntityContext(EntityContext arg0) throws EJBException,
+                RemoteException {
+            // no-op
+        }
+
+        public void unsetEntityContext() throws EJBException, RemoteException {
+            // no-op
+        }
+    }
+}

Reply via email to