1. /*
  2. * @(#)VetoableChangeSupport.java 1.36 00/02/02
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.beans;
  11. import java.io.Serializable;
  12. import java.io.ObjectOutputStream;
  13. import java.io.ObjectInputStream;
  14. import java.io.IOException;
  15. /**
  16. * This is a utility class that can be used by beans that support constrained
  17. * properties. You can use an instance of this class as a member field
  18. * of your bean and delegate various work to it.
  19. *
  20. * This class is serializable. When it is serialized it will save
  21. * (and restore) any listeners that are themselves serializable. Any
  22. * non-serializable listeners will be skipped during serialization.
  23. */
  24. public class VetoableChangeSupport implements java.io.Serializable {
  25. /**
  26. * Constructs a <code>VetoableChangeSupport</code> object.
  27. *
  28. * @param sourceBean The bean to be given as the source for any events.
  29. */
  30. public VetoableChangeSupport(Object sourceBean) {
  31. if (sourceBean == null) {
  32. throw new NullPointerException();
  33. }
  34. source = sourceBean;
  35. }
  36. /**
  37. * Add a VetoableListener to the listener list.
  38. * The listener is registered for all properties.
  39. *
  40. * @param listener The VetoableChangeListener to be added
  41. */
  42. public synchronized void addVetoableChangeListener(
  43. VetoableChangeListener listener) {
  44. if (listeners == null) {
  45. listeners = new java.util.Vector();
  46. }
  47. listeners.addElement(listener);
  48. }
  49. /**
  50. * Remove a VetoableChangeListener from the listener list.
  51. * This removes a PropertyChangeListener that was registered
  52. * for all properties.
  53. *
  54. * @param listener The VetoableChangeListener to be removed
  55. */
  56. public synchronized void removeVetoableChangeListener(
  57. VetoableChangeListener listener) {
  58. if (listeners == null) {
  59. return;
  60. }
  61. listeners.removeElement(listener);
  62. }
  63. /**
  64. * Add a VetoableChangeListener for a specific property. The listener
  65. * will be invoked only when a call on fireVetoableChange names that
  66. * specific property.
  67. *
  68. * @param propertyName The name of the property to listen on.
  69. * @param listener The VetoableChangeListener to be added
  70. */
  71. public synchronized void addVetoableChangeListener(
  72. String propertyName,
  73. VetoableChangeListener listener) {
  74. if (children == null) {
  75. children = new java.util.Hashtable();
  76. }
  77. VetoableChangeSupport child = (VetoableChangeSupport)children.get(propertyName);
  78. if (child == null) {
  79. child = new VetoableChangeSupport(source);
  80. children.put(propertyName, child);
  81. }
  82. child.addVetoableChangeListener(listener);
  83. }
  84. /**
  85. * Remove a VetoableChangeListener for a specific property.
  86. *
  87. * @param propertyName The name of the property that was listened on.
  88. * @param listener The VetoableChangeListener to be removed
  89. */
  90. public synchronized void removeVetoableChangeListener(
  91. String propertyName,
  92. VetoableChangeListener listener) {
  93. if (children == null) {
  94. return;
  95. }
  96. VetoableChangeSupport child = (VetoableChangeSupport)children.get(propertyName);
  97. if (child == null) {
  98. return;
  99. }
  100. child.removeVetoableChangeListener(listener);
  101. }
  102. /**
  103. * Report a vetoable property update to any registered listeners. If
  104. * anyone vetos the change, then fire a new event reverting everyone to
  105. * the old value and then rethrow the PropertyVetoException.
  106. * <p>
  107. * No event is fired if old and new are equal and non-null.
  108. *
  109. * @param propertyName The programmatic name of the property
  110. * that is about to change..
  111. * @param oldValue The old value of the property.
  112. * @param newValue The new value of the property.
  113. * @exception PropertyVetoException if the recipient wishes the property
  114. * change to be rolled back.
  115. */
  116. public void fireVetoableChange(String propertyName,
  117. Object oldValue, Object newValue)
  118. throws PropertyVetoException {
  119. if (listeners == null && children == null) {
  120. return;
  121. }
  122. PropertyChangeEvent evt = new PropertyChangeEvent(source, propertyName,
  123. oldValue, newValue);
  124. fireVetoableChange(evt);
  125. }
  126. /**
  127. * Report a int vetoable property update to any registered listeners.
  128. * No event is fired if old and new are equal and non-null.
  129. * <p>
  130. * This is merely a convenience wrapper around the more general
  131. * fireVetoableChange method that takes Object values.
  132. *
  133. * @param propertyName The programmatic name of the property
  134. * that is about to change.
  135. * @param oldValue The old value of the property.
  136. * @param newValue The new value of the property.
  137. */
  138. public void fireVetoableChange(String propertyName,
  139. int oldValue, int newValue)
  140. throws PropertyVetoException {
  141. if (oldValue == newValue) {
  142. return;
  143. }
  144. fireVetoableChange(propertyName, new Integer(oldValue), new Integer(newValue));
  145. }
  146. /**
  147. * Report a boolean vetoable property update to any registered listeners.
  148. * No event is fired if old and new are equal and non-null.
  149. * <p>
  150. * This is merely a convenience wrapper around the more general
  151. * fireVetoableChange method that takes Object values.
  152. *
  153. * @param propertyName The programmatic name of the property
  154. * that is about to change.
  155. * @param oldValue The old value of the property.
  156. * @param newValue The new value of the property.
  157. */
  158. public void fireVetoableChange(String propertyName,
  159. boolean oldValue, boolean newValue)
  160. throws PropertyVetoException {
  161. if (oldValue == newValue) {
  162. return;
  163. }
  164. fireVetoableChange(propertyName, new Boolean(oldValue), new Boolean(newValue));
  165. }
  166. /**
  167. * Fire a vetoable property update to any registered listeners. If
  168. * anyone vetos the change, then fire a new event reverting everyone to
  169. * the old value and then rethrow the PropertyVetoException.
  170. * <p>
  171. * No event is fired if old and new are equal and non-null.
  172. *
  173. * @param evt The PropertyChangeEvent to be fired.
  174. * @exception PropertyVetoException if the recipient wishes the property
  175. * change to be rolled back.
  176. */
  177. public void fireVetoableChange(PropertyChangeEvent evt)
  178. throws PropertyVetoException {
  179. Object oldValue = evt.getOldValue();
  180. Object newValue = evt.getNewValue();
  181. String propertyName = evt.getPropertyName();
  182. if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
  183. return;
  184. }
  185. java.util.Vector targets = null;
  186. VetoableChangeSupport child = null;
  187. synchronized (this) {
  188. if (listeners != null) {
  189. targets = (java.util.Vector) listeners.clone();
  190. }
  191. if (children != null && propertyName != null) {
  192. child = (VetoableChangeSupport)children.get(propertyName);
  193. }
  194. }
  195. if (listeners != null) {
  196. try {
  197. for (int i = 0; i < targets.size(); i++) {
  198. VetoableChangeListener target =
  199. (VetoableChangeListener)targets.elementAt(i);
  200. target.vetoableChange(evt);
  201. }
  202. } catch (PropertyVetoException veto) {
  203. // Create an event to revert everyone to the old value.
  204. evt = new PropertyChangeEvent(source, propertyName, newValue, oldValue);
  205. for (int i = 0; i < targets.size(); i++) {
  206. try {
  207. VetoableChangeListener target =
  208. (VetoableChangeListener)targets.elementAt(i);
  209. target.vetoableChange(evt);
  210. } catch (PropertyVetoException ex) {
  211. // We just ignore exceptions that occur during reversions.
  212. }
  213. }
  214. // And now rethrow the PropertyVetoException.
  215. throw veto;
  216. }
  217. }
  218. if (child != null) {
  219. child.fireVetoableChange(evt);
  220. }
  221. }
  222. /**
  223. * Check if there are any listeners for a specific property.
  224. *
  225. * @param propertyName the property name.
  226. * @return true if there are one or more listeners for the given property
  227. */
  228. public synchronized boolean hasListeners(String propertyName) {
  229. if (listeners != null && !listeners.isEmpty()) {
  230. // there is a generic listener
  231. return true;
  232. }
  233. if (children != null) {
  234. VetoableChangeSupport child = (VetoableChangeSupport)children.get(propertyName);
  235. if (child != null && child.listeners != null) {
  236. return !child.listeners.isEmpty();
  237. }
  238. }
  239. return false;
  240. }
  241. /**
  242. * @serialData Null terminated list of <code>VetoableChangeListeners</code>.
  243. * <p>
  244. * At serialization time we skip non-serializable listeners and
  245. * only serialize the serializable listeners.
  246. *
  247. */
  248. private void writeObject(ObjectOutputStream s) throws IOException {
  249. s.defaultWriteObject();
  250. java.util.Vector v = null;
  251. synchronized (this) {
  252. if (listeners != null) {
  253. v = (java.util.Vector) listeners.clone();
  254. }
  255. }
  256. if (v != null) {
  257. for(int i = 0; i < v.size(); i++) {
  258. VetoableChangeListener l = (VetoableChangeListener)v.elementAt(i);
  259. if (l instanceof Serializable) {
  260. s.writeObject(l);
  261. }
  262. }
  263. }
  264. s.writeObject(null);
  265. }
  266. private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
  267. s.defaultReadObject();
  268. Object listenerOrNull;
  269. while(null != (listenerOrNull = s.readObject())) {
  270. addVetoableChangeListener((VetoableChangeListener)listenerOrNull);
  271. }
  272. }
  273. /**
  274. * "listeners" lists all the generic listeners.
  275. *
  276. * This is transient - its state is written in the writeObject method.
  277. */
  278. transient private java.util.Vector listeners;
  279. /**
  280. * Hashtable for managing listeners for specific properties.
  281. * Maps property names to VetoableChangeSupport objects.
  282. * @serial
  283. * @since 1.2
  284. */
  285. private java.util.Hashtable children;
  286. /**
  287. * The object to be provided as the "source" for any generated events.
  288. * @serial
  289. */
  290. private Object source;
  291. /**
  292. * Internal version number
  293. * @serial
  294. */
  295. private int vetoableChangeSupportSerializedDataVersion = 2;
  296. /**
  297. * Serialization version ID, so we're compatible with JDK 1.1
  298. */
  299. static final long serialVersionUID = -5090210921595982017L;
  300. }