SeamFramework.orgCommunity Documentation
The Web Beans event notification facility allows Web Beans to interact in a totally decoupled manner. Event producers raise events that are then delivered to event observers by the Web Bean manager. This basic schema might sound like the familiar observer/observable pattern, but there are a couple of twists:
não só os produtores são desacoplados dos observadores; os observadores são totalmente desacoplados dos produtores,
observadores podem especificar uma combinação de "seletores" para reduzir o conjunto de eventos que irão receber notificações, e
observadores podem ser notificados imediatamente ou podem especificar que a notificação do evento deveria esperar até o têrmino da transação corrente
Um método observador (observer method) é um método de um Web Bean com um parâmetro anotado@Observes.
public void onAnyDocumentEvent(@Observes Document document) { ... }
The annotated parameter is called the event parameter. The type of the event parameter is the observed event type. Observer methods may also specify "selectors", which are just instances of Web Beans binding types. When a binding type is used as an event selector, it is called an event binding type.
@BindingType
@Target({PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface Updated { ... }
Especificamos os bindings de eventos do observador anotando o parâmetro do evento:
public void afterDocumentUpdate(@Observes @Updated Document document) { ... }
Um método observador não necessita especificar qualquer bindings de evento neste caso, ele está interessado em todos os eventos de um determinado tipo. Se ele especificar o bindings de evento, ele estará apenas interessado em eventos que também têm esses bindings de evento.
O método observador pode ter parâmetros adicionais que são injetados de acordo com a semântica usual de injeção de parâmetros em métodos de Web Beans
public void afterDocumentUpdate(@Observes @Updated Document document, User user) { ... }
O evento produtor pode obter um objeto notificador de evento (event notifier) por injeção:
@Observable Event<Document
> documentEvent
The @Observable annotation implicitly defines a Web Bean with scope @Dependent and deployment type @Standard, with an implementation provided by the Web Bean manager.
Um produtor lança eventos chamando o método fire() da interface Event, passando um objeto event object:
documentEvent.fire(document);
Um objeto de evento pode ser uma instância de qualquer classe Java que não tem qualquer tipo de variáveis ou parâmetros tipo curinga. O evento será entregue a cada método observador que:
tenha um parâmetro evento em que objeto evento objeto é atribuído, e
especifica nenhum evento bindings.
The Web Bean manager simply calls all the observer methods, passing the event object as the value of the event parameter. If any observer method throws an exception, the Web Bean manager stops calling observer methods, and the exception is rethrown by the fire() method.
Para especificar um "seletor", o produtor do evento pode passar uma instância do tipo de binding do evento para o método fire():
documentEvent.fire( document, new AnnotationLiteral<Updated
>(){} );
O classe auxiliar AnnotationLiteral permite instanciar tipo de binding inline, uma vez que, esta é de outra maneira, difícil de fazer em Java.
O evento será entregue a todo método observador (observer method) que:
tenha um parâmetro evento em que objeto evento objeto é atribuído, e
não especifica qualquer binding de evento exceto para o binding de evento passado para o fire().
Alternativamente, bindings de eventos podem ser especificados anotando o ponto de injeção do notificador do evento:
@Observable @Updated Event<Document
> documentUpdatedEvent
Em seguida, todos os eventos disparados por essa instância de Event tem o binding de evento anotada. O evento será entregue a cada método observador que:
tenha um parâmetro evento em que objeto evento objeto é atribuído, e
não especifica qualquer binding de evento exceto para os bindings de evento passados para o fire() ou os bindings de evento anotados do ponto de injeção do notificador de evento.
It's often useful to register an event observer dynamically. The application may implement the Observer interface and register an instance with an event notifier by calling the observe() method.
documentEvent.observe( new Observer<Document
>() { public void notify(Document doc) { ... } } );
Tipo de binding de eventos podem ser especificados pelo notificador do evento no ponto de injeção ou passando instâncias do tipo de binding de evento para o método observador observe() method:
documentEvent.observe( new Observer<Document
>() { public void notify(Document doc) { ... } },
new AnnotationLiteral<Updated
>(){} );
Um tipo de binding de evento pode ter anotações membro:
@BindingType
@Target({PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface Role {
RoleType value();
}
O valor do membro é utilizado para reduzir as mensagens entregues ao observador:
public void adminLoggedIn(@Observes @Role(ADMIN) LoggedIn event) { ... }
Membros de tipo de binding de evento podem ser especificados estaticamente pelo produtor do evento, através de anotações no ponto de notificação do evento:
@Observable @Role(ADMIN) Event<LoggedIn
> LoggedInEvent;}}
Alternativamente, o valor do membro do tipo de binding de evento pode ser determinado dinamicamente pelo produtor do evento. Vamos começar escrevendo uma sub classe abstrata de AnnotationLiteral:
abstract class RoleBinding
extends AnnotationLiteral<Role
>
implements Role {}
O produtor do evento (event producer) passa uma instância dessa classe para fire():
documentEvent.fire( document, new RoleBinding() { public void value() { return user.getRole(); } } );
Tipos de event binding podem ser combinados, por exemplo:
@Observable @Blog Event<Document
> blogEvent;
...
if (document.isBlog()) blogEvent.fire(document, new AnnotationLiteral<Updated
>(){});
Quando esse evento ocorre, todos os métodos observadores que seguem esse evento serão notificados:
public void afterBlogUpdate(@Observes @Updated @Blog Document document) { ... }
public void afterDocumentUpdate(@Observes @Updated Document document) { ... }
public void onAnyBlogEvent(@Observes @Blog Document document) { ... }
public void onAnyDocumentEvent(@Observes Document document) { ... }}}
Transactional observers receive their event notifications during the before or after completion phase of the transaction in which the event was raised. For example, the following observer method needs to refresh a query result set that is cached in the application context, but only when transactions that update the Category tree succeed:
public void refreshCategoryTree(@AfterTransactionSuccess @Observes CategoryUpdateEvent event) { ... }
Existem três tipos de observadores transacionais:
@AfterTransactionSuccess observadores são chamados durante a fase após a conclusão da transação, mas somente se a transação concluída com sucesso
@AfterTransactionFailure observadores são chamados durante a fase após a conclusão da transação, mas somente se a transação não seja concluída com êxito
@AfterTransactionCompletion observadores são chamados durante a fase, após a conclusão da transacção
@BeforeTransactionCompletion observadores são chamados durante a fase antes da conclusão da transacção
Observadores transacionais são muito importantes para um modelo de objetos stateful como o Web Beans, porque o estado é muitas vezes mantido por mais de uma única transação atômica.
Imagine que fizemos cache do conjunto de resultados da consulta JPA no escopo de aplicação (application scope):
@ApplicationScoped @Singleton
public class Catalog {
@PersistenceContext EntityManager em;
List<Product
> products;
@Produces @Catalog
List<Product
> getCatalog() {
if (products==null) {
products = em.createQuery("select p from Product p where p.deleted = false")
.getResultList();
}
return products;
}
}
From time to time, a Product is created or deleted. When this occurs, we need to refresh the Product catalog. But we should wait until after the transaction completes successfully before performing this refresh!
O Web Bean que cria e remove Products pode lançar eventos, por exemplo:
@Stateless
public class ProductManager {
@PersistenceContext EntityManager em;
@Observable Event<Product
> productEvent;
public void delete(Product product) {
em.delete(product);
productEvent.fire(product, new AnnotationLiteral<Deleted
>(){});
}
public void persist(Product product) {
em.persist(product);
productEvent.fire(product, new AnnotationLiteral<Created
>(){});
}
...
}
E agora Catalog pode observar os eventos após o término da transação com sucesso:
@ApplicationScoped @Singleton
public class Catalog {
...
void addProduct(@AfterTransactionSuccess @Observes @Created Product product) {
products.add(product);
}
void addProduct(@AfterTransactionSuccess @Observes @Deleted Product product) {
products.remove(product);
}
}