How it works...

The magic happens in the AsyncTask class, where we will first take a look at the performLookups method: 

    private void performLookups() throws NamingException{
Context ctx = new InitialContext();
userTransaction = (UserTransaction)
ctx.lookup("java:comp/UserTransaction");
userBean = (UserBean) ctx.lookup("java:global/
ch09-async-transaction/UserBean");
}

This gives you the instances of both UserTransaction and UserBean from the application server. Then, you can relax and rely on what has already been instantiated.

As our task implements a Callable<V> object, it needs to implement the call() method, as follows:

    @Override
public User call() throws Exception {
performLookups();
try {
userTransaction.begin();
User user = userBean.getUser();
userTransaction.commit();
return user;
} catch (IllegalStateException | SecurityException |
HeuristicMixedException | HeuristicRollbackException
| NotSupportedException | RollbackException |
SystemException e) {
userTransaction.rollback();
return null;
}
}

You can see Callable as a Runnable interface that returns a result. 

Our transaction code resides here:

userTransaction.begin();
User user = userBean.getUser();
userTransaction.commit();

If anything goes wrong, we have the following code:

} catch (IllegalStateException | SecurityException | 
HeuristicMixedException | HeuristicRollbackException
| NotSupportedException | RollbackException |
SystemException e) {
userTransaction.rollback();
return null;
}

Now, we will look at AsyncService:

  1. First, we have some declarations, as in the following code snippet:
    private AsyncTask asyncTask;

@Resource(name = "LocalManagedExecutorService")
private ManagedExecutorService executor;

@PostConstruct
public void init(){
asyncTask = new AsyncTask();
}
We ask the container to give us an instance from ManagedExecutorService, which is responsible for executing the task in the enterprise context.
  1. Then, we call an init() method and the bean is constructed (@PostConstruct). This instantiates the task.

Now, we have our task execution:

    @GET
public void asyncService(@Suspended AsyncResponse response){

Future<User> result = executor.submit(asyncTask);

while(!result.isDone()){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ex) {
System.err.println(ex.getMessage());
}
}

try {
response.resume(Response.ok(result.get()).build());
} catch (InterruptedException | ExecutionException ex) {
System.err.println(ex.getMessage());
response.resume(Response.status(Response.
Status.INTERNAL_SERVER_ERROR)
.entity(ex.getMessage()).build());
}

}
  1. Note that the executor returns Future<User>:
Future<User> result = executor.submit(asyncTask);

This means this task is executed asynchronously.

  1. Then, we can check its execution status until it's done, as follows:
while(!result.isDone()){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ex) {
System.err.println(ex.getMessage());
}
}
  1. Once the task is done, we write it to the asynchronous response with the following code:
response.resume(Response.ok(result.get()).build());