Author: dblevins
Date: Wed Jun  2 04:36:07 2010
New Revision: 950367

URL: http://svn.apache.org/viewvc?rev=950367&view=rev
Log:
Patch from Matthew B. Jones, OPENEJB-1135: EJB 3.1 @Asynchronous method 
invocations
Thanks, Matthew!


Added:
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/asynch/
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/asynch/AsynchMethodRunnable.java
   (with props)
Modified:
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java
    
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java

Added: 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/asynch/AsynchMethodRunnable.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/asynch/AsynchMethodRunnable.java?rev=950367&view=auto
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/asynch/AsynchMethodRunnable.java
 (added)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/asynch/AsynchMethodRunnable.java
 Wed Jun  2 04:36:07 2010
@@ -0,0 +1,73 @@
+package org.apache.openejb.core.asynch;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+
+import javax.ejb.AsyncResult;
+
+import org.apache.openejb.InterfaceType;
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.core.CoreDeploymentInfo;
+import org.apache.openejb.core.ThreadContext;
+
+/**
+ * Abstract base class that will execute a bean in an
+ * asynchronous fashion. This class should be subclassed
+ * in the various containers (Stateless, Singleton, etc.)
+ * that need to provide this functionality.
+ * 
+ * @author Matthew B. Jones
+ *
+ */
+public abstract class AsynchMethodRunnable implements Callable<Object>{
+       protected Method callMethod;
+       protected Method runMethod;
+       protected Object[] args;
+       protected InterfaceType type;
+       protected CoreDeploymentInfo deployInfo;
+       protected Object primKey;
+       
+       public AsynchMethodRunnable(Method callMethod, Method runMethod, 
Object[] args, InterfaceType type, CoreDeploymentInfo deployInfo, Object 
primKey){
+               this.callMethod = callMethod;
+               this.runMethod = runMethod;
+               this.args = args;
+               this.type = type;
+               this.deployInfo = deployInfo;
+               this.primKey = primKey;
+       }
+       
+       protected abstract Object performInvoke(Object bean, ThreadContext 
callContext) throws OpenEJBException;
+       
+       protected abstract Object createBean(ThreadContext callContext) throws 
OpenEJBException;
+       
+       protected abstract void releaseBean(Object bean, ThreadContext 
callContext) throws OpenEJBException;
+
+       public Object call() throws Exception{
+               ThreadContext callContext = new ThreadContext(this.deployInfo, 
this.primKey);
+        ThreadContext oldCallContext = ThreadContext.enter(callContext);
+               Object bean = this.createBean(callContext);
+               try{
+                       Object result = this.performInvoke(bean, callContext);
+                       if(result == null){
+                               return null;
+                       }else if(!(result instanceof AsyncResult)){
+                               // The bean isn't returning the right result!
+                               // TODO What should we do?
+                               System.err.println("Bad things happened!");
+                               return null;
+                       }else{
+                               AsyncResult asynchResult = (AsyncResult)result;
+                               return asynchResult.get();
+                       }
+               }catch(Exception e){
+                       e.printStackTrace();
+                       throw e;
+               }finally{
+                       if (bean != null) {
+                this.releaseBean(bean, callContext);
+            }
+            ThreadContext.exit(oldCallContext);
+               }
+       }
+
+}

Propchange: 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/asynch/AsynchMethodRunnable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java
URL: 
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java?rev=950367&r1=950366&r2=950367&view=diff
==============================================================================
--- 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java
 (original)
+++ 
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java
 Wed Jun  2 04:36:07 2010
@@ -16,45 +16,53 @@
  */
 package org.apache.openejb.core.singleton;
 
+import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.afterInvoke;
+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 java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.locks.Lock;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
 
+import javax.ejb.Asynchronous;
+import javax.ejb.ConcurrentAccessTimeoutException;
 import javax.ejb.EJBAccessException;
 import javax.ejb.EJBHome;
 import javax.ejb.EJBLocalHome;
 import javax.ejb.EJBLocalObject;
 import javax.ejb.EJBObject;
-import javax.ejb.ConcurrentAccessTimeoutException;
 import javax.interceptor.AroundInvoke;
 
 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.RpcContainer;
-import org.apache.openejb.util.Duration;
 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.asynch.AsynchMethodRunnable;
 import org.apache.openejb.core.interceptor.InterceptorData;
 import org.apache.openejb.core.interceptor.InterceptorStack;
 import org.apache.openejb.core.timer.EjbTimerService;
 import org.apache.openejb.core.transaction.TransactionPolicy;
 import org.apache.openejb.core.webservices.AddressingSupport;
 import org.apache.openejb.core.webservices.NoAddressingSupport;
-
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleApplicationException;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.afterInvoke;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
 import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.util.Duration;
 import org.apache.xbean.finder.ClassFinder;
 
 /**
@@ -70,7 +78,9 @@ public class SingletonContainer implemen
     private SecurityService securityService;
     private long wait = 30;
     private TimeUnit unit = TimeUnit.SECONDS;
-
+    private BlockingQueue<Runnable> asynchQueue = new 
LinkedBlockingQueue<Runnable>();
+    private ThreadPoolExecutor asynchPool = new ThreadPoolExecutor(1, 20, 60, 
TimeUnit.SECONDS, asynchQueue);
+    private CompletionService<Object> asynchService = new 
ExecutorCompletionService<Object>(asynchPool);
 
     public SingletonContainer(Object id, SecurityService securityService) 
throws OpenEJBException {
         this.containerID = id;
@@ -182,6 +192,14 @@ public class SingletonContainer implemen
         // Use the backup way to determine call type if null was supplied.
         if (type == null) type = deployInfo.getInterfaceType(callInterface);
         
+        Method runMethod = deployInfo.getMatchingBeanMethod(callMethod);
+        if(runMethod.getAnnotation(Asynchronous.class) != null){
+               // Need to invoke this bean asynchronously
+               AsynchMethodRunnable asynch = new 
SingletonMethodRunnable(callMethod, runMethod, args, type, deployInfo, primKey);
+               Future<Object> future = this.asynchService.submit(asynch);
+               return future;
+        }
+        
         ThreadContext callContext = new ThreadContext(deployInfo, primKey);
         ThreadContext oldCallContext = ThreadContext.enter(callContext);
         try {
@@ -203,9 +221,6 @@ public class SingletonContainer implemen
 
             callContext.setCurrentOperation(Operation.BUSINESS);
             callContext.setCurrentAllowedStates(SingletonContext.getStates());
-
-            Method runMethod = deployInfo.getMatchingBeanMethod(callMethod);
-
             callContext.set(Method.class, runMethod);
             callContext.setInvokedInterface(callInterface);
 
@@ -346,4 +361,29 @@ public class SingletonContainer implemen
     protected ProxyInfo 
createEJBObject(org.apache.openejb.core.CoreDeploymentInfo deploymentInfo, 
Method callMethod) {
         return new ProxyInfo(deploymentInfo, null);
     }
+    
+    public class SingletonMethodRunnable extends AsynchMethodRunnable{
+       
+       public SingletonMethodRunnable(
+                               Method callMethod,
+                               Method runMethod, Object[] args, InterfaceType 
type,
+                               CoreDeploymentInfo deployInfo, Object primKey) {
+                       super(callMethod, runMethod, args, type, deployInfo, 
primKey);
+               }
+
+               protected Object performInvoke(Object bean, ThreadContext 
callContext) throws OpenEJBException{
+               return _invoke(this.callMethod, this.runMethod, this.args, 
(Instance)bean, callContext, this.type);
+       }
+
+               @Override
+               protected Object createBean(ThreadContext callContext) throws 
OpenEJBException{
+                       return instanceManager.getInstance(callContext);
+               }
+
+               @Override
+               protected void releaseBean(Object bean, ThreadContext 
callContext) throws OpenEJBException{
+                       // Singleton doesn't have to do anything here
+               }
+       
+    }
 }

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=950367&r1=950366&r2=950367&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 Jun  2 04:36:07 2010
@@ -16,12 +16,25 @@
  */
 package org.apache.openejb.core.stateless;
 
+import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.afterInvoke;
+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 java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
+import javax.ejb.Asynchronous;
 import javax.ejb.EJBAccessException;
 import javax.ejb.EJBHome;
 import javax.ejb.EJBLocalHome;
@@ -29,22 +42,24 @@ import javax.ejb.EJBLocalObject;
 import javax.ejb.EJBObject;
 import javax.interceptor.AroundInvoke;
 
-import org.apache.openejb.*;
+import org.apache.openejb.ApplicationException;
+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.SystemException;
 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.asynch.AsynchMethodRunnable;
 import org.apache.openejb.core.interceptor.InterceptorData;
 import org.apache.openejb.core.interceptor.InterceptorStack;
 import org.apache.openejb.core.timer.EjbTimerService;
 import org.apache.openejb.core.transaction.TransactionPolicy;
 import org.apache.openejb.core.webservices.AddressingSupport;
 import org.apache.openejb.core.webservices.NoAddressingSupport;
-
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleApplicationException;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.afterInvoke;
-import static 
org.apache.openejb.core.transaction.EjbTransactionUtil.createTransactionPolicy;
 import org.apache.openejb.spi.SecurityService;
 import org.apache.openejb.util.Duration;
 import org.apache.openejb.util.Pool;
@@ -61,6 +76,9 @@ public class StatelessContainer implemen
 
     private Object containerID = null;
     private SecurityService securityService;
+    private BlockingQueue<Runnable> asynchQueue = new 
LinkedBlockingQueue<Runnable>();
+    private ThreadPoolExecutor asynchPool = new ThreadPoolExecutor(1, 20, 60, 
TimeUnit.SECONDS, asynchQueue);
+    private CompletionService<Object> asynchService = new 
ExecutorCompletionService<Object>(asynchPool);
 
     public StatelessContainer(Object id, SecurityService securityService, 
Duration accessTimeout, Duration closeTimeout, Pool.Builder poolBuilder, int 
callbackThreads) {
         this.containerID = id;
@@ -143,6 +161,14 @@ public class StatelessContainer implemen
 
         // Use the backup way to determine call type if null was supplied.
         if (type == null) type = deployInfo.getInterfaceType(callInterface);
+        
+        Method runMethod = deployInfo.getMatchingBeanMethod(callMethod);
+        if(runMethod.getAnnotation(Asynchronous.class) != null){
+               // Need to invoke this bean asynchronously
+               AsynchMethodRunnable asynch = new 
StatelessMethodRunnable(callMethod, runMethod, args, type, deployInfo, primKey);
+               Future<Object> future = this.asynchService.submit(asynch);
+               return future;
+        }
 
         ThreadContext callContext = new ThreadContext(deployInfo, primKey);
         ThreadContext oldCallContext = ThreadContext.enter(callContext);
@@ -166,9 +192,6 @@ public class StatelessContainer implemen
 
             callContext.setCurrentOperation(Operation.BUSINESS);
             callContext.setCurrentAllowedStates(StatelessContext.getStates());
-
-            Method runMethod = deployInfo.getMatchingBeanMethod(callMethod);
-
             callContext.set(Method.class, runMethod);
             callContext.setInvokedInterface(callInterface);
             Object retValue = _invoke(callMethod, runMethod, args, (Instance) 
bean, callContext, type);
@@ -303,6 +326,35 @@ public class StatelessContainer implemen
         }
         return returnValue;
     }
+    
+    public class StatelessMethodRunnable extends AsynchMethodRunnable{
+       
+       public StatelessMethodRunnable(
+                               Method callMethod,
+                               Method runMethod, Object[] args, InterfaceType 
type,
+                               CoreDeploymentInfo deployInfo, Object primKey) {
+                       super(callMethod, runMethod, args, type, deployInfo, 
primKey);
+               }
+
+               protected Object performInvoke(Object bean, ThreadContext 
callContext) throws OpenEJBException{
+               return _invoke(this.callMethod, this.runMethod, this.args, 
(Instance)bean, callContext, this.type);
+       }
+
+               @Override
+               protected Object createBean(ThreadContext callContext) throws 
OpenEJBException{
+                       return instanceManager.getInstance(callContext);
+               }
+
+               @Override
+               protected void releaseBean(Object bean, ThreadContext 
callContext) throws OpenEJBException{
+                       if(callContext.isDiscardInstance()){
+                instanceManager.discardInstance(callContext, bean);
+            } else {
+                instanceManager.poolInstance(callContext, bean);
+            }
+               }
+       
+    }
 
     protected ProxyInfo 
createEJBObject(org.apache.openejb.core.CoreDeploymentInfo deploymentInfo, 
Method callMethod) {
         return new ProxyInfo(deploymentInfo, null);


Reply via email to