1 /*
2 * Copyright 1998-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 */
82
83 public BeanContextChildSupport(BeanContextChild bcc) {
84 super();
85
86 beanContextChildPeer = (bcc != null) ? bcc : this;
87
88 pcSupport = new PropertyChangeSupport(beanContextChildPeer);
89 vcSupport = new VetoableChangeSupport(beanContextChildPeer);
90 }
91
92 /**
93 * Sets the <code>BeanContext</code> for
94 * this <code>BeanContextChildSupport</code>.
95 * @param bc the new value to be assigned to the <code>BeanContext</code>
96 * property
97 * @throws <code>PropertyVetoException</code> if the change is rejected
98 */
99 public synchronized void setBeanContext(BeanContext bc) throws PropertyVetoException {
100 if (bc == beanContext) return;
101
102 BeanContext oldValue = beanContext;
103 BeanContext newValue = bc;
104
105 if (!rejectedSetBCOnce) {
106 if (rejectedSetBCOnce = !validatePendingSetBeanContext(bc)) {
107 throw new PropertyVetoException(
108 "setBeanContext() change rejected:",
109 new PropertyChangeEvent(beanContextChildPeer, "beanContext", oldValue, newValue)
110 );
111 }
112
113 try {
114 fireVetoableChange("beanContext",
115 oldValue,
116 newValue
117 );
118 } catch (PropertyVetoException pve) {
119 rejectedSetBCOnce = true;
120
121 throw pve; // re-throw
122 }
123 }
124
125 if (beanContext != null) releaseBeanContextResources();
126
127 beanContext = newValue;
128 rejectedSetBCOnce = false;
129
130 firePropertyChange("beanContext",
131 oldValue,
132 newValue
133 );
134
135 if (beanContext != null) initializeBeanContextResources();
136 }
137
138 /**
139 * Gets the nesting <code>BeanContext</code>
140 * for this <code>BeanContextChildSupport</code>.
141 * @return the nesting <code>BeanContext</code> for
142 * this <code>BeanContextChildSupport</code>.
143 */
144 public synchronized BeanContext getBeanContext() { return beanContext; }
145
146 /**
147 * Add a PropertyChangeListener for a specific property.
148 * The same listener object may be added more than once. For each
149 * property, the listener will be invoked the number of times it was added
150 * for that property.
151 * If <code>name</code> or <code>pcl</code> is null, no exception is thrown
152 * and no action is taken.
153 *
154 * @param name The name of the property to listen on
155 * @param pcl The <code>PropertyChangeListener</code> to be added
156 */
157 public void addPropertyChangeListener(String name, PropertyChangeListener pcl) {
158 pcSupport.addPropertyChangeListener(name, pcl);
159 }
160
161 /**
162 * Remove a PropertyChangeListener for a specific property.
163 * If <code>pcl</code> was added more than once to the same event
164 * source for the specified property, it will be notified one less time
165 * after being removed.
166 * If <code>name</code> is null, no exception is thrown
167 * and no action is taken.
168 * If <code>pcl</code> is null, or was never added for the specified
169 * property, no exception is thrown and no action is taken.
170 *
171 * @param name The name of the property that was listened on
172 * @param pcl The PropertyChangeListener to be removed
173 */
174 public void removePropertyChangeListener(String name, PropertyChangeListener pcl) {
175 pcSupport.removePropertyChangeListener(name, pcl);
176 }
177
178 /**
179 * Add a VetoableChangeListener for a specific property.
180 * The same listener object may be added more than once. For each
181 * property, the listener will be invoked the number of times it was added
182 * for that property.
183 * If <code>name</code> or <code>vcl</code> is null, no exception is thrown
184 * and no action is taken.
185 *
186 * @param name The name of the property to listen on
187 * @param vcl The <code>VetoableChangeListener</code> to be added
188 */
189 public void addVetoableChangeListener(String name, VetoableChangeListener vcl) {
190 vcSupport.addVetoableChangeListener(name, vcl);
191 }
192
193 /**
194 * Removes a <code>VetoableChangeListener</code>.
195 * If <code>pcl</code> was added more than once to the same event
196 * source for the specified property, it will be notified one less time
197 * after being removed.
198 * If <code>name</code> is null, no exception is thrown
199 * and no action is taken.
200 * If <code>vcl</code> is null, or was never added for the specified
201 * property, no exception is thrown and no action is taken.
202 *
203 * @param name The name of the property that was listened on
204 * @param vcl The <code>VetoableChangeListener</code> to be removed
205 */
206 public void removeVetoableChangeListener(String name, VetoableChangeListener vcl) {
207 vcSupport.removeVetoableChangeListener(name, vcl);
208 }
209
210 /**
211 * A service provided by the nesting BeanContext has been revoked.
212 *
213 * Subclasses may override this method in order to implement their own
214 * behaviors.
215 * @param bcsre The <code>BeanContextServiceRevokedEvent</code> fired as a
216 * result of a service being revoked
217 */
218 public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { }
219
220 /**
221 * A new service is available from the nesting BeanContext.
222 *
223 * Subclasses may override this method in order to implement their own
224 * behaviors
225 * @param bcsae The BeanContextServiceAvailableEvent fired as a
226 * result of a service becoming available
227 *
228 */
229 public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) { }
230
231 /**
232 * Gets the <tt>BeanContextChild</tt> associated with this
233 * <tt>BeanContextChildSupport</tt>.
234 *
235 * @return the <tt>BeanContextChild</tt> peer of this class
236 */
237 public BeanContextChild getBeanContextChildPeer() { return beanContextChildPeer; }
238
239 /**
240 * Reports whether or not this class is a delegate of another.
241 *
242 * @return true if this class is a delegate of another
243 */
244 public boolean isDelegated() { return !this.equals(beanContextChildPeer); }
245
246 /**
247 * Report a bound property update to any registered listeners. No event is
248 * fired if old and new are equal and non-null.
249 * @param name The programmatic name of the property that was changed
250 * @param oldValue The old value of the property
251 * @param newValue The new value of the property
252 */
253 public void firePropertyChange(String name, Object oldValue, Object newValue) {
254 pcSupport.firePropertyChange(name, oldValue, newValue);
255 }
256
257 /**
258 * Report a vetoable property update to any registered listeners.
259 * If anyone vetos the change, then fire a new event
260 * reverting everyone to the old value and then rethrow
261 * the PropertyVetoException. <P>
262 *
263 * No event is fired if old and new are equal and non-null.
264 * <P>
265 * @param name The programmatic name of the property that is about to
266 * change
267 *
268 * @param oldValue The old value of the property
269 * @param newValue - The new value of the property
270 *
271 * @throws PropertyVetoException if the recipient wishes the property
272 * change to be rolled back.
273 */
274 public void fireVetoableChange(String name, Object oldValue, Object newValue) throws PropertyVetoException {
275 vcSupport.fireVetoableChange(name, oldValue, newValue);
276 }
277
278 /**
279 * Called from setBeanContext to validate (or otherwise) the
280 * pending change in the nesting BeanContext property value.
281 * Returning false will cause setBeanContext to throw
282 * PropertyVetoException.
283 * @param newValue the new value that has been requested for
284 * the BeanContext property
285 * @return <code>true</code> if the change operation is to be vetoed
286 */
287 public boolean validatePendingSetBeanContext(BeanContext newValue) {
288 return true;
289 }
290
291 /**
292 * This method may be overridden by subclasses to provide their own
293 * release behaviors. When invoked any resources held by this instance
294 * obtained from its current BeanContext property should be released
295 * since the object is no longer nested within that BeanContext.
296 */
297
298 protected void releaseBeanContextResources() {
299 // do nothing
300 }
301
302 /**
303 * This method may be overridden by subclasses to provide their own
304 * initialization behaviors. When invoked any resources requried by the
305 * BeanContextChild should be obtained from the current BeanContext.
306 */
307
308 protected void initializeBeanContextResources() {
309 // do nothing
310 }
311
312 /**
313 * Write the persistence state of the object.
314 */
315
316 private void writeObject(ObjectOutputStream oos) throws IOException {
317
318 /*
319 * dont serialize if we are delegated and the delegator isnt also
320 * serializable.
321 */
322
323 if (!equals(beanContextChildPeer) && !(beanContextChildPeer instanceof Serializable))
324 throw new IOException("BeanContextChildSupport beanContextChildPeer not Serializable");
325
326 else
327 oos.defaultWriteObject();
328
329 }
330
331
332 /**
333 * Restore a persistent object, must wait for subsequent setBeanContext()
334 * to fully restore any resources obtained from the new nesting
335 * BeanContext
336 */
337
338 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
339 ois.defaultReadObject();
340 }
341
342 /*
343 * fields
344 */
345
346 /**
347 * The <code>BeanContext</code> in which
348 * this <code>BeanContextChild</code> is nested.
349 */
350 public BeanContextChild beanContextChildPeer;
351
352 /**
353 * The <tt>PropertyChangeSupport</tt> associated with this
354 * <tt>BeanContextChildSupport</tt>.
355 */
356 protected PropertyChangeSupport pcSupport;
357
358 /**
359 * The <tt>VetoableChangeSupport</tt> associated with this
360 * <tt>BeanContextChildSupport</tt>.
361 */
362 protected VetoableChangeSupport vcSupport;
363
364 protected transient BeanContext beanContext;
365
366 /**
367 * A flag indicating that there has been
368 * at least one <code>PropertyChangeVetoException</code>
369 * thrown for the attempted setBeanContext operation.
370 */
371 protected transient boolean rejectedSetBCOnce;
372
373 }