You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2010/11/09 06:07:14 UTC

svn commit: r1032845 - in /openejb/branches/openejb-3.1.x/container/openejb-core/src: main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java test/java/org/apache/openejb/core/stateless/StatelessPoolLeakTest.java

Author: dblevins
Date: Tue Nov  9 05:07:13 2010
New Revision: 1032845

URL: http://svn.apache.org/viewvc?rev=1032845&view=rev
Log:
OPENEJB-1394: Stateless pool leak on failed PostConstruct

Added:
    openejb/branches/openejb-3.1.x/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessPoolLeakTest.java   (with props)
Modified:
    openejb/branches/openejb-3.1.x/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java

Modified: openejb/branches/openejb-3.1.x/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java?rev=1032845&r1=1032844&r2=1032845&view=diff
==============================================================================
--- openejb/branches/openejb-3.1.x/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java (original)
+++ openejb/branches/openejb-3.1.x/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java Tue Nov  9 05:07:13 2010
@@ -161,7 +161,19 @@ public class StatelessInstanceManager {
 
         if (instance == null) {
 
-            instance = ceateInstance(callContext);
+            try {
+                instance = ceateInstance(callContext);
+            } catch (Throwable t) {
+                // push null back on the pool to prevent leaks
+                data.pool.push((Pool.Entry) null);
+
+                if (t instanceof OpenEJBException) {
+                    throw (OpenEJBException) t;
+                } else {
+                    // assuming the exception handing in createInstance doesn't change, this line should never be reached
+                    throw new org.apache.openejb.ApplicationException(new RemoteException("Cannot obtain a free instance.", t));
+                }
+            }
         }
         return instance;
     }

Added: openejb/branches/openejb-3.1.x/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessPoolLeakTest.java
URL: http://svn.apache.org/viewvc/openejb/branches/openejb-3.1.x/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessPoolLeakTest.java?rev=1032845&view=auto
==============================================================================
--- openejb/branches/openejb-3.1.x/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessPoolLeakTest.java (added)
+++ openejb/branches/openejb-3.1.x/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessPoolLeakTest.java Tue Nov  9 05:07:13 2010
@@ -0,0 +1,186 @@
+/**
+ *
+ * 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.stateless;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.PostConstruct;
+import javax.ejb.Stateless;
+import javax.ejb.EJBException;
+import javax.naming.InitialContext;
+
+import junit.framework.TestCase;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.ProxyFactoryInfo;
+import org.apache.openejb.assembler.classic.SecurityServiceInfo;
+import org.apache.openejb.assembler.classic.StatelessSessionContainerInfo;
+import org.apache.openejb.assembler.classic.TransactionServiceInfo;
+import org.apache.openejb.config.ConfigurationFactory;
+import org.apache.openejb.core.ivm.naming.InitContextFactory;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.jee.StatelessBean;
+
+/**
+ * @version $Revision: 961763 $ $Date: 2010-07-08 09:39:00 -0400 (Thu, 08 Jul 2010) $
+ */
+public class StatelessPoolLeakTest extends TestCase {
+
+    public void test() throws Exception {
+
+        InitialContext ctx = new InitialContext();
+        Object object = ctx.lookup("CounterBeanLocal");
+        final Counter counter = (Counter) object;
+
+        assertLeakFree(counter);
+
+        assertLeakFree(counter);
+
+        assertLeakFree(counter);
+    }
+
+    private void assertLeakFree(Counter counter) {
+        assertCreateFailure(counter);
+
+        // perform another failure, should also be a create exception
+        // if a leak is present, this will result in a pool Timeout
+        assertCreateFailure(counter);
+
+        assertInstanceCreated(counter);
+
+        // Make the bean throw a runtime exception
+        // which will cause the pool to be empty again
+        assertBusinessFailure(counter);
+
+        assertInstanceCreated(counter);
+
+        assertBusinessFailure(counter);
+    }
+
+    private void assertBusinessFailure(Counter counter) {
+        CounterBean.failOnCreate.set(false);
+        CounterBean.failOnBusinessMethod.set(true);
+
+        final int expected = CounterBean.instances.get();
+        assertFailure(counter);
+        assertEquals(expected, CounterBean.instances.get());
+    }
+
+    private void assertInstanceCreated(Counter counter) {
+        CounterBean.failOnCreate.set(false);
+        CounterBean.failOnBusinessMethod.set(false);
+
+        final int expected = CounterBean.instances.get() + 1;
+        // Should now be successful
+        counter.count();
+        assertEquals(expected, CounterBean.instances.get());
+    }
+
+    private void assertCreateFailure(Counter counter) {
+        CounterBean.failOnCreate.set(true);
+        CounterBean.failOnBusinessMethod.set(false);
+
+        // perform one failure, should be a create exception
+        final int expected = CounterBean.instances.get() + 1;
+        assertFailure(counter);
+        assertEquals(expected, CounterBean.instances.get());
+    }
+
+    private void assertFailure(Counter counter) {
+        try {
+            counter.count();
+            fail("Exception should have failed on create");
+        } catch (Throwable t) {
+
+            if (!EJBException.class.equals(t.getClass())) {
+                fail("An EJBException should have been thrown:" + t.getClass().getName());
+            }
+
+            if (!CustomException.class.equals(t.getCause().getClass())) {
+                fail("A CustomException should have been the cause: " + t.getCause().getClass().getName());
+            }
+        }
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName());
+
+        ConfigurationFactory config = new ConfigurationFactory();
+        Assembler assembler = new Assembler();
+
+        assembler.createProxyFactory(config.configureService(ProxyFactoryInfo.class));
+        assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
+        assembler.createSecurityService(config.configureService(SecurityServiceInfo.class));
+
+        // containers
+        StatelessSessionContainerInfo statelessContainerInfo = config.configureService(StatelessSessionContainerInfo.class);
+        statelessContainerInfo.properties.setProperty("TimeOut", "100");
+        statelessContainerInfo.properties.setProperty("MaxSize", "1");
+        statelessContainerInfo.properties.setProperty("MinSize", "0");
+        statelessContainerInfo.properties.setProperty("StrictPooling", "true");
+        assembler.createContainer(statelessContainerInfo);
+
+        // Setup the descriptor information
+
+        StatelessBean bean = new StatelessBean(CounterBean.class);
+        bean.addBusinessLocal(Counter.class.getName());
+
+        EjbJar ejbJar = new EjbJar();
+        ejbJar.addEnterpriseBean(bean);
+
+        CounterBean.instances.set(0);
+        assembler.createApplication(config.configureApplication(ejbJar));
+
+    }
+
+    public static interface Counter {
+        int count();
+    }
+
+    public static class CustomException extends RuntimeException {
+
+    }
+    
+    @Stateless
+    public static class CounterBean implements Counter {
+
+        public static AtomicInteger instances = new AtomicInteger();
+        public static AtomicBoolean failOnCreate = new AtomicBoolean();
+        public static AtomicBoolean failOnBusinessMethod = new AtomicBoolean();
+
+        private int count;
+
+        public CounterBean() {
+            count = instances.incrementAndGet();
+        }
+
+        @PostConstruct
+        public void postConstruct() {
+            if (failOnCreate.get()) throw new CustomException();
+        }
+        
+        public int count(){
+            if (failOnBusinessMethod.get()) throw new CustomException();
+        	return instances.get();
+        }
+    }
+}

Propchange: openejb/branches/openejb-3.1.x/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessPoolLeakTest.java
------------------------------------------------------------------------------
    svn:eol-style = native