You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by ma...@apache.org on 2008/07/23 10:55:52 UTC

svn commit: r679032 - in /openejb/trunk/openejb3/container/openejb-core/src: main/java/org/apache/openejb/core/stateless/ test/java/org/apache/openejb/core/stateless/

Author: manugeorge
Date: Wed Jul 23 01:55:51 2008
New Revision: 679032

URL: http://svn.apache.org/viewvc?rev=679032&view=rev
Log:
OPENEJB-865 Timeout ignored for stateless session beans

Solution 
Use a Semaphore without a timeout when the timeout property is 0 or -ve. Use a semaphore with the timeout when the timeout property is given in milliseconds.

Added:
    openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessInstanceManagerPoolingTest.java
Modified:
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java?rev=679032&r1=679031&r2=679032&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java Wed Jul 23 01:55:51 2008
@@ -21,6 +21,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import javax.ejb.EJBAccessException;
 import javax.ejb.EJBHome;
@@ -32,13 +33,13 @@
 
 import org.apache.openejb.ContainerType;
 import org.apache.openejb.DeploymentInfo;
+import org.apache.openejb.InterfaceType;
 import org.apache.openejb.OpenEJBException;
 import org.apache.openejb.ProxyInfo;
-import org.apache.openejb.InterfaceType;
 import org.apache.openejb.core.CoreDeploymentInfo;
+import org.apache.openejb.core.ExceptionType;
 import org.apache.openejb.core.Operation;
 import org.apache.openejb.core.ThreadContext;
-import org.apache.openejb.core.ExceptionType;
 import org.apache.openejb.core.interceptor.InterceptorData;
 import org.apache.openejb.core.interceptor.InterceptorStack;
 import org.apache.openejb.core.timer.EjbTimerService;
@@ -46,6 +47,7 @@
 import org.apache.openejb.core.transaction.TransactionContext;
 import org.apache.openejb.core.transaction.TransactionPolicy;
 import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.util.Duration;
 import org.apache.xbean.finder.ClassFinder;
 
 /**
@@ -66,7 +68,7 @@
         this.transactionManager = transactionManager;
         this.securityService = securityService;
 
-        instanceManager = new StatelessInstanceManager(transactionManager, securityService, timeOut, poolSize, strictPooling);
+        instanceManager = new StatelessInstanceManager(transactionManager, securityService, new Duration(timeOut,TimeUnit.MILLISECONDS), poolSize, strictPooling);
 
         for (DeploymentInfo deploymentInfo : deploymentRegistry.values()) {
             org.apache.openejb.core.CoreDeploymentInfo di = (org.apache.openejb.core.CoreDeploymentInfo) deploymentInfo;

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java?rev=679032&r1=679031&r2=679032&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessInstanceManager.java Wed Jul 23 01:55:51 2008
@@ -41,6 +41,7 @@
 import org.apache.openejb.core.interceptor.InterceptorData;
 import org.apache.openejb.core.interceptor.InterceptorStack;
 import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.util.Duration;
 import org.apache.openejb.util.LinkedListStack;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
@@ -55,28 +56,25 @@
     private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources");
 
     protected int poolLimit = 0;
+    protected Duration timeout;
     protected int beanCount = 0;
     protected boolean strictPooling = false;
 
-    protected HashMap<Object,Semaphore> semaphores;
-
     protected final SafeToolkit toolkit = SafeToolkit.getToolkit("StatefulInstanceManager");
     private TransactionManager transactionManager;
     private SecurityService securityService;
 
-    public StatelessInstanceManager(TransactionManager transactionManager, SecurityService securityService, int timeout, int poolSize, boolean strictPooling) {
+    public StatelessInstanceManager(TransactionManager transactionManager, SecurityService securityService, Duration timeout, int poolSize, boolean strictPooling) {
         this.transactionManager = transactionManager;
         this.securityService = securityService;
         this.poolLimit = poolSize;
         this.strictPooling = strictPooling;
-
+        this.timeout = timeout;
+        
         if (strictPooling && poolSize < 1) {
             throw new IllegalArgumentException("Cannot use strict pooling with a pool size less than one.  Strict pooling blocks threads till an instance in the pool is available.  Please increase the pool size or set strict pooling to false");
         }
 
-        if (this.strictPooling) {
-            this.semaphores = new HashMap();
-        }
     }
 
     /**
@@ -99,12 +97,22 @@
         CoreDeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
         Data data = (Data) deploymentInfo.getContainerData();
         Stack pool = data.getPool();
+        
         if(strictPooling){
+        	boolean acquired = false;
             try {
-                semaphores.get(deploymentInfo.getDeploymentID()).acquire();
+            	if(timeout.getTime() <= 0L){
+            		data.getSemaphore().acquire();
+            		acquired = true;
+            	} else {
+                    acquired = data.getSemaphore().tryAcquire(timeout.getTime(),timeout.getUnit());
+            	}
             } catch (InterruptedException e2) {
                 throw new OpenEJBException("Unexpected Interruption of current thread: ",e2);
             }
+            if(!acquired){
+            	throw new IllegalStateException("An invocation of the Stateless Session Bean "+deploymentInfo.getEjbName()+" has timed-out"); 
+            }
         }
         Object bean = pool.pop();
 
@@ -300,7 +308,7 @@
 
         if (strictPooling) {
             pool.push(bean);
-            semaphores.get(deploymentInfo.getDeploymentID()).release();
+            data.getSemaphore().release();
         } else {
             if (pool.size() >= poolLimit) {
                 freeInstance(callContext, (Instance)bean);
@@ -341,19 +349,12 @@
     }
 
     public void deploy(CoreDeploymentInfo deploymentInfo) {
-        Data data = new Data(poolLimit);
+        Data data = new Data(poolLimit, this.strictPooling);
         deploymentInfo.setContainerData(data);      
-        if (this.strictPooling) {
-            this.semaphores.put(deploymentInfo.getDeploymentID(), new Semaphore(poolLimit));
-        }
-
     }
 
     public void undeploy(CoreDeploymentInfo deploymentInfo) {
         Data data = (Data) deploymentInfo.getContainerData();
-        if (this.strictPooling) {
-            semaphores.remove(deploymentInfo.getDeploymentID());
-        }
         if (data == null) return;
         Stack pool = data.getPool();
         //TODO ejbRemove on each bean in pool.
@@ -363,14 +364,23 @@
 
     private static final class Data {
         private final Stack pool;
-
-        public Data(int poolLimit) {
+        private Semaphore semaphore;
+        
+        public Data(int poolLimit, boolean strictPooling) {
             pool = new LinkedListStack(poolLimit);
+            if (strictPooling) {
+                semaphore = new Semaphore(poolLimit);
+            }
         }
 
         public Stack getPool() {
             return pool;
         }
+        
+        public Semaphore getSemaphore(){
+        	return semaphore;
+        }
+                        
     }
 
 }

Added: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessInstanceManagerPoolingTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessInstanceManagerPoolingTest.java?rev=679032&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessInstanceManagerPoolingTest.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/StatelessInstanceManagerPoolingTest.java Wed Jul 23 01:55:51 2008
@@ -0,0 +1,176 @@
+/**
+ *
+ * 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.List;
+
+import javax.ejb.Remote;
+import javax.ejb.Stateless;
+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: 581127 $ $Date: 2007-10-02 07:43:16 +0530 (Tue, 02 Oct 2007) $
+ */
+public class StatelessInstanceManagerPoolingTest extends TestCase {
+
+    public void testStatelessBeanPooling() throws Exception {
+
+        InitialContext ctx = new InitialContext();            
+        Object object = ctx.lookup("CounterBeanLocal");
+        assertTrue("instanceof counter", object instanceof Counter);
+
+        final Counter counter = (Counter) object;
+        // Do a business method...
+        Runnable r = new Runnable(){
+        	public void run(){
+        		counter.waitFor(10);        	
+        	}
+        };
+        
+        // How much ever the no of client invocations the count should be 10 as only 10 instances will be created.
+        for(int i=0;i<=30;i++){
+        	Thread t = new Thread(r);
+        	t.start();
+        	if(i==30) t.join();
+        }
+
+        assertEquals(10,CounterBean.counter);
+
+    }
+    
+    public void testStatelessBeanTimeout() throws Exception {
+        InitialContext ctx = new InitialContext();            
+        Object object = ctx.lookup("CounterBeanLocal");
+        assertTrue("instanceof counter", object instanceof Counter);
+
+        final Counter counter = (Counter) object;
+        // Do a business method...
+        Runnable r = new Runnable(){
+        	public void run(){
+        		try{
+        		    counter.waitFor(30);
+        		    assertFalse(true);
+        		}catch (Exception ex){
+        			ex.printStackTrace();
+        			assertEquals("An invocation of the Stateless Session Bean CounterBean has timed-out",ex.getMessage());
+        		}
+        	}
+        };
+        
+        // How much ever the no of client invocations the count should be 10 as only 10 instances will be created.
+        for(int i=0;i<=30;i++){
+        	Thread t = new Thread(r);
+        	t.start();        	
+        }
+
+        
+    	
+    }
+
+    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("PoolSize", "10");
+        statelessContainerInfo.properties.setProperty("StrictPooling", "true");
+        assembler.createContainer(statelessContainerInfo);
+
+        // Setup the descriptor information
+
+        StatelessBean bean = new StatelessBean(CounterBean.class);
+        bean.addBusinessLocal(Counter.class.getName());
+        bean.addBusinessRemote(RemoteCounter.class.getName());
+        bean.addPostConstruct("init");
+        bean.addPreDestroy("destroy");
+
+        EjbJar ejbJar = new EjbJar();
+        ejbJar.addEnterpriseBean(bean);
+
+        assembler.createApplication(config.configureApplication(ejbJar));
+
+    }
+
+ 
+    public static interface Counter {
+        int count();
+        void waitFor(int i);
+    }
+    
+    @Remote
+    public static interface RemoteCounter extends Counter {
+
+    }
+
+    public static enum Lifecycle {
+        CONSTRUCTOR, INJECTION, POST_CONSTRUCT, BUSINESS_METHOD, PRE_DESTROY
+    }
+
+    @Stateless
+    public static class CounterBean implements Counter, RemoteCounter {
+
+        public static int counter = 0;
+
+        public CounterBean() {
+        	counter++;
+        }
+        
+        public int count(){
+        	return counter;
+        }
+
+        public void waitFor(int i){
+        	try {
+				Thread.sleep(i);
+			} catch (InterruptedException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+        }
+        
+        public void init(){
+        	
+        }
+        
+        public void destroy(){
+        	
+        }
+    }
+}