Component-based systems heavily use the Publish/Subscribe pattern. Developers use the pattern in single-process applications and applications that are distributed across systems. In many embodiments, the Publish/Subscribe pattern eases application development through centralizing event distribution and allowing a single event mechanism to service all events. Thus, developers write and debug a single event mechanism instead of many. Further, this event mechanism becomes one person's expertise area rather than a requirement on all developers.
Publish/subscribe is also useful in systems built without prior awareness of all instances of objects that can surface a particular event. Systems that show this behavior are becoming more common as applications attempt to federate systems together into a single, logical application. The Seti@Home project is one of the most visible attempts to create ad-hoc federations of computers to extend application resources. This application uses computer screen savers and idle processing time to work on complex equations. There is little chance that the span of the entire application and working processors will ever look the same from moment to moment. In this way, it is difficult to predict and register with each node to receive and send events as the Observer pattern would have you do. Instead, you can centralize the event mechanism in an event service using the Publish/Subscribe pattern, thus easing the burden of event registration and disbursing.
The Jini platform from Sun Microsystems and the Federated Services Project (FSP) from the Jini community service a similar application space. Federations of devices are difficult to predict. Consider an application written for a data center to service all of the disk arrays that have server components on them. Further, consider that the application may have plug-in components and policies that determine how to deal with faults that occur in the arrays. System components are assembled at runtime and throughout the day. (Remember that the system can change even after it is deployed because of the dynamic nature of a set of data center devices.) It is impossible to predict ahead of time what components will have requirements on events from other components. The FSP has a nice solution to this problem built around the Publish/Subscribe pattern.
For more information on the Jini platform, see the Jini.org Web site at http://www.jini.org. For more information on the FSP, see http://fsp.jini.org.
The FSP introduces a centralized event service design based on the Publish/ Subscribe pattern. The centralized design helps address the dynamic nature of the expected domain that FSP services, the hardware management domain. Distributed components register their interest in events by connecting to a centralized event service and registering a proxy to their own class that handles the event when it is received. The event service has no prior knowledge of the events that flow through it and therefore must use a generic interface for all types of events. This technique loses the semantic exactness of the Observer pattern but leverages object-oriented techniques for creating a robust and dynamic service.
Figure 12-1 shows the two major structures that make up FSP's event service. Keep in mind that more classes make up the entire solution structure. The EventService interface and an underlying implementation that uses a variant of Java's Remote Method Invocation (RMI) make up the centralized event service. Clients register a RemoteEventListenerImpl with the event service to receive events. The registration methods themselves take a topic string, discussed in the next section, to identify what events to deliver to the listener.
There are four interesting methods in the event service implementation and one in the event listener:
EventService.post: This method allows clients to publish events to the event service. The event service receives the event and forwards it to subscribers.
EventService.subscribeObserver: This method gives subscribers a mechanism for registering for events they want to observe. Observation in this case implies a listener that will not take action on the event that would affect the event itself or other components in the federated application.
EventService.subscribeResponsibleBefore and EventService.subscribeResponsibleAfter: These methods allow event listeners to subscribe for events they may be able to affect. The result is an event handling chain where each listener has the opportunity to affect the event. For example, if a file system runs out of space on a host, there could be various recourses, such as expanding the file system. Once the event is altered , there may be no reason for the remaining listeners to be concerned with the event.
RemoteEventListenerImpl.notify: This is the event service callback method. All subscribers receive event notification through this method; thus, the data associated with the method is generic in nature.
The responsible listener methods are not a part of the Publish/Subscribe pattern; however, they are useful additions for particular domains. The remaining methods appear similar in nature to the Observer pattern with the addition of the post method. This method allows clients to publish methods and decouples the responsibility of recognizing a useful event from the event service and into external classes.
An interesting part of FSP's implementation of the Publish/Subscribe pattern is its use of topic-based event registration, a technique you will use throughout the rest of the chapter. Topics are character-based mechanisms for identifying an event that does not require adherence to a particular interface or knowledge of the event originator. For example, to identify a problem with a storage network, one could use the topic storage.network.problem . More often, the company, followed by details about the event itself, scopes topics. For example, com.ptmonday. productcatalog.updated identifies a change to your company product catalog. In most cases, the event topics form a hierarchy; Figure 12-2 shows an example event hierarchy.
The embodiment of event topics as a hierarchy is a useful expression as subscribers can often register for whole branches of the hierarchy with wildcards or partial hierarchy specification. Registration for the topic com.servicefoundry in the FSP event service results in subscriber notification for the com.servicefoundry. books, com.servicefoundry.services , and com.servicefoundry.products events, as well as any events that may be branches below the third level of the topic hierarchy. The event hierarchy itself does not have to be static in nature; publishers can originate any topic at any point in the application's lifecycle.
Topic-based mechanisms increase the ability of the event service to ignore the details of the events flowing through it by not forcing the event service to load classes for each event that passes through it; this is a Java Virtual Machine artifact. This technique adapts well to Web Services for several reasons:
Topic hierarchies give an element of object orientation without the complexities of class inheritance: By using dot-delimited topics, you can have an arbitrary level of topic nesting. Traditional object-orientation would use event subclasses to achieve a similar technique, and you are trying to discourage such liberal use of pure inheritance in an environment where the clients are unpredictable as to their architecture.
You can pass arbitrary data types with the event service as long as both the client and the Web Service that originated the event have an informal contract in place: Using this technique, the Web Service can serialize Extensible Markup Language (XML) to the client as a means of creating an architecture-independent data transfer.
The Publish/Subscribe pattern is a good technique for unpredictable networks of objects. It is also a good technique for unpredictable subscriber architectures. Both add up to a good tool for Web Services.