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

arjan tijms arjan.tijms at gmail.com
Sat Jan 17 07:11:11 EST 2015


Hi,

On Sat, Jan 17, 2015 at 11:05 AM, Antonio Goncalves <
antonio.goncalves at gmail.com> wrote:

> @arjan Your example is base on  ManagedExecutorService from the Java EE
> Concurrency spec. That's one topic we've been wondering about : should the
> @Asynchronous interceptor go to the Java EE Concurrency spec or not ? But
> it looks like the spec might not be updated.
>

The example I showed here would IMHO best be placed in the Java EE
Concurrency spec. That would in my opinion be a perfect analogy to
@Transactional and JTA. As given, the interceptor uses CDI/Interceptors and
Concurrency, so theoretically it could also be put into a third spec.

Personally I would find it strange to put something in spec A, when it may
better belong in spec B, just because spec B is not updated. What's holding
the update of Java EE Concurrency back? If most of the EG members would be
of the opinion that an @Asynchronous interceptor belongs best in Java EE
Concurrency, then we can just update that spec, right?

I know that MR releases can be quite fast and agile process wise, while
still packing some punch. JTA 1.2 itself was just such an MR, and JASPIC
1.1 was too. I was somewhat involved with JASPIC 1.1 (as community member)
and I think the setup time was pretty fast. Mid feb 2013 we created the
JIRA issues, the MR draft was published early march 2013 and the release
was with EE 7 end may 2013.

If it would just be about putting a few interceptors formally in Java EE
Concurrency, then why not do such small update for it?

Kind regards,
Arjan


>
> Antonio
>
> On Sat, Jan 17, 2015 at 12:32 AM, arjan tijms <arjan.tijms at gmail.com>
> wrote:
>
>> 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 listcdi-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.
>>>
>>>
>>>
>>
>> _______________________________________________
>> 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.
>>
>
>
>
> --
> Antonio Goncalves
> Software architect, Java Champion and Pluralsight author
>
> Web site <http://www.antoniogoncalves.org> | Twitter
> <http://twitter.com/agoncal> | LinkedIn
> <http://www.linkedin.com/in/agoncal> | Pluralsight
> <http://pluralsight.com/training/Authors/Details/antonio-goncalves> | Paris
> JUG <http://www.parisjug.org> | Devoxx France <http://www.devoxx.fr>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/cdi-dev/attachments/20150117/0b8212d3/attachment.html 


More information about the cdi-dev mailing list