Help

The Web Beans event bus provides a very nice way for stateful components to synchronize their state with changes that take place in the application.

Suppose we have a Web Bean that updates the Product catalog. The following method is responsible for creating new Products.

public class ProductManager {

   @PersistenceContext EntityManager entityManager;
   @Fires @Created Event<Product> productCreated;

   public void create(Product prod) {
      entityManager.persist(prod);
      productCreated.fire(prod);
   }

   ...

}

When a Product is created, the Web Bean fires an event of type Product, with binding type @Created.

Suppose a second Web Bean caches the Product catalog in memory, to minimize database access:

@ApplicationScoped
public class Catalog {
   List<Product> products;
   
   ...
   
   @Produces List<Product> getProducts() {
      if (products==null) {
         products = getProductsFromDatabase();
      }
      return products;
   }
   
   void productCreated(@Observes @AfterTransactionCompletion @Created Product prod) {
      products.add(prod);
   }
   
}

When a new Product is successfully created in the database, the Catalog receives an event notification and adds the new Product to its cache.

Event processing is much more important in an environment with stateful objects like Catalog than it is in an environment with only stateless objects like stateful session beans. Therefore, I believe that event processing is a truly essential feature of Web Beans.

However, the eventing functionality defined by the Web Beans Public Draft is a purely local construct and does not help when the application is distributed across multiple cluster nodes or multiple physical tiers. We've identified this problem as one that must be solved for the revised Public Draft.

Designing a distributed event bus would potentially be a very difficult undertaking, with so many issues to think about: QoS, asynchronicity, transactionality, routing, etc. Fortunately, JMS already has the features we need, and is what is sometimes used today to solve the problems we're talking about. JMS features:

  • asynchronous, distributed semantics
  • a notion of both 1-of-N and N-of-N receivers (queues and topics)
  • a notion of logical channels (to support routing between tiers and applications)
  • support for a range of QoS semantics, including
  • transactionality

Furthermore, JMS is well-understood and well-supported in the EE environment.

So I've proposed that the specification simply define that events may be distributed via JMS.

The application developer would not be exposed to the JMS APIs. The actual interaction with JMS would be handled by the container. All the developer would need to do is specify that events with a specific type and binding types would be distributed by a certain queue or topic.

Of course, absolutely nothing would stop a vendor from also supporting an alternative distribution mechanism as a proprietary extensions (for example, in JBoss we could provide support for JGroups).

What I'm thinking is the following:

Asynchronous event observers

Event observers may specify that they receive events asynchronously:

void productCreated(@Observes @Asynchronously @Created Product product) { ... }

By default, an asynchronous observer is a purely local construct. However, unlike synchronous observers, an asynchronous observer is called in a different set of web beans contexts to the contexts in which the event was fired.

Mapping an event type to a JMS channel

A JMS topic or queue declaration may specify a set of events which are distributed via that queue/topic:

<Topic>
   <destination>java:comp/env/jms/CacheInvalidationEvents</destination>
   <connectionFactory>java:comp/env/jms/TopicConnectionFactory</connectionFactory>
   <events>
      <myapp:Product>
         <myapp:Created/>
      </myapp:Product>
   </events>
</Topic>

This declaration means that any event that is assignable to the specified type and binding types is a distributed event, distributed by the named JMS topic.

Since JMS is a transactional medium, we could support a further setting which writes the event transactionally to the queue/topic. However, this setting needs to be a global setting for the event type. Perhaps a @Transactional annotation for the event type?

Observers of distributed events

The container would validate that all observers for any event distributed via JMS are declared to be asynchronous observers, and throw an exception if there are any synchronous observers for the event.

We need to think carefully about the concept of an asynchronous transaction completion event observer. The following combinations are semantically correct, and need to be supported, even for the distributed case:

@Observes @Asynchronously @AfterTransactionCompletion
@Observes @Asynchronously @AfterTransactionSuccess
@Observes @Asynchronously @AfterTransactionFailue

However, this combination is not meaningful:

@Observes @Asynchronously @BeforeTransactionCompletion

Of course, this is all a work in progress, and I'm interested in hearing feedback on this proposal :-)

6 comments:
 
22. Dec 2008, 18:00 CET | Link
DissapointedBySeamEventModel

Please do not make the same design mistake as in current event model in Seam. In Seam events can be fired only from within (simplifying here) the active FacesContext/ServletRequest (you get the nasty exception). But what about real-world application, when some processing is done by batch processes and asynchronous processing? Image an asynchronous job which processes entities and from within some of these entities e.g. something like email to or invalidate cache event is produced. Then we would have application-scoped event observer which observes these events and react to them.

Currently, Seam events model is so bound to FacesContext/ServletRequest presence that it disqualificates it from being used as a unified, general event model for deployed web application. Now one just need to use Spring events model to have a unified way of issuing application-wide events.

 
22. Dec 2008, 18:25 CET | Link

None of the functionality in Web Beans is dependent on the web tier, since Web Beans is defined to work in things like RMI or WS requests, or with embeddable EJB Lite.

 
26. Dec 2008, 22:10 CET | Link

Hi Gavin,

This would be nice to have. I've had to roll my own using JMS a few times in the past and it would be nice to have a solution out of the box.

Ismael

 
27. Dec 2008, 01:37 CET | Link

Great! I think this would open the specification to the EIP and SOA world.
A webbean produce an event fired to a jms topic --> a bpel process is initiated --> the process finish --> an observer webbean is notified
From what I've read think a schema like this is possible? Could you confirm?

 
27. Dec 2008, 14:41 CET | Link

Yes, it would certainly be possible for ESB solutions / whatever to integrate with the web beans event bus.

 
05. Jan 2009, 04:04 CET | Link

I'm pretty sure that Seam events should work outside the servlet lifecycle. Can you provide details in Seam JIRA please?