Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Check out EJB 3.1 <code>@Asynchronous methods</code>. This is exactly what they are for.</p> <p>Small example that uses OpenEJB 4.0.0-SNAPSHOTs. Here we have a <code>@Singleton</code> bean with one method marked <code>@Asynchronous</code>. Every time that method is invoked by anyone, in this case your JSF managed bean, it will immediately return regardless of how long the method actually takes.</p> <pre><code>@Singleton public class JobProcessor { @Asynchronous @Lock(READ) @AccessTimeout(-1) public Future&lt;String&gt; addJob(String jobName) { // Pretend this job takes a while doSomeHeavyLifting(); // Return our result return new AsyncResult&lt;String&gt;(jobName); } private void doSomeHeavyLifting() { try { Thread.sleep(SECONDS.toMillis(10)); } catch (InterruptedException e) { Thread.interrupted(); throw new IllegalStateException(e); } } } </code></pre> <p>Here's a little testcase that invokes that <code>@Asynchronous</code> method several times in a row. </p> <p>Each invocation returns a <a href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html">Future</a> object that essentially starts out <em>empty</em> and will later have its value filled in by the container when the related method call actually completes.</p> <pre><code>import javax.ejb.embeddable.EJBContainer; import javax.naming.Context; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class JobProcessorTest extends TestCase { public void test() throws Exception { final Context context = EJBContainer.createEJBContainer().getContext(); final JobProcessor processor = (JobProcessor) context.lookup("java:global/async-methods/JobProcessor"); final long start = System.nanoTime(); // Queue up a bunch of work final Future&lt;String&gt; red = processor.addJob("red"); final Future&lt;String&gt; orange = processor.addJob("orange"); final Future&lt;String&gt; yellow = processor.addJob("yellow"); final Future&lt;String&gt; green = processor.addJob("green"); final Future&lt;String&gt; blue = processor.addJob("blue"); final Future&lt;String&gt; violet = processor.addJob("violet"); // Wait for the result -- 1 minute worth of work assertEquals("blue", blue.get()); assertEquals("orange", orange.get()); assertEquals("green", green.get()); assertEquals("red", red.get()); assertEquals("yellow", yellow.get()); assertEquals("violet", violet.get()); // How long did it take? final long total = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start); // Execution should be around 9 - 21 seconds assertTrue("" + total, total &gt; 9); assertTrue("" + total, total &lt; 21); } } </code></pre> <p><a href="https://github.com/apache/openejb/tree/trunk/openejb3/examples/async-methods">Example source code</a></p> <p>Under the covers what makes this work is:</p> <ul> <li>The <code>JobProcessor</code> the caller sees is not actually an instance of <code>JobProcessor</code>. Rather it's a subclass or proxy that has all the methods overridden. Methods that are supposed to be asynchronous are handled differently.</li> <li>Calls to an asynchronous method simply result in a <code>Runnable</code> being created that wraps the method and parameters you gave. This runnable is given to an <a href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executor.html">Executor</a> which is simply a work queue attached to a thread pool.</li> <li>After adding the work to the queue, the proxied version of the method returns an implementation of <code>Future</code> that is linked to the <code>Runnable</code> which is now waiting on the queue.</li> <li>When the <code>Runnable</code> finally executes the method on the <em>real</em> <code>JobProcessor</code> instance, it will take the return value and set it into the <code>Future</code> making it available to the caller.</li> </ul> <p>Important to note that the <code>AsyncResult</code> object the <code>JobProcessor</code> returns is not the same <code>Future</code> object the caller is holding. It would have been neat if the real <code>JobProcessor</code> could just return <code>String</code> and the caller's version of <code>JobProcessor</code> could return <code>Future&lt;String&gt;</code>, but we didn't see any way to do that without adding more complexity. So the <code>AsyncResult</code> is a simple wrapper object. The container will pull the <code>String</code> out, throw the <code>AsyncResult</code> away, then put the <code>String</code> in the <em>real</em> <code>Future</code> that the caller is holding.</p> <p>To get progress along the way, simply pass a thread-safe object like <a href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html">AtomicInteger</a> to the <code>@Asynchronous</code> method and have the bean code periodically update it with the percent complete.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload