Patch: FYI: Merge java.beans

Tom Tromey tromey@redhat.com
Mon Jul 15 09:03:00 GMT 2002


I'm checking this in.  This patch re-syncs java.beans with Classpath.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* Makefile.in: Rebuilt.
	* Makefile.am (awt_java_source_files): Added new files.
	* java/beans/ExceptionListener.java: Merged with Classpath.
	* java/beans/PropertyChangeEvent.java: Merged with Classpath.
	* java/beans/PropertyChangeListener.java: Merged with Classpath.
	* java/beans/PropertyChangeListenerProxy.java: Merged with Classpath.
	* java/beans/PropertyChangeSupport.java: Merged with Classpath.
	* java/beans/VetoableChangeListener.java: Merged with Classpath.
	* java/beans/VetoableChangeListenerProxy.java: Merged with Classpath.
	* java/beans/VetoableChangeSupport.java: Merged with Classpath.

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.231
diff -u -r1.231 Makefile.am
--- Makefile.am 14 Jul 2002 22:18:34 -0000 1.231
+++ Makefile.am 15 Jul 2002 16:03:13 -0000
@@ -799,6 +799,7 @@
 java/beans/Customizer.java \
 java/beans/DesignMode.java \
 java/beans/EventSetDescriptor.java \
+java/beans/ExceptionListener.java \
 java/beans/FeatureDescriptor.java \
 java/beans/IndexedPropertyDescriptor.java \
 java/beans/IntrospectionException.java \
@@ -807,6 +808,7 @@
 java/beans/ParameterDescriptor.java \
 java/beans/PropertyChangeEvent.java \
 java/beans/PropertyChangeListener.java \
+java/beans/PropertyChangeListenerProxy.java \
 java/beans/PropertyChangeSupport.java \
 java/beans/PropertyDescriptor.java \
 java/beans/PropertyEditor.java \
@@ -815,6 +817,7 @@
 java/beans/PropertyVetoException.java \
 java/beans/SimpleBeanInfo.java \
 java/beans/VetoableChangeListener.java \
+java/beans/VetoableChangeListenerProxy.java \
 java/beans/VetoableChangeSupport.java \
 java/beans/Visibility.java
 
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.in,v
retrieving revision 1.251
diff -u -r1.251 Makefile.in
--- Makefile.in 14 Jul 2002 22:18:34 -0000 1.251
+++ Makefile.in 15 Jul 2002 16:03:17 -0000
@@ -568,6 +568,7 @@
 java/beans/Customizer.java \
 java/beans/DesignMode.java \
 java/beans/EventSetDescriptor.java \
+java/beans/ExceptionListener.java \
 java/beans/FeatureDescriptor.java \
 java/beans/IndexedPropertyDescriptor.java \
 java/beans/IntrospectionException.java \
@@ -576,6 +577,7 @@
 java/beans/ParameterDescriptor.java \
 java/beans/PropertyChangeEvent.java \
 java/beans/PropertyChangeListener.java \
+java/beans/PropertyChangeListenerProxy.java \
 java/beans/PropertyChangeSupport.java \
 java/beans/PropertyDescriptor.java \
 java/beans/PropertyEditor.java \
@@ -584,6 +586,7 @@
 java/beans/PropertyVetoException.java \
 java/beans/SimpleBeanInfo.java \
 java/beans/VetoableChangeListener.java \
+java/beans/VetoableChangeListenerProxy.java \
 java/beans/VetoableChangeSupport.java \
 java/beans/Visibility.java
 
@@ -1776,7 +1779,7 @@
 
 DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
-TAR = tar
+TAR = gtar
 GZIP_ENV = --best
 DIST_SUBDIRS =  @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include
 DEP_FILES =  .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
@@ -2197,6 +2200,7 @@
 .deps/java/beans/BeanInfo.P .deps/java/beans/Beans.P \
 .deps/java/beans/Customizer.P .deps/java/beans/DesignMode.P \
 .deps/java/beans/EventSetDescriptor.P \
+.deps/java/beans/ExceptionListener.P \
 .deps/java/beans/FeatureDescriptor.P \
 .deps/java/beans/IndexedPropertyDescriptor.P \
 .deps/java/beans/IntrospectionException.P \
@@ -2204,6 +2208,7 @@
 .deps/java/beans/ParameterDescriptor.P \
 .deps/java/beans/PropertyChangeEvent.P \
 .deps/java/beans/PropertyChangeListener.P \
+.deps/java/beans/PropertyChangeListenerProxy.P \
 .deps/java/beans/PropertyChangeSupport.P \
 .deps/java/beans/PropertyDescriptor.P .deps/java/beans/PropertyEditor.P \
 .deps/java/beans/PropertyEditorManager.P \
@@ -2211,6 +2216,7 @@
 .deps/java/beans/PropertyVetoException.P \
 .deps/java/beans/SimpleBeanInfo.P \
 .deps/java/beans/VetoableChangeListener.P \
+.deps/java/beans/VetoableChangeListenerProxy.P \
 .deps/java/beans/VetoableChangeSupport.P .deps/java/beans/Visibility.P \
 .deps/java/beans/beancontext/BeanContext.P \
 .deps/java/beans/beancontext/BeanContextChild.P \
Index: java/beans/ExceptionListener.java
===================================================================
RCS file: java/beans/ExceptionListener.java
diff -N java/beans/ExceptionListener.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ java/beans/ExceptionListener.java 15 Jul 2002 16:03:17 -0000
@@ -0,0 +1,57 @@
+/* ExceptionListener.java -- listen for recoverable internal exceptions
+   Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.beans;
+
+/**
+ * This interface allows a class to monitor internal exceptions, to try to
+ * recover from them.
+ *
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.4
+ * @status updated to 1.4
+ */
+public interface ExceptionListener
+{
+  /**
+   * Fired after an exception occurs.
+   *
+   * @param e the trapped exception
+   */
+  void exceptionThrown(Exception e);
+} // interface ExceptionListener
Index: java/beans/PropertyChangeEvent.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/PropertyChangeEvent.java,v
retrieving revision 1.4
diff -u -r1.4 PropertyChangeEvent.java
--- java/beans/PropertyChangeEvent.java 22 Jan 2002 22:40:11 -0000 1.4
+++ java/beans/PropertyChangeEvent.java 15 Jul 2002 16:03:17 -0000
@@ -1,5 +1,5 @@
-/* java.beans.PropertyChangeEvent
-   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+/* PropertyChangeEvent.java -- describes a change in a property
+   Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 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
@@ -38,87 +38,152 @@
 
 package java.beans;
 
+import java.util.EventObject;
+
 /**
- ** PropertyChangeEvents are fired in the PropertyChange
- ** and VetoableChange event classes.  They represent the
- ** old and new values as well as the source Bean.<P>
- **
- ** If the old or new value is a primitive type, it must
- ** be wrapped in the appropriate wrapper type
- ** (java.lang.Integer for int, etc., etc.).<P>
- **
- ** If the old or new values are unknown (although why
- ** that would be I do not know), they may be null.<P>
- **
- ** Right now Sun put in a propagationId, reserved for
- ** future use.  Read the comments on the constructor
- ** and on setPropagationId for more information.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.1.0, 29 Jul 1998
- **/
-
-public class PropertyChangeEvent extends java.util.EventObject {
-	String propertyName;
-	Object oldValue;
-	Object newValue;
-	Object propagationId;
-
-	private static final long serialVersionUID = 7042693688939648123L;
-
-	/** Create a new PropertyChangeEvent.  Remember that if
-	 ** you received a PropertyChangeEvent and are sending
-	 ** a new one, you should also set the propagation ID
-	 ** from the old PropertyChangeEvent.
-	 ** @param source the Bean containing the property.
-	 ** @param propertyName the property's name.
-	 ** @param oldValue the old value of the property.
-	 ** @param newValue the new value of the property.
-	 **/
-	public PropertyChangeEvent(Object source, String propertyName, Object oldVal, Object newVal) {
-		super(source);
-		this.propertyName = propertyName;
-		oldValue = oldVal;
-		newValue = newVal;
-	}
-
-	/** Get the property name.
-	 ** @return the property name.
-	 **/
-	public String getPropertyName() {
-		return propertyName;
-	}
-
-	/** Get the property's old value.
-	 ** @return the property's old value.
-	 **/
-	public Object getOldValue() {
-		return oldValue;
-	}
-
-	/** Get the property's new value.
-	 ** @return the property's new value.
-	 **/
-	public Object getNewValue() {
-		return newValue;
-	}
-
-	/** Set the propagation ID.  This is a way for the event
-	 ** to be passed from hand to hand and retain a little
-	 ** extra state.  Right now it is unused, but it should
-	 ** be propagated anyway so that future versions of
-	 ** JavaBeans can use it, for God knows what.
-	 ** @param propagationId the propagation ID.
-	 **/
-	public void setPropagationId(Object propagationId) {
-		this.propagationId = propagationId;
-	}
-
-	/** Get the propagation ID.
-	 ** @return the propagation ID.
-	 **/
-	public Object getPropagationId() {
-		return propagationId;
-	}
-}
+ * PropertyChangeEvents are fired in the PropertyChange and VetoableChange
+ * event classes.  They represent the old and new values as well as the
+ * source Bean. If the old or new value is a primitive type, it must be
+ * wrapped in the appropriate wrapper type (java.lang.Integer for int, etc.,
+ * etc.).
+ *
+ * <p>If the old or new values are unknown (although why that would be I do
+ * not know), they may be null. Also, if the set of properties itself has
+ * changed, the name should be null, and the old and new values may also be
+ * null. Right now Sun put in a propagationId, reserved for future use. Read
+ * the comments on the constructor and on setPropagationId for more
+ * information.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.1
+ * @status udpated to 1.4
+ */
+public class PropertyChangeEvent extends EventObject
+{
+  /**
+   * Compatible with JDK 1.1+.
+   */
+  private static final long serialVersionUID = 7042693688939648123L;
+
+  /**
+   * The name of the property that changed, may be null. Package visible for
+   * use by PropertyChangeSupport.
+   *
+   * @serial the changed property name
+   */
+  final String propertyName;
+
+  /**
+   * The new value of the property, may be null. Package visible for use by
+   * PropertyChangeSupport.
+   *
+   * @serial the new property value
+   */
+  final Object newValue;
+
+  /**
+   * The old value of the property, may be null. Package visible for use by
+   * PropertyChangeSupport.
+   *
+   * @serial the old property value
+   */
+  final Object oldValue;
+
+  /**
+   * The propagation ID, reserved for future use. May be null.
+   *
+   * @see #getPropagationId()
+   * @serial the Propagation ID
+   */
+  private Object propagationId;
+
+  /**
+   * Create a new PropertyChangeEvent. Remember that if you received a
+   * PropertyChangeEvent and are sending a new one, you should also set the
+   * propagation ID from the old PropertyChangeEvent.
+   *
+   * @param source the Bean containing the property
+   * @param propertyName the property's name
+   * @param oldValue the old value of the property
+   * @param newValue the new value of the property
+   * @throws IllegalArgumentException if source is null
+   */
+  public PropertyChangeEvent(Object source, String propertyName,
+                             Object oldVal, Object newVal)
+  {
+    super(source);
+    this.propertyName = propertyName;
+    oldValue = oldVal;
+    newValue = newVal;
+  }
+
+  /**
+   * Get the property name. May be null if multiple properties changed.
+   *
+   * @return the property name
+   */
+  public String getPropertyName()
+  {
+    return propertyName;
+  }
+
+  /**
+   * Get the property's new value. May be null if multiple properties changed.
+   *
+   * @return the property's new value
+   */
+  public Object getNewValue()
+  {
+    return newValue;
+  }
+
+  /**
+   * Get the property's old value. May be null if multiple properties changed.
+   *
+   * @return the property's old value
+   */
+  public Object getOldValue()
+  {
+    return oldValue;
+  }
+
+  /**
+   * Set the propagation ID.  This is a way for the event to be passed from
+   * hand to hand and retain a little extra state.  Right now it is unused,
+   * but it should be propagated anyway so that future versions of JavaBeans
+   * can use it, for God knows what.
+   *
+   * @param propagationId the propagation ID
+   * @see #getPropagationId()
+   */
+  public void setPropagationId(Object propagationId)
+  {
+    this.propagationId = propagationId;
+  }
+
+  /**
+   * Get the propagation ID. Right now, it is not used for anything.
+   *
+   * @return the propagation ID
+   * @see #setPropagationId(Object)
+   */
+  public Object getPropagationId()
+  {
+    return propagationId;
+  }
+
+  /**
+   * Utility method to rollback a change.
+   *
+   * @param event the event to rollback
+   * @return a new event with old and new swapped
+   */
+  PropertyChangeEvent rollback()
+  {
+    PropertyChangeEvent result
+      = new PropertyChangeEvent(source, propertyName, newValue, oldValue);
+    result.propagationId = propagationId;
+    return result;
+  }
+} // class PropertyChangeEvent
Index: java/beans/PropertyChangeListener.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/PropertyChangeListener.java,v
retrieving revision 1.3
diff -u -r1.3 PropertyChangeListener.java
--- java/beans/PropertyChangeListener.java 22 Jan 2002 22:40:11 -0000 1.3
+++ java/beans/PropertyChangeListener.java 15 Jul 2002 16:03:17 -0000
@@ -1,5 +1,5 @@
-/* java.beans.PropertyChangeListener
-   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+/* PropertyChangeListener.java -- listen for changes in a bound property
+   Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 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
@@ -41,22 +41,21 @@
 import java.util.EventListener;
 
 /**
- ** PropertyChangeListener allows a class to monitor
- ** properties of a Bean for changes.<P>
- **
- ** A propertyChange() event will only be fired
- ** <EM>after</EM> the property has changed.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.1.0, 29 Jul 1998
- ** @see java.beans.PropertyChangeSupport
- **/
-
+ * PropertyChangeListener allows a class to monitor properties of a Bean for
+ * changes. A propertyChange() event will only be fired <em>after</em> the
+ * property has changed.
+ *
+ * @author John Keiser
+ * @see PropertyChangeSupport
+ * @since 1.1
+ * @status updated to 1.4
+ */
 public interface PropertyChangeListener extends EventListener
 {
-  /** Fired after a Bean's property has changed.
-   ** @param e the change (containing the old and new values)
-   **/
-  public abstract void propertyChange(PropertyChangeEvent e);
-}
+  /**
+   * Fired after a Bean's property has changed.
+   *
+   * @param e the change (containing the old and new values)
+   */
+  void propertyChange(PropertyChangeEvent e);
+} // interface PropertyChangeListener
Index: java/beans/PropertyChangeListenerProxy.java
===================================================================
RCS file: java/beans/PropertyChangeListenerProxy.java
diff -N java/beans/PropertyChangeListenerProxy.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ java/beans/PropertyChangeListenerProxy.java 15 Jul 2002 16:03:17 -0000
@@ -0,0 +1,102 @@
+/* PropertyChangeListenerProxy.java -- adds a name to a property listener
+   Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.beans;
+
+import java.util.EventListenerProxy;
+
+/**
+ * This class provides an extension to <code>PropertyChangeListener</code> -
+ * associating a name with the listener. This can be used to filter the
+ * changes that one is interested in.
+ *
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.4
+ * @status udpated to 1.4
+ */
+public class PropertyChangeListenerProxy extends EventListenerProxy
+  implements PropertyChangeListener
+{
+  /**
+   * The name of the property to listen for. Package visible for use by
+   * PropertyChangeSupport.
+   */
+  final String propertyName;
+
+  /**
+   * Create a new proxy which filters property change events and only passes
+   * changes to the named property on to the delegate. A null propertyName
+   * or listener does not fail now, but may cause a NullPointerException down
+   * the road.
+   *
+   * @param propertyName the property's name to filter on
+   * @param listener the delegate listener
+   */
+  public PropertyChangeListenerProxy(String propertyName,
+                                     PropertyChangeListener listener)
+  {
+    super(listener);
+    this.propertyName = propertyName;
+  }
+
+  /**
+   * Forwards the event on to the delegate if the property name matches.
+   *
+   * @param event the event to pass on, if it meets the filter
+   * @throws NullPointerException if the delegate this was created with is null
+   */
+  public void propertyChange(PropertyChangeEvent event)
+  {
+    // Note: Sun does not filter, under the assumption that since
+    // PropertyChangeSupport unwraps proxys, this method should never be
+    // called by normal use of listeners.
+    String name = event == null ? null : event.getPropertyName();
+    if (name == null ? propertyName == null : name.equals(propertyName))
+      ((PropertyChangeListener) getListener()).propertyChange(event);
+  }
+
+  /**
+   * Gets the name of the property this proxy is filtering on.
+   *
+   * @return the property name
+   */
+  public String getPropertyName()
+  {
+    return propertyName;
+  }
+} // class PropertyChangeListenerProxy
Index: java/beans/PropertyChangeSupport.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/PropertyChangeSupport.java,v
retrieving revision 1.3
diff -u -r1.3 PropertyChangeSupport.java
--- java/beans/PropertyChangeSupport.java 22 Jan 2002 22:40:11 -0000 1.3
+++ java/beans/PropertyChangeSupport.java 15 Jul 2002 16:03:18 -0000
@@ -1,5 +1,5 @@
-/* java.beans.PropertyChangeSupport
-   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* PropertyChangeSupport.java -- support to manage property change listeners
+   Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 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
@@ -37,214 +37,452 @@
 
 
 package java.beans;
-import java.util.Hashtable;
-import java.util.Vector;
-import java.util.Enumeration;
+
+import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
-import java.io.IOException;
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Vector;
 
 /**
- ** PropertyChangeSupport makes it easy to fire property
- ** change events and handle listeners.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.2.0, 15 Mar 1999
- **/
-
-public class PropertyChangeSupport implements java.io.Serializable {
-	transient Hashtable propertyListeners = new Hashtable();
-	transient Vector listeners = new Vector();
-	Hashtable children;
-	Object source;
-	int propertyChangeSupportSerializedDataVersion = 2;
-	private static final long serialVersionUID = 6401253773779951803L;
-
-	/**
-	 * Saves the state of the object to the stream. */
-	private void writeObject(ObjectOutputStream stream) throws IOException {
-		children = propertyListeners.isEmpty() ? null : propertyListeners;
-		stream.defaultWriteObject();
-		for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) {
-			PropertyChangeListener l = (PropertyChangeListener)e.nextElement();
-			if (l instanceof Serializable)
-			  stream.writeObject(l);
-		}
-		stream.writeObject(null);
-	}
-
-	/**
-	 * Reads the object back from stream (deserialization).
-	 */
-	private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
-		stream.defaultReadObject();
-		propertyListeners = (children == null) ? new Hashtable() : children;
-		PropertyChangeListener l;
-		while ((l = (PropertyChangeListener)stream.readObject()) != null) {
-			addPropertyChangeListener(l);
-		}
-		// FIXME: XXX: There is no spec for JDK 1.1 serialization
-		// so it is unclear what to do if the value of
-		// propertyChangeSupportSerializedDataVersion is 1.
-	}
-
-	/** Create PropertyChangeSupport to work with a specific
-	 ** source bean.
-	 ** @param source the source bean to use.
-	 **/
-	public PropertyChangeSupport(Object source) {
-		this.source = source;
-	}
-
-	/** Adds a PropertyChangeListener to the list of listeners.
-	 ** All property change events will be sent to this listener.
-	 ** <P>
-	 **
-	 ** The listener add is not unique: that is, <em>n</em> adds with
-	 ** the same listener will result in <em>n</em> events being sent
-	 ** to that listener for every property change.
-	 ** <P>
-	 **
-	 ** Adding a null listener will cause undefined behavior.
-	 **
-	 ** @param l the listener to add.
-	 **/
-	public void addPropertyChangeListener(PropertyChangeListener l) {
-		listeners.addElement(l);
-	}
-
-	/** Adds a PropertyChangeListener listening on the specified property.
-	 ** Events will be sent to the listener for that particular property.
-	 ** <P>
-	 **
-	 ** The listener add is not unique; that is, <em>n</em> adds on a
-	 ** particular property for a particular listener will result in
-	 ** <em>n</em> events being sent to that listener when that
-	 ** property is changed.
-	 ** <P>
-	 **
-	 ** The effect is cumulative, too; if you are registered to listen
-	 ** to receive events on all property changes, and then you
-	 ** register on a particular property, you will receive change
-	 ** events for that property twice.
-	 ** <P>
-	 **
-	 ** Adding a null listener will cause undefined behavior.
-	 **
-	 ** @param propertyName the name of the property to listen on.
-	 ** @param l the listener to add.
-	 **/
-	public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
-		synchronized(propertyListeners) {
-			Vector v = (Vector)propertyListeners.get(propertyName);
-			try {
-				v.addElement(l);
-			} catch(NullPointerException e) {
-				/* If v is not found, create a new vector. */
-				v = new Vector();
-				v.addElement(l);
-				propertyListeners.put(propertyName, v);
-			}
-		}
-	}
-
-	/** Removes a PropertyChangeListener from the list of listeners.
-	 ** If any specific properties are being listened on, they must
-	 ** be deregistered by themselves; this will only remove the
-	 ** general listener to all properties.
-	 ** <P>
-	 **
-	 ** If <code>add()</code> has been called multiple times for a
-	 ** particular listener, <code>remove()</code> will have to be
-	 ** called the same number of times to deregister it.
-	 **
-	 ** @param l the listener to remove.
-	 **/
-	public void removePropertyChangeListener(PropertyChangeListener l) {
-		listeners.removeElement(l);
-	}
-
-	/** Removes a PropertyChangeListener from listening to a specific property.
-	 ** <P>
-	 **
-	 ** If <code>add()</code> has been called multiple times for a
-	 ** particular listener on a property, <code>remove()</code> will
-	 ** have to be called the same number of times to deregister it.
-	 **
-	 ** @param propertyName the property to stop listening on.
-	 ** @param l the listener to remove.
-	 **/
-	public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) {
-		synchronized(propertyListeners) {
-			Vector v = (Vector)propertyListeners.get(propertyName);
-			try {
-				v.removeElement(l);
-				if(v.size() == 0) {
-					propertyListeners.remove(propertyName);
-				}
-			} catch(NullPointerException e) {
-				/* if v is not found, do nothing. */
-			}
-		}
-	}
-
-	/** Fire a PropertyChangeEvent to all the listeners.
-	 **
-	 ** @param event the event to fire.
-	 **/
-	public void firePropertyChange(PropertyChangeEvent event) {
-		for(int i=0;i<listeners.size();i++) {
-			((PropertyChangeListener)listeners.elementAt(i)).propertyChange(event);
-		}
-		Vector moreListeners = (Vector)propertyListeners.get(event.getPropertyName());
-		if(moreListeners != null) {
-			for(int i=0;i<moreListeners.size();i++) {
-				((PropertyChangeListener)moreListeners.elementAt(i)).propertyChange(event);
-			}
-		}
-	}
-
-	/** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners.
-	 **
-	 ** @param propertyName the name of the property that changed.
-	 ** @param oldVal the old value.
-	 ** @param newVal the new value.
-	 **/
-	public void firePropertyChange(String propertyName, Object oldVal, Object newVal) {
-		firePropertyChange(new PropertyChangeEvent(source,propertyName,oldVal,newVal));
-	}
-
-	/** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners.
-	 **
-	 ** @param propertyName the name of the property that changed.
-	 ** @param oldVal the old value.
-	 ** @param newVal the new value.
-	 **/
-	public void firePropertyChange(String propertyName, boolean oldVal, boolean newVal) {
-		firePropertyChange(new PropertyChangeEvent(source, propertyName, new Boolean(oldVal), new Boolean(newVal)));
-	}
-
-	/** Fire a PropertyChangeEvent containing the old and new values of the property to all the listeners.
-	 **
-	 ** @param propertyName the name of the property that changed.
-	 ** @param oldVal the old value.
-	 ** @param newVal the new value.
-	 **/
-	public void firePropertyChange(String propertyName, int oldVal, int newVal) {
-		firePropertyChange(new PropertyChangeEvent(source, propertyName, new Integer(oldVal), new Integer(newVal)));
-	}
-
-	/** Tell whether the specified property is being listened on or not.
-	 ** This will only return <code>true</code> if there are listeners
-	 ** on all properties or if there is a listener specifically on this
-	 ** property.
-	 **
-	 ** @param propertyName the property that may be listened on
-	 ** @return whether the property is being listened on
-	 **/
-	 public boolean hasListeners(String propertyName) {
-	 	return listeners.size() > 0  || propertyListeners.get(propertyName) != null;
-	 }
-}
+ * PropertyChangeSupport makes it easy to fire property change events and
+ * handle listeners. It allows chaining of listeners, as well as filtering
+ * by property name. In addition, it will serialize only those listeners
+ * which are serializable, ignoring the others without problem. This class
+ * is thread-safe.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class PropertyChangeSupport implements Serializable
+{
+  /**
+   * Compatible with JDK 1.1+.
+   */
+  private static final long serialVersionUID = 6401253773779951803L;
+
+  /**
+   * Maps property names (String) to named listeners (PropertyChangeSupport).
+   * If this is a child instance, this field will be null.
+   *
+   * @serial the map of property names to named listener managers
+   * @since 1.2
+   */
+  private Hashtable children;
+
+  /**
+   * The non-null source object for any generated events.
+   *
+   * @serial the event source
+   */
+  private final Object source;
+
+  /**
+   * A field to compare serialization versions - this class uses version 2.
+   *
+   * @serial the serialization format
+   */
+  private final int propertyChangeSupportSerializedDataVersion = 2;
+
+  /**
+   * The list of all registered property listeners. If this instance was
+   * created by user code, this only holds the global listeners (ie. not tied
+   * to a name), and may be null. If it was created by this class, as a
+   * helper for named properties, then this vector will be non-null, and this
+   * instance appears as a value in the <code>children</code> hashtable of
+   * another instance, so that the listeners are tied to the key of that
+   * hashtable entry.
+   */
+  private transient Vector listeners;
+
+  /**
+   * Create a PropertyChangeSupport to work with a specific source bean.
+   *
+   * @param source the source bean to use
+   * @throws NullPointerException if source is null
+   */
+  public PropertyChangeSupport(Object source)
+  {
+    this.source = source;
+    if (source == null)
+      throw new NullPointerException();
+  }
+
+  /**
+   * Adds a PropertyChangeListener to the list of global listeners. All
+   * property change events will be sent to this listener. The listener add
+   * is not unique: that is, <em>n</em> adds with the same listener will
+   * result in <em>n</em> events being sent to that listener for every
+   * property change. Adding a null listener may cause a NullPointerException
+   * down the road. This method will unwrap a PropertyChangeListenerProxy,
+   * registering the underlying delegate to the named property list.
+   *
+   * @param l the listener to add
+   */
+  public synchronized void addPropertyChangeListener(PropertyChangeListener l)
+  {
+    if (l instanceof PropertyChangeListenerProxy)
+      {
+        PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+        addPropertyChangeListener(p.propertyName,
+                                  (PropertyChangeListener) p.getListener());
+      }
+    else
+      {
+        if (listeners == null)
+          listeners = new Vector();
+        listeners.add(l);
+      }
+  }
+
+  /**
+   * Removes a PropertyChangeListener from the list of global listeners. If
+   * any specific properties are being listened on, they must be deregistered
+   * by themselves; this will only remove the general listener to all
+   * properties. If <code>add()</code> has been called multiple times for a
+   * particular listener, <code>remove()</code> will have to be called the
+   * same number of times to deregister it. This method will unwrap a
+   * PropertyChangeListenerProxy, removing the underlying delegate from the
+   * named property list.
+   *
+   * @param l the listener to remove
+   */
+  public synchronized void
+    removePropertyChangeListener(PropertyChangeListener l)
+  {
+    if (l instanceof PropertyChangeListenerProxy)
+      {
+        PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+        removePropertyChangeListener(p.propertyName,
+                                     (PropertyChangeListener) p.getListener());
+      }
+    else if (listeners != null)
+      {
+        listeners.remove(l);
+        if (listeners.isEmpty())
+          listeners = null;
+      }
+  }
+
+  /**
+   * Returns an array of all registered property change listeners. Those that
+   * were registered under a name will be wrapped in a
+   * <code>PropertyChangeListenerProxy</code>, so you must check whether the
+   * listener is an instance of the proxy class in order to see what name the
+   * real listener is registered under. If there are no registered listeners,
+   * this returns an empty array.
+   *
+   * @return the array of registered listeners
+   * @see PropertyChangeListenerProxy
+   * @since 1.4
+   */
+  public synchronized PropertyChangeListener[] getPropertyChangeListeners()
+  {
+    ArrayList list = new ArrayList();
+    if (listeners != null)
+      list.addAll(listeners);
+    if (children != null)
+      {
+        int i = children.size();
+        Iterator iter = children.entrySet().iterator();
+        while (--i >= 0)
+          {
+            Entry e = (Entry) iter.next();
+            String name = (String) e.getKey();
+            Vector v = ((PropertyChangeSupport) e.getValue()).listeners;
+            int j = v.size();
+            while (--j >= 0)
+              list.add(new PropertyChangeListenerProxy
+                (name, (PropertyChangeListener) v.get(j)));
+          }
+      }
+    return (PropertyChangeListener[])
+      list.toArray(new PropertyChangeListener[list.size()]);
+  }
+
+  /**
+   * Adds a PropertyChangeListener listening on the specified property. Events
+   * will be sent to the listener only if the property name matches. The
+   * listener add is not unique; that is, <em>n</em> adds on a particular
+   * property for a particular listener will result in <em>n</em> events
+   * being sent to that listener when that property is changed. The effect is
+   * cumulative, too; if you are registered to listen to receive events on
+   * all property changes, and then you register on a particular property,
+   * you will receive change events for that property twice. Adding a null
+   * listener may cause a NullPointerException down the road. This method
+   * will unwrap a PropertyChangeListenerProxy, registering the underlying
+   * delegate to the named property list if the names match, and discarding
+   * it otherwise.
+   *
+   * @param propertyName the name of the property to listen on
+   * @param l the listener to add
+   * @throws NullPointerException if propertyName is null
+   */
+  public synchronized void addPropertyChangeListener(String propertyName,
+                                                     PropertyChangeListener l)
+  {
+    while (l instanceof PropertyChangeListenerProxy)
+      {
+        PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+        if (propertyName == null ? p.propertyName != null
+            : ! propertyName.equals(p.propertyName))
+          return;
+        l = (PropertyChangeListener) p.getListener();
+      }
+    PropertyChangeSupport s = null;
+    if (children == null)
+      children = new Hashtable();
+    else
+      s = (PropertyChangeSupport) children.get(propertyName);
+    if (s == null)
+      {
+        s = new PropertyChangeSupport(source);
+        s.listeners = new Vector();
+        children.put(propertyName, s);
+      }
+    s.listeners.add(l);
+  }
+
+  /**
+   * Removes a PropertyChangeListener from listening to a specific property.
+   * If <code>add()</code> has been called multiple times for a particular
+   * listener on a property, <code>remove()</code> will have to be called the
+   * same number of times to deregister it. This method will unwrap a
+   * PropertyChangeListenerProxy, removing the underlying delegate from the
+   * named property list if the names match.
+   *
+   * @param propertyName the property to stop listening on
+   * @param l the listener to remove
+   * @throws NullPointerException if propertyName is null
+   */
+  public synchronized void
+    removePropertyChangeListener(String propertyName, PropertyChangeListener l)
+  {
+    if (children == null)
+      return;
+    PropertyChangeSupport s
+      = (PropertyChangeSupport) children.get(propertyName);
+    if (s == null)
+      return;
+    while (l instanceof PropertyChangeListenerProxy)
+      {
+        PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l;
+        if (propertyName == null ? p.propertyName != null
+            : ! propertyName.equals(p.propertyName))
+          return;
+        l = (PropertyChangeListener) p.getListener();
+      }
+    s.listeners.remove(l);
+    if (s.listeners.isEmpty())
+      {
+        children.remove(propertyName);
+        if (children.isEmpty())
+          children = null;
+      }
+  }
+
+  /**
+   * Returns an array of all property change listeners registered under the
+   * given property name. If there are no registered listeners, this returns
+   * an empty array.
+   *
+   * @return the array of registered listeners
+   * @throws NullPointerException if propertyName is null
+   * @since 1.4
+   */
+  public synchronized PropertyChangeListener[]
+    getPropertyChangeListeners(String propertyName)
+  {
+    if (children == null)
+      return new PropertyChangeListener[0];
+    PropertyChangeSupport s
+      = (PropertyChangeSupport) children.get(propertyName);
+    if (s == null)
+      return new PropertyChangeListener[0];
+    return (PropertyChangeListener[])
+      s.listeners.toArray(new PropertyChangeListener[s.listeners.size()]);
+  }
+
+  /**
+   * Fire a PropertyChangeEvent containing the old and new values of the
+   * property to all the global listeners, and to all the listeners for the
+   * specified property name. This does nothing if old and new are non-null
+   * and equal.
+   *
+   * @param propertyName the name of the property that changed
+   * @param oldVal the old value
+   * @param newVal the new value
+   */
+  public void firePropertyChange(String propertyName,
+                                 Object oldVal, Object newVal)
+  {
+    firePropertyChange(new PropertyChangeEvent(source, propertyName,
+                                               oldVal, newVal));
+  }
+
+  /**
+   * Fire a PropertyChangeEvent containing the old and new values of the
+   * property to all the global listeners, and to all the listeners for the
+   * specified property name. This does nothing if old and new are equal.
+   *
+   * @param propertyName the name of the property that changed
+   * @param oldVal the old value
+   * @param newVal the new value
+   */
+  public void firePropertyChange(String propertyName, int oldVal, int newVal)
+  {
+    if (oldVal != newVal)
+      firePropertyChange(new PropertyChangeEvent(source, propertyName,
+                                                 new Integer(oldVal),
+                                                 new Integer(newVal)));
+  }
+
+  /**
+   * Fire a PropertyChangeEvent containing the old and new values of the
+   * property to all the global listeners, and to all the listeners for the
+   * specified property name. This does nothing if old and new are equal.
+   *
+   * @param propertyName the name of the property that changed
+   * @param oldVal the old value
+   * @param newVal the new value
+   */
+  public void firePropertyChange(String propertyName,
+                                 boolean oldVal, boolean newVal)
+  {
+    if (oldVal != newVal)
+      firePropertyChange(new PropertyChangeEvent(source, propertyName,
+                                                 Boolean.valueOf(oldVal),
+                                                 Boolean.valueOf(newVal)));
+  }
+
+  /**
+   * Fire a PropertyChangeEvent to all the global listeners, and to all the
+   * listeners for the specified property name. This does nothing if old and
+   * new values of the event are equal.
+   *
+   * @param event the event to fire
+   * @throws NullPointerException if event is null
+   */
+  public void firePropertyChange(PropertyChangeEvent event)
+  {
+    if (event.oldValue != null && event.oldValue.equals(event.newValue))
+      return;
+    Vector v = listeners; // Be thread-safe.
+    if (v != null)
+      {
+        int i = v.size();
+        while (--i >= 0)
+          ((PropertyChangeListener) v.get(i)).propertyChange(event);
+      }
+    Hashtable h = children; // Be thread-safe.
+    if (h != null && event.propertyName != null)
+      {
+        PropertyChangeSupport s
+          = (PropertyChangeSupport) h.get(event.propertyName);
+        if (s != null)
+          {
+            v = s.listeners; // Be thread-safe.
+            int i = v == null ? 0 : v.size();
+            while (--i >= 0)
+              ((PropertyChangeListener) v.get(i)).propertyChange(event);
+          }
+      }
+  }
+
+  /**
+   * Tell whether the specified property is being listened on or not. This
+   * will only return <code>true</code> if there are listeners on all
+   * properties or if there is a listener specifically on this property.
+   *
+   * @param propertyName the property that may be listened on
+   * @return whether the property is being listened on
+   * @throws NullPointerException if propertyName is null
+   */
+  public synchronized boolean hasListeners(String propertyName)
+  {
+    return listeners != null || (children != null
+                                 && children.get(propertyName) != null);
+  }
+
+  /**
+   * Saves the state of the object to the stream.
+   *
+   * @param s the stream to write to
+   * @throws IOException if anything goes wrong
+   * @serialData this writes out a null-terminated list of serializable
+   *             global property change listeners (the listeners for a named
+   *             property are written out as the global listeners of the
+   *             children, when the children hashtable is saved)
+   */
+  private synchronized void writeObject(ObjectOutputStream s)
+    throws IOException
+  {
+    s.defaultWriteObject();
+    if (listeners != null)
+      {
+        int i = listeners.size();
+        while (--i >= 0)
+          if (listeners.get(i) instanceof Serializable)
+            s.writeObject(listeners.get(i));
+      }
+    s.writeObject(null);
+  }
+
+  /**
+   * Reads the object back from stream (deserialization).
+   *
+   * XXX Since serialization for 1.1 streams was not documented, this may
+   * not work if propertyChangeSupportSerializedDataVersion is 1.
+   *
+   * @param s the stream to read from
+   * @throws IOException if reading the stream fails
+   * @throws ClassNotFoundException if deserialization fails
+   * @serialData this reads in a null-terminated list of serializable
+   *             global property change listeners (the listeners for a named
+   *             property are written out as the global listeners of the
+   *             children, when the children hashtable is saved)
+   */
+  private void readObject(ObjectInputStream s)
+    throws IOException, ClassNotFoundException
+  {
+    s.defaultReadObject();
+    PropertyChangeListener l = (PropertyChangeListener) s.readObject();
+    while (l != null)
+      {
+        addPropertyChangeListener(l);
+        l = (PropertyChangeListener) s.readObject();
+      }
+    // Sun is not as careful with children as we are, and lets some proxys
+    // in that can never receive events. So, we clean up anything that got
+    // serialized, to make sure our invariants hold.
+    if (children != null)
+      {
+        int i = children.size();
+        Iterator iter = children.entrySet().iterator();
+        while (--i >= 0)
+          {
+            Entry e = (Entry) iter.next();
+            String name = (String) e.getKey();
+            PropertyChangeSupport pcs = (PropertyChangeSupport) e.getValue();
+            if (pcs.listeners == null)
+              pcs.listeners = new Vector();
+            if (pcs.children != null)
+              pcs.listeners.addAll
+                (Arrays.asList(pcs.getPropertyChangeListeners(name)));
+            if (pcs.listeners.size() == 0)
+              iter.remove();
+            else
+              pcs.children = null;
+          }
+        if (children.size() == 0)
+          children = null;
+      }
+  }
+} // class PropertyChangeSupport
Index: java/beans/VetoableChangeListener.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/VetoableChangeListener.java,v
retrieving revision 1.3
diff -u -r1.3 VetoableChangeListener.java
--- java/beans/VetoableChangeListener.java 22 Jan 2002 22:40:11 -0000 1.3
+++ java/beans/VetoableChangeListener.java 15 Jul 2002 16:03:18 -0000
@@ -1,5 +1,5 @@
-/* java.beans.VetoableChangeListener
-   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+/* VetoableChangeListener.java -- listen for a change which can be vetoed
+   Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 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
@@ -41,37 +41,33 @@
 import java.util.EventListener;
 
 /**
- ** VetoableChangeListener allows a class to monitor
- ** proposed changes to properties of a Bean and, if
- ** desired, prevent them from occurring.<P>
- **
- ** A vetoableChange() event will be fired <EM>before</EM>
- ** the property has changed.  If any listener rejects the
- ** change by throwing the PropertyChangeException, a new
- ** vetoableChange() event will be fired to all listeners
- ** who received a vetoableChange() event in the first
- ** place informing them of a reversion to the old value.
- ** The value, of course, never actually changed.<P>
- **
- ** <STRONG>Note:</STRONG> This class may not be reliably
- ** used to determine whether a property has actually
- ** changed.  Use the PropertyChangeListener interface
- ** for that instead.
- **
- ** @author John Keiser
- ** @version 1.1.0, 29 Jul 1998
- ** @since JDK1.1
- ** @see java.beans.PropertyChangeListener
- ** @see java.beans.VetoableChangeSupport
- **/
-
+ * VetoableChangeListener allows a class to monitor proposed changes to
+ * properties of a Bean and, if desired, prevent them from occurring. A
+ * vetoableChange() event will be fired <em>after</em> the property change has
+ * been requested, but before it is permanent. If any listener rejects the
+ * change by throwing the PropertyChangeException, a new vetoableChange()
+ * event will be fired to all listeners who received a vetoableChange() event
+ * in the first place, informing them to revert back to the old value. Thus,
+ * the listener that threw the exception the first time should be prepared
+ * to rethrow it the second time. The value, of course, never actually changed.
+ *
+ * <p><strong>Note:</strong> This class may not be reliably used to determine
+ * whether a property has actually changed.  Use the PropertyChangeListener
+ * interface for that instead.
+ *
+ * @author John Keiser
+ * @see java.beans.PropertyChangeListener
+ * @see java.beans.VetoableChangeSupport
+ * @since 1.1
+ * @status updated to 1.4
+ */
 public interface VetoableChangeListener extends EventListener
 {
-  /** Fired before a Bean's property changes.
-   ** @param e the change (containing the old and new values)
-   ** @exception PropertyChangeException if the listener
-   **            does not desire the change to be made.
-   **/
-  public abstract void vetoableChange(PropertyChangeEvent e)
-    throws PropertyVetoException;
-}
+  /**
+   * Fired before a Bean's property changes.
+   *
+   * @param e the change (containing the old and new values)
+   * @throws PropertyVetoException if the change is vetoed by the listener
+   */
+  void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException;
+} // interface VetoableChangeListener
Index: java/beans/VetoableChangeListenerProxy.java
===================================================================
RCS file: java/beans/VetoableChangeListenerProxy.java
diff -N java/beans/VetoableChangeListenerProxy.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ java/beans/VetoableChangeListenerProxy.java 15 Jul 2002 16:03:18 -0000
@@ -0,0 +1,102 @@
+/* VetoableChangeListenerProxy.java -- adds a name to a vetoable listener
+   Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.beans;
+
+import java.util.EventListenerProxy;
+
+/**
+ * This class provides an extension to <code>VetoableChangeListener</code> -
+ * associating a name with the listener. This can be used to filter the
+ * changes that one is interested in.
+ *
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.4
+ * @status udpated to 1.4
+ */
+public class VetoableChangeListenerProxy extends EventListenerProxy
+  implements VetoableChangeListener
+{
+  /**
+   * The name of the property to listen for. Package visible for use by
+   * VetoableChangeSupport.
+   */
+  final String propertyName;
+
+  /**
+   * Create a new proxy which filters property change events and only passes
+   * changes to the named property on to the delegate.
+   *
+   * @param propertyName the property's name to filter on
+   * @param listener the delegate listener
+   */
+  public VetoableChangeListenerProxy(String propertyName,
+                                     VetoableChangeListener listener)
+  {
+    super(listener);
+    this.propertyName = propertyName;
+  }
+
+  /**
+   * Forwards the event on to the delegate if the property name matches.
+   *
+   * @param event the event to pass on, if it meets the filter
+   * @throws NullPointerException if the delegate this was created with is null
+   * @throws PropertyVetoException if the change is vetoed by the listener
+   */
+  public void vetoableChange(PropertyChangeEvent event)
+    throws PropertyVetoException
+  {
+    // Note: Sun does not filter, under the assumption that since
+    // VetoableChangeSupport unwraps proxys, this method should never be
+    // called by normal use of listeners.
+    String name = event == null ? null : event.getPropertyName();
+    if (name == null ? propertyName == null : name.equals(propertyName))
+      ((VetoableChangeListener) getListener()).vetoableChange(event);
+  }
+
+  /**
+   * Gets the name of the property this proxy is filtering on.
+   *
+   * @return the property name
+   */
+  public String getPropertyName()
+  {
+    return propertyName;
+  }
+} // class VetoableChangeListenerProxy
Index: java/beans/VetoableChangeSupport.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/beans/VetoableChangeSupport.java,v
retrieving revision 1.4
diff -u -r1.4 VetoableChangeSupport.java
--- java/beans/VetoableChangeSupport.java 22 Jan 2002 22:40:11 -0000 1.4
+++ java/beans/VetoableChangeSupport.java 15 Jul 2002 16:03:18 -0000
@@ -1,5 +1,5 @@
-/* java.beans.VetoableChangeSupport
-   Copyright (C) 1998 Free Software Foundation, Inc.
+/* VetoableChangeSupport.java -- support to manage vetoable change listeners
+   Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 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
@@ -35,265 +35,496 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
+
 package java.beans;
-import java.util.Hashtable;
-import java.util.Vector;
-import java.util.Enumeration;
+
+import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
-import java.io.IOException;
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Vector;
 
 /**
- ** VetoableChangeSupport makes it easy to fire vetoable
- ** change events and handle listeners as well as reversion
- ** of old values when things go wrong.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.2.0, 15 Mar 1998
- **/
-
-public class VetoableChangeSupport implements java.io.Serializable {
-	transient Hashtable propertyListeners = new Hashtable();
-	transient Vector listeners = new Vector();
-	Hashtable children;
-	Object source;
-	int vetoableChangeSupportSerializedDataVersion = 2;
-	private static final long serialVersionUID = -5090210921595982017L;
-
-	/**
-	 * Saves the state of the object to the stream. */
-	private void writeObject(ObjectOutputStream stream) throws IOException {
-		children = propertyListeners.isEmpty() ? null : propertyListeners;
-		stream.defaultWriteObject();
-		for (Enumeration e = listeners.elements(); e.hasMoreElements(); ) {
-			VetoableChangeListener l = (VetoableChangeListener)e.nextElement();
-			if (l instanceof Serializable)
-			  stream.writeObject(l);
-		}
-		stream.writeObject(null);
-	}
-
-	/**
-	 * Reads the object back from stream (deserialization).
-	 */
-	private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
-		stream.defaultReadObject();
-		propertyListeners = (children == null) ? new Hashtable() : children;
-		VetoableChangeListener l;
-		while ((l = (VetoableChangeListener)stream.readObject()) != null) {
-			addVetoableChangeListener(l);
-		}
-		// FIXME: XXX: There is no spec for JDK 1.1 serialization
-		// so it is unclear what to do if the value of
-		// vetoableChangeSupportSerializedDataVersion is 1.
-	}
-
-
-	/** Create VetoableChangeSupport to work with a specific
-	 ** source bean.
-	 ** @param source the source bean to use.
-	 **/
-	public VetoableChangeSupport(Object source) {
-		this.source = source;
-	}
-
-	/** Adds a VetoableChangeListener to the list of listeners.
-	 ** All property change events will be sent to this listener.
-	 ** <P>
-	 **
-	 ** The listener add is not unique: that is, <em>n</em> adds with
-	 ** the same listener will result in <em>n</em> events being sent
-	 ** to that listener for every property change.
-	 ** <P>
-	 **
-	 ** Adding a null listener will cause undefined behavior.
-	 **
-	 ** @param l the listener to add.
-	 **/
-	public void addVetoableChangeListener(VetoableChangeListener l) {
-		listeners.addElement(l);
-	}
-
-	/** Adds a VetoableChangeListener listening on the specified property.
-	 ** Events will be sent to the listener for that particular property.
-	 ** <P>
-	 **
-	 ** The listener add is not unique; that is, <em>n</em> adds on a
-	 ** particular property for a particular listener will result in
-	 ** <em>n</em> events being sent to that listener when that
-	 ** property is changed.
-	 ** <P>
-	 **
-	 ** The effect is cumulative, too; if you are registered to listen
-	 ** to receive events on all property changes, and then you
-	 ** register on a particular property, you will receive change
-	 ** events for that property twice.
-	 ** <P>
-	 **
-	 ** Adding a null listener will cause undefined behavior.
-	 **
-	 ** @param propertyName the name of the property to listen on.
-	 ** @param l the listener to add.
-	 **/
-	public void addVetoableChangeListener(String propertyName, VetoableChangeListener l) {
-		synchronized(propertyListeners) {
-			Vector v = (Vector)propertyListeners.get(propertyName);
-			try {
-				v.addElement(l);
-			} catch(NullPointerException e) {
-				/* If v is not found, create a new vector. */
-				v = new Vector();
-				v.addElement(l);
-				propertyListeners.put(propertyName, v);
-			}
-		}
-	}
-
-	/** Removes a VetoableChangeListener from the list of listeners.
-	 ** If any specific properties are being listened on, they must
-	 ** be deregistered by themselves; this will only remove the
-	 ** general listener to all properties.
-	 ** <P>
-	 **
-	 ** If <code>add()</code> has been called multiple times for a
-	 ** particular listener, <code>remove()</code> will have to be
-	 ** called the same number of times to deregister it.
-	 **
-	 ** @param l the listener to remove.
-	 **/
-	public void removeVetoableChangeListener(VetoableChangeListener l) {
-		listeners.removeElement(l);
-	}
-
-	/** Removes a VetoableChangeListener from listening to a specific property.
-	 ** <P>
-	 **
-	 ** If <code>add()</code> has been called multiple times for a
-	 ** particular listener on a property, <code>remove()</code> will
-	 ** have to be called the same number of times to deregister it.
-	 **
-	 ** @param propertyName the property to stop listening on.
-	 ** @param l the listener to remove.
-	 **/
-	public void removeVetoableChangeListener(String propertyName, VetoableChangeListener l) {
-		synchronized(propertyListeners) {
-			Vector v = (Vector)propertyListeners.get(propertyName);
-			try {
-				v.removeElement(l);
-				if(v.size() == 0) {
-					propertyListeners.remove(propertyName);
-				}
-			} catch(NullPointerException e) {
-				/* if v is not found, do nothing. */
-			}
-		}
-	}
-
-
-	/** Fire a VetoableChangeEvent to all the listeners.
-	 ** If any listener objects, a reversion event will be sent to
-	 ** those listeners who received the initial event.
-	 **
-	 ** @param proposedChange the event to send.
-	 ** @exception PropertyVetoException if the change is vetoed.
-	 **/
-	public void fireVetoableChange(PropertyChangeEvent proposedChange) throws PropertyVetoException {
-		int currentListener=0;
-		try {
-			for(;currentListener<listeners.size();currentListener++) {
-				((VetoableChangeListener)listeners.elementAt(currentListener)).vetoableChange(proposedChange);
-			}
-		} catch(PropertyVetoException e) {
-			PropertyChangeEvent reversion = new PropertyChangeEvent(proposedChange.getSource(),proposedChange.getPropertyName(),proposedChange.getNewValue(),proposedChange.getOldValue());
-			for(int sendAgain=0;sendAgain<currentListener;sendAgain++) {
-				try {
-					((VetoableChangeListener)listeners.elementAt(sendAgain)).vetoableChange(reversion);
-				} catch(PropertyVetoException e2) {
-				}
-			}
-			throw e;
-		}
-
-		Vector moreListeners = (Vector)propertyListeners.get(proposedChange.getPropertyName());
-		if(moreListeners != null) {
-			try {
-				for(currentListener = 0; currentListener < moreListeners.size(); currentListener++) {
-					((VetoableChangeListener)moreListeners.elementAt(currentListener)).vetoableChange(proposedChange);
-				}
-			} catch(PropertyVetoException e) {
-				PropertyChangeEvent reversion = new PropertyChangeEvent(proposedChange.getSource(),proposedChange.getPropertyName(),proposedChange.getNewValue(),proposedChange.getOldValue());
-				for(int sendAgain=0;sendAgain<listeners.size();sendAgain++) {
-					try {
-						((VetoableChangeListener)listeners.elementAt(currentListener)).vetoableChange(proposedChange);
-					} catch(PropertyVetoException e2) {		
-					}
-				}
-
-				for(int sendAgain=0;sendAgain<currentListener;sendAgain++) {
-					try {
-						((VetoableChangeListener)moreListeners.elementAt(sendAgain)).vetoableChange(reversion);
-					} catch(PropertyVetoException e2) {
-					}
-				}
-				throw e;
-			}
-		}
-	}
-
-	/** Fire a VetoableChangeEvent containing the old and new values of the property to all the listeners.
-	 ** If any listener objects, a reversion event will be sent to
-	 ** those listeners who received the initial event.
-	 **
-	 ** @param propertyName the name of the property that
-	 ** changed.
-	 ** @param oldVal the old value.
-	 ** @param newVal the new value.
-	 ** @exception PropertyVetoException if the change is vetoed.
-	 **/
-	public void fireVetoableChange(String propertyName, Object oldVal, Object newVal) throws PropertyVetoException {
-		fireVetoableChange(new PropertyChangeEvent(source,propertyName,oldVal,newVal));
-	}
-
-	/** Fire a VetoableChangeEvent containing the old and new values of the property to all the listeners.
-	 ** If any listener objects, a reversion event will be sent to
-	 ** those listeners who received the initial event.
-	 **
-	 ** @param propertyName the name of the property that
-	 ** changed.
-	 ** @param oldVal the old value.
-	 ** @param newVal the new value.
-	 ** @exception PropertyVetoException if the change is vetoed.
-	 **/
-	public void fireVetoableChange(String propertyName, boolean oldVal, boolean newVal) throws PropertyVetoException {
-		fireVetoableChange(new PropertyChangeEvent(source,propertyName,new Boolean(oldVal),new Boolean(newVal)));
-	}
-
-	/** Fire a VetoableChangeEvent containing the old and new values of the property to all the listeners.
-	 ** If any listener objects, a reversion event will be sent to
-	 ** those listeners who received the initial event.
-	 **
-	 ** @param propertyName the name of the property that
-	 ** changed.
-	 ** @param oldVal the old value.
-	 ** @param newVal the new value.
-	 ** @exception PropertyVetoException if the change is vetoed.
-	 **/
-	public void fireVetoableChange(String propertyName, int oldVal, int newVal) throws PropertyVetoException {
-		fireVetoableChange(new PropertyChangeEvent(source,propertyName,new Integer(oldVal),new Integer(newVal)));
-	}
-
-
-	/** Tell whether the specified property is being listened on or not.
-	 ** This will only return <code>true</code> if there are listeners
-	 ** on all properties or if there is a listener specifically on this
-	 ** property.
-	 **
-	 ** @param propertyName the property that may be listened on
-	 ** @return whether the property is being listened on
-	 **/
-	public boolean hasListeners(String propertyName) {
-		return listeners.size() > 0  || propertyListeners.get(propertyName) != null;
-	}
-}
+ * VetoableChangeSupport makes it easy to fire vetoable change events and
+ * handle listeners. It allows chaining of listeners, as well as filtering
+ * by property name. In addition, it will serialize only those listeners
+ * which are serializable, ignoring the others without problem. This class
+ * is thread-safe.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class VetoableChangeSupport implements Serializable
+{
+  /**
+   * Compatible with JDK 1.1+.
+   */
+  private static final long serialVersionUID = -5090210921595982017L;
+
+  /**
+   * Maps property names (String) to named listeners (VetoableChangeSupport).
+   * If this is a child instance, this field will be null.
+   *
+   * @serial the map of property names to named listener managers
+   * @since 1.2
+   */
+  private Hashtable children;
+
+  /**
+   * The non-null source object for any generated events.
+   *
+   * @serial the event source
+   */
+  private final Object source;
+
+  /**
+   * A field to compare serialization versions - this class uses version 2.
+   *
+   * @serial the serialization format
+   */
+  private final int vetoableChangeSupportSerializedDataVersion = 2;
+
+  /**
+   * The list of all registered vetoable listeners. If this instance was
+   * created by user code, this only holds the global listeners (ie. not tied
+   * to a name), and may be null. If it was created by this class, as a
+   * helper for named properties, then this vector will be non-null, and this
+   * instance appears as a value in the <code>children</code> hashtable of
+   * another instance, so that the listeners are tied to the key of that
+   * hashtable entry.
+   */
+  private transient Vector listeners;
+
+  /**
+   * Create a VetoableChangeSupport to work with a specific source bean.
+   *
+   * @param source the source bean to use
+   * @throws NullPointerException if source is null
+   */
+  public VetoableChangeSupport(Object source)
+  {
+    this.source = source;
+    if (source == null)
+      throw new NullPointerException();
+  }
+
+  /**
+   * Adds a VetoableChangeListener to the list of global listeners. All
+   * vetoable change events will be sent to this listener. The listener add
+   * is not unique: that is, <em>n</em> adds with the same listener will
+   * result in <em>n</em> events being sent to that listener for every
+   * vetoable change. Adding a null listener may cause a NullPointerException
+   * down the road. This method will unwrap a VetoableChangeListenerProxy,
+   * registering the underlying delegate to the named property list.
+   *
+   * @param l the listener to add
+   */
+  public synchronized void addVetoableChangeListener(VetoableChangeListener l)
+  {
+    if (l instanceof VetoableChangeListenerProxy)
+      {
+        VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+        addVetoableChangeListener(p.propertyName,
+                                  (VetoableChangeListener) p.getListener());
+      }
+    else
+      {
+        if (listeners == null)
+          listeners = new Vector();
+        listeners.add(l);
+      }
+  }
+
+  /**
+   * Removes a VetoableChangeListener from the list of global listeners. If
+   * any specific properties are being listened on, they must be deregistered
+   * by themselves; this will only remove the general listener to all
+   * properties. If <code>add()</code> has been called multiple times for a
+   * particular listener, <code>remove()</code> will have to be called the
+   * same number of times to deregister it. This method will unwrap a
+   * VetoableChangeListenerProxy, removing the underlying delegate from the
+   * named property list.
+   *
+   * @param l the listener to remove
+   */
+  public synchronized void
+    removeVetoableChangeListener(VetoableChangeListener l)
+  {
+    if (l instanceof VetoableChangeListenerProxy)
+      {
+        VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+        removeVetoableChangeListener(p.propertyName,
+                                     (VetoableChangeListener) p.getListener());
+      }
+    else if (listeners != null)
+      {
+        listeners.remove(l);
+        if (listeners.isEmpty())
+          listeners = null;
+      }
+  }
+
+  /**
+   * Returns an array of all registered vetoable change listeners. Those that
+   * were registered under a name will be wrapped in a
+   * <code>VetoableChangeListenerProxy</code>, so you must check whether the
+   * listener is an instance of the proxy class in order to see what name the
+   * real listener is registered under. If there are no registered listeners,
+   * this returns an empty array.
+   *
+   * @return the array of registered listeners
+   * @see VetoableChangeListenerProxy
+   * @since 1.4
+   */
+  public synchronized VetoableChangeListener[] getVetoableChangeListeners()
+  {
+    ArrayList list = new ArrayList();
+    if (listeners != null)
+      list.addAll(listeners);
+    if (children != null)
+      {
+        int i = children.size();
+        Iterator iter = children.entrySet().iterator();
+        while (--i >= 0)
+          {
+            Entry e = (Entry) iter.next();
+            String name = (String) e.getKey();
+            Vector v = ((VetoableChangeSupport) e.getValue()).listeners;
+            int j = v.size();
+            while (--j >= 0)
+              list.add(new VetoableChangeListenerProxy
+                (name, (VetoableChangeListener) v.get(j)));
+          }
+      }
+    return (VetoableChangeListener[])
+      list.toArray(new VetoableChangeListener[list.size()]);
+  }
+
+  /**
+   * Adds a VetoableChangeListener listening on the specified property. Events
+   * will be sent to the listener only if the property name matches. The
+   * listener add is not unique; that is, <em>n</em> adds on a particular
+   * property for a particular listener will result in <em>n</em> events
+   * being sent to that listener when that property is changed. The effect is
+   * cumulative, too; if you are registered to listen to receive events on
+   * all vetoable changes, and then you register on a particular property,
+   * you will receive change events for that property twice. Adding a null
+   * listener may cause a NullPointerException down the road. This method
+   * will unwrap a VetoableChangeListenerProxy, registering the underlying
+   * delegate to the named property list if the names match, and discarding
+   * it otherwise.
+   *
+   * @param propertyName the name of the property to listen on
+   * @param l the listener to add
+   * @throws NullPointerException if propertyName is null
+   */
+  public synchronized void addVetoableChangeListener(String propertyName,
+                                                     VetoableChangeListener l)
+  {
+    while (l instanceof VetoableChangeListenerProxy)
+      {
+        VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+        if (propertyName == null ? p.propertyName != null
+            : ! propertyName.equals(p.propertyName))
+          return;
+        l = (VetoableChangeListener) p.getListener();
+      }
+    VetoableChangeSupport s = null;
+    if (children == null)
+      children = new Hashtable();
+    else
+      s = (VetoableChangeSupport) children.get(propertyName);
+    if (s == null)
+      {
+        s = new VetoableChangeSupport(source);
+        s.listeners = new Vector();
+        children.put(propertyName, s);
+      }
+    s.listeners.add(l);
+  }
+
+  /**
+   * Removes a VetoableChangeListener from listening to a specific property.
+   * If <code>add()</code> has been called multiple times for a particular
+   * listener on a property, <code>remove()</code> will have to be called the
+   * same number of times to deregister it. This method will unwrap a
+   * VetoableChangeListenerProxy, removing the underlying delegate from the
+   * named property list if the names match.
+   *
+   * @param propertyName the property to stop listening on
+   * @param l the listener to remove
+   * @throws NullPointerException if propertyName is null
+   */
+  public synchronized void
+    removeVetoableChangeListener(String propertyName, VetoableChangeListener l)
+  {
+    if (children == null)
+      return;
+    VetoableChangeSupport s
+      = (VetoableChangeSupport) children.get(propertyName);
+    if (s == null)
+      return;
+    while (l instanceof VetoableChangeListenerProxy)
+      {
+        VetoableChangeListenerProxy p = (VetoableChangeListenerProxy) l;
+        if (propertyName == null ? p.propertyName != null
+            : ! propertyName.equals(p.propertyName))
+          return;
+        l = (VetoableChangeListener) p.getListener();
+      }
+    s.listeners.remove(l);
+    if (s.listeners.isEmpty())
+      {
+        children.remove(propertyName);
+        if (children.isEmpty())
+          children = null;
+      }
+  }
+
+  /**
+   * Returns an array of all vetoable change listeners registered under the
+   * given property name. If there are no registered listeners, this returns
+   * an empty array.
+   *
+   * @return the array of registered listeners
+   * @throws NullPointerException if propertyName is null
+   * @since 1.4
+   */
+  public synchronized VetoableChangeListener[]
+    getVetoableChangeListeners(String propertyName)
+  {
+    if (children == null)
+      return new VetoableChangeListener[0];
+    VetoableChangeSupport s
+      = (VetoableChangeSupport) children.get(propertyName);
+    if (s == null)
+      return new VetoableChangeListener[0];
+    return (VetoableChangeListener[])
+      s.listeners.toArray(new VetoableChangeListener[s.listeners.size()]);
+  }
+
+  /**
+   * Fire a PropertyChangeEvent containing the old and new values of the
+   * property to all the global listeners, and to all the listeners for the
+   * specified property name. This does nothing if old and new are non-null
+   * and equal. If the change is vetoed, a new event is fired to notify
+   * listeners about the rollback before the exception is thrown.
+   *
+   * @param propertyName the name of the property that changed
+   * @param oldVal the old value
+   * @param newVal the new value
+   * @throws PropertyVetoException if the change is vetoed by a listener
+   */
+  public void fireVetoableChange(String propertyName,
+                                 Object oldVal, Object newVal)
+    throws PropertyVetoException
+  {
+    fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+                                               oldVal, newVal));
+  }
+
+  /**
+   * Fire a PropertyChangeEvent containing the old and new values of the
+   * property to all the global listeners, and to all the listeners for the
+   * specified property name. This does nothing if old and new are equal.
+   * If the change is vetoed, a new event is fired to notify listeners about
+   * the rollback before the exception is thrown.
+   *
+   * @param propertyName the name of the property that changed
+   * @param oldVal the old value
+   * @param newVal the new value
+   * @throws PropertyVetoException if the change is vetoed by a listener
+   */
+  public void fireVetoableChange(String propertyName, int oldVal, int newVal)
+    throws PropertyVetoException
+  {
+    if (oldVal != newVal)
+      fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+                                                 new Integer(oldVal),
+                                                 new Integer(newVal)));
+  }
+
+  /**
+   * Fire a PropertyChangeEvent containing the old and new values of the
+   * property to all the global listeners, and to all the listeners for the
+   * specified property name. This does nothing if old and new are equal.
+   * If the change is vetoed, a new event is fired to notify listeners about
+   * the rollback before the exception is thrown.
+   *
+   * @param propertyName the name of the property that changed
+   * @param oldVal the old value
+   * @param newVal the new value
+   * @throws PropertyVetoException if the change is vetoed by a listener
+   */
+  public void fireVetoableChange(String propertyName,
+                                 boolean oldVal, boolean newVal)
+    throws PropertyVetoException
+  {
+    if (oldVal != newVal)
+      fireVetoableChange(new PropertyChangeEvent(source, propertyName,
+                                                 Boolean.valueOf(oldVal),
+                                                 Boolean.valueOf(newVal)));
+  }
+
+  /**
+   * Fire a PropertyChangeEvent to all the global listeners, and to all the
+   * listeners for the specified property name. This does nothing if old and
+   * new values of the event are equal. If the change is vetoed, a new event
+   * is fired to notify listeners about the rollback before the exception is
+   * thrown.
+   *
+   * @param event the event to fire
+   * @throws NullPointerException if event is null
+   * @throws PropertyVetoException if the change is vetoed by a listener
+   */
+  public void fireVetoableChange(PropertyChangeEvent event)
+    throws PropertyVetoException
+  {
+    if (event.oldValue != null && event.oldValue.equals(event.newValue))
+      return;
+    Vector v = listeners; // Be thread-safe.
+    if (v != null)
+      {
+        int i = v.size();
+        try
+          {
+            while (--i >= 0)
+              ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+          }
+        catch (PropertyVetoException e)
+          {
+            event = event.rollback();
+            int limit = i;
+            i = v.size();
+            while (--i >= limit)
+              ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+            throw e;
+          }
+      }
+    Hashtable h = children; // Be thread-safe.
+    if (h != null && event.propertyName != null)
+      {
+        VetoableChangeSupport s
+          = (VetoableChangeSupport) h.get(event.propertyName);
+        if (s != null)
+          {
+            Vector v1 = s.listeners; // Be thread-safe.
+            int i = v1 == null ? 0 : v1.size();
+            try
+              {
+                while (--i >= 0)
+                  ((VetoableChangeListener) v1.get(i)).vetoableChange(event);
+              }
+            catch (PropertyVetoException e)
+              {
+                event = event.rollback();
+                int limit = i;
+                i = v.size();
+                while (--i >= 0)
+                  ((VetoableChangeListener) v.get(i)).vetoableChange(event);
+                i = v1.size();
+                while (--i >= limit)
+                  ((VetoableChangeListener) v1.get(i)).vetoableChange(event);
+                throw e;
+              }
+          }
+      }
+  }
+
+  /**
+   * Tell whether the specified property is being listened on or not. This
+   * will only return <code>true</code> if there are listeners on all
+   * properties or if there is a listener specifically on this property.
+   *
+   * @param propertyName the property that may be listened on
+   * @return whether the property is being listened on
+   * @throws NullPointerException if propertyName is null
+   */
+  public synchronized boolean hasListeners(String propertyName)
+  {
+    return listeners != null || (children != null
+                                 && children.get(propertyName) != null);
+  }
+
+  /**
+   * Saves the state of the object to the stream.
+   *
+   * @param s the stream to write to
+   * @throws IOException if anything goes wrong
+   * @serialData this writes out a null-terminated list of serializable
+   *             global vetoable change listeners (the listeners for a named
+   *             property are written out as the global listeners of the
+   *             children, when the children hashtable is saved)
+   */
+  private synchronized void writeObject(ObjectOutputStream s)
+    throws IOException
+  {
+    s.defaultWriteObject();
+    if (listeners != null)
+      {
+        int i = listeners.size();
+        while (--i >= 0)
+          if (listeners.get(i) instanceof Serializable)
+            s.writeObject(listeners.get(i));
+      }
+    s.writeObject(null);
+  }
+
+  /**
+   * Reads the object back from stream (deserialization).
+   *
+   * XXX Since serialization for 1.1 streams was not documented, this may
+   * not work if vetoableChangeSupportSerializedDataVersion is 1.
+   *
+   * @param s the stream to read from
+   * @throws IOException if reading the stream fails
+   * @throws ClassNotFoundException if deserialization fails
+   * @serialData this reads in a null-terminated list of serializable
+   *             global vetoable change listeners (the listeners for a named
+   *             property are written out as the global listeners of the
+   *             children, when the children hashtable is saved)
+   */
+  private void readObject(ObjectInputStream s)
+    throws IOException, ClassNotFoundException
+  {
+    s.defaultReadObject();
+    VetoableChangeListener l = (VetoableChangeListener) s.readObject();
+    while (l != null)
+      {
+        addVetoableChangeListener(l);
+        l = (VetoableChangeListener) s.readObject();
+      }
+    // Sun is not as careful with children as we are, and lets some proxys
+    // in that can never receive events. So, we clean up anything that got
+    // serialized, to make sure our invariants hold.
+    if (children != null)
+      {
+        int i = children.size();
+        Iterator iter = children.entrySet().iterator();
+        while (--i >= 0)
+          {
+            Entry e = (Entry) iter.next();
+            String name = (String) e.getKey();
+            VetoableChangeSupport vcs = (VetoableChangeSupport) e.getValue();
+            if (vcs.listeners == null)
+              vcs.listeners = new Vector();
+            if (vcs.children != null)
+              vcs.listeners.addAll
+                (Arrays.asList(vcs.getVetoableChangeListeners(name)));
+            if (vcs.listeners.size() == 0)
+              iter.remove();
+            else
+              vcs.children = null;
+          }
+        if (children.size() == 0)
+          children = null;
+      }
+  }
+} // class VetoableChangeSupport



More information about the Java-patches mailing list