Observer Pattern - An Enterprise JavaBean Implementation
Download: EJBObserverPattern.zip
Motivation
I recently needed an infrastructure that would allow an arbitrary number of Enterprise JavaBeans to observe changes to a collection of central business entities. The application environment in which I am developing consists of a number of EJB applications running on more than one host. All of the applications are designed to work together as a single, integrated suite. The database environment is distributed. A central store of data is shared by the entire suite while each application maintains a separate store of data that is specific to that application.
One part of the suite is responsible for accepting transactions from the outside world. Each transaction arrives in the form of an XML document. A typical transaction might require changes to the central data store as well as one or more application data stores. All changes must be done within the scope of a single transaction, i.e. if one application aborts the transaction then all participants must abort the transaction.
Also, there are some data constraints that cross application boundaries. It is possible for one application to abort a transaction because a change made to the central repository is unacceptable within the context of some application specific data. e.g. Application X may require that a customer has a fax number. If a transaction attempts to grant Customer A permission to use Application X and Customer A does not have a fax number then Application X must abort the transaction.
It was the enforcement of these distributed data constraints that motivated my use of the observer pattern. Each application needs to observe changes in the shared repository as they occur -- and within the transaction in which they occur. If a proposed change to the shared data is unacceptable to any given application then the transaction must be aborted before the change is made permanent.
Implementation
What follows is essentially the process that I went through to implement this pattern. I have omitted some of the more glaring mistakes to protect the
stupid
guilty.
Note: All of the source files are available for download. The java classes are contained within a package called EJBObserverPattern.
The java.util.Observable class and the java.util.Observer interface work great within the scope of a single Java VM. But I discovered that they aren't much use in implementing the observer pattern across VMs with EJBs as implementations of Observer. The first step in creating an EJB observer might be to extend java.util.Observer to create a remote interface:
public interface RemoteObserver extends javax.ejb.EJBObject, java.util.Observer { }
If you did this you'd quickly find out that java.util.Observer.update(...) does not declare java.rmi.RemoteException, something required of all methods of a remote interface. At this point I found it necessary to create a new observer interface and observable class that would work in the EJB universe. I created my own observer and observable classes which parallel the respective classes in java.util.
The EJBObserver Interface
A new interface is required that I called EJBObserver:
package EJBObserverPattern; public interface EJBObserver { /** * @param observable a reference to the object being observed * @param arg the arguments being passed to the observer */ public void update (EJBObservable observable, Object arg) throws java.rmi.RemoteException, javax.ejb.EJBException; }
Note: A common pattern in EJB implementations is to define a superinterface to be extended by both the remote interface and the bean itself. This is commonly called a business interface. EJBObserver is a business interface.
Yet Another Note: My development environment adheres to the EJB 1.0 specification. Thus, I have to explicitly declare javax.ejb.EJBException. EJB 1.1 and later redefines EJBException as a subclass of RuntimeException making it unnecessary to explicitly declare it in a method signature.
The EJBObservable Class
My new class EJBObservable defines all the same methods as java.util.Observable (why change a paradigm that works.) Thus, my EJBObserver update method takes an EJBObservable object; this mirrors java.util.Observer, which takes a java.util.Observable object. I marked EJBObservable as serializable by implementing java.io.Serializable. This is necessary since instances of this class will be sent to remote EJB observers:
package EJBObserverPattern; import java.rmi.RemoteException; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.ejb.EJBException; /** * A class to be subclassed by any entity which may be observed * by instances of EJBObserver. * * @see java.util.Observable */ public class EJBObservable implements java.io.Serializable { /** * The collection of observers. Using a Set will guarantee * no duplicate observers. */ protected Set mObservers = new HashSet(); protected boolean mChanged = false; /* The methods for adding, deleting, and counting observers are all trivial, as are the methods for checking and setting the 'changed' indicator. Their semantics are identical to the respective methods in java.util.Observable. */ public void addObserver (EJBObserver observer) { mObservers.add (observer); } public void deleteObserver (EJBObserver observer) { mObservers.remove (observer); } public void deleteObservers () { mObservers.clear(); } publ