001: /*
002: * @(#)Observable.java 1.38 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.util;
029:
030: /**
031: * This class represents an observable object, or "data"
032: * in the model-view paradigm. It can be subclassed to represent an
033: * object that the application wants to have observed.
034: * <p>
035: * An observable object can have one or more observers. An observer
036: * may be any object that implements interface <tt>Observer</tt>. After an
037: * observable instance changes, an application calling the
038: * <code>Observable</code>'s <code>notifyObservers</code> method
039: * causes all of its observers to be notified of the change by a call
040: * to their <code>update</code> method.
041: * <p>
042: * The order in which notifications will be delivered is unspecified.
043: * The default implementation provided in the Observerable class will
044: * notify Observers in the order in which they registered interest, but
045: * subclasses may change this order, use no guaranteed order, deliver
046: * notifications on separate threads, or may guarantee that their
047: * subclass follows this order, as they choose.
048: * <p>
049: * Note that this notification mechanism is has nothing to do with threads
050: * and is completely separate from the <tt>wait</tt> and <tt>notify</tt>
051: * mechanism of class <tt>Object</tt>.
052: * <p>
053: * When an observable object is newly created, its set of observers is
054: * empty. Two observers are considered the same if and only if the
055: * <tt>equals</tt> method returns true for them.
056: *
057: * @author Chris Warth
058: * @version 1.31, 02/02/00
059: * @see java.util.Observable#notifyObservers()
060: * @see java.util.Observable#notifyObservers(java.lang.Object)
061: * @see java.util.Observer
062: * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
063: * @since JDK1.0
064: */
065: public class Observable {
066: private boolean changed = false;
067: private Vector obs;
068:
069: /** Construct an Observable with zero Observers. */
070:
071: public Observable() {
072: obs = new Vector();
073: }
074:
075: /**
076: * Adds an observer to the set of observers for this object, provided
077: * that it is not the same as some observer already in the set.
078: * The order in which notifications will be delivered to multiple
079: * observers is not specified. See the class comment.
080: *
081: * @param o an observer to be added.
082: * @throws NullPointerException if the parameter o is null.
083: */
084: public synchronized void addObserver(Observer o) {
085: if (o == null)
086: throw new NullPointerException();
087: if (!obs.contains(o)) {
088: obs.addElement(o);
089: }
090: }
091:
092: /**
093: * Deletes an observer from the set of observers of this object.
094: *
095: * @param o the observer to be deleted.
096: */
097: public synchronized void deleteObserver(Observer o) {
098: obs.removeElement(o);
099: }
100:
101: /**
102: * If this object has changed, as indicated by the
103: * <code>hasChanged</code> method, then notify all of its observers
104: * and then call the <code>clearChanged</code> method to
105: * indicate that this object has no longer changed.
106: * <p>
107: * Each observer has its <code>update</code> method called with two
108: * arguments: this observable object and <code>null</code>. In other
109: * words, this method is equivalent to:
110: * <blockquote><tt>
111: * notifyObservers(null)</tt></blockquote>
112: *
113: * @see java.util.Observable#clearChanged()
114: * @see java.util.Observable#hasChanged()
115: * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
116: */
117: public void notifyObservers() {
118: notifyObservers(null);
119: }
120:
121: /**
122: * If this object has changed, as indicated by the
123: * <code>hasChanged</code> method, then notify all of its observers
124: * and then call the <code>clearChanged</code> method to indicate
125: * that this object has no longer changed.
126: * <p>
127: * Each observer has its <code>update</code> method called with two
128: * arguments: this observable object and the <code>arg</code> argument.
129: *
130: * @param arg any object.
131: * @see java.util.Observable#clearChanged()
132: * @see java.util.Observable#hasChanged()
133: * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
134: */
135: public void notifyObservers(Object arg) {
136: /*
137: * a temporary array buffer, used as a snapshot of the state of
138: * current Observers.
139: */
140: Object[] arrLocal;
141:
142: synchronized (this ) {
143: /* We don't want the Observer doing callbacks into
144: * arbitrary code while holding its own Monitor.
145: * The code where we extract each Observable from
146: * the Vector and store the state of the Observer
147: * needs synchronization, but notifying observers
148: * does not (should not). The worst result of any
149: * potential race-condition here is that:
150: * 1) a newly-added Observer will miss a
151: * notification in progress
152: * 2) a recently unregistered Observer will be
153: * wrongly notified when it doesn't care
154: */
155: if (!changed)
156: return;
157: arrLocal = obs.toArray();
158: clearChanged();
159: }
160:
161: for (int i = arrLocal.length - 1; i >= 0; i--)
162: ((Observer) arrLocal[i]).update(this , arg);
163: }
164:
165: /**
166: * Clears the observer list so that this object no longer has any observers.
167: */
168: public synchronized void deleteObservers() {
169: obs.removeAllElements();
170: }
171:
172: /**
173: * Marks this <tt>Observable</tt> object as having been changed; the
174: * <tt>hasChanged</tt> method will now return <tt>true</tt>.
175: */
176: protected synchronized void setChanged() {
177: changed = true;
178: }
179:
180: /**
181: * Indicates that this object has no longer changed, or that it has
182: * already notified all of its observers of its most recent change,
183: * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
184: * This method is called automatically by the
185: * <code>notifyObservers</code> methods.
186: *
187: * @see java.util.Observable#notifyObservers()
188: * @see java.util.Observable#notifyObservers(java.lang.Object)
189: */
190: protected synchronized void clearChanged() {
191: changed = false;
192: }
193:
194: /**
195: * Tests if this object has changed.
196: *
197: * @return <code>true</code> if and only if the <code>setChanged</code>
198: * method has been called more recently than the
199: * <code>clearChanged</code> method on this object;
200: * <code>false</code> otherwise.
201: * @see java.util.Observable#clearChanged()
202: * @see java.util.Observable#setChanged()
203: */
204: public synchronized boolean hasChanged() {
205: return changed;
206: }
207:
208: /**
209: * Returns the number of observers of this <tt>Observable</tt> object.
210: *
211: * @return the number of observers of this object.
212: */
213: public synchronized int countObservers() {
214: return obs.size();
215: }
216: }
|