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

Mark Struberg struberg at yahoo.de
Sat Jan 17 07:53:04 EST 2015


EE concurrency spec needs an update anyway. It currently doesn't explicitly require @RequestScoped beans to be supported on a new Thread. That breaks tons of frameworks and makes it barely usable in EE7.

LieGrue,
strub

On Saturday, 17 January 2015, 13:12, arjan tijms <arjan.tijms at gmail.com> wrote:


>
>
>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 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.
>>>>
>>>
>>>_______________________________________________
>>>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 | Twitter | LinkedIn | Pluralsight | Paris JUG | Devoxx France
>
>
>
>_______________________________________________
>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.
>
>


More information about the cdi-dev mailing list