<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">&lt;<a
                moz-do-not-send="true" href="mailto:jharting@redhat.com"
                target="_blank">jharting@redhat.com</a>&gt;</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(
                          ()-&gt; { return ctx.proceed(); } ));<br>
                              }<br>
                          <br>
                          }<br>
                          <br>
                        </div>
                        <div>With FutureDelegator as follows:<br>
                          <br>
                          public class FutureDelegator implements
                          Future&lt;Object&gt; {<br>
                              <br>
                              private Future&lt;?&gt; future;<br>
                              <br>
                              public FutureDelegator(Future&lt;?&gt;
                          future) {<br>
                                  this.future = future;<br>
                              }<br>
                          <br>
                              @Override<br>
                              public Object get() throws
                          InterruptedException, ExecutionException {<br>
                                  AsyncResult&lt;?&gt; asyncResult =
                          (AsyncResult&lt;?&gt;) 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&lt;?&gt; asyncResult =
                          (AsyncResult&lt;?&gt;) 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&lt;Boolean&gt; asyncInvocation =
                          new ThreadLocal&lt;Boolean&gt;();<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(
                          ()-&gt; { <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>