The Observer Pattern in Mixed Dependency Injection Contexts (Spring, JSF)


One of the most well-known patterns is the Observer pattern, well described in the Gang of Four (GoF) book. It allows to separate the application logic from the view(s) (if you have the focus on MVC implementations) or simply implements a notification mechanism that allows to update objects if others change their state (publisher – subscriber implementations).

Basically, the Observer pattern describes object dependencies. So, it’s a good idea to use an environment that allows to implement it with Dependency Injection (DI), like Spring or JSF. JSF is not primarily a DI container, you have to trick with its Expression Language (EL) a bit. But it delivers the basics to do so.

There already exist an example how to implement an Observer pattern with Spring. So, this article additionally shows how to do it with JSF. We’ll also have a look at using bean references in mixed DI environments. I use this in a JSF project that uses Spring/Acegi for security. Spring allows to access Spring beans by JSF backing beans. Although, if you need it vice versa you need the JSF-Spring framework.

The most important thing with an Observer implementation in such a mixed environment is the configuration of the beans. But, to get the complete picture I present the bean definitions, first.

The example shows two Observer beans and one Observable bean, that sends a notification if its state changes. To simplify the example, the getter of a simple String property, set per Dependency Injection, initiates the notification of the Observers.

Normally, you can implement classes and the pattern will work with DI. But, the “limitations” of JSF need a type definition to get it work. So, we also have interfaces for the Observer and Observable implementations. Following the GoF guys this is best practice anyway.

The example code is based on JDK 1.5, Spring Framework 2.0 and JSF 1.1.

The Observable interface:

package com.test;
import java.util.ArrayList;
public interface Observable {
    public void setObservers(ArrayList<Observer> observers);
    public ArrayList<Observer> getObservers();
    // We notify all observers after our state changed.
    public void notifyObservers();
}

The Observer interface:

package com.test;
public interface Observer {
    // Observable has changed its state.
    public void update();
}

Here’s the corresponding implementation for the Observable:

package com.test;
public class TestObservable implements Observable {
    String simpleProperty = "";
    ArrayList<Observer> observers = new ArrayList<Observer>();
    public String getSimpleProperty() {
        return simpleProperty;
    }
    public void setSimpleProperty(String simpleProperty) {
        this.simpleProperty = simpleProperty;
        this.notifyObservers();
    }
    // Observable interface.
    public void setObservers(ArrayList<Observer> observers) {
        this.observers = observers;
    }
    // Observable interface.
    public ArrayList<Observer> getObservers() {
        return observers;
    }
    // Observable interface.
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

The implementation for the first Observer:

package com.test;
public class TestObserver1 implements Observer {
    public void update() {
        // update my presentation, etc.
    }
}

The implementation for the second Observer:

package com.test;
public class TestObserver2 implements Observer {
    public void update() {
        // update my presentation, etc.
    }
}

What we have to do next is to declare the relations between our three beans. The Observable has a list property for the references of the two Observers. This is very flexible if you have to extend the number of Observers. You declare additional implementations and add the references to the list property. Very convenient. As we use Interfaces we can move and exchange references without extra work. Although, this is not as important to Spring as to JSF ;-) .

Additionally, we have used the scoping that comes with Spring Framework 2.0. It allows to manage Spring beans like JSF managed beans. We use “session” context here. The “aop:scoped-proxy” manages relations to unscoped Spring beans that may lose references, because of session contexts that get “lost” during runtime.

We first have a look at the declarations for a single environment. Here’s the important part of the Spring application context:

<bean id="testObservable"
    class="com.test.TestObservable" scope="session">
    <aop:scoped-proxy/>
    <property name="simpleProperty">
        <value>Hello World</value>
    </property>
    <property name="observers">
        <list>
            <ref bean="testObserver1" />
            <ref bean="testObserver2" />
        </list>
    </property>
</bean>

<bean id="testObserver1"
    class="com.test.TestObserver1" scope="session">
    <aop:scoped-proxy/>
</bean>

<bean id="testObserver2"
    class="com.test.TestObserver2" scope="session">
    <aop:scoped-proxy/>
</bean>

And here’s the important section of the JSF managed bean configuration:

<managed-bean>
    <managed-bean-name>testObservable</managed-bean-name>
    <managed-bean-class>com.test.TestObservable</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
        <property-name>simpleProperty</property-name>
        <value>Hello World</value>
    </managed-property>
    <managed-property>
        <property-name>observers</property-name>
        <list-entries>
            <value-class>com.test.Observer</value-class>
            <value>#{testObserver1}</value>
            <value>#{testObserver2}</value>
        </list-entries>
    </managed-property>
</managed-bean>

<managed-bean>
    <managed-bean-name>testObserver1</managed-bean-name>
    <managed-bean-class>com.test.TestObserver1</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

<managed-bean>
    <managed-bean-name>testObserver2</managed-bean-name>
    <managed-bean-class>com.test.TestObserver2</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

What can we do with all this in a mixed environment? Well, first of all you can move JSF managed beans to the Spring context following a simple conversion schema for the declarations. With the new Spring scoping you can add more comfort to your existing JSF managed beans. Second, you can have beans in both context and can choose the environment your bean needs most. Although, this is more a theoretical consideration. If your project manager doesn’t know much about Spring you may try to keep as many beans as possible in the JSF context. If Spring is in the center of your architecture you’ll move all beans to the Spring context to get the most out of both environments ;-) .

To complete all this, here’s an example for a “distributed” Observer. We have to keep in mind that without using JSF-Spring we can only reference Spring beans from a JSF managed bean. So, we have to declare the Observers as Spring beans and the Observable as JSF managed bean. Else, we can’t resolve the references from Observable to the Observers. Don’t ask if this is really useful for an Observer pattern. But, it indicates what could be done in other contexts.

For our example the adaptation is quite simple. As the beans use the same names in Spring and JSF context we only delete something in both declaration. Spring looses the Observable and JSF the Observers. This is possible because the Spring resolver does the dirty work to find Spring beans by name, via the JSF expression language.

Spring first (what else :-) ):

<bean id="testObserver1"
    class="com.test.TestObserver1" scope="session">
    <aop:scoped-proxy/>
</bean>

<bean id="testObserver2"
    class="com.test.TestObserver2" scope="session">
    <aop:scoped-proxy/>
</bean>

And the JSF context:

<managed-bean>
    <managed-bean-name>testObservable</managed-bean-name>
    <managed-bean-class>com.test.TestObservable</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
        <property-name>simpleProperty</property-name>
        <value>Hello World</value>
    </managed-property>
    <managed-property>
        <property-name>observers</property-name>
        <list-entries>
            <value-class>com.test.Observer</value-class>
            <value>#{testObserver1}</value>
            <value>#{testObserver2}</value>
        </list-entries>
    </managed-property>
</managed-bean>


blog comments powered by Disqus