Service Event Management
One means of interservice communication is by direct peer-to-peer cooperation and collaboration. No special mechanisms are required to support this kind of communication because it is already defined as explicit invocations.
However, with a plug-and-play architecture, services become more independent and unaware of other services. To facilitate interservice communication between these autonomous services, general mechanisms are needed to convey information between these services and to manage unordered synchronous communications.
Each service is responsible for specifying service events that can be emitted when significant events that may be of interest to other services occur within the service. Also, each service must establish listeners to other services’ events in order to be notified of and react to other significant events occurring within the system.
Service Event Registration
Services can register their events with the wt.services.StandardManager when they are started. Registering service events at startup time makes the events known to processes, such as access control. The following example illustrates how events are registered in an overridden wt.services.StandardManager’s registerEvents method for the version control service:
| A more implicit means of registering events is by not doing so in the registerEvents method, but by allowing the event to be registered when it is first emitted. Once this occurs, all listeners subscribing to this event will be notified. |
Service Event Subscription
In order for services to be notified of events occurring within the system, they must subscribe to each particular service event of interest. To do this, you must invoke the wt.services.ManagerService.addEventListener method with a listener and key identifying the event of interest.
The listener specified during subscription must implement the wt.events.KeyedEventListener interface. It defines the notifyEvent and notifyVetoableEvent methods. The wt.services.ServiceEventListenerAdapter class is provided as a utility whereby a listener can extend it and override only the methods that are required for notification. The notifyEvent is a general method that can be used in all subscription cases. The notifyVetoableEvent method is more specialized; its intended use is to provide a means of vetoing an event via an exception.
Typically event listeners are implemented using either anonymous or named instances of inner classes. This allows the outer class to be designed without implementing the wt.events.KeyedEventListener interface. This keeps the outer class pure in that its type directly reflects its purpose without having to implement a listener interface. The following is an example of how to override the performStartupProcess method and define and add a listener for a specific event:
Service Event Notification
A list of all listeners subscribed to a particular event is maintained by the ManagerService. This list is traversed in an unordered fashion and each listener is executed one after the other using synchronous Java method invocations. Listener notification methods execute in the same thread and database transaction as the event emitter. This means that database operations performed by a listener in response to a notification call are included in the transaction of the event emitter. The following is an example that shows the dispatching of an event like PersistenceManagerEvent.PREPARE_FOR_MODIFICATION:
Service Event Exception Handling
When a listener vetoes an event, it does so by throwing an exception. When an exception is thrown, each listener that has already been notified of this event can handle this exception by either passing the exception through, catching and re- throwing it to clean up, or by implementing a "finally" clause to clean up.
As discussed earlier, event notification is dispatched within the same thread and transaction frame as the event emitter. This means that an event emitter must roll back any database updates that it has made if there has been a veto by another listener. The following example illustrates this guideline. If the POST_STORE event is vetoed, control is transferred to the "finally" clause, where the transaction will be rolled back because the line that set the transaction to null was never reached.
Service Event Conventions
The meaning of any particular service event is up to the designer of the event. Events should include all the information required by event listeners for follow-on processing. The wt.events package includes a base event class, wt.events.KeyedEvent, which can be extended to create new event types.
A common event design pattern includes pre- and post-events. Pre-events are used to indicate to listeners that an event is about to begin. They are typically intended to give listeners the opportunity to validate and possibly veto the event. Post-events are used to notify listeners that an event has finished. They are most useful when a service needs to perform some kind of post-processing as a result of the event. Not all events have to be either pre- or post-events. A singular definition of an event can be used to indicate some special occurrence, which may or may not have happened.