| /* Observable.java -- an object to be observed | |
| Copyright (C) 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package java.util; | |
| /** | |
| * This class represents an object which is observable. Other objects may | |
| * register their intent to be notified when this object changes; and when | |
| * this object does change, it will trigger the <code>update</code> method | |
| * of each observer. | |
| * | |
| * Note that the <code>notifyObservers()</code> method of this class is | |
| * unrelated to the <code>notify()</code> of Object. | |
| * | |
| * @author Warren Levy (warrenl@cygnus.com) | |
| * @author Eric Blake (ebb9@email.byu.edu) | |
| * @see Observer | |
| * @status updated to 1.4 | |
| */ | |
| public class Observable | |
| { | |
| /** Tracks whether this object has changed. */ | |
| private boolean changed; | |
| /* List of the Observers registered as interested in this Observable. */ | |
| private LinkedHashSet observers; | |
| /** | |
| * Constructs an Observable with zero Observers. | |
| */ | |
| public Observable() | |
| { | |
| observers = new LinkedHashSet(); | |
| } | |
| /** | |
| * Adds an Observer. If the observer was already added this method does | |
| * nothing. | |
| * | |
| * @param observer Observer to add | |
| * @throws NullPointerException if observer is null | |
| */ | |
| public synchronized void addObserver(Observer observer) | |
| { | |
| if (observer == null) | |
| throw new NullPointerException("can't add null observer"); | |
| observers.add(observer); | |
| } | |
| /** | |
| * Reset this Observable's state to unchanged. This is called automatically | |
| * by <code>notifyObservers</code> once all observers have been notified. | |
| * | |
| * @see #notifyObservers() | |
| */ | |
| protected synchronized void clearChanged() | |
| { | |
| changed = false; | |
| } | |
| /** | |
| * Returns the number of observers for this object. | |
| * | |
| * @return number of Observers for this | |
| */ | |
| public synchronized int countObservers() | |
| { | |
| return observers.size(); | |
| } | |
| /** | |
| * Deletes an Observer of this Observable. | |
| * | |
| * @param victim Observer to delete | |
| */ | |
| public synchronized void deleteObserver(Observer victim) | |
| { | |
| observers.remove(victim); | |
| } | |
| /** | |
| * Deletes all Observers of this Observable. | |
| */ | |
| public synchronized void deleteObservers() | |
| { | |
| observers.clear(); | |
| } | |
| /** | |
| * True if <code>setChanged</code> has been called more recently than | |
| * <code>clearChanged</code>. | |
| * | |
| * @return whether or not this Observable has changed | |
| */ | |
| public synchronized boolean hasChanged() | |
| { | |
| return changed; | |
| } | |
| /** | |
| * If the Observable has actually changed then tell all Observers about it, | |
| * then reset state to unchanged. | |
| * | |
| * @see #notifyObservers(Object) | |
| * @see Observer#update(Observable, Object) | |
| */ | |
| public void notifyObservers() | |
| { | |
| notifyObservers(null); | |
| } | |
| /** | |
| * If the Observable has actually changed then tell all Observers about it, | |
| * then reset state to unchanged. Note that though the order of | |
| * notification is unspecified in subclasses, in Observable it is in the | |
| * order of registration. | |
| * | |
| * @param obj argument to Observer's update method | |
| * @see Observer#update(Observable, Object) | |
| */ | |
| public void notifyObservers(Object obj) | |
| { | |
| if (! hasChanged()) | |
| return; | |
| // Create clone inside monitor, as that is relatively fast and still | |
| // important to keep threadsafe, but update observers outside of the | |
| // lock since update() can call arbitrary code. | |
| Set s; | |
| synchronized (this) | |
| { | |
| s = (Set) observers.clone(); | |
| } | |
| int i = s.size(); | |
| Iterator iter = s.iterator(); | |
| while (--i >= 0) | |
| ((Observer) iter.next()).update(this, obj); | |
| clearChanged(); | |
| } | |
| /** | |
| * Marks this Observable as having changed. | |
| */ | |
| protected synchronized void setChanged() | |
| { | |
| changed = true; | |
| } | |
| } |