package de.uni_passau.fim.pkjab.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import de.uni_passau.fim.pkjab.model.messages.Message;
/**
* This class represents an observable object, or "data" in the model-view
* paradigm.
* It can be subclassed to represent an object that the application wants
* to have observed.
* An observable object can have zero, one or more observers. An observer may be
* any object that implements interface {@link Observer} and is an
* instance of the Generic O. After an observable instance changes, it should
* call {@link #notifyObservers()} to let all of its observers be notified of the change by a
* call to their {@link Observer#update()} method.
* The order in which notifications will be delivered is unspecified. All notifications are
* done in the callee's thread and are blocking.
* Note that this notification mechanism is completely separate from the wait and notify
* mechanism of class <code>Object</code>.
* When an observable object is newly created,
* its set of observers is empty. Two observers are considered the same if
* and only if the equals method returns true for them.
*
* This class is a variation of the java.util.Observable.
* The java.util.Observable has not been used because it does not support
* type safety with generics.
* Other parts of the java.util.Observable have been omitted because they
* are not necessary in this context
*
* A concrete implementation <code>ConcreteObservable</code> of this abstract class should not inherit <code>Observable</code>
* but instead {@code Observerable<ConcreteObserver>} with a marker interface {@code ConcreteObserver extends Observer}.
* This increases type safety.
*
* @param <O> specifies which classes can observe this
* @author Alex
* @see Observer
*
* @uml.annotations for <code>observers</code>
* collection_type="charybdis.utilities.Observable.O"
*/
public abstract class Observable {
/**
* A list of <code>Observers</code> that will be notified of by
* the <code>notifyObservers</code> method.
*/
private final List observers = new ArrayList();
/**
* Adds an observer to the set of observers for this object,
* provided that it is not the same as some observer already in the set.
* An observer which is already attached is ignored.
*
* @param observer an observer to be added.
* @throws IllegalArgumentException if <code>observer</code> is <code>null</code>
*/
public synchronized void attach(Observer observer) {
if (observer == null) {
throw new NullPointerException();
}
if (!observers.contains(observer)) {
observers.add(observer);
}
}
/**
* Removes an observer from the set of observers of this object.
* Passing null or a object not in the list to this method will have no effect.
* @param observer the observer to be removed.
* @throws IllegalArgumentException if <code>observer</code> is <code>null</code>
*/
public synchronized void detach(Observer observer) throws IllegalArgumentException {
observers.remove(observer);
}
/**
* Notifies all of the observers of this object.
* Each observer's update method will be called.
*/
protected synchronized void notifyObservers(Message msg) {
for (Iterator it = observers.iterator(); it.hasNext(); ) {
((Observer)it.next()).update(msg);
}
}
/**
* Returns an umodifiable list of all observers.
* All access on this list should be synchronized.
*
* @return list of observers
*/
protected List getObservers() {
return Collections.unmodifiableList(observers);
}
}