[cdi-dev] Building EJB-like @Asynchronous via interceptor in CDI

Jozef Hartinger jharting at redhat.com
Fri Jan 16 16:41:33 EST 2015


Hi Arjan,

I did some changes recently in Weld interceptors and this usecase now 
works smoothly. The code is not part of a release yet. See this test for 
a simple implementation of an @Async interceptor (basically the same as 
your initial attempt). Note that the chain is repeatable but at the same 
time it is not reset after dispatch to a different thread so you no 
longer need the ThreadLocal nor any other workaround.

https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/thread/async/AsyncInterceptor.java

Jozef

On 01/16/2015 06:17 PM, arjan tijms wrote:
> Hi,
>
> I'm attempting to emulate EJB's @Asynchronous in CDI using interceptors.
>
> Originally I had defined my interceptor as follows;
>
> @Interceptor
> @Asynchronous
> @Priority(APPLICATION)
> public class AsynchronousInterceptor implements Serializable {
>
>     private static final long serialVersionUID = 1L;
>
>     @Resource
>     private ManagedExecutorService managedExecutorService;
>
>     @AroundInvoke
>     public Object submitAsync(InvocationContext ctx) throws Exception {
>         return new FutureDelegator(managedExecutorService.submit( ()-> 
> { return ctx.proceed(); } ));
>     }
>
> }
>
> With FutureDelegator as follows:
>
> public class FutureDelegator implements Future<Object> {
>
>     private Future<?> future;
>
>     public FutureDelegator(Future<?> future) {
>         this.future = future;
>     }
>
>     @Override
>     public Object get() throws InterruptedException, ExecutionException {
>         AsyncResult<?> asyncResult = (AsyncResult<?>) future.get();
>         if (asyncResult == null) {
>             return null;
>         }
>
>         return asyncResult.get();
>     }
>
>     @Override
>     public Object get(long timeout, TimeUnit unit) throws 
> InterruptedException,    ExecutionException, TimeoutException {
>         AsyncResult<?> asyncResult = (AsyncResult<?>) 
> future.get(timeout, unit);
>         if (asyncResult == null) {
>             return null;
>         }
>
>         return asyncResult.get();
>     }
>
>     @Override
>     public boolean cancel(boolean mayInterruptIfRunning) {
>         return future.cancel(mayInterruptIfRunning);
>     }
>
>     @Override
>     public boolean isCancelled() {
>         return future.isCancelled();
>     }
>     @Override
>     public boolean isDone() {
>         return future.isDone();
>     }
>
> }
>
> This of course didn't quite work, as the InvocationContext will be 
> reset after the @AroundInvoke method returns, and an infinite 
> intercept loop results (on Weld).
>
> I got it to work though on Weld by using a thread local check to break 
> that loop:
>
> @Interceptor
> @Asynchronous
> @Priority(PLATFORM_BEFORE)
> public class AsynchronousInterceptor implements Serializable {
>
>     private static final long serialVersionUID = 1L;
>
>     @Resource
>     private ManagedExecutorService managedExecutorService;
>
>     private static final ThreadLocal<Boolean> asyncInvocation = new 
> ThreadLocal<Boolean>();
>
>     @AroundInvoke
>     public synchronized Object submitAsync(InvocationContext ctx) 
> throws Exception {
>
>         if (TRUE.equals(asyncInvocation.get())) {
>             return ctx.proceed();
>         }
>
>         return new FutureDelegator(managedExecutorService.submit( ()-> {
>             try {
>                 asyncInvocation.set(TRUE);
>                 return ctx.proceed();
>             } finally {
>                  asyncInvocation.remove();
>             }
>         }));
>     }
>
> }
>
> But I've got a feeling this works just by chance and not because the 
> workaround is so clever.
>
> What do you guys think, what would be the best way to support this 
> with the current CDI version? Or would CDI/Interceptors need something 
> like Servlet's async support, where the InvocationContext is put into 
> async mode whereafter it "simply" allows an other thread to continue 
> processing on it?
>
> Kind regards,
> Arjan Tijms
>
>
>
>
>
>
>
> _______________________________________________
> cdi-dev mailing list
> cdi-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/cdi-dev
>
> Note that for all code provided on this list, the provider licenses the code under the Apache License, Version 2 (http://www.apache.org/licenses/LICENSE-2.0.html). For all other ideas provided on this list, the provider waives all patent and other intellectual property rights inherent in such information.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/cdi-dev/attachments/20150116/3c3ab5f7/attachment-0001.html 


More information about the cdi-dev mailing list