Evaluating Software Design Patterns
— the "Gang of Four" patterns implemented in Java 6

dk.rode.thesis.observer
Class ObserverManager

java.lang.Object
  extended by dk.rode.thesis.observer.ObserverManager
All Implemented Interfaces:
Observable<Object>

@ParticipantUsage(value="Observer",
                  type=java.lang.reflect.Method.class)
@Participant(value={"Subject","ConcreteSubject"})
public class ObserverManager
extends Object
implements Observable<Object>

An observer manager is a stand-alone manager storing any type of observer that will be notified with methods declared in its class that are annotated with a matching Executor annotation. Registered observers subscribe to all or nothing. A real subject implementation can use this manager as a component, delegating the notification and work to it. The subject, if any, must be supplied as one of the arguments to the notifyObservers(Object...) method.

When observers are added, the matching methods will be found: methods annotated with the Executor annotation declaring a context to which the owner type of the manager is assignable to. The methods represent the notification mechanism for the observer in question and will be executed, using the observer object as the target if not static, when notifyObservers(Object...) is invoked.

The formal parameter types of applicable methods must be supplied at construction time, and matching arguments supplied to the notifyObserver method. The formal parameter types ignore primitive types, i.e. Integer.class and Integer.TYPE can both represent int, for example.

Any manager must use an error handler to determine how errors during notification should be handled, for example if the notification should continue in case of errors or stop immediately. For convenience, the ObserverManager.NotificationPolicy enumeration defines two such default error handlers.

The observer manager is not thread-safe! It does not enforce synchronisation, neither when adding or removing observers, nor when observers are notified. It could be potentially dangerous or least time consuming to notify observers from a synchronised context, holding a lock on the manager itself. If synchronisation is required, the context using the manager must enforce it.

Implementation notes:
An observer manager can be seen as a simple version of the Change Manager object described by Gamma et al. [Gamma95, p.299] that allows the subject to be supplied as an argument to the notifyObservers(Object...) method.

By using annotations and reflection, any method with a matching signature can be used to notify the observer. This includes static and/or private methods if the security manager allows it.

Methods annotated with the Executor annotation must declare the applicable context, i.e. classes allowed to use it. This ensures that different observer registries can use the same annotation in the same class.

Observers are only stored as weak references, and the manager will not prevent ordinary garbage collection of the observers. Hence, anonymous non-referenced observers are not a good idea for this manager as they will be garbage collected without warning.

As always, reflection can cause numerous runtime errors! Hence, the observer manager utilises error handlers to determine how errors should be processed in case of notification errors.

An alternative to annotations is to use a regular interface to specify both the observer type and the means (method) to perform the notification. The Chain of Responsibility pattern utilises such an approach to identify its handlers (observers) in the HandlerChain class.

Author:
Gunni Rode / rode.dk
See Also:
Executor

Nested Class Summary
static class ObserverManager.NotificationPolicy
          Default error handlers for observer registries.
 
Field Summary
private  ErrorHandler errorHandler
          An error handler used to handle errors thrown during notification to a given observer, which will decide if a given type of error will cause the overall notification to fail.
private  Map<Method,List<WeakReference<Object>>> observers
          The observers registered in this manager.
private  Class<?> ownerType
          The owner type of this manager.
private  Class<?>[] parameterTypes
          The formal parameter types declared for all methods to be used to notify registered observers.
private  int size
          The number of registered observers.
 
Constructor Summary
ObserverManager(Class<?> ownerType, Class<?>... parameterTypes)
          Constructor.
ObserverManager(ErrorHandler errorHandler, Class<?> ownerType, Class<?>... parameterTypes)
          Constructor.
ObserverManager(ObserverManager manager)
          Copy constructor.
 
Method Summary
<T> boolean
addObserver(Class<? extends T> clazz, T observer)
          Adds the observer supplied as observer to this manager, associated with the methods annotated in the class supplied as clazz with a context type the owner type of this manager is assignable to, if any.
 boolean addObserver(Object observer)
          Adds the observer supplied as observer to this manager, associated with the methods annotated in the class of object with a context type the owner type of this manager is assignable to, if any.
 Map<Method,List<Object>> getObserverMethods()
          Returns the observers and their associated notification methods, regardless if static or not, registered to this manager.
 Collection<Object> getObservers()
          Returns the observers currently associated with this observable sequence.
 Class<?> getOwnerType()
          Returns the owner type of this manager.
 boolean notifyObservers(Object... arguments)
          Notifies all observers stored in this manager, using the arguments for each method supplied as arguments.
private  boolean remove(Method method, Object observer)
          Removes the specific notification method supplied as method from the observer supplied as observer.
<T> boolean
removeObserver(Class<? extends T> clazz, T observer)
          Removes the observer supplied as observer from this manager.
 boolean removeObserver(Object observer)
          Removes the observer supplied as observer from this manager.
 int size()
          Return the number of observers associated with this manager.
 String toString()
          Returns the string representation of this manager.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

errorHandler

private final ErrorHandler errorHandler
An error handler used to handle errors thrown during notification to a given observer, which will decide if a given type of error will cause the overall notification to fail.

Default handler is ObserverManager.NotificationPolicy.StopOnError.

Never null.


observers

private final Map<Method,List<WeakReference<Object>>> observers
The observers registered in this manager.

Keys are the methods to perform the notification and the associated value a list of observers to be notified using that method, stored as weak references.

Never null, but can be empty.


ownerType

private final Class<?> ownerType
The owner type of this manager.

For an observer to be registered to this manager, this type must be assignable to the class specified in Executor.value() for each annotated method.

Never null.


parameterTypes

private final Class<?>[] parameterTypes
The formal parameter types declared for all methods to be used to notify registered observers.

Primitive types are ignored, i.e. the parameter types may contain both Integer.class and Integer.TYPE to represent an int.

Never null, but can be empty.


size

private int size
The number of registered observers.

A given observer may be included more than once if it is notified with more than one annotated method.

Constructor Detail

ObserverManager

public ObserverManager(Class<?> ownerType,
                       Class<?>... parameterTypes)
Constructor.

The error handling policy used is ObserverManager.NotificationPolicy.StopOnError, i.e. the notification will stop in case the notification of an observer fails.

Parameters:
ownerType - The owner type of this manager; cannot be null.
parameterTypes - The formal parameter types required by all annotated methods used to notify observers stored in this manager, ignoring primitive types; can be null.
Throws:
NullPointerException - If ownerType is null.

ObserverManager

public ObserverManager(ErrorHandler errorHandler,
                       Class<?> ownerType,
                       Class<?>... parameterTypes)
Constructor.

Parameters:
errorHandler - The error handler determining if the notification should continue in case of errors; cannot be null.
ownerType - The owner type of this manager; cannot be null.
parameterTypes - The formal parameter types required by all annotated methods used to notify observers stored in this manager, ignoring primitive types; can be null.
Throws:
NullPointerException - If errorHandler or ownerType are null.

ObserverManager

public ObserverManager(ObserverManager manager)
Copy constructor.

Parameters:
manager - The manager to copy; cannot be null.
Throws:
NullPointerException - If manager is null.
Method Detail

addObserver

public <T> boolean addObserver(Class<? extends T> clazz,
                               @Participant(value="ConcreteObserver")
                               T observer)
Adds the observer supplied as observer to this manager, associated with the methods annotated in the class supplied as clazz with a context type the owner type of this manager is assignable to, if any.

observer is used as the target for all non-static methods registered by this invocation.

Adding observer multiple times has no effect.

Type Parameters:
T - The type of clazz.
Parameters:
clazz - The class literal supplying the type to fetch the methods from; cannot be null.
observer - The observer; cannot be null.
Returns:
True if observer was added as an observer, false if not.
Throws:
NullPointerException - If either argument is null.
See Also:
removeObserver(Class, Object)

addObserver

public boolean addObserver(@Participant(value="ConcreteObserver")
                           Object observer)
Adds the observer supplied as observer to this manager, associated with the methods annotated in the class of object with a context type the owner type of this manager is assignable to, if any.

observer is used as the target for all non-static methods registered by this invocation.

Adding observer multiple times has no effect.

Specified by:
addObserver in interface Observable<Object>
Parameters:
observer - The observer; cannot be null.
Returns:
True if observer was added as an observer, false if not.
Throws:
NullPointerException - If observer is null.
See Also:
removeObserver(Object)

getObserverMethods

public Map<Method,List<Object>> getObserverMethods()
Returns the observers and their associated notification methods, regardless if static or not, registered to this manager.

Modifying the returned map will not affect this manager.

Returns:
A map containing the methods as keys and the associated observers as the values; never null, but can be empty.

getObservers

public Collection<Object> getObservers()
Description copied from interface: Observable
Returns the observers currently associated with this observable sequence.

No specific order is maintained.

Modifying the returned collection will not affect this observable.

Specified by:
getObservers in interface Observable<Object>
Returns:
The collection of observers; never null, but can be empty.

getOwnerType

public Class<?> getOwnerType()
Returns the owner type of this manager.

All methods associated with a registered observer in this manager is annotated with a context type this type is assignable to.

Returns:
The owner type of this manager; never null.

notifyObservers

public boolean notifyObservers(Object... arguments)
Notifies all observers stored in this manager, using the arguments for each method supplied as arguments.

In case the notification to a given observer (per method) fails, the error handler supplied at construction time will try and handle the error. If the error is manageable, the notification will continue; otherwise an exception is thrown.

No specific order of notification among observers is enforced.

Parameters:
arguments - The arguments to supply to each observer.
Returns:
True if the notification caused errors that could be handled by this manager, false if no errors. In case of errors that cannot be handled, a runtime exception is thrown.
Throws:
IllegalArgumentException - If arguments does not match the formal observer parameter types specified at construction time.
RuntimeException - If the notification failed in a manner that could not be handled by this manager.

remove

private boolean remove(Method method,
                       Object observer)
Removes the specific notification method supplied as method from the observer supplied as observer.

If method is the last method associated with observer, observer will also be removed.

Parameters:
method - The specific method to remove; cannot be null.
observer - The observer; cannot be null.
Returns:
True if method was removed, false if not.
Throws:
NullPointerException - If either argument is null.

removeObserver

public <T> boolean removeObserver(Class<? extends T> clazz,
                                  T observer)
Removes the observer supplied as observer from this manager.

If object is not associated with this manager, this method does nothing.

Type Parameters:
T - The type of clazz.
Parameters:
clazz - The class literal supplying the type; cannot be null.
observer - The observer to remove; cannot be null.
Returns:
True if observer was removed, false if not.
Throws:
NullPointerException - If either argument is null.
See Also:
addObserver(Class, Object)

removeObserver

public boolean removeObserver(Object observer)
Removes the observer supplied as observer from this manager.

If object is not associated with this manager, this method does nothing.

Specified by:
removeObserver in interface Observable<Object>
Parameters:
observer - The observer to remove; cannot be null.
Returns:
True if observer was removed, false if not.
Throws:
NullPointerException - If observer is null.
See Also:
addObserver(Object)

size

public int size()
Return the number of observers associated with this manager.

Returns:
The number of observers.

toString

public String toString()
Returns the string representation of this manager.

Overrides:
toString in class Object
Returns:
The string representation; never null.

Gunni Rode / rode.dk

Feel free to use and/or modify the Java 6 source code developed for this thesis AT YOUR OWN RISK, but note that the source code comes WITHOUT ANY — and I do mean WITHOUT ANY — form of warranty WHAT SO EVER!

The original thesis and source code are available at rode.dk/thesis.