Статьи

Элегантный Async в Errai


Если вы еще не слышали об инфраструктуре Errai, вам действительно нужно
проверить наше интервью с Майком Броком , руководителем проекта в JBoss. Краткое введение — Errai представляет собой сочетание программирования на основе сообщений, RPC и Push-сообщений, основанное на GWT. Фреймворк построен на ErraiBus, который поддерживает модель программирования, которая пронизывает как клиента, так и сервера. В этом нет ничего нового; это центральная идея шаблона проектирования SOA. Релиз
Errai1.0 был в марте, и теперь в недавнем
блоге Брока было объявлено о новых API асинхронных задач.

Последний коммит в транк Errai предлагает новый и простой (но всеобъемлющий) способ генерации асинхронных задач. Это очень удобно при потоковой передаче данных, таких как акции, новости или твиты. Однако управление потоками было проблемой во многих демонстрациях Errai, и это вызвало не совсем элегантный код. Эта новая функциональность является частью стандартного API MessageBuilder.  

Два новых вспомогательных класса являются первым дополнением к Errai. Они помогают в создании управляемых контекстов, которые обеспечивают хранение сеансов. Первым является SessionContext, который облегчает создание атрибутов области сеанса. Вторым является LocalContext, который включает атрибуты локальной области (каждая вкладка и окно имеют свой собственный LocalContext).  

Вторая особенность — это то, что Брок называет «предоставленными частями сообщения». Предоставленные части сообщения полезны, потому что они создают возможность повторного использования сообщения. Они отличаются от обычных частей сообщения, потому что они решаются поставщиками во время передачи.  

Задержанные и повторяющиеся вызовы передачи сообщений были последними двумя дополнениями к API обмена сообщениями в Errai.

Брок приводит пример этих новых функций в действии:

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);

Приведенный выше код генерирует непрерывно отвечающее сообщение (один раз каждые 100 миллисекунд). AsyncTask — дескриптор текущей задачи, и его можно использовать для отмены задачи (с помощью task.cancel (true)). Методы replyRepeating (), replyDelayed (), sendRepeating () и sendDelayed () возвращают экземпляр AsyncTask.

Брок говорит, что это все, что вам нужно знать, чтобы собрать все это вместе:

@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;
}
}
}

Поскольку вы используете инновационную среду программирования, ориентированную на обмен сообщениями, Errai работает как на стороне клиента, так и на стороне сервера. Служба исполнителя на сервере и простая реализация клиента на основе таймера прозрачно управляют всем планированием потока.

Брок говорит, что таких примеров будет больше, поскольку он исправляет ошибки, но он призывает вас, разработчика, проверить этот «довольно милый» проект.

Вот некоторые из функций, которые были только что выпущены с Errai 1.0:

  • Поддержка асинхронного ввода-вывода в ErraiBus для Apache Tomcat, JBoss AS и Jetty. А также стандартная поддержка синхронного ввода-вывода для всех контейнеров сервлетов.
  • Простая в использовании однородная модель программирования, которая пронизывает как сервер, так и клиента.
  • Первоначальный публичный релиз нашей среды консоли / приложения Workspaces RAD.

Версия 1.1, которая будет выпущена в ближайшие недели, добавит поддержку Glassfish, WebLogic и WebSphere.

Вы можете скачать Errai 1.0
здесь .