Friday, March 15, 2013

Java EE 6 - Part 7 - Writing Asynchronous Session Beans

This is a very useful enhancement in EJB 3.1 that lets the client make a server method call asynchronously.

In the past we needed to write a lot of code to achieve the same result. The client used to create a temporary JMS queue destination and pass it to the server in the remote method call and the server did its task asynchronously and used the temporary queue to send its response back to client. This has now been taken care of by Java EE 6 framework with the introduction of the @Asynchronous annotations for session beans.

Project: EJB31-Common


package helloworld.beans;

import java.util.concurrent.Future;
import javax.ejb.Remote;

/**
 * Interface for the asynch session bean.
 *
 * @author rwatsh
 */
@Remote
public interface HelloEjbAsynchronousRemote {

    Future ejbAsynchronousSayHello(String name);
   
}

Project: EJB31-ejb

package helloworld.beans;

import java.util.Date;
import java.util.concurrent.Future;
import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.Stateless;

/**
 * Stateless session bean with a long running task executed asynchronously.
 *
 * @author rwatsh
 */
@Stateless
public class HelloEjbAsynchronous implements HelloEjbAsynchronousRemote {

    @Asynchronous
    @Override
    public Future ejbAsynchronousSayHello(String name) {
        System.out.println(new Date().toString() + " - Begin - HelloEjbAsynchronous.ejbAsynchronousSayHello: " + name);

        // simulate some delay
        try {
            Thread.sleep(50000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(new Date().toString() + " - End - HelloEjbAsynchronous.ejbAsynchronousSayHello: " + name);

        return new AsyncResult("Hello " + name);
    }
 }


Project: StandAloneApp

package standaloneapp;

import helloworld.beans.HelloEjbAsynchronousRemote;
import java.util.concurrent.Future;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
 * This client can be a SwingWorker waiting for server task to complete and
 * respond asynchronously while the client carries on with other UI tasks.
 *
 * @author rwatsh
 */
public class AsyncClient {

    private static HelloEjbAsynchronousRemote helloWorldBean;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        System.err.println("standaloneapp.Main.main: Stand-alone App started");
        String jndiPath = "java:global/EJB31/EJB31-ejb/HelloEjbAsynchronous";
        try {
            Context ctx = new InitialContext();
            System.out.println("standaloneapp.Main.main: looking up bean at: "
                    + jndiPath);
            helloWorldBean = (HelloEjbAsynchronousRemote) ctx.lookup(jndiPath);
            System.out.println("standaloneapp.Main.main: found HelloWorldBean: "
                    + helloWorldBean);
            System.out.println("standaloneapp.Main.main: calling sayHello");

            Future future = helloWorldBean.ejbAsynchronousSayHello("Watsh");

            while (!future.isDone()) {
                Thread.sleep(10000);
                System.out.println("Doing some other client tasks and waiting for server to respond");
            }

            String greeting = (String) future.get();

            System.out.println("standaloneapp.Main.main: HelloWorldBean said: "
                    + greeting);
        } catch (NamingException ex) {
            System.err.println(
                    "standaloneapp.Main.main: Could not find HelloWorldBeanRemote");
            System.err.println("standaloneapp.Main.main: JNDI path used for lookup: " + jndiPath);
            ex.printStackTrace();
        }
    }
}



No comments: