2 * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
26 package java.beans.beancontext;
28 import java.awt.Component;
29 import java.awt.Container;
31 import java.beans.Beans;
32 import java.beans.AppletInitializer;
34 import java.beans.DesignMode;
36 import java.beans.PropertyChangeEvent;
37 import java.beans.PropertyChangeListener;
38 import java.beans.PropertyChangeSupport;
40 import java.beans.VetoableChangeListener;
41 import java.beans.VetoableChangeSupport;
42 import java.beans.PropertyVetoException;
44 import java.beans.Visibility;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.io.ObjectInputStream;
49 import java.io.ObjectOutputStream;
50 import java.io.Serializable;
54 import java.util.ArrayList;
55 import java.util.Collection;
56 import java.util.HashMap;
57 import java.util.Iterator;
58 import java.util.Locale;
63 * This helper class provides a utility implementation of the
64 * java.beans.beancontext.BeanContext interface.
67 * Since this class directly implements the BeanContext interface, the class
68 * can, and is intended to be used either by subclassing this implementation,
69 * or via ad-hoc delegation of an instance of this class from another.
72 * @author Laurence P. G. Cable
75 public class BeanContextSupport extends BeanContextChildSupport
76 implements BeanContext,
78 PropertyChangeListener,
79 VetoableChangeListener {
81 // Fix for bug 4282900 to pass JCK regression test
82 static final long serialVersionUID = -4879613978649577204L;
86 * Construct a BeanContextSupport instance
89 * @param peer The peer <tt>BeanContext</tt> we are
90 * supplying an implementation for,
92 * if this object is its own peer
93 * @param lcle The current Locale for this BeanContext. If
94 * <tt>lcle</tt> is <tt>null</tt>, the default locale
95 * is assigned to the <tt>BeanContext</tt> instance.
96 * @param dTime The initial state,
97 * <tt>true</tt> if in design mode,
98 * <tt>false</tt> if runtime.
99 * @param visible The initial visibility.
100 * @see java.util.Locale#getDefault()
101 * @see java.util.Locale#setDefault(java.util.Locale)
103 public BeanContextSupport(BeanContext peer, Locale lcle, boolean dTime, boolean visible) {
106 locale = lcle != null ? lcle : Locale.getDefault();
108 okToUseGui = visible;
114 * Create an instance using the specified Locale and design mode.
116 * @param peer The peer <tt>BeanContext</tt> we
117 * are supplying an implementation for,
118 * or <tt>null</tt> if this object is its own peer
119 * @param lcle The current Locale for this <tt>BeanContext</tt>. If
120 * <tt>lcle</tt> is <tt>null</tt>, the default locale
121 * is assigned to the <tt>BeanContext</tt> instance.
122 * @param dtime The initial state, <tt>true</tt>
124 * <tt>false</tt> if runtime.
125 * @see java.util.Locale#getDefault()
126 * @see java.util.Locale#setDefault(java.util.Locale)
128 public BeanContextSupport(BeanContext peer, Locale lcle, boolean dtime) {
129 this (peer, lcle, dtime, true);
133 * Create an instance using the specified locale
135 * @param peer The peer BeanContext we are
136 * supplying an implementation for,
137 * or <tt>null</tt> if this object
139 * @param lcle The current Locale for this
140 * <tt>BeanContext</tt>. If
141 * <tt>lcle</tt> is <tt>null</tt>,
143 * is assigned to the <tt>BeanContext</tt>
145 * @see java.util.Locale#getDefault()
146 * @see java.util.Locale#setDefault(java.util.Locale)
148 public BeanContextSupport(BeanContext peer, Locale lcle) {
149 this (peer, lcle, false, true);
153 * Create an instance using with a default locale
155 * @param peer The peer <tt>BeanContext</tt> we are
156 * supplying an implementation for,
157 * or <tt>null</tt> if this object
160 public BeanContextSupport(BeanContext peer) {
161 this (peer, null, false, true);
165 * Create an instance that is not a delegate of another object
168 public BeanContextSupport() {
169 this (null, null, false, true);
173 * Gets the instance of <tt>BeanContext</tt> that
174 * this object is providing the implementation for.
175 * @return the BeanContext instance
177 public BeanContext getBeanContextPeer() { return (BeanContext)getBeanContextChildPeer(); }
181 * The instantiateChild method is a convenience hook
182 * in BeanContext to simplify
183 * the task of instantiating a Bean, nested,
184 * into a <tt>BeanContext</tt>.
187 * The semantics of the beanName parameter are defined by java.beans.Beans.instantate.
190 * @param beanName the name of the Bean to instantiate within this BeanContext
191 * @throws IOException if there is an I/O error when the bean is being deserialized
192 * @throws ClassNotFoundException if the class
193 * identified by the beanName parameter is not found
194 * @return the new object
196 public Object instantiateChild(String beanName)
197 throws IOException, ClassNotFoundException {
198 BeanContext bc = getBeanContextPeer();
200 return Beans.instantiate(bc.getClass().getClassLoader(), beanName, bc);
204 * Gets the number of children currently nested in
207 * @return number of children
210 synchronized(children) {
211 return children.size();
216 * Reports whether or not this
217 * <tt>BeanContext</tt> is empty.
218 * A <tt>BeanContext</tt> is considered
219 * empty when it contains zero
221 * @return if there are not children
223 public boolean isEmpty() {
224 synchronized(children) {
225 return children.isEmpty();
230 * Determines whether or not the specified object
231 * is currently a child of this <tt>BeanContext</tt>.
232 * @param o the Object in question
233 * @return if this object is a child
235 public boolean contains(Object o) {
236 synchronized(children) {
237 return children.containsKey(o);
242 * Determines whether or not the specified object
243 * is currently a child of this <tt>BeanContext</tt>.
244 * @param o the Object in question
245 * @return if this object is a child
247 public boolean containsKey(Object o) {
248 synchronized(children) {
249 return children.containsKey(o);
254 * Gets all JavaBean or <tt>BeanContext</tt> instances
255 * currently nested in this <tt>BeanContext</tt>.
256 * @return an <tt>Iterator</tt> of the nested children
258 public Iterator iterator() {
259 synchronized(children) {
260 return new BCSIterator(children.keySet().iterator());
265 * Gets all JavaBean or <tt>BeanContext</tt>
266 * instances currently nested in this BeanContext.
268 public Object[] toArray() {
269 synchronized(children) {
270 return children.keySet().toArray();
275 * Gets an array containing all children of
276 * this <tt>BeanContext</tt> that match
277 * the types contained in arry.
278 * @param arry The array of object
279 * types that are of interest.
280 * @return an array of children
282 public Object[] toArray(Object[] arry) {
283 synchronized(children) {
284 return children.keySet().toArray(arry);
289 /************************************************************************/
292 * protected final subclass that encapsulates an iterator but implements
293 * a noop remove() method.
296 protected static final class BCSIterator implements Iterator {
297 BCSIterator(Iterator i) { super(); src = i; }
299 public boolean hasNext() { return src.hasNext(); }
300 public Object next() { return src.next(); }
301 public void remove() { /* do nothing */ }
303 private Iterator src;
306 /************************************************************************/
309 * protected nested class containing per child information, an instance
310 * of which is associated with each child in the "children" hashtable.
311 * subclasses can extend this class to include their own per-child state.
313 * Note that this 'value' is serialized with the corresponding child 'key'
314 * when the BeanContextSupport is serialized.
317 protected class BCSChild implements Serializable {
319 private static final long serialVersionUID = -5815286101609939109L;
321 BCSChild(Object bcc, Object peer) {
328 Object getChild() { return child; }
330 void setRemovePending(boolean v) { removePending = v; }
332 boolean isRemovePending() { return removePending; }
334 boolean isProxyPeer() { return proxyPeer != null; }
336 Object getProxyPeer() { return proxyPeer; }
342 private Object child;
343 private Object proxyPeer;
345 private transient boolean removePending;
350 * Subclasses can override this method to insert their own subclass
351 * of Child without having to override add() or the other Collection
352 * methods that add children to the set.
355 * @param targetChild the child to create the Child on behalf of
356 * @param peer the peer if the tragetChild and the peer are related by an implementation of BeanContextProxy
359 protected BCSChild createBCSChild(Object targetChild, Object peer) {
360 return new BCSChild(targetChild, peer);
363 /************************************************************************/
366 * Adds/nests a child within this <tt>BeanContext</tt>.
368 * Invoked as a side effect of java.beans.Beans.instantiate().
369 * If the child object is not valid for adding then this method
370 * throws an IllegalStateException.
374 * @param targetChild The child objects to nest
375 * within this <tt>BeanContext</tt>
376 * @return true if the child was added successfully.
377 * @see #validatePendingAdd
379 public boolean add(Object targetChild) {
381 if (targetChild == null) throw new IllegalArgumentException();
383 // The specification requires that we do nothing if the child
384 // is already nested herein.
386 if (children.containsKey(targetChild)) return false; // test before locking
388 synchronized(BeanContext.globalHierarchyLock) {
389 if (children.containsKey(targetChild)) return false; // check again
391 if (!validatePendingAdd(targetChild)) {
392 throw new IllegalStateException();
396 // The specification requires that we invoke setBeanContext() on the
397 // newly added child if it implements the java.beans.beancontext.BeanContextChild interface
399 BeanContextChild cbcc = getChildBeanContextChild(targetChild);
400 BeanContextChild bccp = null;
402 synchronized(targetChild) {
404 if (targetChild instanceof BeanContextProxy) {
405 bccp = ((BeanContextProxy)targetChild).getBeanContextProxy();
407 if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()");
410 BCSChild bcsc = createBCSChild(targetChild, bccp);
411 BCSChild pbcsc = null;
413 synchronized (children) {
414 children.put(targetChild, bcsc);
416 if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));
419 if (cbcc != null) synchronized(cbcc) {
421 cbcc.setBeanContext(getBeanContextPeer());
422 } catch (PropertyVetoException pve) {
424 synchronized (children) {
425 children.remove(targetChild);
427 if (bccp != null) children.remove(bccp);
430 throw new IllegalStateException();
433 cbcc.addPropertyChangeListener("beanContext", childPCL);
434 cbcc.addVetoableChangeListener("beanContext", childVCL);
437 Visibility v = getChildVisibility(targetChild);
446 if (getChildSerializable(targetChild) != null) serializable++;
448 childJustAddedHook(targetChild, bcsc);
451 v = getChildVisibility(bccp);
460 if (getChildSerializable(bccp) != null) serializable++;
462 childJustAddedHook(bccp, pbcsc);
468 // The specification requires that we fire a notification of the change
470 fireChildrenAdded(new BeanContextMembershipEvent(getBeanContextPeer(), bccp == null ? new Object[] { targetChild } : new Object[] { targetChild, bccp } ));
478 * Removes a child from this BeanContext. If the child object is not
479 * for adding then this method throws an IllegalStateException.
480 * @param targetChild The child objects to remove
481 * @see #validatePendingRemove
483 public boolean remove(Object targetChild) {
484 return remove(targetChild, true);
488 * internal remove used when removal caused by
489 * unexpected <tt>setBeanContext</tt> or
490 * by <tt>remove()</tt> invocation.
491 * @param targetChild the JavaBean, BeanContext, or Object to be removed
492 * @param callChildSetBC used to indicate that
493 * the child should be notified that it is no
494 * longer nested in this <tt>BeanContext</tt>.
496 protected boolean remove(Object targetChild, boolean callChildSetBC) {
498 if (targetChild == null) throw new IllegalArgumentException();
500 synchronized(BeanContext.globalHierarchyLock) {
501 if (!containsKey(targetChild)) return false;
503 if (!validatePendingRemove(targetChild)) {
504 throw new IllegalStateException();
507 BCSChild bcsc = (BCSChild)children.get(targetChild);
508 BCSChild pbcsc = null;
511 // we are required to notify the child that it is no longer nested here if
512 // it implements java.beans.beancontext.BeanContextChild
514 synchronized(targetChild) {
515 if (callChildSetBC) {
516 BeanContextChild cbcc = getChildBeanContextChild(targetChild);
517 if (cbcc != null) synchronized(cbcc) {
518 cbcc.removePropertyChangeListener("beanContext", childPCL);
519 cbcc.removeVetoableChangeListener("beanContext", childVCL);
522 cbcc.setBeanContext(null);
523 } catch (PropertyVetoException pve1) {
524 cbcc.addPropertyChangeListener("beanContext", childPCL);
525 cbcc.addVetoableChangeListener("beanContext", childVCL);
526 throw new IllegalStateException();
532 synchronized (children) {
533 children.remove(targetChild);
535 if (bcsc.isProxyPeer()) {
536 pbcsc = (BCSChild)children.get(peer = bcsc.getProxyPeer());
537 children.remove(peer);
541 if (getChildSerializable(targetChild) != null) serializable--;
543 childJustRemovedHook(targetChild, bcsc);
546 if (getChildSerializable(peer) != null) serializable--;
548 childJustRemovedHook(peer, pbcsc);
552 fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } ));
560 * Tests to see if all objects in the
561 * specified <tt>Collection</tt> are children of
562 * this <tt>BeanContext</tt>.
563 * @param c the specified <tt>Collection</tt>
565 * @return <tt>true</tt> if all objects
566 * in the collection are children of
567 * this <tt>BeanContext</tt>, false if not.
569 public boolean containsAll(Collection c) {
570 synchronized(children) {
571 Iterator i = c.iterator();
573 if(!contains(i.next()))
581 * add Collection to set of Children (Unsupported)
582 * implementations must synchronized on the hierarchy lock and "children" protected field
583 * @throws UnsupportedOperationException
585 public boolean addAll(Collection c) {
586 throw new UnsupportedOperationException();
590 * remove all specified children (Unsupported)
591 * implementations must synchronized on the hierarchy lock and "children" protected field
592 * @throws UnsupportedOperationException
594 public boolean removeAll(Collection c) {
595 throw new UnsupportedOperationException();
600 * retain only specified children (Unsupported)
601 * implementations must synchronized on the hierarchy lock and "children" protected field
602 * @throws UnsupportedOperationException
604 public boolean retainAll(Collection c) {
605 throw new UnsupportedOperationException();
609 * clear the children (Unsupported)
610 * implementations must synchronized on the hierarchy lock and "children" protected field
611 * @throws UnsupportedOperationException
613 public void clear() {
614 throw new UnsupportedOperationException();
618 * Adds a BeanContextMembershipListener
620 * @param bcml the BeanContextMembershipListener to add
621 * @throws NullPointerException
624 public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) {
625 if (bcml == null) throw new NullPointerException("listener");
627 synchronized(bcmListeners) {
628 if (bcmListeners.contains(bcml))
631 bcmListeners.add(bcml);
636 * Removes a BeanContextMembershipListener
638 * @param bcml the BeanContextMembershipListener to remove
639 * @throws NullPointerException
642 public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) {
643 if (bcml == null) throw new NullPointerException("listener");
645 synchronized(bcmListeners) {
646 if (!bcmListeners.contains(bcml))
649 bcmListeners.remove(bcml);
654 * @param name the name of the resource requested.
655 * @param bcc the child object making the request.
657 * @return the requested resource as an InputStream
658 * @throws NullPointerException
661 public InputStream getResourceAsStream(String name, BeanContextChild bcc) {
662 if (name == null) throw new NullPointerException("name");
663 if (bcc == null) throw new NullPointerException("bcc");
665 if (containsKey(bcc)) {
666 ClassLoader cl = bcc.getClass().getClassLoader();
668 return cl != null ? cl.getResourceAsStream(name)
669 : ClassLoader.getSystemResourceAsStream(name);
670 } else throw new IllegalArgumentException("Not a valid child");
674 * @param name the name of the resource requested.
675 * @param bcc the child object making the request.
677 * @return the requested resource as an InputStream
680 public URL getResource(String name, BeanContextChild bcc) {
681 if (name == null) throw new NullPointerException("name");
682 if (bcc == null) throw new NullPointerException("bcc");
684 if (containsKey(bcc)) {
685 ClassLoader cl = bcc.getClass().getClassLoader();
687 return cl != null ? cl.getResource(name)
688 : ClassLoader.getSystemResource(name);
689 } else throw new IllegalArgumentException("Not a valid child");
693 * Sets the new design time value for this <tt>BeanContext</tt>.
694 * @param dTime the new designTime value
696 public synchronized void setDesignTime(boolean dTime) {
697 if (designTime != dTime) {
700 firePropertyChange("designMode", Boolean.valueOf(!dTime), Boolean.valueOf(dTime));
706 * Reports whether or not this object is in
707 * currently in design time mode.
708 * @return <tt>true</tt> if in design time mode,
709 * <tt>false</tt> if not
711 public synchronized boolean isDesignTime() { return designTime; }
714 * Sets the locale of this BeanContext.
715 * @param newLocale the new locale. This method call will have
716 * no effect if newLocale is <CODE>null</CODE>.
717 * @throws PropertyVetoException if the new value is rejected
719 public synchronized void setLocale(Locale newLocale) throws PropertyVetoException {
721 if ((locale != null && !locale.equals(newLocale)) && newLocale != null) {
724 fireVetoableChange("locale", old, newLocale); // throws
728 firePropertyChange("locale", old, newLocale);
733 * Gets the locale for this <tt>BeanContext</tt>.
735 * @return the current Locale of the <tt>BeanContext</tt>
737 public synchronized Locale getLocale() { return locale; }
741 * This method is typically called from the environment in order to determine
742 * if the implementor "needs" a GUI.
745 * The algorithm used herein tests the BeanContextPeer, and its current children
746 * to determine if they are either Containers, Components, or if they implement
747 * Visibility and return needsGui() == true.
749 * @return <tt>true</tt> if the implementor needs a GUI
751 public synchronized boolean needsGui() {
752 BeanContext bc = getBeanContextPeer();
755 if (bc instanceof Visibility) return ((Visibility)bc).needsGui();
757 if (bc instanceof Container || bc instanceof Component)
761 synchronized(children) {
762 for (Iterator i = children.keySet().iterator(); i.hasNext();) {
766 return ((Visibility)c).needsGui();
767 } catch (ClassCastException cce) {
771 if (c instanceof Container || c instanceof Component)
780 * notify this instance that it may no longer render a GUI.
783 public synchronized void dontUseGui() {
787 // lets also tell the Children that can that they may not use their GUI's
788 synchronized(children) {
789 for (Iterator i = children.keySet().iterator(); i.hasNext();) {
790 Visibility v = getChildVisibility(i.next());
792 if (v != null) v.dontUseGui();
799 * Notify this instance that it may now render a GUI
802 public synchronized void okToUseGui() {
806 // lets also tell the Children that can that they may use their GUI's
807 synchronized(children) {
808 for (Iterator i = children.keySet().iterator(); i.hasNext();) {
809 Visibility v = getChildVisibility(i.next());
811 if (v != null) v.okToUseGui();
818 * Used to determine if the <tt>BeanContext</tt>
819 * child is avoiding using its GUI.
820 * @return is this instance avoiding using its GUI?
823 public boolean avoidingGui() {
824 return !okToUseGui && needsGui();
828 * Is this <tt>BeanContext</tt> in the
829 * process of being serialized?
830 * @return if this <tt>BeanContext</tt> is
831 * currently being serialized
833 public boolean isSerializing() { return serializing; }
836 * Returns an iterator of all children
837 * of this <tt>BeanContext</tt>.
838 * @return an iterator for all the current BCSChild values
840 protected Iterator bcsChildren() { synchronized(children) { return children.values().iterator(); } }
843 * called by writeObject after defaultWriteObject() but prior to
844 * serialization of currently serializable children.
846 * This method may be overridden by subclasses to perform custom
847 * serialization of their state prior to this superclass serializing
850 * This method should not however be used by subclasses to replace their
851 * own implementation (if any) of writeObject().
854 protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {
858 * called by readObject after defaultReadObject() but prior to
859 * deserialization of any children.
861 * This method may be overridden by subclasses to perform custom
862 * deserialization of their state prior to this superclass deserializing
865 * This method should not however be used by subclasses to replace their
866 * own implementation (if any) of readObject().
869 protected void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {
873 * Called by readObject with the newly deserialized child and BCSChild.
874 * @param child the newly deserialized child
875 * @param bcsc the newly deserialized BCSChild
877 protected void childDeserializedHook(Object child, BCSChild bcsc) {
878 synchronized(children) {
879 children.put(child, bcsc);
884 * Used by writeObject to serialize a Collection.
885 * @param oos the <tt>ObjectOutputStream</tt>
886 * to use during serialization
887 * @param coll the <tt>Collection</tt> to serialize
888 * @throws IOException if serialization failed
890 protected final void serialize(ObjectOutputStream oos, Collection coll) throws IOException {
892 Object[] objects = coll.toArray();
894 for (int i = 0; i < objects.length; i++) {
895 if (objects[i] instanceof Serializable)
901 oos.writeInt(count); // number of subsequent objects
903 for (int i = 0; count > 0; i++) {
904 Object o = objects[i];
914 * used by readObject to deserialize a collection.
915 * @param ois the ObjectInputStream to use
916 * @param coll the Collection
918 protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException {
921 count = ois.readInt();
923 while (count-- > 0) {
924 coll.add(ois.readObject());
929 * Used to serialize all children of
930 * this <tt>BeanContext</tt>.
931 * @param oos the <tt>ObjectOutputStream</tt>
932 * to use during serialization
933 * @throws IOException if serialization failed
935 public final void writeChildren(ObjectOutputStream oos) throws IOException {
936 if (serializable <= 0) return;
938 boolean prev = serializing;
944 synchronized(children) {
945 Iterator i = children.entrySet().iterator();
947 while (i.hasNext() && count < serializable) {
948 Map.Entry entry = (Map.Entry)i.next();
950 if (entry.getKey() instanceof Serializable) {
952 oos.writeObject(entry.getKey()); // child
953 oos.writeObject(entry.getValue()); // BCSChild
954 } catch (IOException ioe) {
965 if (count != serializable) {
966 throw new IOException("wrote different number of children than expected");
972 * Serialize the BeanContextSupport, if this instance has a distinct
973 * peer (that is this object is acting as a delegate for another) then
974 * the children of this instance are not serialized here due to a
975 * 'chicken and egg' problem that occurs on deserialization of the
976 * children at the same time as this instance.
978 * Therefore in situations where there is a distinct peer to this instance
979 * it should always call writeObject() followed by writeChildren() and
980 * readObject() followed by readChildren().
982 * @param oos the ObjectOutputStream
985 private synchronized void writeObject(ObjectOutputStream oos) throws IOException, ClassNotFoundException {
988 synchronized (BeanContext.globalHierarchyLock) {
990 oos.defaultWriteObject(); // serialize the BeanContextSupport object
992 bcsPreSerializationHook(oos);
994 if (serializable > 0 && this.equals(getBeanContextPeer()))
997 serialize(oos, (Collection)bcmListeners);
1005 * When an instance of this class is used as a delegate for the
1006 * implementation of the BeanContext protocols (and its subprotocols)
1007 * there exists a 'chicken and egg' problem during deserialization
1010 public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1011 int count = serializable;
1013 while (count-- > 0) {
1014 Object child = null;
1015 BeanContextSupport.BCSChild bscc = null;
1018 child = ois.readObject();
1019 bscc = (BeanContextSupport.BCSChild)ois.readObject();
1020 } catch (IOException ioe) {
1022 } catch (ClassNotFoundException cnfe) {
1027 synchronized(child) {
1028 BeanContextChild bcc = null;
1031 bcc = (BeanContextChild)child;
1032 } catch (ClassCastException cce) {
1038 bcc.setBeanContext(getBeanContextPeer());
1040 bcc.addPropertyChangeListener("beanContext", childPCL);
1041 bcc.addVetoableChangeListener("beanContext", childVCL);
1043 } catch (PropertyVetoException pve) {
1048 childDeserializedHook(child, bscc);
1054 * deserialize contents ... if this instance has a distinct peer the
1055 * children are *not* serialized here, the peer's readObject() must call
1056 * readChildren() after deserializing this instance.
1059 private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1061 synchronized(BeanContext.globalHierarchyLock) {
1062 ois.defaultReadObject();
1066 bcsPreDeserializationHook(ois);
1068 if (serializable > 0 && this.equals(getBeanContextPeer()))
1071 deserialize(ois, bcmListeners = new ArrayList(1));
1076 * subclasses may envelope to monitor veto child property changes.
1079 public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
1080 String propertyName = pce.getPropertyName();
1081 Object source = pce.getSource();
1083 synchronized(children) {
1084 if ("beanContext".equals(propertyName) &&
1085 containsKey(source) &&
1086 !getBeanContextPeer().equals(pce.getNewValue())
1088 if (!validatePendingRemove(source)) {
1089 throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce);
1090 } else ((BCSChild)children.get(source)).setRemovePending(true);
1096 * subclasses may envelope to monitor child property changes.
1099 public void propertyChange(PropertyChangeEvent pce) {
1100 String propertyName = pce.getPropertyName();
1101 Object source = pce.getSource();
1103 synchronized(children) {
1104 if ("beanContext".equals(propertyName) &&
1105 containsKey(source) &&
1106 ((BCSChild)children.get(source)).isRemovePending()) {
1107 BeanContext bc = getBeanContextPeer();
1109 if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {
1110 remove(source, false);
1112 ((BCSChild)children.get(source)).setRemovePending(false);
1120 * Subclasses of this class may override, or envelope, this method to
1121 * add validation behavior for the BeanContext to examine child objects
1122 * immediately prior to their being added to the BeanContext.
1125 * @return true iff the child may be added to this BeanContext, otherwise false.
1128 protected boolean validatePendingAdd(Object targetChild) {
1134 * Subclasses of this class may override, or envelope, this method to
1135 * add validation behavior for the BeanContext to examine child objects
1136 * immediately prior to their being removed from the BeanContext.
1139 * @return true iff the child may be removed from this BeanContext, otherwise false.
1142 protected boolean validatePendingRemove(Object targetChild) {
1147 * subclasses may override this method to simply extend add() semantics
1148 * after the child has been added and before the event notification has
1149 * occurred. The method is called with the child synchronized.
1152 protected void childJustAddedHook(Object child, BCSChild bcsc) {
1156 * subclasses may override this method to simply extend remove() semantics
1157 * after the child has been removed and before the event notification has
1158 * occurred. The method is called with the child synchronized.
1161 protected void childJustRemovedHook(Object child, BCSChild bcsc) {
1165 * Gets the Component (if any) associated with the specified child.
1166 * @param child the specified child
1167 * @return the Component (if any) associated with the specified child.
1169 protected static final Visibility getChildVisibility(Object child) {
1171 return (Visibility)child;
1172 } catch (ClassCastException cce) {
1178 * Gets the Serializable (if any) associated with the specified Child
1179 * @param child the specified child
1180 * @return the Serializable (if any) associated with the specified Child
1182 protected static final Serializable getChildSerializable(Object child) {
1184 return (Serializable)child;
1185 } catch (ClassCastException cce) {
1191 * Gets the PropertyChangeListener
1192 * (if any) of the specified child
1193 * @param child the specified child
1194 * @return the PropertyChangeListener (if any) of the specified child
1196 protected static final PropertyChangeListener getChildPropertyChangeListener(Object child) {
1198 return (PropertyChangeListener)child;
1199 } catch (ClassCastException cce) {
1205 * Gets the VetoableChangeListener
1206 * (if any) of the specified child
1207 * @param child the specified child
1208 * @return the VetoableChangeListener (if any) of the specified child
1210 protected static final VetoableChangeListener getChildVetoableChangeListener(Object child) {
1212 return (VetoableChangeListener)child;
1213 } catch (ClassCastException cce) {
1219 * Gets the BeanContextMembershipListener
1220 * (if any) of the specified child
1221 * @param child the specified child
1222 * @return the BeanContextMembershipListener (if any) of the specified child
1224 protected static final BeanContextMembershipListener getChildBeanContextMembershipListener(Object child) {
1226 return (BeanContextMembershipListener)child;
1227 } catch (ClassCastException cce) {
1233 * Gets the BeanContextChild (if any) of the specified child
1234 * @param child the specified child
1235 * @return the BeanContextChild (if any) of the specified child
1236 * @throws IllegalArgumentException if child implements both BeanContextChild and BeanContextProxy
1238 protected static final BeanContextChild getChildBeanContextChild(Object child) {
1240 BeanContextChild bcc = (BeanContextChild)child;
1242 if (child instanceof BeanContextChild && child instanceof BeanContextProxy)
1243 throw new IllegalArgumentException("child cannot implement both BeanContextChild and BeanContextProxy");
1246 } catch (ClassCastException cce) {
1248 return ((BeanContextProxy)child).getBeanContextProxy();
1249 } catch (ClassCastException cce1) {
1256 * Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
1259 protected final void fireChildrenAdded(BeanContextMembershipEvent bcme) {
1262 synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1264 for (int i = 0; i < copy.length; i++)
1265 ((BeanContextMembershipListener)copy[i]).childrenAdded(bcme);
1269 * Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
1272 protected final void fireChildrenRemoved(BeanContextMembershipEvent bcme) {
1275 synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1277 for (int i = 0; i < copy.length; i++)
1278 ((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme);
1282 * protected method called from constructor and readObject to initialize
1283 * transient state of BeanContextSupport instance.
1285 * This class uses this method to instantiate inner class listeners used
1286 * to monitor PropertyChange and VetoableChange events on children.
1288 * subclasses may envelope this method to add their own initialization
1292 protected synchronized void initialize() {
1293 children = new HashMap(serializable + 1);
1294 bcmListeners = new ArrayList(1);
1296 childPCL = new PropertyChangeListener() {
1299 * this adaptor is used by the BeanContextSupport class to forward
1300 * property changes from a child to the BeanContext, avoiding
1301 * accidential serialization of the BeanContext by a badly
1302 * behaved Serializable child.
1305 public void propertyChange(PropertyChangeEvent pce) {
1306 BeanContextSupport.this.propertyChange(pce);
1310 childVCL = new VetoableChangeListener() {
1313 * this adaptor is used by the BeanContextSupport class to forward
1314 * vetoable changes from a child to the BeanContext, avoiding
1315 * accidential serialization of the BeanContext by a badly
1316 * behaved Serializable child.
1319 public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
1320 BeanContextSupport.this.vetoableChange(pce);
1326 * Gets a copy of the this BeanContext's children.
1327 * @return a copy of the current nested children
1329 protected final Object[] copyChildren() {
1330 synchronized(children) { return children.keySet().toArray(); }
1334 * Tests to see if two class objects,
1335 * or their names are equal.
1336 * @param first the first object
1337 * @param second the second object
1338 * @return true if equal, false if not
1340 protected static final boolean classEquals(Class first, Class second) {
1341 return first.equals(second) || first.getName().equals(second.getName());
1351 * all accesses to the <code> protected HashMap children </code> field
1352 * shall be synchronized on that object.
1354 protected transient HashMap children;
1356 private int serializable = 0; // children serializable
1359 * all accesses to the <code> protected ArrayList bcmListeners </code> field
1360 * shall be synchronized on that object.
1362 protected transient ArrayList bcmListeners;
1367 * The current locale of this BeanContext.
1369 protected Locale locale;
1372 * A <tt>boolean</tt> indicating if this
1373 * instance may now render a GUI.
1375 protected boolean okToUseGui;
1379 * A <tt>boolean</tt> indicating whether or not
1380 * this object is currently in design time mode.
1382 protected boolean designTime;
1388 private transient PropertyChangeListener childPCL;
1390 private transient VetoableChangeListener childVCL;
1392 private transient boolean serializing;