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:
- 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.
- 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());
}
}
- Note that the executor returns Future<User>:
Future<User> result = executor.submit(asyncTask);
This means this task is executed asynchronously.
- 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());
}
}
- Once the task is done, we write it to the asynchronous response with the following code:
response.resume(Response.ok(result.get()).build());