Enterprise Integration Zone is brought to you in partnership with:

Mitch Pronschinske is the Lead Research Analyst at DZone. Researching and compiling content for DZone's research guides is his primary job. He likes to make his own ringtones, watches cartoons/anime, enjoys card and board games, and plays the accordion. Mitch is a DZone Zone Leader and has posted 2576 posts at DZone. You can read more from them at their website. View Full User Profile

Elegant Async in Errai

04.26.2010
| 11407 views |
  • submit to reddit
If you haven't heard of the Errai framework, you really need to check out our interview with Mike Brock, the project lead at JBoss.  A brief introduction - Errai is a fusion of Message-Oriented Programming, RPC, and Push Messaging based on GWT.  The framework is built on ErraiBus, which espouses a  programming model that permeates both the client and the server.  This is nothing new; its a central idea behind the SOA design pattern.  The Errai1.0 release was in March and now a recent blog by Brock announced new asynchronous task APIs.

The latest commit to the Errai trunk features a new and simple (yet comprehensive) way to generate asynchronous tasks.  This comes in very handy when streaming live data such as stocks, news, or tweets across the wire.  However, managing threads has been a pain in many Errai demos and it has caused some less-than-elegant code.  This new functionality comes as a part of the standard MessageBuilder API.  

Two new helper classes are the first addition to Errai.  They assist in the generation of managed contexts which enable session storage.  The first is SessionContext, which facilitates the creation of session scoped attributes.  The second is LocalContext, which enables locally-scoped attributes (each tab and window is its own LocalContext).  

The second feature is what Brock calls "provided message parts."  Provided message parts are beneficial because they create message reusability.  They are different from regular message parts because they are resolved by the providers at the time of transmission.  

Delayed and repeating message transmission calls were the final two additions to the messaging API in Errai.

Brock gives an example of these new features in action:
AsyncTask task = MessageBuilder.createConversation(message)
.toSubject("TimeChannel").signalling()
.withProvided(TimeServerParts.TimeString, new <>ResourceProvider() {
public String get() {
return String.valueOf(System.currentTimeMillis());
}
}).noErrorHandling().replyRepeating(TimeUnit.MILLISECONDS, 100);
The code above generates a continuously replying message (once every 100 miliseconds).  AsyncTask is a handle for the current task and it can be used to cancel the task (with task.cancel(true)).  replyRepeating(), replyDelayed(), sendRepeating(), and sendDelayed() methods all return an instance of AsyncTask.

Brock says that's all you need to know to pull this all together:
@Service("TimeServer")
@RequireAuthentication
public class TimeDisplay implements MessageCallback {
private MessageBus bus;

@Inject
public TimeDisplay(MessageBus bus) {
this.bus = bus;
}

public void callback(final Message message) {
if (message.getCommandType() == null) return;

/**
* Create a local context to store state that is unique to this client instance. (not session wide).
*/
final LocalContext context = LocalContext.get(message);

/**
* Switch on the TimeServerCommand type provided
*/
switch (TimeServerCommands.valueOf(message.getCommandType())) {
case Start:
/**
* We want to start streaming.
*/
AsyncTask task = MessageBuilder.createConversation(message)
.toSubject("TimeChannel").signalling()
.withProvided(TimeServerParts.TimeString, new <>ResourceProvider() {
public String get() {
return String.valueOf(System.currentTimeMillis());
}
}).noErrorHandling().replyRepeating(TimeUnit.MILLISECONDS, 100);

/**
* Store the task as an attribute uniquely identified by it's class type.
*/
context.setAttribute(AsyncTask.class, task);

/**
* Create a listener that will kill the task gracefully if the subject is unsubscribed. This
* isn't 100% necessary, as the task will be auto-killed ungracefully. But this provides
* and opportunity to clean up after ourselves.
*/
bus.addUnsubscribeListener(new UnsubscribeListener() {
public void onUnsubscribe(SubscriptionEvent event) {
if ("TimeChannel".equals(event.getSubject())) {
/**
* Delete this listener after this execution.
*/
event.setDisposeListener(true);

/**
* Stop the task from running.
*/
context.getAttribute(AsyncTask.class).cancel(true);

/**
* Destroy the local context. Sort of unnecessary, but helps reduce memory usage.
*/
context.destroy();
}
}
});
break;

case Stop:
/**
* Access our stored AsyncTask from this instance and cancel it.
*/
context.getAttribute(AsyncTask.class).cancel(true);

/**
* Destroy the local context. Sort of unnecessary, but helps reduce memory usage.
*/
context.destroy();
break;
}
}
}

Since you're using Errai's innovative messaging-oriented programming framework, the API works on both the client and server side.  An executor service on the server and a simple timer-based implementation of the client transparently manage all of the thread scheduling.

Brock says there will be more examples like this as he irons out the bugs, but he encourages you, the developer, to check out this "pretty sweet" project.

Here are some of the features that were just released with Errai 1.0:

  • Async IO support in ErraiBus for Apache Tomcat, JBoss AS, and Jetty. As well as standard synchronous IO support for all servlet containers.
  • Easy to use homogeneous programming model that permeates both the server and client.
  • Initial public release of our Workspaces RAD console/app framework.

Version 1.1, which will be released in the coming weeks will add support for Glassfish, WebLogic and WebSphere.

You can download Errai 1.0 here.