KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > beans > beancontext > BeanContextSupport


1 /*
2  * @(#)BeanContextSupport.java 1.46 03/01/13
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.beans.beancontext;
9
10 import java.awt.Component JavaDoc;
11 import java.awt.Container JavaDoc;
12
13 import java.beans.Beans JavaDoc;
14 import java.beans.AppletInitializer JavaDoc;
15
16 import java.beans.DesignMode JavaDoc;
17
18 import java.beans.PropertyChangeEvent JavaDoc;
19 import java.beans.PropertyChangeListener JavaDoc;
20 import java.beans.PropertyChangeSupport JavaDoc;
21
22 import java.beans.VetoableChangeListener JavaDoc;
23 import java.beans.VetoableChangeSupport JavaDoc;
24 import java.beans.PropertyVetoException JavaDoc;
25
26 import java.beans.Visibility JavaDoc;
27
28 import java.io.IOException JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.io.ObjectInputStream JavaDoc;
31 import java.io.ObjectOutputStream JavaDoc;
32 import java.io.Serializable JavaDoc;
33
34 import java.net.URL JavaDoc;
35
36 import java.util.ArrayList JavaDoc;
37 import java.util.Collection JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.Iterator JavaDoc;
40 import java.util.Locale JavaDoc;
41 import java.util.Map JavaDoc;
42
43
44 /**
45  * This helper class provides a utility implementation of the
46  * java.beans.beancontext.BeanContext interface.
47  * </p>
48  * <p>
49  * Since this class directly implements the BeanContext interface, the class
50  * can, and is intended to be used either by subclassing this implementation,
51  * or via ad-hoc delegation of an instance of this class from another.
52  * </p>
53  *
54  * @author Laurence P. G. Cable
55  * @version 1.46, 01/13/03
56  * @since 1.2
57  */

58 public class BeanContextSupport extends BeanContextChildSupport JavaDoc
59        implements BeanContext JavaDoc,
60           Serializable JavaDoc,
61           PropertyChangeListener JavaDoc,
62           VetoableChangeListener JavaDoc {
63
64     // Fix for bug 4282900 to pass JCK regression test
65
static final long serialVersionUID = -4879613978649577204L;
66
67     /**
68      *
69      * Construct a BeanContextSupport instance
70      *
71      *
72      * @param peer The peer <tt>BeanContext</tt> we are
73      * supplying an implementation for,
74      * or <tt>null</tt>
75      * if this object is its own peer
76      * @param lcle The current Locale for this BeanContext. If
77      * <tt>lcle</tt> is <tt>null</tt>, the default locale
78      * is assigned to the <tt>BeanContext</tt> instance.
79      * @param dTime The initial state,
80      * <tt>true</tt> if in design mode,
81      * <tt>false</tt> if runtime.
82      * @param visible The initial visibility.
83      * @see java.util.Locale#getDefault()
84      * @see java.util.Locale#setDefault(java.util.Locale)
85      */

86     public BeanContextSupport(BeanContext JavaDoc peer, Locale JavaDoc lcle, boolean dTime, boolean visible) {
87     super(peer);
88
89     locale = lcle != null ? lcle : Locale.getDefault();
90     designTime = dTime;
91     okToUseGui = visible;
92
93     initialize();
94     }
95
96     /**
97      * Create an instance using the specified Locale and design mode.
98      *
99      * @param peer The peer <tt>BeanContext</tt> we
100      * are supplying an implementation for,
101      * or <tt>null</tt> if this object is its own peer
102      * @param lcle The current Locale for this <tt>BeanContext</tt>. If
103      * <tt>lcle</tt> is <tt>null</tt>, the default locale
104      * is assigned to the <tt>BeanContext</tt> instance.
105      * @param dtime The initial state, <tt>true</tt>
106      * if in design mode,
107      * <tt>false</tt> if runtime.
108      * @see java.util.Locale#getDefault()
109      * @see java.util.Locale#setDefault(java.util.Locale)
110      */

111     public BeanContextSupport(BeanContext JavaDoc peer, Locale JavaDoc lcle, boolean dtime) {
112     this (peer, lcle, dtime, true);
113     }
114
115     /**
116      * Create an instance using the specified locale
117      *
118      * @param peer The peer BeanContext we are
119      * supplying an implementation for,
120      * or <tt>null</tt> if this object
121      * is its own peer
122      * @param lcle The current Locale for this
123      * <tt>BeanContext</tt>. If
124      * <tt>lcle</tt> is <tt>null</tt>,
125      * the default locale
126      * is assigned to the <tt>BeanContext</tt>
127      * instance.
128      * @see java.util.Locale#getDefault()
129      * @see java.util.Locale#setDefault(java.util.Locale)
130      */

131     public BeanContextSupport(BeanContext JavaDoc peer, Locale JavaDoc lcle) {
132     this (peer, lcle, false, true);
133     }
134
135     /**
136      * Create an instance using with a default locale
137      *
138      * @param peer The peer <tt>BeanContext</tt> we are
139      * supplying an implementation for,
140      * or <tt>null</tt> if this object
141      * is its own peer
142      */

143     public BeanContextSupport(BeanContext JavaDoc peer) {
144     this (peer, null, false, true);
145     }
146
147     /**
148      * Create an instance that is not a delegate of another object
149      */

150
151     public BeanContextSupport() {
152     this (null, null, false, true);
153     }
154
155     /**
156      * Gets the instance of <tt>BeanContext</tt> that
157      * this object is providing the implementation for.
158      * @return the BeanContext instance
159      */

160     public BeanContext JavaDoc getBeanContextPeer() { return (BeanContext JavaDoc)getBeanContextChildPeer(); }
161
162     /**
163      * <p>
164      * The instantiateChild method is a convenience hook
165      * in BeanContext to simplify
166      * the task of instantiating a Bean, nested,
167      * into a <tt>BeanContext</tt>.
168      * </p>
169      * <p>
170      * The semantics of the beanName parameter are defined by java.beans.Beans.instantate.
171      * </p>
172      *
173      * @param beanName the name of the Bean to instantiate within this BeanContext
174      * @throws IOException if there is an I/O error when the bean is being deserialized
175      * @throws ClassNotFoundException if the class
176      * identified by the beanName parameter is not found
177      * @return the new object
178      */

179     public Object JavaDoc instantiateChild(String JavaDoc beanName)
180        throws IOException JavaDoc, ClassNotFoundException JavaDoc {
181     BeanContext JavaDoc bc = getBeanContextPeer();
182
183     return Beans.instantiate(bc.getClass().getClassLoader(), beanName, bc);
184     }
185
186     /**
187      * Gets the number of children currently nested in
188      * this BeanContext.
189      *
190      * @return number of children
191      */

192     public int size() {
193     synchronized(children) {
194         return children.size();
195     }
196     }
197
198     /**
199      * Reports whether or not this
200      * <tt>BeanContext</tt> is empty.
201      * A <tt>BeanContext</tt> is considered
202      * empty when it contains zero
203      * nested children.
204      * @return if there are not children
205      */

206     public boolean isEmpty() {
207     synchronized(children) {
208         return children.isEmpty();
209     }
210     }
211
212     /**
213      * Determines whether or not the specified object
214      * is currently a child of this <tt>BeanContext</tt>.
215      * @param o the Object in question
216      * @return if this object is a child
217      */

218     public boolean contains(Object JavaDoc o) {
219     synchronized(children) {
220         return children.containsKey(o);
221     }
222     }
223
224     /**
225      * Determines whether or not the specified object
226      * is currently a child of this <tt>BeanContext</tt>.
227      * @param o the Object in question
228      * @return if this object is a child
229      */

230     public boolean containsKey(Object JavaDoc o) {
231     synchronized(children) {
232         return children.containsKey(o);
233     }
234     }
235
236     /**
237      * Gets all JavaBean or <tt>BeanContext</tt> instances
238      * currently nested in this <tt>BeanContext</tt>.
239      * @return an <tt>Iterator</tt> of the nested children
240      */

241     public Iterator JavaDoc iterator() {
242     synchronized(children) {
243         return new BCSIterator(children.keySet().iterator());
244     }
245     }
246
247     /**
248      * Gets all JavaBean or <tt>BeanContext</tt>
249      * instances currently nested in this BeanContext.
250      */

251     public Object JavaDoc[] toArray() {
252     synchronized(children) {
253         return children.keySet().toArray();
254     }
255     }
256
257     /**
258      * Gets an array containing all children of
259      * this <tt>BeanContext</tt> that match
260      * the types contained in arry.
261      * @param arry The array of object
262      * types that are of interest.
263      * @return an array of children
264      */

265     public Object JavaDoc[] toArray(Object JavaDoc[] arry) {
266     synchronized(children) {
267         return children.keySet().toArray(arry);
268     }
269     }
270
271
272     /************************************************************************/
273
274     /**
275      * protected final subclass that encapsulates an iterator but implements
276      * a noop remove() method.
277      */

278
279     protected static final class BCSIterator implements Iterator JavaDoc {
280     BCSIterator(Iterator JavaDoc i) { super(); src = i; }
281
282     public boolean hasNext() { return src.hasNext(); }
283     public Object JavaDoc next() { return src.next(); }
284     public void remove() { /* do nothing */ }
285
286     private Iterator JavaDoc src;
287     }
288
289     /************************************************************************/
290
291     /*
292      * protected nested class containing per child information, an instance
293      * of which is associated with each child in the "children" hashtable.
294      * subclasses can extend this class to include their own per-child state.
295      *
296      * Note that this 'value' is serialized with the corresponding child 'key'
297      * when the BeanContextSupport is serialized.
298      */

299
300     protected class BCSChild implements Serializable JavaDoc {
301
302     private static final long serialVersionUID = -5815286101609939109L;
303
304     BCSChild(Object JavaDoc bcc, Object JavaDoc peer) {
305         super();
306
307         child = bcc;
308         proxyPeer = peer;
309     }
310
311     Object JavaDoc getChild() { return child; }
312
313     void setRemovePending(boolean v) { removePending = v; }
314
315     boolean isRemovePending() { return removePending; }
316
317         boolean isProxyPeer() { return proxyPeer != null; }
318
319     Object JavaDoc getProxyPeer() { return proxyPeer; }
320     /*
321      * fields
322      */

323
324
325     private Object JavaDoc child;
326     private Object JavaDoc proxyPeer;
327
328     private transient boolean removePending;
329     }
330
331     /**
332      * <p>
333      * Subclasses can override this method to insert their own subclass
334      * of Child without having to override add() or the other Collection
335      * methods that add children to the set.
336      * </p>
337      *
338      * @param targetChild the child to create the Child on behalf of
339      * @param peer the peer if the tragetChild and the peer are related by an implementation of BeanContextProxy
340      */

341
342     protected BCSChild createBCSChild(Object JavaDoc targetChild, Object JavaDoc peer) {
343     return new BCSChild(targetChild, peer);
344     }
345
346     /************************************************************************/
347
348     /**
349      * Adds/nests a child within this <tt>BeanContext</tt>.
350      * <p>
351      * Invoked as a side effect of java.beans.Beans.instantiate().
352      * If the child object is not valid for adding then this method
353      * throws an IllegalStateException.
354      * </p>
355      *
356      *
357      * @param targetChild The child objects to nest
358      * within this <tt>BeanContext</tt>
359      * @return true if the child was added successfully.
360      * @see #validatePendingAdd
361      */

362     public boolean add(Object JavaDoc targetChild) {
363
364     if (targetChild == null) throw new IllegalArgumentException JavaDoc();
365
366     // The specification requires that we do nothing if the child
367
// is already nested herein.
368

369     if (children.containsKey(targetChild)) return false; // test before locking
370

371     synchronized(BeanContext.globalHierarchyLock) {
372         if (children.containsKey(targetChild)) return false; // check again
373

374         if (!validatePendingAdd(targetChild)) {
375             throw new IllegalStateException JavaDoc();
376         }
377
378
379         // The specification requires that we invoke setBeanContext() on the
380
// newly added child if it implements the java.beans.beancontext.BeanContextChild interface
381

382         BeanContextChild JavaDoc cbcc = getChildBeanContextChild(targetChild);
383         BeanContextChild JavaDoc bccp = null;
384
385         synchronized(targetChild) {
386
387         if (targetChild instanceof BeanContextProxy JavaDoc) {
388             bccp = ((BeanContextProxy JavaDoc)targetChild).getBeanContextProxy();
389
390             if (bccp == null) throw new NullPointerException JavaDoc("BeanContextPeer.getBeanContextProxy()");
391         }
392
393             BCSChild bcsc = createBCSChild(targetChild, bccp);
394         BCSChild pbcsc = null;
395
396             synchronized (children) {
397             children.put(targetChild, bcsc);
398
399             if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));
400         }
401
402             if (cbcc != null) synchronized(cbcc) {
403             try {
404                     cbcc.setBeanContext(getBeanContextPeer());
405                 } catch (PropertyVetoException JavaDoc pve) {
406
407                 synchronized (children) {
408                 children.remove(targetChild);
409
410                 if (bccp != null) children.remove(bccp);
411             }
412
413                     throw new IllegalStateException JavaDoc();
414                 }
415
416                 cbcc.addPropertyChangeListener("beanContext", childPCL);
417                 cbcc.addVetoableChangeListener("beanContext", childVCL);
418         }
419
420             Visibility JavaDoc v = getChildVisibility(targetChild);
421
422             if (v != null) {
423                 if (okToUseGui)
424                     v.okToUseGui();
425                 else
426                     v.dontUseGui();
427             }
428
429             if (getChildSerializable(targetChild) != null) serializable++;
430
431             childJustAddedHook(targetChild, bcsc);
432
433         if (bccp != null) {
434                 v = getChildVisibility(bccp);
435
436                 if (v != null) {
437                     if (okToUseGui)
438                         v.okToUseGui();
439                     else
440                         v.dontUseGui();
441                 }
442
443             if (getChildSerializable(bccp) != null) serializable++;
444
445                 childJustAddedHook(bccp, pbcsc);
446         }
447
448
449         }
450
451         // The specification requires that we fire a notification of the change
452

453         fireChildrenAdded(new BeanContextMembershipEvent JavaDoc(getBeanContextPeer(), bccp == null ? new Object JavaDoc[] { targetChild } : new Object JavaDoc[] { targetChild, bccp } ));
454
455         }
456
457     return true;
458     }
459
460     /**
461      * Removes a child from this BeanContext. If the child object is not
462      * for adding then this method throws an IllegalStateException.
463      * @param targetChild The child objects to remove
464      * @see #validatePendingRemove
465      */

466     public boolean remove(Object JavaDoc targetChild) {
467     return remove(targetChild, true);
468     }
469
470     /**
471      * internal remove used when removal caused by
472      * unexpected <tt>setBeanContext</tt> or
473      * by <tt>remove()</tt> invocation.
474      * @param targetChild the JavaBean, BeanContext, or Object to be removed
475      * @param callChildSetBC used to indicate that
476      * the child should be notified that it is no
477      * longer nested in this <tt>BeanContext</tt>.
478      */

479     protected boolean remove(Object JavaDoc targetChild, boolean callChildSetBC) {
480
481     if (targetChild == null) throw new IllegalArgumentException JavaDoc();
482
483     synchronized(BeanContext.globalHierarchyLock) {
484         if (!containsKey(targetChild)) return false;
485
486         if (!validatePendingRemove(targetChild)) {
487             throw new IllegalStateException JavaDoc();
488         }
489
490             BCSChild bcsc = (BCSChild)children.get(targetChild);
491         BCSChild pbcsc = null;
492         Object JavaDoc peer = null;
493
494         // we are required to notify the child that it is no longer nested here if
495
// it implements java.beans.beancontext.BeanContextChild
496

497         synchronized(targetChild) {
498             if (callChildSetBC) {
499                 BeanContextChild JavaDoc cbcc = getChildBeanContextChild(targetChild);
500                 if (cbcc != null) synchronized(cbcc) {
501                     cbcc.removePropertyChangeListener("beanContext", childPCL);
502                     cbcc.removeVetoableChangeListener("beanContext", childVCL);
503
504             try {
505                         cbcc.setBeanContext(null);
506                     } catch (PropertyVetoException JavaDoc pve1) {
507                         cbcc.addPropertyChangeListener("beanContext", childPCL);
508                         cbcc.addVetoableChangeListener("beanContext", childVCL);
509                         throw new IllegalStateException JavaDoc();
510                     }
511
512             }
513             }
514
515             synchronized (children) {
516             children.remove(targetChild);
517
518             if (bcsc.isProxyPeer()) {
519             pbcsc = (BCSChild)children.get(peer = bcsc.getProxyPeer());
520             children.remove(peer);
521             }
522         }
523
524             if (getChildSerializable(targetChild) != null) serializable--;
525
526             childJustRemovedHook(targetChild, bcsc);
527
528         if (peer != null) {
529                 if (getChildSerializable(peer) != null) serializable--;
530
531                 childJustRemovedHook(peer, pbcsc);
532         }
533         }
534
535         fireChildrenRemoved(new BeanContextMembershipEvent JavaDoc(getBeanContextPeer(), peer == null ? new Object JavaDoc[] { targetChild } : new Object JavaDoc[] { targetChild, peer } ));
536
537     }
538
539     return true;
540     }
541
542     /**
543      * Tests to see if all objects in the
544      * specified <tt>Collection</tt> are children of
545      * this <tt>BeanContext</tt>.
546      * @param c the specified <tt>Collection</tt>
547      *
548      * @return <tt>true</tt> if all objects
549      * in the collection are children of
550      * this <tt>BeanContext</tt>, false if not.
551      */

552     public boolean containsAll(Collection JavaDoc c) {
553     synchronized(children) {
554         Iterator JavaDoc i = c.iterator();
555         while (i.hasNext())
556             if(!contains(i.next()))
557             return false;
558
559         return true;
560     }
561     }
562
563     /**
564      * add Collection to set of Children (Unsupported)
565      * implementations must synchronized on the hierarchy lock and "children" protected field
566      * @throws UnsupportedOperationException
567      */

568     public boolean addAll(Collection JavaDoc c) {
569     throw new UnsupportedOperationException JavaDoc();
570     }
571
572     /**
573      * remove all specified children (Unsupported)
574      * implementations must synchronized on the hierarchy lock and "children" protected field
575      * @throws UnsupportedOperationException
576      */

577     public boolean removeAll(Collection JavaDoc c) {
578     throw new UnsupportedOperationException JavaDoc();
579     }
580
581
582     /**
583      * retain only specified children (Unsupported)
584      * implementations must synchronized on the hierarchy lock and "children" protected field
585      * @throws UnsupportedOperationException
586      */

587     public boolean retainAll(Collection JavaDoc c) {
588     throw new UnsupportedOperationException JavaDoc();
589     }
590
591     /**
592      * clear the children (Unsupported)
593      * implementations must synchronized on the hierarchy lock and "children" protected field
594      * @throws UnsupportedOperationException
595      */

596     public void clear() {
597     throw new UnsupportedOperationException JavaDoc();
598     }
599
600     /**
601      * Adds a BeanContextMembershipListener
602      *
603      * @param bcml the BeanContextMembershipListener to add
604      * @throws NullPointerException
605      */

606
607     public void addBeanContextMembershipListener(BeanContextMembershipListener JavaDoc bcml) {
608     if (bcml == null) throw new NullPointerException JavaDoc("listener");
609
610     synchronized(bcmListeners) {
611         if (bcmListeners.contains(bcml))
612         return;
613         else
614             bcmListeners.add(bcml);
615     }
616     }
617
618     /**
619      * Removes a BeanContextMembershipListener
620      *
621      * @param bcml the BeanContextMembershipListener to remove
622      * @throws NullPointerException
623      */

624
625     public void removeBeanContextMembershipListener(BeanContextMembershipListener JavaDoc bcml) {
626     if (bcml == null) throw new NullPointerException JavaDoc("listener");
627
628     synchronized(bcmListeners) {
629         if (!bcmListeners.contains(bcml))
630         return;
631         else
632             bcmListeners.remove(bcml);
633     }
634     }
635
636     /**
637      * @param name the name of the resource requested.
638      * @param bcc the child object making the request.
639      *
640      * @return the requested resource as an InputStream
641      * @throws NullPointerException
642      */

643
644     public InputStream JavaDoc getResourceAsStream(String JavaDoc name, BeanContextChild JavaDoc bcc) {
645     if (name == null) throw new NullPointerException JavaDoc("name");
646     if (bcc == null) throw new NullPointerException JavaDoc("bcc");
647
648     if (containsKey(bcc)) {
649         ClassLoader JavaDoc cl = bcc.getClass().getClassLoader();
650
651         return cl != null ? cl.getResourceAsStream(name)
652                   : ClassLoader.getSystemResourceAsStream(name);
653     } else throw new IllegalArgumentException JavaDoc("Not a valid child");
654     }
655
656     /**
657      * @param name the name of the resource requested.
658      * @param bcc the child object making the request.
659      *
660      * @return the requested resource as an InputStream
661      */

662
663     public URL JavaDoc getResource(String JavaDoc name, BeanContextChild JavaDoc bcc) {
664     if (name == null) throw new NullPointerException JavaDoc("name");
665     if (bcc == null) throw new NullPointerException JavaDoc("bcc");
666
667     if (containsKey(bcc)) {
668         ClassLoader JavaDoc cl = bcc.getClass().getClassLoader();
669
670         return cl != null ? cl.getResource(name)
671                   : ClassLoader.getSystemResource(name);
672     } else throw new IllegalArgumentException JavaDoc("Not a valid child");
673     }
674
675     /**
676      * Sets the new design time value for this <tt>BeanContext</tt>.
677      * @param dTime the new designTime value
678      */

679     public synchronized void setDesignTime(boolean dTime) {
680     if (designTime != dTime) {
681         designTime = dTime;
682
683         firePropertyChange("designMode", Boolean.valueOf(!dTime), Boolean.valueOf(dTime));
684     }
685     }
686
687   
688     /**
689      * Reports whether or not this object is in
690      * currently in design time mode.
691      * @return <tt>true</tt> if in design time mode,
692      * <tt>false</tt> if not
693      */

694     public synchronized boolean isDesignTime() { return designTime; }
695
696     /**
697      * Sets the locale of this BeanContext.
698      * @param newLocale the new locale. This method call will have
699      * no effect if newLocale is <CODE>null</CODE>.
700      * @throws PropertyVetoException if the new value is rejected
701      */

702     public synchronized void setLocale(Locale JavaDoc newLocale) throws PropertyVetoException JavaDoc {
703
704     if ((locale != null && !locale.equals(newLocale)) && newLocale != null) {
705         Locale JavaDoc old = locale;
706
707         fireVetoableChange("locale", old, newLocale); // throws
708

709         locale = newLocale;
710
711         firePropertyChange("locale", old, newLocale);
712     }
713     }
714
715     /**
716      * Gets the locale for this <tt>BeanContext</tt>.
717      *
718      * @return the current Locale of the <tt>BeanContext</tt>
719      */

720     public synchronized Locale JavaDoc getLocale() { return locale; }
721
722     /**
723      * <p>
724      * This method is typically called from the environment in order to determine
725      * if the implementor "needs" a GUI.
726      * </p>
727      * <p>
728      * The algorithm used herein tests the BeanContextPeer, and its current children
729      * to determine if they are either Containers, Components, or if they implement
730      * Visibility and return needsGui() == true.
731      * </p>
732      * @return <tt>true</tt> if the implementor needs a GUI
733      */

734     public synchronized boolean needsGui() {
735     BeanContext JavaDoc bc = getBeanContextPeer();
736
737     if (bc != this) {
738         if (bc instanceof Visibility JavaDoc) return ((Visibility JavaDoc)bc).needsGui();
739
740         if (bc instanceof Container JavaDoc || bc instanceof Component JavaDoc)
741         return true;
742     }
743
744     synchronized(children) {
745         for (Iterator JavaDoc i = children.keySet().iterator(); i.hasNext();) {
746             Object JavaDoc c = i.next();
747
748             try {
749                 return ((Visibility JavaDoc)c).needsGui();
750             } catch (ClassCastException JavaDoc cce) {
751                 // do nothing ...
752
}
753
754             if (c instanceof Container JavaDoc || c instanceof Component JavaDoc)
755                 return true;
756         }
757     }
758
759     return false;
760     }
761
762     /**
763      * notify this instance that it may no longer render a GUI.
764      */

765
766     public synchronized void dontUseGui() {
767     if (okToUseGui) {
768         okToUseGui = false;
769
770         // lets also tell the Children that can that they may not use their GUI's
771
synchronized(children) {
772             for (Iterator JavaDoc i = children.keySet().iterator(); i.hasNext();) {
773             Visibility JavaDoc v = getChildVisibility(i.next());
774
775             if (v != null) v.dontUseGui();
776            }
777         }
778     }
779     }
780
781     /**
782      * Notify this instance that it may now render a GUI
783      */

784
785     public synchronized void okToUseGui() {
786     if (!okToUseGui) {
787         okToUseGui = true;
788
789         // lets also tell the Children that can that they may use their GUI's
790
synchronized(children) {
791             for (Iterator JavaDoc i = children.keySet().iterator(); i.hasNext();) {
792             Visibility JavaDoc v = getChildVisibility(i.next());
793
794             if (v != null) v.okToUseGui();
795             }
796         }
797     }
798     }
799
800     /**
801      * Used to determine if the <tt>BeanContext</tt>
802      * child is avoiding using its GUI.
803      * @return is this instance avoiding using its GUI?
804      * @see Visibility
805      */

806     public boolean avoidingGui() {
807     return !okToUseGui && needsGui();
808     }
809
810     /**
811      * Is this <tt>BeanContext</tt> in the
812      * process of being serialized?
813      * @return if this <tt>BeanContext</tt> is
814      * currently being serialized
815      */

816     public boolean isSerializing() { return serializing; }
817
818     /**
819      * Returns an iterator of all children
820      * of this <tt>BeanContext</tt>.
821      * @return an iterator for all the current BCSChild values
822      */

823     protected Iterator JavaDoc bcsChildren() { synchronized(children) { return children.values().iterator(); } }
824
825     /**
826      * called by writeObject after defaultWriteObject() but prior to
827      * serialization of currently serializable children.
828      *
829      * This method may be overridden by subclasses to perform custom
830      * serialization of their state prior to this superclass serializing
831      * the children.
832      *
833      * This method should not however be used by subclasses to replace their
834      * own implementation (if any) of writeObject().
835      */

836
837     protected void bcsPreSerializationHook(ObjectOutputStream JavaDoc oos) throws IOException JavaDoc {
838     }
839
840     /**
841      * called by readObject after defaultReadObject() but prior to
842      * deserialization of any children.
843      *
844      * This method may be overridden by subclasses to perform custom
845      * deserialization of their state prior to this superclass deserializing
846      * the children.
847      *
848      * This method should not however be used by subclasses to replace their
849      * own implementation (if any) of readObject().
850      */

851
852     protected void bcsPreDeserializationHook(ObjectInputStream JavaDoc ois) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
853     }
854
855     /**
856      * Called by readObject with the newly deserialized child and BCSChild.
857      * @param child the newly deserialized child
858      * @param bcsc the newly deserialized BCSChild
859      */

860     protected void childDeserializedHook(Object JavaDoc child, BCSChild bcsc) {
861     synchronized(children) {
862         children.put(child, bcsc);
863     }
864     }
865
866     /**
867      * Used by writeObject to serialize a Collection.
868      * @param oos the <tt>ObjectOutputStream</tt>
869      * to use during serialization
870      * @param coll the <tt>Collection</tt> to serialize
871      * @throws IOException if serialization failed
872      */

873     protected final void serialize(ObjectOutputStream JavaDoc oos, Collection JavaDoc coll) throws IOException JavaDoc {
874     int count = 0;
875     Object JavaDoc[] objects = coll.toArray();
876     
877     for (int i = 0; i < objects.length; i++) {
878         if (objects[i] instanceof Serializable JavaDoc)
879         count++;
880         else
881         objects[i] = null;
882     }
883
884         oos.writeInt(count); // number of subsequent objects
885

886     for (int i = 0; count > 0; i++) {
887         Object JavaDoc o = objects[i];
888
889         if (o != null) {
890         oos.writeObject(o);
891         count--;
892         }
893     }
894     }
895
896     /**
897      * used by readObject to deserialize a collection.
898      * @param ois the ObjectInputStream to use
899      * @param coll the Collection
900      */

901     protected final void deserialize(ObjectInputStream JavaDoc ois, Collection JavaDoc coll) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
902     int count = 0;
903
904     count = ois.readInt();
905
906     while (count-- > 0) {
907         coll.add(ois.readObject());
908     }
909     }
910
911     /**
912      * Used to serialize all children of
913      * this <tt>BeanContext</tt>.
914      * @param oos the <tt>ObjectOutputStream</tt>
915      * to use during serialization
916      * @throws IOException if serialization failed
917      */

918     public final void writeChildren(ObjectOutputStream JavaDoc oos) throws IOException JavaDoc {
919     if (serializable <= 0) return;
920
921     boolean prev = serializing;
922
923     serializing = true;
924
925     int count = 0;
926
927     synchronized(children) {
928         Iterator JavaDoc i = children.entrySet().iterator();
929
930         while (i.hasNext() && count < serializable) {
931             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)i.next();
932
933             if (entry.getKey() instanceof Serializable JavaDoc) {
934                 try {
935                 oos.writeObject(entry.getKey()); // child
936
oos.writeObject(entry.getValue()); // BCSChild
937
} catch (IOException JavaDoc ioe) {
938                 serializing = prev;
939                 throw ioe;
940             }
941             count++;
942             }
943         }
944     }
945     
946         serializing = prev;
947
948     if (count != serializable) {
949         throw new IOException JavaDoc("wrote different number of children than expected");
950     }
951
952     }
953
954     /**
955      * Serialize the BeanContextSupport, if this instance has a distinct
956      * peer (that is this object is acting as a delegate for another) then
957      * the children of this instance are not serialized here due to a
958      * 'chicken and egg' problem that occurs on deserialization of the
959      * children at the same time as this instance.
960      *
961      * Therefore in situations where there is a distinct peer to this instance
962      * it should always call writeObject() followed by writeChildren() and
963      * readObject() followed by readChildren().
964      *
965      * @param oos the ObjectOutputStream
966      */

967
968     private synchronized void writeObject(ObjectOutputStream JavaDoc oos) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
969     serializing = true;
970
971     synchronized (BeanContext.globalHierarchyLock) {
972         try {
973             oos.defaultWriteObject(); // serialize the BeanContextSupport object
974

975             bcsPreSerializationHook(oos);
976
977             if (serializable > 0 && this.equals(getBeanContextPeer()))
978                 writeChildren(oos);
979
980             serialize(oos, (Collection JavaDoc)bcmListeners);
981         } finally {
982             serializing = false;
983         }
984     }
985     }
986
987     /**
988      * When an instance of this class is used as a delegate for the
989      * implementation of the BeanContext protocols (and its subprotocols)
990      * there exists a 'chicken and egg' problem during deserialization
991      */

992
993     public final void readChildren(ObjectInputStream JavaDoc ois) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
994     int count = serializable;
995
996     while (count-- > 0) {
997         Object JavaDoc child = null;
998         BeanContextSupport.BCSChild JavaDoc bscc = null;
999       
1000        try {
1001            child = ois.readObject();
1002            bscc = (BeanContextSupport.BCSChild JavaDoc)ois.readObject();
1003        } catch (IOException JavaDoc ioe) {
1004        continue;
1005        } catch (ClassNotFoundException JavaDoc cnfe) {
1006        continue;
1007        }
1008
1009
1010        synchronized(child) {
1011        BeanContextChild JavaDoc bcc = null;
1012
1013        try {
1014            bcc = (BeanContextChild JavaDoc)child;
1015        } catch (ClassCastException JavaDoc cce) {
1016            // do nothing;
1017
}
1018
1019        if (bcc != null) {
1020            try {
1021            bcc.setBeanContext(getBeanContextPeer());
1022
1023                   bcc.addPropertyChangeListener("beanContext", childPCL);
1024                   bcc.addVetoableChangeListener("beanContext", childVCL);
1025    
1026            } catch (PropertyVetoException JavaDoc pve) {
1027            continue;
1028            }
1029        }
1030
1031        childDeserializedHook(child, bscc);
1032        }
1033    }
1034    }
1035
1036    /**
1037     * deserialize contents ... if this instance has a distinct peer the
1038     * children are *not* serialized here, the peer's readObject() must call
1039     * readChildren() after deserializing this instance.
1040     */

1041
1042    private synchronized void readObject(ObjectInputStream JavaDoc ois) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1043
1044    synchronized(BeanContext.globalHierarchyLock) {
1045        ois.defaultReadObject();
1046
1047        initialize();
1048
1049        bcsPreDeserializationHook(ois);
1050
1051        if (serializable > 0 && this.equals(getBeanContextPeer()))
1052            readChildren(ois);
1053
1054        deserialize(ois, bcmListeners = new ArrayList JavaDoc(1));
1055    }
1056    }
1057
1058    /**
1059     * subclasses may envelope to monitor veto child property changes.
1060     */

1061
1062    public void vetoableChange(PropertyChangeEvent JavaDoc pce) throws PropertyVetoException JavaDoc {
1063    String JavaDoc propertyName = pce.getPropertyName();
1064    Object JavaDoc source = pce.getSource();
1065
1066    synchronized(children) {
1067        if ("beanContext".equals(propertyName) &&
1068            containsKey(source) &&
1069            !getBeanContextPeer().equals(pce.getNewValue())
1070        ) {
1071            if (!validatePendingRemove(source)) {
1072            throw new PropertyVetoException JavaDoc("current BeanContext vetoes setBeanContext()", pce);
1073            } else ((BCSChild)children.get(source)).setRemovePending(true);
1074        }
1075    }
1076    }
1077
1078    /**
1079     * subclasses may envelope to monitor child property changes.
1080     */

1081
1082    public void propertyChange(PropertyChangeEvent JavaDoc pce) {
1083    String JavaDoc propertyName = pce.getPropertyName();
1084    Object JavaDoc source = pce.getSource();
1085
1086    synchronized(children) {
1087        if ("beanContext".equals(propertyName) &&
1088            containsKey(source) &&
1089            ((BCSChild)children.get(source)).isRemovePending()) {
1090            BeanContext JavaDoc bc = getBeanContextPeer();
1091
1092            if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {
1093                remove(source, false);
1094            } else {
1095            ((BCSChild)children.get(source)).setRemovePending(false);
1096            }
1097        }
1098        }
1099    }
1100
1101    /**
1102     * <p>
1103     * Subclasses of this class may override, or envelope, this method to
1104     * add validation behavior for the BeanContext to examine child objects
1105     * immediately prior to their being added to the BeanContext.
1106     * </p>
1107     *
1108     * @return true iff the child may be added to this BeanContext, otherwise false.
1109     */

1110
1111    protected boolean validatePendingAdd(Object JavaDoc targetChild) {
1112    return true;
1113    }
1114
1115    /**
1116     * <p>
1117     * Subclasses of this class may override, or envelope, this method to
1118     * add validation behavior for the BeanContext to examine child objects
1119     * immediately prior to their being removed from the BeanContext.
1120     * </p>
1121     *
1122     * @return true iff the child may be removed from this BeanContext, otherwise false.
1123     */

1124
1125    protected boolean validatePendingRemove(Object JavaDoc targetChild) {
1126    return true;
1127    }
1128
1129    /**
1130     * subclasses may override this method to simply extend add() semantics
1131     * after the child has been added and before the event notification has
1132     * occurred. The method is called with the child synchronized.
1133     */

1134
1135    protected void childJustAddedHook(Object JavaDoc child, BCSChild bcsc) {
1136    }
1137
1138    /**
1139     * subclasses may override this method to simply extend remove() semantics
1140     * after the child has been removed and before the event notification has
1141     * occurred. The method is called with the child synchronized.
1142     */

1143
1144    protected void childJustRemovedHook(Object JavaDoc child, BCSChild bcsc) {
1145    }
1146
1147    /**
1148     * Gets the Component (if any) associated with the specified child.
1149     * @param child the specified child
1150     * @return the Component (if any) associated with the specified child.
1151     */

1152    protected static final Visibility JavaDoc getChildVisibility(Object JavaDoc child) {
1153    try {
1154        return (Visibility JavaDoc)child;
1155    } catch (ClassCastException JavaDoc cce) {
1156        return null;
1157    }
1158    }
1159 
1160    /**
1161     * Gets the Serializable (if any) associated with the specified Child
1162     * @param child the specified child
1163     * @return the Serializable (if any) associated with the specified Child
1164     */

1165    protected static final Serializable JavaDoc getChildSerializable(Object JavaDoc child) {
1166        try {
1167        return (Serializable JavaDoc)child;
1168    } catch (ClassCastException JavaDoc cce) {
1169        return null;
1170    }
1171    }
1172
1173    /**
1174     * Gets the PropertyChangeListener
1175     * (if any) of the specified child
1176     * @param child the specified child
1177     * @return the PropertyChangeListener (if any) of the specified child
1178     */

1179    protected static final PropertyChangeListener JavaDoc getChildPropertyChangeListener(Object JavaDoc child) {
1180    try {
1181        return (PropertyChangeListener JavaDoc)child;
1182    } catch (ClassCastException JavaDoc cce) {
1183        return null;
1184    }
1185    }
1186
1187    /**
1188     * Gets the VetoableChangeListener
1189     * (if any) of the specified child
1190     * @param child the specified child
1191     * @return the VetoableChangeListener (if any) of the specified child
1192     */

1193    protected static final VetoableChangeListener JavaDoc getChildVetoableChangeListener(Object JavaDoc child) {
1194    try {
1195        return (VetoableChangeListener JavaDoc)child;
1196    } catch (ClassCastException JavaDoc cce) {
1197        return null;
1198    }
1199    }
1200
1201    /**
1202     * Gets the BeanContextMembershipListener
1203     * (if any) of the specified child
1204     * @param child the specified child
1205     * @return the BeanContextMembershipListener (if any) of the specified child
1206     */

1207    protected static final BeanContextMembershipListener JavaDoc getChildBeanContextMembershipListener(Object JavaDoc child) {
1208    try {
1209        return (BeanContextMembershipListener JavaDoc)child;
1210    } catch (ClassCastException JavaDoc cce) {
1211        return null;
1212    }
1213    }
1214
1215    /**
1216     * Gets the BeanContextChild (if any) of the specified child
1217     * @param child the specified child
1218     * @return the BeanContextChild (if any) of the specified child
1219     * @throws IllegalArgumentException if child implements both BeanContextChild and BeanContextProxy
1220     */

1221    protected static final BeanContextChild JavaDoc getChildBeanContextChild(Object JavaDoc child) {
1222        try {
1223        BeanContextChild JavaDoc bcc = (BeanContextChild JavaDoc)child;
1224
1225        if (child instanceof BeanContextChild JavaDoc && child instanceof BeanContextProxy JavaDoc)
1226        throw new IllegalArgumentException JavaDoc("child cannot implement both BeanContextChild and BeanContextProxy");
1227        else
1228        return bcc;
1229    } catch (ClassCastException JavaDoc cce) {
1230        try {
1231        return ((BeanContextProxy JavaDoc)child).getBeanContextProxy();
1232        } catch (ClassCastException JavaDoc cce1) {
1233            return null;
1234        }
1235    }
1236    }
1237
1238    /**
1239     * Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
1240     */

1241
1242    protected final void fireChildrenAdded(BeanContextMembershipEvent JavaDoc bcme) {
1243    Object JavaDoc[] copy;
1244                              
1245    synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1246
1247    for (int i = 0; i < copy.length; i++)
1248        ((BeanContextMembershipListener JavaDoc)copy[i]).childrenAdded(bcme);
1249    }
1250
1251    /**
1252     * Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
1253     */

1254
1255    protected final void fireChildrenRemoved(BeanContextMembershipEvent JavaDoc bcme) {
1256    Object JavaDoc[] copy;
1257                              
1258    synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1259
1260    for (int i = 0; i < copy.length; i++)
1261        ((BeanContextMembershipListener JavaDoc)copy[i]).childrenRemoved(bcme);
1262    }
1263
1264    /**
1265     * protected method called from constructor and readObject to initialize
1266     * transient state of BeanContextSupport instance.
1267     *
1268     * This class uses this method to instantiate inner class listeners used
1269     * to monitor PropertyChange and VetoableChange events on children.
1270     *
1271     * subclasses may envelope this method to add their own initialization
1272     * behavior
1273     */

1274
1275    protected synchronized void initialize() {
1276    children = new HashMap JavaDoc(serializable + 1);
1277    bcmListeners = new ArrayList JavaDoc(1);
1278
1279    childPCL = new PropertyChangeListener JavaDoc() {
1280
1281        /*
1282         * this adaptor is used by the BeanContextSupport class to forward
1283         * property changes from a child to the BeanContext, avoiding
1284         * accidential serialization of the BeanContext by a badly
1285         * behaved Serializable child.
1286         */

1287
1288        public void propertyChange(PropertyChangeEvent JavaDoc pce) {
1289            BeanContextSupport.this.propertyChange(pce);
1290        }
1291    };
1292
1293    childVCL = new VetoableChangeListener JavaDoc() {
1294
1295        /*
1296         * this adaptor is used by the BeanContextSupport class to forward
1297         * vetoable changes from a child to the BeanContext, avoiding
1298         * accidential serialization of the BeanContext by a badly
1299         * behaved Serializable child.
1300         */

1301
1302        public void vetoableChange(PropertyChangeEvent JavaDoc pce) throws PropertyVetoException JavaDoc {
1303            BeanContextSupport.this.vetoableChange(pce);
1304             }
1305        };
1306    }
1307
1308    /**
1309     * Gets a copy of the this BeanContext's children.
1310     * @return a copy of the current nested children
1311     */

1312    protected final Object JavaDoc[] copyChildren() {
1313    synchronized(children) { return children.keySet().toArray(); }
1314    }
1315
1316    /**
1317     * Tests to see if two class objects,
1318     * or their names are equal.
1319     * @param first the first object
1320     * @param second the second object
1321     * @return true if equal, false if not
1322     */

1323    protected static final boolean classEquals(Class JavaDoc first, Class JavaDoc second) {
1324    return first.equals(second) || first.getName().equals(second.getName());
1325    }
1326
1327
1328    /*
1329     * fields
1330     */

1331
1332
1333    /**
1334     * all accesses to the <code> protected HashMap children </code> field
1335     * shall be synchronized on that object.
1336     */

1337    protected transient HashMap JavaDoc children;
1338
1339    private int serializable = 0; // children serializable
1340

1341    /**
1342     * all accesses to the <code> protected ArrayList bcmListeners </code> field
1343     * shall be synchronized on that object.
1344     */

1345    protected transient ArrayList JavaDoc bcmListeners;
1346
1347    //
1348

1349    /**
1350     * The current locale of this BeanContext.
1351     */

1352    protected Locale JavaDoc locale;
1353
1354    /**
1355     * A <tt>boolean</tt> indicating if this
1356     * instance may now render a GUI.
1357     */

1358    protected boolean okToUseGui;
1359
1360
1361    /**
1362     * A <tt>boolean</tt> indicating whether or not
1363     * this object is currently in design time mode.
1364     */

1365    protected boolean designTime;
1366
1367    /*
1368     * transient
1369     */

1370
1371    private transient PropertyChangeListener JavaDoc childPCL;
1372
1373    private transient VetoableChangeListener JavaDoc childVCL;
1374
1375    private transient boolean serializing;
1376}
1377
Popular Tags