001: /*
002: * @(#)VetoableChangeSupport.java 1.47 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.beans;
029:
030: import java.io.Serializable;
031: import java.io.ObjectOutputStream;
032: import java.io.ObjectInputStream;
033: import java.io.IOException;
034: import java.util.ArrayList;
035: import java.util.Arrays;
036: import java.util.List;
037:
038: /**
039: * This is a utility class that can be used by beans that support constrained
040: * properties. You can use an instance of this class as a member field
041: * of your bean and delegate various work to it.
042: *
043: * This class is serializable. When it is serialized it will save
044: * (and restore) any listeners that are themselves serializable. Any
045: * non-serializable listeners will be skipped during serialization.
046: */
047:
048: public class VetoableChangeSupport implements java.io.Serializable {
049: /**
050: * Constructs a <code>VetoableChangeSupport</code> object.
051: *
052: * @param sourceBean The bean to be given as the source for any events.
053: */
054:
055: public VetoableChangeSupport(Object sourceBean) {
056: if (sourceBean == null) {
057: throw new NullPointerException();
058: }
059: source = sourceBean;
060: }
061:
062: /**
063: * Add a VetoableListener to the listener list.
064: * The listener is registered for all properties.
065: *
066: * @param listener The VetoableChangeListener to be added
067: */
068:
069: public synchronized void addVetoableChangeListener(
070: VetoableChangeListener listener) {
071: if (listeners == null) {
072: listeners = new java.util.Vector();
073: }
074: listeners.addElement(listener);
075: }
076:
077: /**
078: * Remove a VetoableChangeListener from the listener list.
079: * This removes a PropertyChangeListener that was registered
080: * for all properties.
081: *
082: * @param listener The VetoableChangeListener to be removed
083: */
084: public synchronized void removeVetoableChangeListener(
085: VetoableChangeListener listener) {
086: if (listeners == null) {
087: return;
088: }
089: listeners.removeElement(listener);
090: }
091:
092: /**
093: * Add a VetoableChangeListener for a specific property. The listener
094: * will be invoked only when a call on fireVetoableChange names that
095: * specific property.
096: *
097: * @param propertyName The name of the property to listen on.
098: * @param listener The VetoableChangeListener to be added
099: */
100:
101: /* public synchronized void addVetoableChangeListener(
102: String propertyName,
103: VetoableChangeListener listener) {
104: if (children == null) {
105: children = new java.util.Hashtable();
106: }
107: VetoableChangeSupport child = (VetoableChangeSupport)children.get(propertyName);
108: if (child == null) {
109: child = new VetoableChangeSupport(source);
110: children.put(propertyName, child);
111: }
112: child.addVetoableChangeListener(listener);
113: }
114: */
115:
116: /**
117: * Remove a VetoableChangeListener for a specific property.
118: *
119: * @param propertyName The name of the property that was listened on.
120: * @param listener The VetoableChangeListener to be removed
121: */
122:
123: /* public synchronized void removeVetoableChangeListener(
124: String propertyName,
125: VetoableChangeListener listener) {
126: if (children == null) {
127: return;
128: }
129: VetoableChangeSupport child = (VetoableChangeSupport)children.get(propertyName);
130: if (child == null) {
131: return;
132: }
133: child.removeVetoableChangeListener(listener);
134: }
135: */
136:
137: /**
138: * Report a vetoable property update to any registered listeners. If
139: * anyone vetos the change, then fire a new event reverting everyone to
140: * the old value and then rethrow the PropertyVetoException.
141: * <p>
142: * No event is fired if old and new are equal and non-null.
143: *
144: * @param propertyName The programmatic name of the property
145: * that is about to change..
146: * @param oldValue The old value of the property.
147: * @param newValue The new value of the property.
148: * @exception PropertyVetoException if the recipient wishes the property
149: * change to be rolled back.
150: */
151: public void fireVetoableChange(String propertyName,
152: Object oldValue, Object newValue)
153: throws PropertyVetoException {
154: if (listeners == null && children == null) {
155: return;
156: }
157: PropertyChangeEvent evt = new PropertyChangeEvent(source,
158: propertyName, oldValue, newValue);
159: fireVetoableChange(evt);
160: }
161:
162: /**
163: * Report a int vetoable property update to any registered listeners.
164: * No event is fired if old and new are equal and non-null.
165: * <p>
166: * This is merely a convenience wrapper around the more general
167: * fireVetoableChange method that takes Object values.
168: *
169: * @param propertyName The programmatic name of the property
170: * that is about to change.
171: * @param oldValue The old value of the property.
172: * @param newValue The new value of the property.
173: */
174:
175: /* public void fireVetoableChange(String propertyName,
176: int oldValue, int newValue)
177: throws PropertyVetoException {
178: if (oldValue == newValue) {
179: return;
180: }
181: fireVetoableChange(propertyName, new Integer(oldValue), new Integer(newValue));
182: }
183: */
184:
185: /**
186: * Report a boolean vetoable property update to any registered listeners.
187: * No event is fired if old and new are equal and non-null.
188: * <p>
189: * This is merely a convenience wrapper around the more general
190: * fireVetoableChange method that takes Object values.
191: *
192: * @param propertyName The programmatic name of the property
193: * that is about to change.
194: * @param oldValue The old value of the property.
195: * @param newValue The new value of the property.
196: */
197:
198: /* public void fireVetoableChange(String propertyName,
199: boolean oldValue, boolean newValue)
200: throws PropertyVetoException {
201: if (oldValue == newValue) {
202: return;
203: }
204: fireVetoableChange(propertyName, new Boolean(oldValue), new Boolean(newValue));
205: }
206: */
207:
208: /**
209: * Fire a vetoable property update to any registered listeners. If
210: * anyone vetos the change, then fire a new event reverting everyone to
211: * the old value and then rethrow the PropertyVetoException.
212: * <p>
213: * No event is fired if old and new are equal and non-null.
214: *
215: * @param evt The PropertyChangeEvent to be fired.
216: * @exception PropertyVetoException if the recipient wishes the property
217: * change to be rolled back.
218: */
219: private void fireVetoableChange(PropertyChangeEvent evt)
220: throws PropertyVetoException {
221: Object oldValue = evt.getOldValue();
222: Object newValue = evt.getNewValue();
223: String propertyName = evt.getPropertyName();
224: if (oldValue != null && newValue != null
225: && oldValue.equals(newValue)) {
226: return;
227: }
228: java.util.Vector targets = null;
229: VetoableChangeSupport child = null;
230: synchronized (this ) {
231: if (listeners != null) {
232: targets = (java.util.Vector) listeners.clone();
233: }
234: if (children != null && propertyName != null) {
235: child = (VetoableChangeSupport) children
236: .get(propertyName);
237: }
238: }
239: if (listeners != null) {
240: try {
241: for (int i = 0; i < targets.size(); i++) {
242: VetoableChangeListener target = (VetoableChangeListener) targets
243: .elementAt(i);
244: target.vetoableChange(evt);
245: }
246: } catch (PropertyVetoException veto) {
247: // Create an event to revert everyone to the old value.
248: evt = new PropertyChangeEvent(source, propertyName,
249: newValue, oldValue);
250: for (int i = 0; i < targets.size(); i++) {
251: try {
252: VetoableChangeListener target = (VetoableChangeListener) targets
253: .elementAt(i);
254: target.vetoableChange(evt);
255: } catch (PropertyVetoException ex) {// We just ignore exceptions that occur during reversions.
256: }
257: }
258: // And now rethrow the PropertyVetoException.
259: throw veto;
260: }
261: }
262: if (child != null) {
263: child.fireVetoableChange(evt);
264: }
265: }
266:
267: /**
268: * Check if there are any listeners for a specific property.
269: *
270: * @param propertyName the property name.
271: * @return true if there are one or more listeners for the given property
272: */
273:
274: /* public synchronized boolean hasListeners(String propertyName) {
275: if (listeners != null && !listeners.isEmpty()) {
276: // there is a generic listener
277: return true;
278: }
279: if (children != null) {
280: VetoableChangeSupport child = (VetoableChangeSupport)children.get(propertyName);
281: if (child != null && child.listeners != null) {
282: return !child.listeners.isEmpty();
283: }
284: }
285: return false;
286: }
287: */
288:
289: /**
290: * @serialData Null terminated list of <code>VetoableChangeListeners</code>.
291: * <p>
292: * At serialization time we skip non-serializable listeners and
293: * only serialize the serializable listeners.
294: *
295: */
296:
297: private void writeObject(ObjectOutputStream s) throws IOException {
298: s.defaultWriteObject();
299: java.util.Vector v = null;
300: synchronized (this ) {
301: if (listeners != null) {
302: v = (java.util.Vector) listeners.clone();
303: }
304: }
305: if (v != null) {
306: for (int i = 0; i < v.size(); i++) {
307: VetoableChangeListener l = (VetoableChangeListener) v
308: .elementAt(i);
309: if (l instanceof Serializable) {
310: s.writeObject(l);
311: }
312: }
313: }
314: s.writeObject(null);
315: }
316:
317: private void readObject(ObjectInputStream s)
318: throws ClassNotFoundException, IOException {
319: s.defaultReadObject();
320: Object listenerOrNull;
321: while (null != (listenerOrNull = s.readObject())) {
322: addVetoableChangeListener((VetoableChangeListener) listenerOrNull);
323: }
324: }
325:
326: /**
327: * "listeners" lists all the generic listeners.
328: *
329: * This is transient - its state is written in the writeObject method.
330: */
331: transient private java.util.Vector listeners;
332: /**
333: * Hashtable for managing listeners for specific properties.
334: * Maps property names to VetoableChangeSupport objects.
335: * @serial
336: * @since 1.2
337: */
338: private java.util.Hashtable children;
339: /**
340: * The object to be provided as the "source" for any generated events.
341: * @serial
342: */
343: private Object source;
344: /**
345: * Internal version number
346: * @serial
347: */
348: private int vetoableChangeSupportSerializedDataVersion = 2;
349: /**
350: * Serialization version ID, so we're compatible with JDK 1.1
351: */
352: static final long serialVersionUID = -5090210921595982017L;
353:
354: // Focus-related functionality added
355: //-------------------------------------------------------------------------
356: public synchronized VetoableChangeListener[] getVetoableChangeListeners() {
357: List returnList = new ArrayList();
358: // Add all the VetoableChangeListeners
359: if (listeners != null) {
360: returnList.addAll(listeners);
361: }
362: return (VetoableChangeListener[]) (returnList
363: .toArray(new VetoableChangeListener[0]));
364: }
365:
366: /*
367: public synchronized VetoableChangeListener[] getVetoableChangeListeners(
368: String propertyName) {
369: List returnList = new ArrayList();
370: if (children != null) {
371: VetoableChangeSupport support =
372: (VetoableChangeSupport)children.get(propertyName);
373: if (support != null) {
374: returnList.addAll(
375: Arrays.asList(support.getVetoableChangeListeners()));
376: }
377: }
378: return (VetoableChangeListener[])(returnList.toArray
379: (new VetoableChangeListener[0]));
380: }
381:
382: public void fireVetoableChange(String propertyName,
383: int oldValue, int newValue)
384: throws PropertyVetoException {
385: if (oldValue == newValue) {
386: return;
387: }
388: fireVetoableChange(propertyName, new Integer(oldValue), new Integer(newValue));
389: }
390:
391: public void fireVetoableChange(String propertyName,
392: boolean oldValue, boolean newValue)
393: throws PropertyVetoException {
394: if (oldValue == newValue) {
395: return;
396: }
397: fireVetoableChange(propertyName, new Boolean(oldValue), new Boolean(newValue));
398: }
399:
400: public synchronized void addVetoableChangeListener(
401: String propertyName,
402: VetoableChangeListener listener) {
403: if (children == null) {
404: children = new java.util.Hashtable();
405: }
406: VetoableChangeSupport child = (VetoableChangeSupport)children.get(propertyName);
407: if (child == null) {
408: child = new VetoableChangeSupport(source);
409: children.put(propertyName, child);
410: }
411: child.addVetoableChangeListener(listener);
412: }
413:
414: public synchronized void removeVetoableChangeListener(
415: String propertyName,
416: VetoableChangeListener listener) {
417: if (children == null) {
418: return;
419: }
420: VetoableChangeSupport child = (VetoableChangeSupport)children.get(propertyName);
421: if (child == null) {
422: return;
423: }
424: child.removeVetoableChangeListener(listener);
425: }
426: */
427: }
|