1 /* 2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.beans.beancontext; 27 28 import java.beans.PropertyChangeEvent; 29 import java.beans.PropertyChangeListener; 30 import java.beans.PropertyChangeSupport; 31 32 import java.beans.VetoableChangeListener; 33 import java.beans.VetoableChangeSupport; 34 35 import java.beans.PropertyVetoException; 36 37 import java.io.IOException; 38 import java.io.ObjectInputStream; 39 import java.io.ObjectOutputStream; 40 import java.io.Serializable; 41 42 /** 43 * <p> 44 * This is a general support class to provide support for implementing the 45 * BeanContextChild protocol. 46 * 47 * This class may either be directly subclassed, or encapsulated and delegated 48 * to in order to implement this interface for a given component. 49 * </p> 50 * 51 * @author Laurence P. G. Cable 52 * @since 1.2 53 * 54 * @see java.beans.beancontext.BeanContext 55 * @see java.beans.beancontext.BeanContextServices 56 * @see java.beans.beancontext.BeanContextChild 57 */ 58 59 public class BeanContextChildSupport implements BeanContextChild, BeanContextServicesListener, Serializable { 60 61 static final long serialVersionUID = 6328947014421475877L; 62 63 /** 64 * construct a BeanContextChildSupport where this class has been 65 * subclassed in order to implement the JavaBean component itself. 66 */ 67 68 public BeanContextChildSupport() { 69 super(); 70 71 beanContextChildPeer = this; 72 73 pcSupport = new PropertyChangeSupport(beanContextChildPeer); 74 vcSupport = new VetoableChangeSupport(beanContextChildPeer); 75 } 76 77 /** 78 * construct a BeanContextChildSupport where the JavaBean component 79 * itself implements BeanContextChild, and encapsulates this, delegating 80 * that interface to this implementation 81 * @param bcc the underlying bean context child 82 */ 83 84 public BeanContextChildSupport(BeanContextChild bcc) { 85 super(); 86 87 beanContextChildPeer = (bcc != null) ? bcc : this; 88 89 pcSupport = new PropertyChangeSupport(beanContextChildPeer); 90 vcSupport = new VetoableChangeSupport(beanContextChildPeer); 91 } 92 93 /** 94 * Sets the {@code BeanContext} for 95 * this {@code BeanContextChildSupport}. 96 * @param bc the new value to be assigned to the {@code BeanContext} 97 * property 98 * @throws PropertyVetoException if the change is rejected 99 */ 100 public synchronized void setBeanContext(BeanContext bc) throws PropertyVetoException { 101 if (bc == beanContext) return; 102 103 BeanContext oldValue = beanContext; 104 BeanContext newValue = bc; 105 106 if (!rejectedSetBCOnce) { 107 if (rejectedSetBCOnce = !validatePendingSetBeanContext(bc)) { 108 throw new PropertyVetoException( 109 "setBeanContext() change rejected:", 110 new PropertyChangeEvent(beanContextChildPeer, "beanContext", oldValue, newValue) 111 ); 112 } 113 114 try { 115 fireVetoableChange("beanContext", 116 oldValue, 117 newValue 118 ); 119 } catch (PropertyVetoException pve) { 120 rejectedSetBCOnce = true; 121 122 throw pve; // re-throw 123 } 124 } 125 126 if (beanContext != null) releaseBeanContextResources(); 127 128 beanContext = newValue; 129 rejectedSetBCOnce = false; 130 131 firePropertyChange("beanContext", 132 oldValue, 133 newValue 134 ); 135 136 if (beanContext != null) initializeBeanContextResources(); 137 } 138 139 /** 140 * Gets the nesting {@code BeanContext} 141 * for this {@code BeanContextChildSupport}. 142 * @return the nesting {@code BeanContext} for 143 * this {@code BeanContextChildSupport}. 144 */ 145 public synchronized BeanContext getBeanContext() { return beanContext; } 146 147 /** 148 * Add a PropertyChangeListener for a specific property. 149 * The same listener object may be added more than once. For each 150 * property, the listener will be invoked the number of times it was added 151 * for that property. 152 * If {@code name} or {@code pcl} is null, no exception is thrown 153 * and no action is taken. 154 * 155 * @param name The name of the property to listen on 156 * @param pcl The {@code PropertyChangeListener} to be added 157 */ 158 public void addPropertyChangeListener(String name, PropertyChangeListener pcl) { 159 pcSupport.addPropertyChangeListener(name, pcl); 160 } 161 162 /** 163 * Remove a PropertyChangeListener for a specific property. 164 * If {@code pcl} was added more than once to the same event 165 * source for the specified property, it will be notified one less time 166 * after being removed. 167 * If {@code name} is null, no exception is thrown 168 * and no action is taken. 169 * If {@code pcl} is null, or was never added for the specified 170 * property, no exception is thrown and no action is taken. 171 * 172 * @param name The name of the property that was listened on 173 * @param pcl The PropertyChangeListener to be removed 174 */ 175 public void removePropertyChangeListener(String name, PropertyChangeListener pcl) { 176 pcSupport.removePropertyChangeListener(name, pcl); 177 } 178 179 /** 180 * Add a VetoableChangeListener for a specific property. 181 * The same listener object may be added more than once. For each 182 * property, the listener will be invoked the number of times it was added 183 * for that property. 184 * If {@code name} or {@code vcl} is null, no exception is thrown 185 * and no action is taken. 186 * 187 * @param name The name of the property to listen on 188 * @param vcl The {@code VetoableChangeListener} to be added 189 */ 190 public void addVetoableChangeListener(String name, VetoableChangeListener vcl) { 191 vcSupport.addVetoableChangeListener(name, vcl); 192 } 193 194 /** 195 * Removes a {@code VetoableChangeListener}. 196 * If {@code pcl} was added more than once to the same event 197 * source for the specified property, it will be notified one less time 198 * after being removed. 199 * If {@code name} is null, no exception is thrown 200 * and no action is taken. 201 * If {@code vcl} is null, or was never added for the specified 202 * property, no exception is thrown and no action is taken. 203 * 204 * @param name The name of the property that was listened on 205 * @param vcl The {@code VetoableChangeListener} to be removed 206 */ 207 public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) { 208 vcSupport.removeVetoableChangeListener(name, vcl); 209 } 210 211 /** 212 * A service provided by the nesting BeanContext has been revoked. 213 * 214 * Subclasses may override this method in order to implement their own 215 * behaviors. 216 * @param bcsre The {@code BeanContextServiceRevokedEvent} fired as a 217 * result of a service being revoked 218 */ 219 public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { } 220 221 /** 222 * A new service is available from the nesting BeanContext. 223 * 224 * Subclasses may override this method in order to implement their own 225 * behaviors 226 * @param bcsae The BeanContextServiceAvailableEvent fired as a 227 * result of a service becoming available 228 * 229 */ 230 public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { } 231 232 /** 233 * Gets the {@code BeanContextChild} associated with this 234 * {@code BeanContextChildSupport}. 235 * 236 * @return the {@code BeanContextChild} peer of this class 237 */ 238 public BeanContextChild getBeanContextChildPeer() { return beanContextChildPeer; } 239 240 /** 241 * Reports whether or not this class is a delegate of another. 242 * 243 * @return true if this class is a delegate of another 244 */ 245 public boolean isDelegated() { return !this.equals(beanContextChildPeer); } 246 247 /** 248 * Report a bound property update to any registered listeners. No event is 249 * fired if old and new are equal and non-null. 250 * @param name The programmatic name of the property that was changed 251 * @param oldValue The old value of the property 252 * @param newValue The new value of the property 253 */ 254 public void firePropertyChange(String name, Object oldValue, Object newValue) { 255 pcSupport.firePropertyChange(name, oldValue, newValue); 256 } 257 258 /** 259 * Report a vetoable property update to any registered listeners. 260 * If anyone vetos the change, then fire a new event 261 * reverting everyone to the old value and then rethrow 262 * the PropertyVetoException. <P> 263 * 264 * No event is fired if old and new are equal and non-null. 265 * 266 * @param name The programmatic name of the property that is about to 267 * change 268 * 269 * @param oldValue The old value of the property 270 * @param newValue - The new value of the property 271 * 272 * @throws PropertyVetoException if the recipient wishes the property 273 * change to be rolled back. 274 */ 275 public void fireVetoableChange(String name, Object oldValue, Object newValue) throws PropertyVetoException { 276 vcSupport.fireVetoableChange(name, oldValue, newValue); 277 } 278 279 /** 280 * Called from setBeanContext to validate (or otherwise) the 281 * pending change in the nesting BeanContext property value. 282 * Returning false will cause setBeanContext to throw 283 * PropertyVetoException. 284 * @param newValue the new value that has been requested for 285 * the BeanContext property 286 * @return {@code true} if the change operation is to be vetoed 287 */ 288 public boolean validatePendingSetBeanContext(BeanContext newValue) { 289 return true; 290 } 291 292 /** 293 * This method may be overridden by subclasses to provide their own 294 * release behaviors. When invoked any resources held by this instance 295 * obtained from its current BeanContext property should be released 296 * since the object is no longer nested within that BeanContext. 297 */ 298 299 protected void releaseBeanContextResources() { 300 // do nothing 301 } 302 303 /** 304 * This method may be overridden by subclasses to provide their own 305 * initialization behaviors. When invoked any resources required by the 306 * BeanContextChild should be obtained from the current BeanContext. 307 */ 308 309 protected void initializeBeanContextResources() { 310 // do nothing 311 } 312 313 /** 314 * Write the persistence state of the object. 315 */ 316 317 private void writeObject(ObjectOutputStream oos) throws IOException { 318 319 /* 320 * don't serialize if we are delegated and the delegator is not also 321 * serializable. 322 */ 323 324 if (!equals(beanContextChildPeer) && !(beanContextChildPeer instanceof Serializable)) 325 throw new IOException("BeanContextChildSupport beanContextChildPeer not Serializable"); 326 327 else 328 oos.defaultWriteObject(); 329 330 } 331 332 333 /** 334 * Restore a persistent object, must wait for subsequent setBeanContext() 335 * to fully restore any resources obtained from the new nesting 336 * BeanContext 337 */ 338 339 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 340 ois.defaultReadObject(); 341 } 342 343 /* 344 * fields 345 */ 346 347 /** 348 * The {@code BeanContext} in which 349 * this {@code BeanContextChild} is nested. 350 */ 351 public BeanContextChild beanContextChildPeer; 352 353 /** 354 * The {@code PropertyChangeSupport} associated with this 355 * {@code BeanContextChildSupport}. 356 */ 357 protected PropertyChangeSupport pcSupport; 358 359 /** 360 * The {@code VetoableChangeSupport} associated with this 361 * {@code BeanContextChildSupport}. 362 */ 363 protected VetoableChangeSupport vcSupport; 364 365 /** 366 * The bean context. 367 */ 368 protected transient BeanContext beanContext; 369 370 /** 371 * A flag indicating that there has been 372 * at least one {@code PropertyChangeVetoException} 373 * thrown for the attempted setBeanContext operation. 374 */ 375 protected transient boolean rejectedSetBCOnce; 376 377 }