11
Observer Pattern

WHAT’S IN THIS CHAPTER?            

  • How to implement the observer pattern in plain code
  • How the observer pattern works in the real world
  • How to implement the observer pattern using @Observes and Event firing
  • How to use qualifiers to gain fine-grain control over observers
  • How to implement transaction-sensitive observers and rollbacks

WROX.COM CODE DOWNLOAD FOR THIS CHAPTER

The wrox.com code download for this chapter is found at www.wrox.com/go/projavaeedesignpatterns on the Download Code tab. The code is in the Chapter 11 download and individually named according to the names throughout the chapter.

The observer pattern is one of the most widely used and accepted design patterns in modern programming languages, software, and user interface (UI) frameworks. Most programming languages use observers within their internal application programming interfaces (APIs), and Java is no exception. But Java EE goes further than most and provides a default implementation of the observer pattern, so developers can use this pattern without implementing it from scratch. This chapter focuses on Java’s default implementation of the observer pattern: where it is used, how observers are implemented via annotations in Java EE, and how observers can be made transaction sensitive.

WHAT IS AN OBSERVER?

The idea behind the observer pattern is that an object that changes its state can inform other objects that a change has occurred. In the language of the design pattern, the object that changes its state is called the subject, whereas those objects that receive notification of the change are called the observers. The relationship is one to many, with the subject having many observers.

Imagine a chat application that automatically refreshes every second so it can check for new messages. Also imagine that it has a chat room feature allowing many people to chat together. Each of these chat clients regularly checks with the server to see if there has been a new message posted by one of the other clients. As you can imagine, this is not very performance friendly. Would it not make much more sense if the newly sent message was “pushed” to all subscribed clients? It would certainly be more efficient. The observer pattern can solve this problem. Here, the observer would be the chat server, and each client would be a subject. The server would be registered with each client, and when the client posts a new message (a change in state of the subject), the subject would call a method on the server to notify it of the new message. Then the server would call a method on all its registered clients and send the message to each one.

Description

The GoF1 book states that the observer pattern “defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.” The Head First Design Patterns2 book gives the example of a weather monitoring application that sends a notice when temperatures change. The observer pattern is based on the principle of inheritance and is one of the behavioral design patterns.

To be an observer, each concrete observer implementation needs to share a similar interface. The subject lets each observer add itself to a registry. When the subject changes, the observer calls each subject’s registered implementation to notify the observer about the changes.

This is an efficient implementation because only one call happens for each observer at the time of the change. A naive solution such as regularly checking the subject may produce an unlimited number of calls from different observers even though there had been no change to the object observed.

The observer pattern is not that different from a news subscription. Objects that want to subscribe to changes on another object register themselves to receive news of those changes. Rather than checking the target object, these objects are called when there is a change.

UI Frameworks are another place where observers are heavily used, although this is more related to desktop applications, not enterprise applications. In the context of UI frameworks, the observer pattern is often referred to as the listener pattern. Essentially, these patterns are the same. Button click listeners, drag drop handlers, and value change listeners all rely on an implementation of the observer pattern.

Almost all web frameworks are built on the model-view-controller pattern, which also uses the observer pattern internally. See Chapter 15, “Model View Controller Pattern,” for more details.

Observer Class Diagram

As can be seen from Figure 11.1, the observer pattern introduces an Observer interface that all concrete observers must implement. This interface has just one method that is called by the subject to notify the observers that there has been a change in state. Each subject holds a list of registered observers and calls the notifyObservers method to inform the registered observers about any updates or changes in the subject. It has methods for registering and unregistering observers.

images

Figure 11.1 Class diagram of the observer pattern

IMPLEMENTING THE OBSERVER PATTERN IN PLAIN CODE

Java provides an out-of-the-box implementation of the observer pattern. By implementing the Observer interface and extending the Observable class, developers can easily implement the observer pattern.

The first thing you need to do is create a class that extends the Observable class. In Listing 11-1, a news agency informs several types of subscribers when a new story is published. The subscriber may introduce its own behavior after receiving an update. Listing 11-2 provides an interface for publishing the observable class.

Next, you need to create the class that observes the NewsAgency for changes. This observer must implement the Observer interface as in Listing 11-3.

Finally, you must register the RadioChannel observer with the NewsAgency observable and create some news.

// Create the observer and subject
NewsAgency newsAgency = new NewsAgency();
RadioChannel radioChannel = new RadioChannel();

// Register the observer with the subject
newsAgency.register(radioChannel);

// Now add some news headlines
newsAgency.addNews("Breaking news: Life found on Mars");
newsAgency.addNews("Update: Earth invasion imminent");
newsAgency.addNews("Just in: Hail to our new Martian overlords");

The output in the console should be as follows:

Breaking news: Life found on Mars
Update: Earth invasion imminent
Just in: Hail to our new Martian overlords

Notice that you can register many observers with the NewsAgency and receive updates. Perhaps a TVChannel observer or an InternetNewsChannel observer can register to receive updates from the NewsAgency. In addition, you can have other Publishers (or any other type of object that implements Observable) issue updates to any observer that wants to register itself to receive news. These observers can check the type of the Observable and process the update according to its source.

One significant drawback of implementing the observer pattern in this way is that you have to extend the Observable class. This forces the use of a class hierarchy that might not be desirable. Because you cannot extend more than one class in the single-inheritance world of Java, this way of implementing the observer pattern restricts the inheritance design. You can’t add the Observable behavior to an existing class that already extends another superclass, thus restricting its reuse potential.

But don’t despair. You can also implement the observer pattern by “hand,” without using the internal Observer and Observable interfaces, by following the given class diagram. However, because this book is focused on Java EE, this implementation is left for you to play with.

IMPLEMENTING THE OBSERVER PATTERN IN JAVA EE

Although Java had built-in support for the observer pattern from inception, Java EE offers an easier implementation via the @Observes annotation and javax.enterprise.event.Event<T> interface. Any method annotated with @Observes listens for events of a certain type. When it “hears” such an event, the parameter of the observer method receives an instance of the type and then executes the method.

The @Observes annotation lets any method listen for any event to be fired with the marked object type. Listing 11-4 is a simple example of a bean that fires an event of type String and another bean that listens for events of that type from our bean.

The container injects an Event object of type String into the event instance variable of the EventService class. This forms part of the message when the to fire String object is fired. This instance variable Message object is a String which may be produced by a factory. (See Chapter 6, “Factory Pattern,” for more information about the factory design pattern injected to the EventService class.) To make this example work without creating a factory even simpler, you can just define any String constant to the variable called message and remove the @Inject annotation as follows.

private String message = "produced message";

Now the observable part is completed, so it is time to create an observer that listens for your String events. The addition of the @Observes annotation to the method signature marks the method as an observer of events of the type it precedes. In this case, the @Observes annotation precedes the type String and thus listens for events of that type. The @Observes annotation followed by an object type does the magic and lets the annotated method observe the fired event of the given type.

In Listing 11-5, the @Observes annotation has been added to the serviceTrace method signature, which marks the method as an observer for String events. When an event of type String occurs, the serviceTrace method receives the object that the event produced via its parameter. serviceTrace can then manipulate the String object as it wants. In this case, it prints the message to the console.

If you run the server and invoke the start service method, you will realize how magically a string will be injected to the EventService class, and then a String event is fired “where it will be coughed (observed)” by the serviceTrace method of the TraceObserver class, and a message is printed to the console. Surprisingly, this is all that you need to implement the observer pattern in Java EE without further configuration.

Although in real-world scenarios you probably wouldn’t be firing and observing plain strings but rather your own objects that would be observed by their type, it is still quite easy to differentiate between the same object types of objects and set up different observers to listen for them.

You are now going to look at an example in which you use Qualifiers to disambiguate String objects. You have seen how this can be effective when implementing a factory pattern that produces different implementations of the same type of object.

In Listing 11-6, you start with the code that disambiguates your Strings.

The interface preceding class defines a MessageEvent qualifier and two enum types (SERVICE and PARAMETER) that you will use to act as annotation to mark the strings to be fired by the event instances.

import com.devchronicles.observer.MessageEvent.Type;

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class EventService {

    @Inject
    private String message;

    @Inject @MessageEvent(Type.SERVICE)
    Event<String> serviceEvent;

    @Inject @MessageEvent(Type.PARAMETER)
    Event<String> parameterEvent;

    public void startService(){
        serviceEvent.fire("Starting service "+message);
        parameterEvent.fire("-d -p");
    }

To use the Qualifiers, you just add the MyEvent annotation to the relevant injected instance with the desired enum type in parenthesis. Then you later fire the events from within the startService method, just as you did before in the previous example. The bold parts code lines are all you have added to the previous example in the previous listing.

Now you’ll add the annotations to the observer part. As you did before, you just have to add the Qualifiers to the relevant @Observes annotation.

import com.devchronicles.observer.javaee.MessageEvent.Type;

@Stateless
public class TraceObserver {

    public void serviceTrace(
           @Observes @MessageEvent(Type.SERVICE) String message) {
        System.out.println("Service message: " + message);
    }

    public void parameterTrace(

          @Observes @MessageEvent(Type.PARAMETER) String message) {
        System.out.println("with parameters: " + message);
   }

Firing and observing your own object types is even simpler. The object type is unique, and it’s not necessary to create your own annotation qualifiers; you can use the object instead.

Observable events are transactional and are delivered in the transactional phase that you define for that event. That may be before or after the transaction has completed or after a successful or unsuccessful transaction.

Now you’ll see this in action. In Listing 11-7, you define three observer methods that specify a transaction phase during which the observers listen for events of type String.

There are five transitional phases: BEFORE_COMPLETION, AFTER_COMPLETION, AFTER_SUCCESS, AFTER_FAILURE, and the default IN_PROGRESS. In Listing 11-7, we have not implemented BEFORE_COMPLETION. In Listing 11-8 we implement a class that demonstrates event firing in successful and failure scenarios.

The Children class simulates a successful transaction in the getThirdChild method and an unsuccessful transaction in the getSixthChild method by causing an IndexOutOfBoundsException.

You’ll examine each method to see how the events are observed. The getThirdChild method fires a String event, passes it the message Successful event, and then finishes successfully. The output from calling this method follows:

In progress: Successful event
After completion message: Successful event
After success message: Successful event

The onInProgress method is invoked immediately when the event is fired and while the transaction is still in flight. The other two methods—onCompletion and onSuccess—must wait until the transaction reaches the AFTER_COMPLETION and AFTER_SUCCESS phases, respectively, before they can execute.

Next you’ll look at the getSixthChild method, which fails by causing an IndexOutOfBoundsException. The output that results from calling this method follows:

In progress: Rollback event occurred.
Exception caught.
After completion message: Rollback event occurred.
After failure message: Rollback event occurred.

As before, the onInProgress method is invoked immediately, and the onCompletion and onFailure methods must wait until the method completes. Once the onInProgress method outputs the message Exception caught and the transaction is marked for rollback by calling the SessionContext method setRollbackOnly, the onInProgress method completes, and you can execute your observers. The onCompletion method is executed, followed by the OnFailure method.

The setRollbackOnly method marks the current transaction for rollback, so it can never be committed. This action triggers the transaction into the AFTER_FAILURE phase and invokes the onFailure method.

Observers can also be given conditional behavior, although it’s limited to being notified if an instance of the bean that defines the observer method already exists in the current context. The observer method is called only if an instance exists. To define an observer method as conditional, add notifyObserver = Reception.IF_EXISTS as an argument to the @Observes annotation.

import javax.enterprise.event.Reception;

public void addMember (
       @Observes(notifyObserver = Reception.IF_EXISTS) String message){
  // Implementation code.
}

The default behavior is to create an instance if it does not exist.

WHERE AND WHEN TO USE THE OBSERVER PATTERN

The observer pattern, which can unleash huge performance gains, is an effective way to promote loose coupling and change the direction of calling/listening.

When designing your application or refactoring another’s code, watch out for unnecessary and time interval-based method executions, which can be good candidates for implementing the observer pattern.

In the Java EE realm, you can migrate existing code to the observer pattern without too much hassle. Java EE observers are usually accompanied by dependency injection, which uses @inject, and factories, which use @produces.

The observer pattern’s greatest strength, the decoupling of classes, is also its greatest weakness. As control of the observable moves to the observer, you lose track of the application’s workflow. Vision becomes obscured as one event triggers another. A complicated implementation of the observer pattern can be a nightmare to debug, so it is recommended that you keep the implementation simple. Avoid multiple layers of observers; using just one layer (or a few) is ideal.

To help future and present developers determine the purpose of your code, the name of an observer should reflect its purpose. In addition, you should incorporate the reason for the observation into the name of its methods, expressing the purpose of the class.

In the Java EE realm, existing code can be migrated to the observer pattern without much hassle. Java EE observers are usually accompanied by dependency injection (@inject) and factories 
(@produces). The heavy and unnecessary use of observers may introduce hard to follow and debug systems. However, since most developers are used to observers from UI or web frameworks, they usually have an instinct to use in the right context most of the time.

Whenever you see a resource subject to change and callers trying to capture the data from subject, never hesitate to use the observer pattern. Transaction-sensitive observers offer functionality that was not easily available in earlier versions. In the BEFORE_COMPLETION phase, you can cancel the current transaction by invoking the setRollbackOnly method, thus allowing nontransactional operations to be performed within a transactional phase. If an exception is thrown, the entire transaction can be rolled back.

During the IN_PROCESS phase, which spans the entire transaction, observable events can be fired and observed immediately. This can be implemented as a type of progress monitor or logger.

A call to an observer method blocks the event emitter and is synchronous but can be made asynchronous by annotating the observer method @Asynchronous. (See Chapter 9, “Asynchronous,” for more information about how to use this annotation.) You should take care when making observers of the BEFORE_COMPLETION phase asynchronous because the setRollbackOnly method is ineffective, and the transaction will not be rolled back. The asynchronous method occurs in a new transaction.

SUMMARY

You have seen how Java’s core observer pattern’s implementation has advanced in Java EE 7 and how it can be made sensitive to the transactional phase of the events that it observes. Its implementation completely decouples business logic from the observer, leaving only the event type and qualifier to connect them. This has raised the concern that vision over the relationship is lost, although this can be mitigated by appropriately naming the class and methods and illustrating the relationship in the class’s documentation.

The transactional phase sensitivity has added another dimension to the observer pattern. It provides integration between the observer methods and the transaction, allowing rollbacks to be invoked.

  EXERCISES  

  1. List as many implementations of the observer pattern as you can that you would find in the Java language.

  2. Create an example that uses notifyObserver = Reception.IF_EXISTS as an argument to the @Observes annotation.

  3. Use the observers transitional sensitivity to monitor the progress of a transaction and log the result of the transaction (success or failure).

NOTES

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset