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

arjan tijms arjan.tijms at gmail.com
Sun Jan 18 12:38:15 EST 2015


Hi

On Sat, Jan 17, 2015 at 11:05 AM, Arne Limburg <
arne.limburg at openknowledge.de> wrote:
> Since we almost don’t use ThreadLocals in OWB, I guess, this should work
out
> of the box.
> Did a quick check of the interceptor code and see no issues with handling
> over the InvocationContext to another thread. However, the
InvocationContext
> has some internal state that could get confused, if proceed() is called in
> parallel from two different threads, but that’s another thing. Just give
it
> a try and tell us about the result :-)

I tested it on a OWB 1.5.0-SNAPSHOT from a few weeks back as part of
TomEE-2.0-SNAPSHOT and using a simple example with a request scoped bean
and no other interceptors it indeed worked out of the box :) Still have to
test with some more complicated setups, but things look promising.

I wonder, should anything still be spec'ed for this? Perhaps just a mention
somewhere that this is indeed allowed, along with a TCK test?

Kind regards,
Arjan




>
> Cheers,
> Arne
>
> Von: arjan tijms <arjan.tijms at gmail.com>
> Datum: Samstag, 17. Januar 2015 00:32
> An: Jozef Hartinger <jharting at redhat.com>
> Cc: "cdi-dev at lists.jboss.org" <cdi-dev at lists.jboss.org>
> Betreff: Re: [cdi-dev] Building EJB-like @Asynchronous via interceptor in
> CDI
>
> Hi,
>
> On Fri, Jan 16, 2015 at 10:41 PM, Jozef Hartinger <jharting at redhat.com>
> wrote:
>>
>> 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.
>
>
> That's quite a coincidence, it's indeed rather similar ;)
>
> I wonder how it now works though, as the InvocationContext "ctx" does not
> seem to be made aware that it's been dispatched to a different thread from
> within the code. Does it use an internal thread local to keep state or so?
>
> I'll also try to see what this does on OWB. Do you think this is something
> that should work, or just something that Weld happens to support
regardless
> of the spec?
>
> Kind regards,
> Arjan
>
>
>
>>
>>
>>
>>
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.orghttps://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/20150118/9610c3b6/attachment.html 


More information about the cdi-dev mailing list