<div dir="ltr">Hi<br><br>On Sat, Jan 17, 2015 at 11:05 AM, Arne Limburg <<a href="mailto:arne.limburg@openknowledge.de">arne.limburg@openknowledge.de</a>> wrote:<br>> Since we almost don’t use ThreadLocals in OWB, I guess, this should work out<br>> of the box.<br>> Did a quick check of the interceptor code and see no issues with handling<br>> over the InvocationContext to another thread. However, the InvocationContext<br>> has some internal state that could get confused, if proceed() is called in<br>> parallel from two different threads, but that’s another thing. Just give it<br>> a try and tell us about the result :-)<div><br></div><div>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.<br></div><div><br></div><div>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?</div><div><br></div><div>Kind regards,</div><div>Arjan</div><div><br></div><div><br></div><div><br></div><div><br>><br>> Cheers,<br>> Arne<br>><br>> Von: arjan tijms <<a href="mailto:arjan.tijms@gmail.com">arjan.tijms@gmail.com</a>><br>> Datum: Samstag, 17. Januar 2015 00:32<br>> An: Jozef Hartinger <<a href="mailto:jharting@redhat.com">jharting@redhat.com</a>><br>> Cc: "<a href="mailto:cdi-dev@lists.jboss.org">cdi-dev@lists.jboss.org</a>" <<a href="mailto:cdi-dev@lists.jboss.org">cdi-dev@lists.jboss.org</a>><br>> Betreff: Re: [cdi-dev] Building EJB-like @Asynchronous via interceptor in<br>> CDI<br>><br>> Hi,<br>><br>> On Fri, Jan 16, 2015 at 10:41 PM, Jozef Hartinger <<a href="mailto:jharting@redhat.com">jharting@redhat.com</a>><br>> wrote:<br>>><br>>> Hi Arjan,<br>>><br>>> I did some changes recently in Weld interceptors and this usecase now<br>>> works smoothly. The code is not part of a release yet. See this test for a<br>>> simple implementation of an @Async interceptor (basically the same as your<br>>> initial attempt). Note that the chain is repeatable but at the same time it<br>>> is not reset after dispatch to a different thread so you no longer need the<br>>> ThreadLocal nor any other workaround.<br>><br>><br>> That's quite a coincidence, it's indeed rather similar ;)<br>><br>> I wonder how it now works though, as the InvocationContext "ctx" does not<br>> seem to be made aware that it's been dispatched to a different thread from<br>> within the code. Does it use an internal thread local to keep state or so?<br>><br>> I'll also try to see what this does on OWB. Do you think this is something<br>> that should work, or just something that Weld happens to support regardless<br>> of the spec?<br>><br>> Kind regards,<br>> Arjan<br>><br>><br>> <br>>><br>>><br>>><br>>> <a href="https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/thread/async/AsyncInterceptor.java">https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/thread/async/AsyncInterceptor.java</a><br>>><br>>> Jozef<br>>><br>>><br>>> On 01/16/2015 06:17 PM, arjan tijms wrote:<br>>><br>>> Hi,<br>>><br>>> I'm attempting to emulate EJB's @Asynchronous in CDI using interceptors.<br>>><br>>> Originally I had defined my interceptor as follows;<br>>><br>>> @Interceptor<br>>> @Asynchronous<br>>> @Priority(APPLICATION)<br>>> public class AsynchronousInterceptor implements Serializable {<br>>><br>>> private static final long serialVersionUID = 1L;<br>>> <br>>> @Resource<br>>> private ManagedExecutorService managedExecutorService;<br>>><br>>> @AroundInvoke<br>>> public Object submitAsync(InvocationContext ctx) throws Exception {<br>>> return new FutureDelegator(managedExecutorService.submit( ()-> {<br>>> return ctx.proceed(); } ));<br>>> }<br>>><br>>> }<br>>><br>>> With FutureDelegator as follows:<br>>><br>>> public class FutureDelegator implements Future<Object> {<br>>> <br>>> private Future<?> future;<br>>> <br>>> public FutureDelegator(Future<?> future) {<br>>> this.future = future;<br>>> }<br>>><br>>> @Override<br>>> public Object get() throws InterruptedException, ExecutionException {<br>>> AsyncResult<?> asyncResult = (AsyncResult<?>) future.get();<br>>> if (asyncResult == null) {<br>>> return null;<br>>> }<br>>> <br>>> return asyncResult.get();<br>>> }<br>>> <br>>> @Override<br>>> public Object get(long timeout, TimeUnit unit) throws<br>>> InterruptedException, ExecutionException, TimeoutException {<br>>> AsyncResult<?> asyncResult = (AsyncResult<?>) future.get(timeout,<br>>> unit);<br>>> if (asyncResult == null) {<br>>> return null;<br>>> }<br>>> <br>>> return asyncResult.get();<br>>> }<br>>> <br>>> @Override<br>>> public boolean cancel(boolean mayInterruptIfRunning) {<br>>> return future.cancel(mayInterruptIfRunning);<br>>> }<br>>> <br>>> @Override<br>>> public boolean isCancelled() {<br>>> return future.isCancelled();<br>>> }<br>>> @Override<br>>> public boolean isDone() {<br>>> return future.isDone();<br>>> }<br>>> <br>>> }<br>>><br>>> This of course didn't quite work, as the InvocationContext will be reset<br>>> after the @AroundInvoke method returns, and an infinite intercept loop<br>>> results (on Weld).<br>>><br>>> I got it to work though on Weld by using a thread local check to break<br>>> that loop:<br>>><br>>> @Interceptor<br>>> @Asynchronous<br>>> @Priority(PLATFORM_BEFORE)<br>>> public class AsynchronousInterceptor implements Serializable {<br>>><br>>> private static final long serialVersionUID = 1L;<br>>> <br>>> @Resource<br>>> private ManagedExecutorService managedExecutorService;<br>>> <br>>> private static final ThreadLocal<Boolean> asyncInvocation = new<br>>> ThreadLocal<Boolean>();<br>>><br>>> @AroundInvoke<br>>> public synchronized Object submitAsync(InvocationContext ctx) throws<br>>> Exception {<br>>> <br>>> if (TRUE.equals(asyncInvocation.get())) {<br>>> return ctx.proceed();<br>>> }<br>>> <br>>> return new FutureDelegator(managedExecutorService.submit( ()-> {<br>>> try {<br>>> asyncInvocation.set(TRUE);<br>>> return ctx.proceed();<br>>> } finally {<br>>> asyncInvocation.remove();<br>>> }<br>>> }));<br>>> }<br>>><br>>> }<br>>><br>>> But I've got a feeling this works just by chance and not because the<br>>> workaround is so clever.<br>>><br>>> What do you guys think, what would be the best way to support this with<br>>> the current CDI version? Or would CDI/Interceptors need something like<br>>> Servlet's async support, where the InvocationContext is put into async mode<br>>> whereafter it "simply" allows an other thread to continue processing on it?<br>>><br>>> Kind regards,<br>>> Arjan Tijms<br>>><br>>><br>>><br>>><br>>><br>>><br>>><br>>> _______________________________________________<br>>> cdi-dev mailing list<br>>> cdi-dev@lists.jboss.orghttps://<a href="http://lists.jboss.org/mailman/listinfo/cdi-dev">lists.jboss.org/mailman/listinfo/cdi-dev</a><br>>><br>>> Note that for all code provided on this list, the provider licenses the<br>>> code under the Apache License, Version 2<br>>> (<a href="http://www.apache.org/licenses/LICENSE-2.0.html">http://www.apache.org/licenses/LICENSE-2.0.html</a>). For all other ideas<br>>> provided on this list, the provider waives all patent and other intellectual<br>>> property rights inherent in such information.<br>>><br>>><br>><br><br></div></div>