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);