The Coefficient event system

Intended audience

This document is intended to people who want to understand how the Coefficient Event System works.

It will be of particular interest for writers of modules, where those modules need to be aware of activity in other parts of the system. Examples include:

  • A mailing list module needs to be aware of changes to project membership, so as to update it's recipients lists.
  • A CVS module needs to be aware of changes to project membership, so as to update CVS access controls.
  • An RSS module needs to be informed whenever documents are uploaded, to provide a "recent documents" feed

Introduction

The Coefficient Event System (new to version 0.9.5-2), is a mechanism that allows system components to be notified of changes in other parts of the system. It does so without the two parts needing to know about each other, thus helping to maintain a clean design. The event system forms the "glue" between the components. Events, when they occur, are published to the event system. From there, interested components are notified that the event has occurred. They then handle the event and perform whatever processing is required.

The event model

The Coefficient event system employs a fairly standard and widely used model for event publishing and handling. The main concepts involved are:

  • Event: an occurrence of some system activity, which other system components need to be notified about.
  • Event publishing: informing the event system that a particular event has occurred.
  • Event Publisher: a class or system component that publishes events when they occur.
  • Event Handler: a class or system component that wishes to be informed when certain events occur, and presumably performs some operation to handle the event. Event handlers must be registered with the event system, and must indicate which types of events they're interested in. Currently, event type matching is done by class. i.e. the instanceof operator is used to test whether a published event is of the appropriate type for a particular handler. This matching scheme allows for the matching of event subclasses, and is thus quite flexible.
  • Event dispatching: the process of notifying an event handler that an event has occurred. In other words, event dispatching refers to the invocation of the handleEvent method on the handler.
  • Event Queue: an internal system structure that temporarily stores published events, ensuring that events are dispatched to handlers in the correct order.

Implementation

The core class hierarchy for the event system is show below. These classes are all in the za.org.coefficient.events package.

These classes are explained briefly below:

CoefficientEvent: this is the base class for all Coefficient event objects. This class implements the Serializable interface, so that is can be sent to a JMS queue (see below). When an event is published in Coefficient, an instance of CoefficientEvent (or a subclass) is created and sent to the event system. RoleChangedEvent is an example of a CoefficientEvent subclass.

CoefficientEventPublisher: this is the interface to be implemented by all Coefficient classes that publish events. Currently, the system isn't really concerned with where events come from, so this interface is not really needed. However, it does make explicit that a class can publish events, which helps to keep the design clear. In future, this interface could be used more extensively. In the diagram above, it is evident that BaseModule implements CoefficientEventPublisher. This make it trivial for any module, including (for instance) MailForum above, to publish events.

CoefficientEventHandler: this is the interface to be implemented by all Coefficient classes that are interested in receiving event notifications (i.e. that handle events). When an event is dispatched to the handler, the handleEvent method is invoked, with the CoefficientEvent instance as parameter.

EventHandlerRegistry: this class implements a singleton registry of event handlers, and is used to determine which handlers are interested in a particular event (i.e. to which handlers an event should be dispatched). Event handlers need to register with the registry to receive events.

EventDispatcher: this class implements the dispatching of events to appopriate handlers, using the registry to decide which handlers should receive the event.

CoefficientEvents: this is a utility class that simplifies the registering of handlers and the publishing of events. It implements two strategies for accessing the relevant event system functions. For managed EJB environments, it uses a JMS message to invoke the methods on a MessageBean. In this scenario, both handler registration and event processing is done asynchronously. For unmanaged environments without JMS, it invokes the appropriate methods directly. In this environment, handler registration is done synchronously, but event processing is done asynchronously by spawing a new Thread to do the work.

CoefficientEventMessageBean: this is the MessageBean mentioned above.

Known issues and future enhancements

Future enhancements could include:

  • Callbacks (to the event publisher)
  • Transactional event processing: event processing happens within transactional boundaries, and can cause the rollback of the entire transaction.

Currently, there is one major known issue:

  • The singleton pattern (used for implementing the EventHandlerRegistry) doesn't transfer very well into distributed EJB environments (where EJB containers can be clustered and distributed, and can even have multiple simultaneous JVM instances and memory spaces. The current EventHandlerRegistry implementation assumes that the entire Coefficient system is running in a single process on a single machine with a single memory space. If this is not the case, unexpected behaviour can result (i.e. events will only be dispatched to handlers that were registered in the local registry, and not to those registered in other processes or on other machines). A safer implementation is needed, probably using some naming and directory service (jndi). If you know of a nice, portable "singleton EJB" implementation, please contribute!