// Observable.java // This file was copied from JDK1.1. // The package name was modified. // All applicable copyrights are still in force. public class Observable { transient private boolean changed = false; transient private Vector obs; /* a temporary array buffer, used as a snapshot of the state of * current Observers. We do notifications on this snapshot while * not under synchronization. */ transient private Observer[] arr = new Observer[2]; /** Construct an Observable with zero Observers */ public Observable() { obs = new Vector(); } /** * Adds an observer to the observer list. If the Observer * has previously been added, it will not be added again. * @param o the observer to be added */ public synchronized void addObserver(Observer o) { if (!obs.contains(o)) { obs.addElement(o); } } /** * Deletes an observer from the observer list. * @param o the observer to be deleted */ public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } /** * Notifies all observers if an observable change occurs. */ public void notifyObservers() { notifyObservers(null); } /** * Notifies all observers of the specified observable change * which occurred. * @param arg what is being notified */ public void notifyObservers(Object arg) { int size=0; synchronized (this) { /* We don't want the Observer doing callbacks into * into arbitrary code while holding its own Monitor. * The code where we extract each Observable from * the Vector and store the state of the Observer * needs synchronization, but notifying observers * does not (should not). The worst result of any * potential race-condition here is that: * 1) a newly-added Observer will miss a * notification in progress * 2) a recently unregistered Observer will be * wrongly notified when it doesn't care */ if (!hasChanged()) return; size = obs.size(); if (size > arr.length) { arr = new Observer[size]; } obs.copyInto(arr); clearChanged(); } for (int i = size -1; i>=0; i--) { if (arr[i] != null) { arr[i].update(this, arg); } } } /** * Deletes observers from the observer list. */ public synchronized void deleteObservers() { obs.removeAllElements(); } /** * Sets a flag to note an observable change. */ protected synchronized void setChanged() { changed = true; } /** * Clears an observable change. */ protected synchronized void clearChanged() { changed = false; } /** * Returns a true boolean if an observable change has occurred. */ public synchronized boolean hasChanged() { return changed; } /** * Counts the number of observers. */ public synchronized int countObservers() { return obs.size(); } }