<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<br>
<div class="moz-cite-prefix">On 01/17/2015 12:32 AM, arjan tijms
wrote:<br>
</div>
<blockquote
cite="mid:CAE=-AhBUu-MAiM1OmH4uVt4c-EU-1P0Sj-xvB8F3a_BvzPGi0A@mail.gmail.com"
type="cite">
<div dir="ltr">Hi,<br>
<div class="gmail_extra"><br>
<div class="gmail_quote">On Fri, Jan 16, 2015 at 10:41 PM,
Jozef Hartinger <span dir="ltr"><<a
moz-do-not-send="true" href="mailto:jharting@redhat.com"
target="_blank">jharting@redhat.com</a>></span>
wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div text="#000000" bgcolor="#FFFFFF"> Hi Arjan,<br>
<br>
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.<br>
</div>
</blockquote>
<div><br>
</div>
<div>That's quite a coincidence, it's indeed rather similar
;)</div>
<div><br>
</div>
<div>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?</div>
</div>
</div>
</div>
</blockquote>
The most straightforward implementations use a mutable integer index
to keep track of which interceptor of the chain is the one to be
invoked next. This index is incremented after each interceptor
invocation and once it reaches the size of the interceptor chain,
the interceptor method is called. In addition, there is a spec
requirement that says that calls to InvocationContext.proceed()
should be repeatable i.e. you should be able implement retry such
as:<br>
<br>
try {<br>
return invocationContext.proceed();<br>
} catch (Exception ignored) {<br>
return invocationContext.proceed(); // retry once again<br>
}<br>
<br>
In order to implement this requirement, InvocationContext's internal
mutable index needs to be reset to the initial position for retry to
work as expected. This clashes with the AsyncInterceptor as it
returns from the interceptor method before the chain is finished.
This causes the index to be reset prematurely and things get stuck
in an infinite loop.<br>
<br>
In order to support AsyncInterceptor we switched to an
implementation where we use multiple InvocationContext
implementations with immutable indexes. That way we do not need to
reset the index and AsyncInterceptor works.<br>
Note that we do not guard access to the state of parameters and
context data and these are therefore expected to be published safely
between threads (as your implementation does).<br>
<br>
<br>
<blockquote
cite="mid:CAE=-AhBUu-MAiM1OmH4uVt4c-EU-1P0Sj-xvB8F3a_BvzPGi0A@mail.gmail.com"
type="cite">
<div dir="ltr">
<div class="gmail_extra">
<div class="gmail_quote">
<div><br>
</div>
<div>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?</div>
</div>
</div>
</div>
</blockquote>
It's something that is currently not required by the spec but
doable. Therefore, it is a good idea to implement it this way.<br>
<blockquote
cite="mid:CAE=-AhBUu-MAiM1OmH4uVt4c-EU-1P0Sj-xvB8F3a_BvzPGi0A@mail.gmail.com"
type="cite">
<div dir="ltr">
<div class="gmail_extra">
<div class="gmail_quote">
<div><br>
</div>
<div>Kind regards,</div>
<div>Arjan</div>
<div><br>
</div>
<div><br>
</div>
<div> </div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div text="#000000" bgcolor="#FFFFFF"> <br>
<a moz-do-not-send="true"
href="https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/interceptors/thread/async/AsyncInterceptor.java"
target="_blank">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
<div>
<div class="h5"><br>
<br>
<div>On 01/16/2015 06:17 PM, arjan tijms wrote:<br>
</div>
</div>
</div>
<blockquote type="cite">
<div>
<div class="h5">
<div dir="ltr">
<div>
<div>Hi,<br>
<br>
</div>
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(
()-> { return ctx.proceed(); } ));<br>
}<br>
<br>
}<br>
<br>
</div>
<div>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 InterruptedException,
ExecutionException, TimeoutException {<br>
AsyncResult<?> asyncResult =
(AsyncResult<?>) future.get(timeout,
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>
</div>
<div>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).<br>
<br>
I got it to work though on Weld by using a
thread local check to break 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 ThreadLocal<Boolean>();<br>
<br>
@AroundInvoke<br>
public synchronized Object
submitAsync(InvocationContext ctx) throws
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>
</div>
<div>But I've got a feeling this works just by
chance and not because the workaround is so
clever.<br>
<br>
</div>
<div>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?<br>
<br>
</div>
<div>Kind regards,<br>
Arjan Tijms<br>
</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
<br>
</div>
</div>
<br>
<fieldset></fieldset>
<br>
</div>
</div>
<pre>_______________________________________________
cdi-dev mailing list
<a moz-do-not-send="true" href="mailto:cdi-dev@lists.jboss.org" target="_blank">cdi-dev@lists.jboss.org</a>
<a moz-do-not-send="true" href="https://lists.jboss.org/mailman/listinfo/cdi-dev" target="_blank">https://lists.jboss.org/mailman/listinfo/cdi-dev</a>
Note that for all code provided on this list, the provider licenses the code under the Apache License, Version 2 (<a moz-do-not-send="true" href="http://www.apache.org/licenses/LICENSE-2.0.html" target="_blank">http://www.apache.org/licenses/LICENSE-2.0.html</a>). For all other ideas provided on this list, the provider waives all patent and other intellectual property rights inherent in such information.</pre>
</blockquote>
<br>
</div>
</blockquote>
</div>
<br>
</div>
</div>
</blockquote>
<br>
</body>
</html>