The Publish/Subscribe pattern structure is similar to the Observer pattern structure, but it has several important differences. Recall that the Observable portion of the observer structure is actually a part of a service that contains some state about which the Observer wants to receive notifications. This is not the case with the Publish/Subscribe pattern. With publish/subscribe, subscribers register with an intermediate service responsible for delivering events. Publishers also use the service to deliver events. There are many implications of this structure, including the following:
Subscribers can subscribe a single time, yet they can receive events from many publishers. This technique, called anonymous publishing , is useful for systems that do not have a static set of objects responsible for events in the system.
Publishers do not have to re-create event publishing and subscriber tracking mechanisms for each class that delivers events.
The application and system can change around an event service without a change to the event service itself.
The pattern structure, shown in Figure 12-3, illustrates the constituent parts of a publish/subscribe implementation. As before, the interfaces indicate an interface available as a Web Services Description Language (WSDL) file and through a Universal Description, Data, and Discovery (UDDI) directory. The PublisherImpl does not have an associated interface simply because the publisher is not required to be available to others. Implementations often allow subscribers to contact a publisher directly to request additional information, in which case an interface representing the publisher makes more sense.
Because EventService does not have any interesting state and is not observable itself, a publisher, PublisherImpl , is likely the originator of an event. The publisher could also be a proxy to an object that has an interesting state. The Publish/Subscribe pattern allows a wide variation of implementation techniques.
The components in the Publish/Subscribe pattern are similar to those in the Observer pattern, with the responsibility of publishing an event split out from the EventService class to an external publisher. In addition, EventService contains an additional operation that allows external publishers to publish an event through the event service. These are the components in the Publish/Subscribe pattern:
Subscriber: The Subscriber component is the definition of the interface that an event service implementation calls to notify a client when a publisher delivers a message to the event service. There is only one important operation on this interface: the update operation. The update operation usually receives an event identifier to ensure that the subscriber is aware of the event that prompted the event service to call the subscriber. A single subscriber may service multiple event registrations. The operation also receives data that fits an informal contract between the subscriber and the publisher.
SubscriberImpl: The concrete subscriber is a Web Service that adheres to the Subscriber interface, or it is a Java component that can send and receive SOAP messages and has a distinct address that the EventService can use to communicate with the subscriber. Upon receiving a message, the event service locates the subscribers registered for the message, and then the event service delivers the message to each concrete subscriber registered in its list of interested parties. The event service requires the address of a subscriber, typically a Uniform Resource Locator (URL) for binding to the subscriber's port. The subscriber then acts on the update message from the event service.
EventService: The EventService interface contains similar operations as the previous chapter's Observable interface, with the addition of an operation used to publish messages. The additional operation, publish , is necessary because of the separation of responsibility for recognizing and publishing events to an external component ”in your case, the PublisherImpl . The publish operation receives an event identifier and data that is forwarded to any subscribers. The other operations, addSubscriber and removeSubscriber , receive an event identifier that the subscriber wants to receive notifications for, as well as a reference for use by the event service to call back to the subscriber.
EventServiceImpl: The implementation of the event service maintains subscriber lists and the event types for which a subscriber registers via the addSubscriber and removeSubscriber operations. Publishers publish an event to the event service with an associated event type via the publish operation. The event service determines what subscribers registered for the event and delivers the event to them. Event services existing outside of the processes that use the event service should use a persistence mechanism to preserve the subscriber list when the event service shuts down.
PublisherImpl (not pictured): A publisher does not have a specific contract to fulfill unless the publisher expects callbacks from subscribers for more information. A publisher assembles the information that a subscriber expects to see, which is an implicit contract between the subscribers and the publishers, and delivers the event data along with a planned event identifier to the event service. Publishers could simply reflect events from business entities, collections, and processes. On the other hand, publishers may surface events that are more complex than a single object instance or that are not associated with a concrete service. For example, a publisher may surface events when parts of a system crash or go down for maintenance. In this sense, there is no business representation of a service that is lost to the user and therefore no concrete service to which users can attach themselves . Instead, if the user just registers with the event service for event types that relate to system events, they do not have to care what form the publisher takes to deliver those events.
Like the Observer pattern, the potential deployment scenarios are interesting. Figure 12-4 illustrates a likely scenario. Consider that for an application like the P.T. Monday Coffee Company application, a single Web server and the Apache Axis environment houses the event service and any publishers within the same physical deployment node.
The collaborations between the components in the Publish/Subscribe pattern are similar to the collaborations in the Observer pattern. A client registers a subscriber with an event service. As part of the registration through the addSubscriber operation on the event service, the client identifies the events that they want to receive through a string-based identifier as well as the port information for the subscriber Web Service. Once registered, the subscriber receives events with a topic that matches the identifier.
Publishers create the data surrounding an event and publish the event through the publish operation on the event service. The publisher itself uses an architecture adapter to connect to the Web Service and deliver the message. Once delivered, the event service searches through the subscribers to locate all of those interested in the event and delivers the event to the subscribers. Figure 12-5 illustrates the entire sequence.
The operations identified as 2 and 3.1 in Figure 12-5 occur across architecture adapters for a Web Service implementation. In the first case, the addSubscriber method registers the client-side subscriber with the EventService Web Service. Apache Axis forwards this registration request to the EventSerice Java implementation. In the latter case, the Java-based EventService calls the update method on client-based Subscriber Web Services through an architecture adapter. The Apache Axis environment on the client receives the update operation and forwards it to the appropriate Java Subscriber service implementation.