001 /* Observable.java -- an object to be observed 002 Copyright (C) 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath 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 for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package java.util; 040 041 /** 042 * This class represents an object which is observable. Other objects may 043 * register their intent to be notified when this object changes; and when 044 * this object does change, it will trigger the <code>update</code> method 045 * of each observer. 046 * 047 * Note that the <code>notifyObservers()</code> method of this class is 048 * unrelated to the <code>notify()</code> of Object. 049 * 050 * @author Warren Levy (warrenl@cygnus.com) 051 * @author Eric Blake (ebb9@email.byu.edu) 052 * @see Observer 053 * @status updated to 1.4 054 */ 055 public class Observable 056 { 057 /** Tracks whether this object has changed. */ 058 private boolean changed; 059 060 /* List of the Observers registered as interested in this Observable. */ 061 private LinkedHashSet observers; 062 063 /** 064 * Constructs an Observable with zero Observers. 065 */ 066 public Observable() 067 { 068 observers = new LinkedHashSet(); 069 } 070 071 /** 072 * Adds an Observer. If the observer was already added this method does 073 * nothing. 074 * 075 * @param observer Observer to add 076 * @throws NullPointerException if observer is null 077 */ 078 public synchronized void addObserver(Observer observer) 079 { 080 if (observer == null) 081 throw new NullPointerException("can't add null observer"); 082 observers.add(observer); 083 } 084 085 /** 086 * Reset this Observable's state to unchanged. This is called automatically 087 * by <code>notifyObservers</code> once all observers have been notified. 088 * 089 * @see #notifyObservers() 090 */ 091 protected synchronized void clearChanged() 092 { 093 changed = false; 094 } 095 096 /** 097 * Returns the number of observers for this object. 098 * 099 * @return number of Observers for this 100 */ 101 public synchronized int countObservers() 102 { 103 return observers.size(); 104 } 105 106 /** 107 * Deletes an Observer of this Observable. 108 * 109 * @param victim Observer to delete 110 */ 111 public synchronized void deleteObserver(Observer victim) 112 { 113 observers.remove(victim); 114 } 115 116 /** 117 * Deletes all Observers of this Observable. 118 */ 119 public synchronized void deleteObservers() 120 { 121 observers.clear(); 122 } 123 124 /** 125 * True if <code>setChanged</code> has been called more recently than 126 * <code>clearChanged</code>. 127 * 128 * @return whether or not this Observable has changed 129 */ 130 public synchronized boolean hasChanged() 131 { 132 return changed; 133 } 134 135 /** 136 * If the Observable has actually changed then tell all Observers about it, 137 * then reset state to unchanged. 138 * 139 * @see #notifyObservers(Object) 140 * @see Observer#update(Observable, Object) 141 */ 142 public void notifyObservers() 143 { 144 notifyObservers(null); 145 } 146 147 /** 148 * If the Observable has actually changed then tell all Observers about it, 149 * then reset state to unchanged. Note that though the order of 150 * notification is unspecified in subclasses, in Observable it is in the 151 * order of registration. 152 * 153 * @param obj argument to Observer's update method 154 * @see Observer#update(Observable, Object) 155 */ 156 public void notifyObservers(Object obj) 157 { 158 if (! hasChanged()) 159 return; 160 // Create clone inside monitor, as that is relatively fast and still 161 // important to keep threadsafe, but update observers outside of the 162 // lock since update() can call arbitrary code. 163 Set s; 164 synchronized (this) 165 { 166 s = (Set) observers.clone(); 167 } 168 int i = s.size(); 169 Iterator iter = s.iterator(); 170 while (--i >= 0) 171 ((Observer) iter.next()).update(this, obj); 172 clearChanged(); 173 } 174 175 /** 176 * Marks this Observable as having changed. 177 */ 178 protected synchronized void setChanged() 179 { 180 changed = true; 181 } 182 }