1.1 --- a/emul/compact/src/main/java/java/beans/PropertyChangeSupport.java Mon Feb 25 19:00:08 2013 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,536 +0,0 @@
1.4 -/*
1.5 - * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
1.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 - *
1.8 - * This code is free software; you can redistribute it and/or modify it
1.9 - * under the terms of the GNU General Public License version 2 only, as
1.10 - * published by the Free Software Foundation. Oracle designates this
1.11 - * particular file as subject to the "Classpath" exception as provided
1.12 - * by Oracle in the LICENSE file that accompanied this code.
1.13 - *
1.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 - * version 2 for more details (a copy is included in the LICENSE file that
1.18 - * accompanied this code).
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License version
1.21 - * 2 along with this work; if not, write to the Free Software Foundation,
1.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 - *
1.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 - * or visit www.oracle.com if you need additional information or have any
1.26 - * questions.
1.27 - */
1.28 -package java.beans;
1.29 -
1.30 -import java.io.Serializable;
1.31 -import java.io.ObjectStreamField;
1.32 -import java.io.ObjectOutputStream;
1.33 -import java.io.ObjectInputStream;
1.34 -import java.io.IOException;
1.35 -import java.util.Hashtable;
1.36 -import java.util.Map.Entry;
1.37 -
1.38 -/**
1.39 - * This is a utility class that can be used by beans that support bound
1.40 - * properties. It manages a list of listeners and dispatches
1.41 - * {@link PropertyChangeEvent}s to them. You can use an instance of this class
1.42 - * as a member field of your bean and delegate these types of work to it.
1.43 - * The {@link PropertyChangeListener} can be registered for all properties
1.44 - * or for a property specified by name.
1.45 - * <p>
1.46 - * Here is an example of {@code PropertyChangeSupport} usage that follows
1.47 - * the rules and recommendations laid out in the JavaBeans™ specification:
1.48 - * <pre>
1.49 - * public class MyBean {
1.50 - * private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
1.51 - *
1.52 - * public void addPropertyChangeListener(PropertyChangeListener listener) {
1.53 - * this.pcs.addPropertyChangeListener(listener);
1.54 - * }
1.55 - *
1.56 - * public void removePropertyChangeListener(PropertyChangeListener listener) {
1.57 - * this.pcs.removePropertyChangeListener(listener);
1.58 - * }
1.59 - *
1.60 - * private String value;
1.61 - *
1.62 - * public String getValue() {
1.63 - * return this.value;
1.64 - * }
1.65 - *
1.66 - * public void setValue(String newValue) {
1.67 - * String oldValue = this.value;
1.68 - * this.value = newValue;
1.69 - * this.pcs.firePropertyChange("value", oldValue, newValue);
1.70 - * }
1.71 - *
1.72 - * [...]
1.73 - * }
1.74 - * </pre>
1.75 - * <p>
1.76 - * A {@code PropertyChangeSupport} instance is thread-safe.
1.77 - * <p>
1.78 - * This class is serializable. When it is serialized it will save
1.79 - * (and restore) any listeners that are themselves serializable. Any
1.80 - * non-serializable listeners will be skipped during serialization.
1.81 - *
1.82 - * @see VetoableChangeSupport
1.83 - */
1.84 -public class PropertyChangeSupport implements Serializable {
1.85 - private PropertyChangeListenerMap map = new PropertyChangeListenerMap();
1.86 -
1.87 - /**
1.88 - * Constructs a <code>PropertyChangeSupport</code> object.
1.89 - *
1.90 - * @param sourceBean The bean to be given as the source for any events.
1.91 - */
1.92 - public PropertyChangeSupport(Object sourceBean) {
1.93 - if (sourceBean == null) {
1.94 - throw new NullPointerException();
1.95 - }
1.96 - source = sourceBean;
1.97 - }
1.98 -
1.99 - /**
1.100 - * Add a PropertyChangeListener to the listener list.
1.101 - * The listener is registered for all properties.
1.102 - * The same listener object may be added more than once, and will be called
1.103 - * as many times as it is added.
1.104 - * If <code>listener</code> is null, no exception is thrown and no action
1.105 - * is taken.
1.106 - *
1.107 - * @param listener The PropertyChangeListener to be added
1.108 - */
1.109 - public void addPropertyChangeListener(PropertyChangeListener listener) {
1.110 - if (listener == null) {
1.111 - return;
1.112 - }
1.113 - if (listener instanceof PropertyChangeListenerProxy) {
1.114 - PropertyChangeListenerProxy proxy =
1.115 - (PropertyChangeListenerProxy)listener;
1.116 - // Call two argument add method.
1.117 - addPropertyChangeListener(proxy.getPropertyName(),
1.118 - proxy.getListener());
1.119 - } else {
1.120 - this.map.add(null, listener);
1.121 - }
1.122 - }
1.123 -
1.124 - /**
1.125 - * Remove a PropertyChangeListener from the listener list.
1.126 - * This removes a PropertyChangeListener that was registered
1.127 - * for all properties.
1.128 - * If <code>listener</code> was added more than once to the same event
1.129 - * source, it will be notified one less time after being removed.
1.130 - * If <code>listener</code> is null, or was never added, no exception is
1.131 - * thrown and no action is taken.
1.132 - *
1.133 - * @param listener The PropertyChangeListener to be removed
1.134 - */
1.135 - public void removePropertyChangeListener(PropertyChangeListener listener) {
1.136 - if (listener == null) {
1.137 - return;
1.138 - }
1.139 - if (listener instanceof PropertyChangeListenerProxy) {
1.140 - PropertyChangeListenerProxy proxy =
1.141 - (PropertyChangeListenerProxy)listener;
1.142 - // Call two argument remove method.
1.143 - removePropertyChangeListener(proxy.getPropertyName(),
1.144 - proxy.getListener());
1.145 - } else {
1.146 - this.map.remove(null, listener);
1.147 - }
1.148 - }
1.149 -
1.150 - /**
1.151 - * Returns an array of all the listeners that were added to the
1.152 - * PropertyChangeSupport object with addPropertyChangeListener().
1.153 - * <p>
1.154 - * If some listeners have been added with a named property, then
1.155 - * the returned array will be a mixture of PropertyChangeListeners
1.156 - * and <code>PropertyChangeListenerProxy</code>s. If the calling
1.157 - * method is interested in distinguishing the listeners then it must
1.158 - * test each element to see if it's a
1.159 - * <code>PropertyChangeListenerProxy</code>, perform the cast, and examine
1.160 - * the parameter.
1.161 - *
1.162 - * <pre>
1.163 - * PropertyChangeListener[] listeners = bean.getPropertyChangeListeners();
1.164 - * for (int i = 0; i < listeners.length; i++) {
1.165 - * if (listeners[i] instanceof PropertyChangeListenerProxy) {
1.166 - * PropertyChangeListenerProxy proxy =
1.167 - * (PropertyChangeListenerProxy)listeners[i];
1.168 - * if (proxy.getPropertyName().equals("foo")) {
1.169 - * // proxy is a PropertyChangeListener which was associated
1.170 - * // with the property named "foo"
1.171 - * }
1.172 - * }
1.173 - * }
1.174 - *</pre>
1.175 - *
1.176 - * @see PropertyChangeListenerProxy
1.177 - * @return all of the <code>PropertyChangeListeners</code> added or an
1.178 - * empty array if no listeners have been added
1.179 - * @since 1.4
1.180 - */
1.181 - public PropertyChangeListener[] getPropertyChangeListeners() {
1.182 - return this.map.getListeners();
1.183 - }
1.184 -
1.185 - /**
1.186 - * Add a PropertyChangeListener for a specific property. The listener
1.187 - * will be invoked only when a call on firePropertyChange names that
1.188 - * specific property.
1.189 - * The same listener object may be added more than once. For each
1.190 - * property, the listener will be invoked the number of times it was added
1.191 - * for that property.
1.192 - * If <code>propertyName</code> or <code>listener</code> is null, no
1.193 - * exception is thrown and no action is taken.
1.194 - *
1.195 - * @param propertyName The name of the property to listen on.
1.196 - * @param listener The PropertyChangeListener to be added
1.197 - */
1.198 - public void addPropertyChangeListener(
1.199 - String propertyName,
1.200 - PropertyChangeListener listener) {
1.201 - if (listener == null || propertyName == null) {
1.202 - return;
1.203 - }
1.204 - listener = this.map.extract(listener);
1.205 - if (listener != null) {
1.206 - this.map.add(propertyName, listener);
1.207 - }
1.208 - }
1.209 -
1.210 - /**
1.211 - * Remove a PropertyChangeListener for a specific property.
1.212 - * If <code>listener</code> was added more than once to the same event
1.213 - * source for the specified property, it will be notified one less time
1.214 - * after being removed.
1.215 - * If <code>propertyName</code> is null, no exception is thrown and no
1.216 - * action is taken.
1.217 - * If <code>listener</code> is null, or was never added for the specified
1.218 - * property, no exception is thrown and no action is taken.
1.219 - *
1.220 - * @param propertyName The name of the property that was listened on.
1.221 - * @param listener The PropertyChangeListener to be removed
1.222 - */
1.223 - public void removePropertyChangeListener(
1.224 - String propertyName,
1.225 - PropertyChangeListener listener) {
1.226 - if (listener == null || propertyName == null) {
1.227 - return;
1.228 - }
1.229 - listener = this.map.extract(listener);
1.230 - if (listener != null) {
1.231 - this.map.remove(propertyName, listener);
1.232 - }
1.233 - }
1.234 -
1.235 - /**
1.236 - * Returns an array of all the listeners which have been associated
1.237 - * with the named property.
1.238 - *
1.239 - * @param propertyName The name of the property being listened to
1.240 - * @return all of the <code>PropertyChangeListeners</code> associated with
1.241 - * the named property. If no such listeners have been added,
1.242 - * or if <code>propertyName</code> is null, an empty array is
1.243 - * returned.
1.244 - * @since 1.4
1.245 - */
1.246 - public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
1.247 - return this.map.getListeners(propertyName);
1.248 - }
1.249 -
1.250 - /**
1.251 - * Reports a bound property update to listeners
1.252 - * that have been registered to track updates of
1.253 - * all properties or a property with the specified name.
1.254 - * <p>
1.255 - * No event is fired if old and new values are equal and non-null.
1.256 - * <p>
1.257 - * This is merely a convenience wrapper around the more general
1.258 - * {@link #firePropertyChange(PropertyChangeEvent)} method.
1.259 - *
1.260 - * @param propertyName the programmatic name of the property that was changed
1.261 - * @param oldValue the old value of the property
1.262 - * @param newValue the new value of the property
1.263 - */
1.264 - public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
1.265 - if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
1.266 - firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
1.267 - }
1.268 - }
1.269 -
1.270 - /**
1.271 - * Reports an integer bound property update to listeners
1.272 - * that have been registered to track updates of
1.273 - * all properties or a property with the specified name.
1.274 - * <p>
1.275 - * No event is fired if old and new values are equal.
1.276 - * <p>
1.277 - * This is merely a convenience wrapper around the more general
1.278 - * {@link #firePropertyChange(String, Object, Object)} method.
1.279 - *
1.280 - * @param propertyName the programmatic name of the property that was changed
1.281 - * @param oldValue the old value of the property
1.282 - * @param newValue the new value of the property
1.283 - */
1.284 - public void firePropertyChange(String propertyName, int oldValue, int newValue) {
1.285 - if (oldValue != newValue) {
1.286 - firePropertyChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue));
1.287 - }
1.288 - }
1.289 -
1.290 - /**
1.291 - * Reports a boolean bound property update to listeners
1.292 - * that have been registered to track updates of
1.293 - * all properties or a property with the specified name.
1.294 - * <p>
1.295 - * No event is fired if old and new values are equal.
1.296 - * <p>
1.297 - * This is merely a convenience wrapper around the more general
1.298 - * {@link #firePropertyChange(String, Object, Object)} method.
1.299 - *
1.300 - * @param propertyName the programmatic name of the property that was changed
1.301 - * @param oldValue the old value of the property
1.302 - * @param newValue the new value of the property
1.303 - */
1.304 - public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
1.305 - if (oldValue != newValue) {
1.306 - firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
1.307 - }
1.308 - }
1.309 -
1.310 - /**
1.311 - * Fires a property change event to listeners
1.312 - * that have been registered to track updates of
1.313 - * all properties or a property with the specified name.
1.314 - * <p>
1.315 - * No event is fired if the given event's old and new values are equal and non-null.
1.316 - *
1.317 - * @param event the {@code PropertyChangeEvent} to be fired
1.318 - */
1.319 - public void firePropertyChange(PropertyChangeEvent event) {
1.320 - Object oldValue = event.getOldValue();
1.321 - Object newValue = event.getNewValue();
1.322 - if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
1.323 - String name = event.getPropertyName();
1.324 -
1.325 - PropertyChangeListener[] common = this.map.get(null);
1.326 - PropertyChangeListener[] named = (name != null)
1.327 - ? this.map.get(name)
1.328 - : null;
1.329 -
1.330 - fire(common, event);
1.331 - fire(named, event);
1.332 - }
1.333 - }
1.334 -
1.335 - private static void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) {
1.336 - if (listeners != null) {
1.337 - for (PropertyChangeListener listener : listeners) {
1.338 - listener.propertyChange(event);
1.339 - }
1.340 - }
1.341 - }
1.342 -
1.343 - /**
1.344 - * Reports a bound indexed property update to listeners
1.345 - * that have been registered to track updates of
1.346 - * all properties or a property with the specified name.
1.347 - * <p>
1.348 - * No event is fired if old and new values are equal and non-null.
1.349 - * <p>
1.350 - * This is merely a convenience wrapper around the more general
1.351 - * {@link #firePropertyChange(PropertyChangeEvent)} method.
1.352 - *
1.353 - * @param propertyName the programmatic name of the property that was changed
1.354 - * @param index the index of the property element that was changed
1.355 - * @param oldValue the old value of the property
1.356 - * @param newValue the new value of the property
1.357 - * @since 1.5
1.358 - */
1.359 - public void fireIndexedPropertyChange(String propertyName, int index, Object oldValue, Object newValue) {
1.360 - if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
1.361 - firePropertyChange(new IndexedPropertyChangeEvent(source, propertyName, oldValue, newValue, index));
1.362 - }
1.363 - }
1.364 -
1.365 - /**
1.366 - * Reports an integer bound indexed property update to listeners
1.367 - * that have been registered to track updates of
1.368 - * all properties or a property with the specified name.
1.369 - * <p>
1.370 - * No event is fired if old and new values are equal.
1.371 - * <p>
1.372 - * This is merely a convenience wrapper around the more general
1.373 - * {@link #fireIndexedPropertyChange(String, int, Object, Object)} method.
1.374 - *
1.375 - * @param propertyName the programmatic name of the property that was changed
1.376 - * @param index the index of the property element that was changed
1.377 - * @param oldValue the old value of the property
1.378 - * @param newValue the new value of the property
1.379 - * @since 1.5
1.380 - */
1.381 - public void fireIndexedPropertyChange(String propertyName, int index, int oldValue, int newValue) {
1.382 - if (oldValue != newValue) {
1.383 - fireIndexedPropertyChange(propertyName, index, Integer.valueOf(oldValue), Integer.valueOf(newValue));
1.384 - }
1.385 - }
1.386 -
1.387 - /**
1.388 - * Reports a boolean bound indexed property update to listeners
1.389 - * that have been registered to track updates of
1.390 - * all properties or a property with the specified name.
1.391 - * <p>
1.392 - * No event is fired if old and new values are equal.
1.393 - * <p>
1.394 - * This is merely a convenience wrapper around the more general
1.395 - * {@link #fireIndexedPropertyChange(String, int, Object, Object)} method.
1.396 - *
1.397 - * @param propertyName the programmatic name of the property that was changed
1.398 - * @param index the index of the property element that was changed
1.399 - * @param oldValue the old value of the property
1.400 - * @param newValue the new value of the property
1.401 - * @since 1.5
1.402 - */
1.403 - public void fireIndexedPropertyChange(String propertyName, int index, boolean oldValue, boolean newValue) {
1.404 - if (oldValue != newValue) {
1.405 - fireIndexedPropertyChange(propertyName, index, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
1.406 - }
1.407 - }
1.408 -
1.409 - /**
1.410 - * Check if there are any listeners for a specific property, including
1.411 - * those registered on all properties. If <code>propertyName</code>
1.412 - * is null, only check for listeners registered on all properties.
1.413 - *
1.414 - * @param propertyName the property name.
1.415 - * @return true if there are one or more listeners for the given property
1.416 - */
1.417 - public boolean hasListeners(String propertyName) {
1.418 - return this.map.hasListeners(propertyName);
1.419 - }
1.420 -
1.421 - /**
1.422 - * @serialData Null terminated list of <code>PropertyChangeListeners</code>.
1.423 - * <p>
1.424 - * At serialization time we skip non-serializable listeners and
1.425 - * only serialize the serializable listeners.
1.426 - */
1.427 - private void writeObject(ObjectOutputStream s) throws IOException {
1.428 - Hashtable<String, PropertyChangeSupport> children = null;
1.429 - PropertyChangeListener[] listeners = null;
1.430 - synchronized (this.map) {
1.431 - for (Entry<String, PropertyChangeListener[]> entry : this.map.getEntries()) {
1.432 - String property = entry.getKey();
1.433 - if (property == null) {
1.434 - listeners = entry.getValue();
1.435 - } else {
1.436 - if (children == null) {
1.437 - children = new Hashtable<String, PropertyChangeSupport>();
1.438 - }
1.439 - PropertyChangeSupport pcs = new PropertyChangeSupport(this.source);
1.440 - pcs.map.set(null, entry.getValue());
1.441 - children.put(property, pcs);
1.442 - }
1.443 - }
1.444 - }
1.445 - ObjectOutputStream.PutField fields = s.putFields();
1.446 - fields.put("children", children);
1.447 - fields.put("source", this.source);
1.448 - fields.put("propertyChangeSupportSerializedDataVersion", 2);
1.449 - s.writeFields();
1.450 -
1.451 - if (listeners != null) {
1.452 - for (PropertyChangeListener l : listeners) {
1.453 - if (l instanceof Serializable) {
1.454 - s.writeObject(l);
1.455 - }
1.456 - }
1.457 - }
1.458 - s.writeObject(null);
1.459 - }
1.460 -
1.461 - private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
1.462 - this.map = new PropertyChangeListenerMap();
1.463 -
1.464 - ObjectInputStream.GetField fields = s.readFields();
1.465 -
1.466 - Hashtable<String, PropertyChangeSupport> children = (Hashtable<String, PropertyChangeSupport>) fields.get("children", null);
1.467 - this.source = fields.get("source", null);
1.468 - fields.get("propertyChangeSupportSerializedDataVersion", 2);
1.469 -
1.470 - Object listenerOrNull;
1.471 - while (null != (listenerOrNull = s.readObject())) {
1.472 - this.map.add(null, (PropertyChangeListener)listenerOrNull);
1.473 - }
1.474 - if (children != null) {
1.475 - for (Entry<String, PropertyChangeSupport> entry : children.entrySet()) {
1.476 - for (PropertyChangeListener listener : entry.getValue().getPropertyChangeListeners()) {
1.477 - this.map.add(entry.getKey(), listener);
1.478 - }
1.479 - }
1.480 - }
1.481 - }
1.482 -
1.483 - /**
1.484 - * The object to be provided as the "source" for any generated events.
1.485 - */
1.486 - private Object source;
1.487 -
1.488 - /**
1.489 - * @serialField children Hashtable
1.490 - * @serialField source Object
1.491 - * @serialField propertyChangeSupportSerializedDataVersion int
1.492 - */
1.493 - private static final ObjectStreamField[] serialPersistentFields = {
1.494 - new ObjectStreamField("children", Hashtable.class),
1.495 - new ObjectStreamField("source", Object.class),
1.496 - new ObjectStreamField("propertyChangeSupportSerializedDataVersion", Integer.TYPE)
1.497 - };
1.498 -
1.499 - /**
1.500 - * Serialization version ID, so we're compatible with JDK 1.1
1.501 - */
1.502 - static final long serialVersionUID = 6401253773779951803L;
1.503 -
1.504 - /**
1.505 - * This is a {@link ChangeListenerMap ChangeListenerMap} implementation
1.506 - * that works with {@link PropertyChangeListener PropertyChangeListener} objects.
1.507 - */
1.508 - private static final class PropertyChangeListenerMap extends ChangeListenerMap<PropertyChangeListener> {
1.509 - private static final PropertyChangeListener[] EMPTY = {};
1.510 -
1.511 - /**
1.512 - * Creates an array of {@link PropertyChangeListener PropertyChangeListener} objects.
1.513 - * This method uses the same instance of the empty array
1.514 - * when {@code length} equals {@code 0}.
1.515 - *
1.516 - * @param length the array length
1.517 - * @return an array with specified length
1.518 - */
1.519 - @Override
1.520 - protected PropertyChangeListener[] newArray(int length) {
1.521 - return (0 < length)
1.522 - ? new PropertyChangeListener[length]
1.523 - : EMPTY;
1.524 - }
1.525 -
1.526 - /**
1.527 - * Creates a {@link PropertyChangeListenerProxy PropertyChangeListenerProxy}
1.528 - * object for the specified property.
1.529 - *
1.530 - * @param name the name of the property to listen on
1.531 - * @param listener the listener to process events
1.532 - * @return a {@code PropertyChangeListenerProxy} object
1.533 - */
1.534 - @Override
1.535 - protected PropertyChangeListener newProxy(String name, PropertyChangeListener listener) {
1.536 - return new PropertyChangeListenerProxy(name, listener);
1.537 - }
1.538 - }
1.539 -}