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