History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/beans/beancontext/BeanContextSupport.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/beans/beancontext/BeanContextSupport.java+1393−0
@@ -0,0 +1,1393 @@
1+/*
2+ * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.beans.beancontext;
27+
28+import java.awt.Component;
29+import java.awt.Container;
30+
31+import java.beans.Beans;
32+import java.beans.AppletInitializer;
33+
34+import java.beans.DesignMode;
35+
36+import java.beans.PropertyChangeEvent;
37+import java.beans.PropertyChangeListener;
38+import java.beans.PropertyChangeSupport;
39+
40+import java.beans.VetoableChangeListener;
41+import java.beans.VetoableChangeSupport;
42+import java.beans.PropertyVetoException;
43+
44+import java.beans.Visibility;
45+
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;
51+
52+import java.net.URL;
53+
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;
59+import java.util.Map;
60+
61+
62+/**
63+ * This helper class provides a utility implementation of the
64+ * java.beans.beancontext.BeanContext interface.
65+ * </p>
66+ * <p>
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.
70+ * </p>
71+ *
72+ * @author Laurence P. G. Cable
73+ * @since 1.2
74+ */
75+public class BeanContextSupport extends BeanContextChildSupport
76+ implements BeanContext,
77+ Serializable,
78+ PropertyChangeListener,
79+ VetoableChangeListener {
80+
81+ // Fix for bug 4282900 to pass JCK regression test
82+ static final long serialVersionUID = -4879613978649577204L;
83+
84+ /**
85+ *
86+ * Construct a BeanContextSupport instance
87+ *
88+ *
89+ * @param peer The peer <tt>BeanContext</tt> we are
90+ * supplying an implementation for,
91+ * or <tt>null</tt>
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)
102+ */
103+ public BeanContextSupport(BeanContext peer, Locale lcle, boolean dTime, boolean visible) {
104+ super(peer);
105+
106+ locale = lcle != null ? lcle : Locale.getDefault();
107+ designTime = dTime;
108+ okToUseGui = visible;
109+
110+ initialize();
111+ }
112+
113+ /**
114+ * Create an instance using the specified Locale and design mode.
115+ *
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>
123+ * if in design mode,
124+ * <tt>false</tt> if runtime.
125+ * @see java.util.Locale#getDefault()
126+ * @see java.util.Locale#setDefault(java.util.Locale)
127+ */
128+ public BeanContextSupport(BeanContext peer, Locale lcle, boolean dtime) {
129+ this (peer, lcle, dtime, true);
130+ }
131+
132+ /**
133+ * Create an instance using the specified locale
134+ *
135+ * @param peer The peer BeanContext we are
136+ * supplying an implementation for,
137+ * or <tt>null</tt> if this object
138+ * is its own peer
139+ * @param lcle The current Locale for this
140+ * <tt>BeanContext</tt>. If
141+ * <tt>lcle</tt> is <tt>null</tt>,
142+ * the default locale
143+ * is assigned to the <tt>BeanContext</tt>
144+ * instance.
145+ * @see java.util.Locale#getDefault()
146+ * @see java.util.Locale#setDefault(java.util.Locale)
147+ */
148+ public BeanContextSupport(BeanContext peer, Locale lcle) {
149+ this (peer, lcle, false, true);
150+ }
151+
152+ /**
153+ * Create an instance using with a default locale
154+ *
155+ * @param peer The peer <tt>BeanContext</tt> we are
156+ * supplying an implementation for,
157+ * or <tt>null</tt> if this object
158+ * is its own peer
159+ */
160+ public BeanContextSupport(BeanContext peer) {
161+ this (peer, null, false, true);
162+ }
163+
164+ /**
165+ * Create an instance that is not a delegate of another object
166+ */
167+
168+ public BeanContextSupport() {
169+ this (null, null, false, true);
170+ }
171+
172+ /**
173+ * Gets the instance of <tt>BeanContext</tt> that
174+ * this object is providing the implementation for.
175+ * @return the BeanContext instance
176+ */
177+ public BeanContext getBeanContextPeer() { return (BeanContext)getBeanContextChildPeer(); }
178+
179+ /**
180+ * <p>
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>.
185+ * </p>
186+ * <p>
187+ * The semantics of the beanName parameter are defined by java.beans.Beans.instantate.
188+ * </p>
189+ *
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
195+ */
196+ public Object instantiateChild(String beanName)
197+ throws IOException, ClassNotFoundException {
198+ BeanContext bc = getBeanContextPeer();
199+
200+ return Beans.instantiate(bc.getClass().getClassLoader(), beanName, bc);
201+ }
202+
203+ /**
204+ * Gets the number of children currently nested in
205+ * this BeanContext.
206+ *
207+ * @return number of children
208+ */
209+ public int size() {
210+ synchronized(children) {
211+ return children.size();
212+ }
213+ }
214+
215+ /**
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
220+ * nested children.
221+ * @return if there are not children
222+ */
223+ public boolean isEmpty() {
224+ synchronized(children) {
225+ return children.isEmpty();
226+ }
227+ }
228+
229+ /**
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
234+ */
235+ public boolean contains(Object o) {
236+ synchronized(children) {
237+ return children.containsKey(o);
238+ }
239+ }
240+
241+ /**
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
246+ */
247+ public boolean containsKey(Object o) {
248+ synchronized(children) {
249+ return children.containsKey(o);
250+ }
251+ }
252+
253+ /**
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
257+ */
258+ public Iterator iterator() {
259+ synchronized(children) {
260+ return new BCSIterator(children.keySet().iterator());
261+ }
262+ }
263+
264+ /**
265+ * Gets all JavaBean or <tt>BeanContext</tt>
266+ * instances currently nested in this BeanContext.
267+ */
268+ public Object[] toArray() {
269+ synchronized(children) {
270+ return children.keySet().toArray();
271+ }
272+ }
273+
274+ /**
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
281+ */
282+ public Object[] toArray(Object[] arry) {
283+ synchronized(children) {
284+ return children.keySet().toArray(arry);
285+ }
286+ }
287+
288+
289+ /************************************************************************/
290+
291+ /**
292+ * protected final subclass that encapsulates an iterator but implements
293+ * a noop remove() method.
294+ */
295+
296+ protected static final class BCSIterator implements Iterator {
297+ BCSIterator(Iterator i) { super(); src = i; }
298+
299+ public boolean hasNext() { return src.hasNext(); }
300+ public Object next() { return src.next(); }
301+ public void remove() { /* do nothing */ }
302+
303+ private Iterator src;
304+ }
305+
306+ /************************************************************************/
307+
308+ /*
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.
312+ *
313+ * Note that this 'value' is serialized with the corresponding child 'key'
314+ * when the BeanContextSupport is serialized.
315+ */
316+
317+ protected class BCSChild implements Serializable {
318+
319+ private static final long serialVersionUID = -5815286101609939109L;
320+
321+ BCSChild(Object bcc, Object peer) {
322+ super();
323+
324+ child = bcc;
325+ proxyPeer = peer;
326+ }
327+
328+ Object getChild() { return child; }
329+
330+ void setRemovePending(boolean v) { removePending = v; }
331+
332+ boolean isRemovePending() { return removePending; }
333+
334+ boolean isProxyPeer() { return proxyPeer != null; }
335+
336+ Object getProxyPeer() { return proxyPeer; }
337+ /*
338+ * fields
339+ */
340+
341+
342+ private Object child;
343+ private Object proxyPeer;
344+
345+ private transient boolean removePending;
346+ }
347+
348+ /**
349+ * <p>
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.
353+ * </p>
354+ *
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
357+ */
358+
359+ protected BCSChild createBCSChild(Object targetChild, Object peer) {
360+ return new BCSChild(targetChild, peer);
361+ }
362+
363+ /************************************************************************/
364+
365+ /**
366+ * Adds/nests a child within this <tt>BeanContext</tt>.
367+ * <p>
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.
371+ * </p>
372+ *
373+ *
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
378+ */
379+ public boolean add(Object targetChild) {
380+
381+ if (targetChild == null) throw new IllegalArgumentException();
382+
383+ // The specification requires that we do nothing if the child
384+ // is already nested herein.
385+
386+ if (children.containsKey(targetChild)) return false; // test before locking
387+
388+ synchronized(BeanContext.globalHierarchyLock) {
389+ if (children.containsKey(targetChild)) return false; // check again
390+
391+ if (!validatePendingAdd(targetChild)) {
392+ throw new IllegalStateException();
393+ }
394+
395+
396+ // The specification requires that we invoke setBeanContext() on the
397+ // newly added child if it implements the java.beans.beancontext.BeanContextChild interface
398+
399+ BeanContextChild cbcc = getChildBeanContextChild(targetChild);
400+ BeanContextChild bccp = null;
401+
402+ synchronized(targetChild) {
403+
404+ if (targetChild instanceof BeanContextProxy) {
405+ bccp = ((BeanContextProxy)targetChild).getBeanContextProxy();
406+
407+ if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()");
408+ }
409+
410+ BCSChild bcsc = createBCSChild(targetChild, bccp);
411+ BCSChild pbcsc = null;
412+
413+ synchronized (children) {
414+ children.put(targetChild, bcsc);
415+
416+ if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));
417+ }
418+
419+ if (cbcc != null) synchronized(cbcc) {
420+ try {
421+ cbcc.setBeanContext(getBeanContextPeer());
422+ } catch (PropertyVetoException pve) {
423+
424+ synchronized (children) {
425+ children.remove(targetChild);
426+
427+ if (bccp != null) children.remove(bccp);
428+ }
429+
430+ throw new IllegalStateException();
431+ }
432+
433+ cbcc.addPropertyChangeListener("beanContext", childPCL);
434+ cbcc.addVetoableChangeListener("beanContext", childVCL);
435+ }
436+
437+ Visibility v = getChildVisibility(targetChild);
438+
439+ if (v != null) {
440+ if (okToUseGui)
441+ v.okToUseGui();
442+ else
443+ v.dontUseGui();
444+ }
445+
446+ if (getChildSerializable(targetChild) != null) serializable++;
447+
448+ childJustAddedHook(targetChild, bcsc);
449+
450+ if (bccp != null) {
451+ v = getChildVisibility(bccp);
452+
453+ if (v != null) {
454+ if (okToUseGui)
455+ v.okToUseGui();
456+ else
457+ v.dontUseGui();
458+ }
459+
460+ if (getChildSerializable(bccp) != null) serializable++;
461+
462+ childJustAddedHook(bccp, pbcsc);
463+ }
464+
465+
466+ }
467+
468+ // The specification requires that we fire a notification of the change
469+
470+ fireChildrenAdded(new BeanContextMembershipEvent(getBeanContextPeer(), bccp == null ? new Object[] { targetChild } : new Object[] { targetChild, bccp } ));
471+
472+ }
473+
474+ return true;
475+ }
476+
477+ /**
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
482+ */
483+ public boolean remove(Object targetChild) {
484+ return remove(targetChild, true);
485+ }
486+
487+ /**
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>.
495+ */
496+ protected boolean remove(Object targetChild, boolean callChildSetBC) {
497+
498+ if (targetChild == null) throw new IllegalArgumentException();
499+
500+ synchronized(BeanContext.globalHierarchyLock) {
501+ if (!containsKey(targetChild)) return false;
502+
503+ if (!validatePendingRemove(targetChild)) {
504+ throw new IllegalStateException();
505+ }
506+
507+ BCSChild bcsc = (BCSChild)children.get(targetChild);
508+ BCSChild pbcsc = null;
509+ Object peer = null;
510+
511+ // we are required to notify the child that it is no longer nested here if
512+ // it implements java.beans.beancontext.BeanContextChild
513+
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);
520+
521+ try {
522+ cbcc.setBeanContext(null);
523+ } catch (PropertyVetoException pve1) {
524+ cbcc.addPropertyChangeListener("beanContext", childPCL);
525+ cbcc.addVetoableChangeListener("beanContext", childVCL);
526+ throw new IllegalStateException();
527+ }
528+
529+ }
530+ }
531+
532+ synchronized (children) {
533+ children.remove(targetChild);
534+
535+ if (bcsc.isProxyPeer()) {
536+ pbcsc = (BCSChild)children.get(peer = bcsc.getProxyPeer());
537+ children.remove(peer);
538+ }
539+ }
540+
541+ if (getChildSerializable(targetChild) != null) serializable--;
542+
543+ childJustRemovedHook(targetChild, bcsc);
544+
545+ if (peer != null) {
546+ if (getChildSerializable(peer) != null) serializable--;
547+
548+ childJustRemovedHook(peer, pbcsc);
549+ }
550+ }
551+
552+ fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } ));
553+
554+ }
555+
556+ return true;
557+ }
558+
559+ /**
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>
564+ *
565+ * @return <tt>true</tt> if all objects
566+ * in the collection are children of
567+ * this <tt>BeanContext</tt>, false if not.
568+ */
569+ public boolean containsAll(Collection c) {
570+ synchronized(children) {
571+ Iterator i = c.iterator();
572+ while (i.hasNext())
573+ if(!contains(i.next()))
574+ return false;
575+
576+ return true;
577+ }
578+ }
579+
580+ /**
581+ * add Collection to set of Children (Unsupported)
582+ * implementations must synchronized on the hierarchy lock and "children" protected field
583+ * @throws UnsupportedOperationException
584+ */
585+ public boolean addAll(Collection c) {
586+ throw new UnsupportedOperationException();
587+ }
588+
589+ /**
590+ * remove all specified children (Unsupported)
591+ * implementations must synchronized on the hierarchy lock and "children" protected field
592+ * @throws UnsupportedOperationException
593+ */
594+ public boolean removeAll(Collection c) {
595+ throw new UnsupportedOperationException();
596+ }
597+
598+
599+ /**
600+ * retain only specified children (Unsupported)
601+ * implementations must synchronized on the hierarchy lock and "children" protected field
602+ * @throws UnsupportedOperationException
603+ */
604+ public boolean retainAll(Collection c) {
605+ throw new UnsupportedOperationException();
606+ }
607+
608+ /**
609+ * clear the children (Unsupported)
610+ * implementations must synchronized on the hierarchy lock and "children" protected field
611+ * @throws UnsupportedOperationException
612+ */
613+ public void clear() {
614+ throw new UnsupportedOperationException();
615+ }
616+
617+ /**
618+ * Adds a BeanContextMembershipListener
619+ *
620+ * @param bcml the BeanContextMembershipListener to add
621+ * @throws NullPointerException
622+ */
623+
624+ public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) {
625+ if (bcml == null) throw new NullPointerException("listener");
626+
627+ synchronized(bcmListeners) {
628+ if (bcmListeners.contains(bcml))
629+ return;
630+ else
631+ bcmListeners.add(bcml);
632+ }
633+ }
634+
635+ /**
636+ * Removes a BeanContextMembershipListener
637+ *
638+ * @param bcml the BeanContextMembershipListener to remove
639+ * @throws NullPointerException
640+ */
641+
642+ public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) {
643+ if (bcml == null) throw new NullPointerException("listener");
644+
645+ synchronized(bcmListeners) {
646+ if (!bcmListeners.contains(bcml))
647+ return;
648+ else
649+ bcmListeners.remove(bcml);
650+ }
651+ }
652+
653+ /**
654+ * @param name the name of the resource requested.
655+ * @param bcc the child object making the request.
656+ *
657+ * @return the requested resource as an InputStream
658+ * @throws NullPointerException
659+ */
660+
661+ public InputStream getResourceAsStream(String name, BeanContextChild bcc) {
662+ if (name == null) throw new NullPointerException("name");
663+ if (bcc == null) throw new NullPointerException("bcc");
664+
665+ if (containsKey(bcc)) {
666+ ClassLoader cl = bcc.getClass().getClassLoader();
667+
668+ return cl != null ? cl.getResourceAsStream(name)
669+ : ClassLoader.getSystemResourceAsStream(name);
670+ } else throw new IllegalArgumentException("Not a valid child");
671+ }
672+
673+ /**
674+ * @param name the name of the resource requested.
675+ * @param bcc the child object making the request.
676+ *
677+ * @return the requested resource as an InputStream
678+ */
679+
680+ public URL getResource(String name, BeanContextChild bcc) {
681+ if (name == null) throw new NullPointerException("name");
682+ if (bcc == null) throw new NullPointerException("bcc");
683+
684+ if (containsKey(bcc)) {
685+ ClassLoader cl = bcc.getClass().getClassLoader();
686+
687+ return cl != null ? cl.getResource(name)
688+ : ClassLoader.getSystemResource(name);
689+ } else throw new IllegalArgumentException("Not a valid child");
690+ }
691+
692+ /**
693+ * Sets the new design time value for this <tt>BeanContext</tt>.
694+ * @param dTime the new designTime value
695+ */
696+ public synchronized void setDesignTime(boolean dTime) {
697+ if (designTime != dTime) {
698+ designTime = dTime;
699+
700+ firePropertyChange("designMode", Boolean.valueOf(!dTime), Boolean.valueOf(dTime));
701+ }
702+ }
703+
704+
705+ /**
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
710+ */
711+ public synchronized boolean isDesignTime() { return designTime; }
712+
713+ /**
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
718+ */
719+ public synchronized void setLocale(Locale newLocale) throws PropertyVetoException {
720+
721+ if ((locale != null && !locale.equals(newLocale)) && newLocale != null) {
722+ Locale old = locale;
723+
724+ fireVetoableChange("locale", old, newLocale); // throws
725+
726+ locale = newLocale;
727+
728+ firePropertyChange("locale", old, newLocale);
729+ }
730+ }
731+
732+ /**
733+ * Gets the locale for this <tt>BeanContext</tt>.
734+ *
735+ * @return the current Locale of the <tt>BeanContext</tt>
736+ */
737+ public synchronized Locale getLocale() { return locale; }
738+
739+ /**
740+ * <p>
741+ * This method is typically called from the environment in order to determine
742+ * if the implementor "needs" a GUI.
743+ * </p>
744+ * <p>
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.
748+ * </p>
749+ * @return <tt>true</tt> if the implementor needs a GUI
750+ */
751+ public synchronized boolean needsGui() {
752+ BeanContext bc = getBeanContextPeer();
753+
754+ if (bc != this) {
755+ if (bc instanceof Visibility) return ((Visibility)bc).needsGui();
756+
757+ if (bc instanceof Container || bc instanceof Component)
758+ return true;
759+ }
760+
761+ synchronized(children) {
762+ for (Iterator i = children.keySet().iterator(); i.hasNext();) {
763+ Object c = i.next();
764+
765+ try {
766+ return ((Visibility)c).needsGui();
767+ } catch (ClassCastException cce) {
768+ // do nothing ...
769+ }
770+
771+ if (c instanceof Container || c instanceof Component)
772+ return true;
773+ }
774+ }
775+
776+ return false;
777+ }
778+
779+ /**
780+ * notify this instance that it may no longer render a GUI.
781+ */
782+
783+ public synchronized void dontUseGui() {
784+ if (okToUseGui) {
785+ okToUseGui = false;
786+
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());
791+
792+ if (v != null) v.dontUseGui();
793+ }
794+ }
795+ }
796+ }
797+
798+ /**
799+ * Notify this instance that it may now render a GUI
800+ */
801+
802+ public synchronized void okToUseGui() {
803+ if (!okToUseGui) {
804+ okToUseGui = true;
805+
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());
810+
811+ if (v != null) v.okToUseGui();
812+ }
813+ }
814+ }
815+ }
816+
817+ /**
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?
821+ * @see Visibility
822+ */
823+ public boolean avoidingGui() {
824+ return !okToUseGui && needsGui();
825+ }
826+
827+ /**
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
832+ */
833+ public boolean isSerializing() { return serializing; }
834+
835+ /**
836+ * Returns an iterator of all children
837+ * of this <tt>BeanContext</tt>.
838+ * @return an iterator for all the current BCSChild values
839+ */
840+ protected Iterator bcsChildren() { synchronized(children) { return children.values().iterator(); } }
841+
842+ /**
843+ * called by writeObject after defaultWriteObject() but prior to
844+ * serialization of currently serializable children.
845+ *
846+ * This method may be overridden by subclasses to perform custom
847+ * serialization of their state prior to this superclass serializing
848+ * the children.
849+ *
850+ * This method should not however be used by subclasses to replace their
851+ * own implementation (if any) of writeObject().
852+ */
853+
854+ protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {
855+ }
856+
857+ /**
858+ * called by readObject after defaultReadObject() but prior to
859+ * deserialization of any children.
860+ *
861+ * This method may be overridden by subclasses to perform custom
862+ * deserialization of their state prior to this superclass deserializing
863+ * the children.
864+ *
865+ * This method should not however be used by subclasses to replace their
866+ * own implementation (if any) of readObject().
867+ */
868+
869+ protected void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {
870+ }
871+
872+ /**
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
876+ */
877+ protected void childDeserializedHook(Object child, BCSChild bcsc) {
878+ synchronized(children) {
879+ children.put(child, bcsc);
880+ }
881+ }
882+
883+ /**
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
889+ */
890+ protected final void serialize(ObjectOutputStream oos, Collection coll) throws IOException {
891+ int count = 0;
892+ Object[] objects = coll.toArray();
893+
894+ for (int i = 0; i < objects.length; i++) {
895+ if (objects[i] instanceof Serializable)
896+ count++;
897+ else
898+ objects[i] = null;
899+ }
900+
901+ oos.writeInt(count); // number of subsequent objects
902+
903+ for (int i = 0; count > 0; i++) {
904+ Object o = objects[i];
905+
906+ if (o != null) {
907+ oos.writeObject(o);
908+ count--;
909+ }
910+ }
911+ }
912+
913+ /**
914+ * used by readObject to deserialize a collection.
915+ * @param ois the ObjectInputStream to use
916+ * @param coll the Collection
917+ */
918+ protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException {
919+ int count = 0;
920+
921+ count = ois.readInt();
922+
923+ while (count-- > 0) {
924+ coll.add(ois.readObject());
925+ }
926+ }
927+
928+ /**
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
934+ */
935+ public final void writeChildren(ObjectOutputStream oos) throws IOException {
936+ if (serializable <= 0) return;
937+
938+ boolean prev = serializing;
939+
940+ serializing = true;
941+
942+ int count = 0;
943+
944+ synchronized(children) {
945+ Iterator i = children.entrySet().iterator();
946+
947+ while (i.hasNext() && count < serializable) {
948+ Map.Entry entry = (Map.Entry)i.next();
949+
950+ if (entry.getKey() instanceof Serializable) {
951+ try {
952+ oos.writeObject(entry.getKey()); // child
953+ oos.writeObject(entry.getValue()); // BCSChild
954+ } catch (IOException ioe) {
955+ serializing = prev;
956+ throw ioe;
957+ }
958+ count++;
959+ }
960+ }
961+ }
962+
963+ serializing = prev;
964+
965+ if (count != serializable) {
966+ throw new IOException("wrote different number of children than expected");
967+ }
968+
969+ }
970+
971+ /**
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.
977+ *
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().
981+ *
982+ * @param oos the ObjectOutputStream
983+ */
984+
985+ private synchronized void writeObject(ObjectOutputStream oos) throws IOException, ClassNotFoundException {
986+ serializing = true;
987+
988+ synchronized (BeanContext.globalHierarchyLock) {
989+ try {
990+ oos.defaultWriteObject(); // serialize the BeanContextSupport object
991+
992+ bcsPreSerializationHook(oos);
993+
994+ if (serializable > 0 && this.equals(getBeanContextPeer()))
995+ writeChildren(oos);
996+
997+ serialize(oos, (Collection)bcmListeners);
998+ } finally {
999+ serializing = false;
1000+ }
1001+ }
1002+ }
1003+
1004+ /**
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
1008+ */
1009+
1010+ public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1011+ int count = serializable;
1012+
1013+ while (count-- > 0) {
1014+ Object child = null;
1015+ BeanContextSupport.BCSChild bscc = null;
1016+
1017+ try {
1018+ child = ois.readObject();
1019+ bscc = (BeanContextSupport.BCSChild)ois.readObject();
1020+ } catch (IOException ioe) {
1021+ continue;
1022+ } catch (ClassNotFoundException cnfe) {
1023+ continue;
1024+ }
1025+
1026+
1027+ synchronized(child) {
1028+ BeanContextChild bcc = null;
1029+
1030+ try {
1031+ bcc = (BeanContextChild)child;
1032+ } catch (ClassCastException cce) {
1033+ // do nothing;
1034+ }
1035+
1036+ if (bcc != null) {
1037+ try {
1038+ bcc.setBeanContext(getBeanContextPeer());
1039+
1040+ bcc.addPropertyChangeListener("beanContext", childPCL);
1041+ bcc.addVetoableChangeListener("beanContext", childVCL);
1042+
1043+ } catch (PropertyVetoException pve) {
1044+ continue;
1045+ }
1046+ }
1047+
1048+ childDeserializedHook(child, bscc);
1049+ }
1050+ }
1051+ }
1052+
1053+ /**
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.
1057+ */
1058+
1059+ private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1060+
1061+ synchronized(BeanContext.globalHierarchyLock) {
1062+ ois.defaultReadObject();
1063+
1064+ initialize();
1065+
1066+ bcsPreDeserializationHook(ois);
1067+
1068+ if (serializable > 0 && this.equals(getBeanContextPeer()))
1069+ readChildren(ois);
1070+
1071+ deserialize(ois, bcmListeners = new ArrayList(1));
1072+ }
1073+ }
1074+
1075+ /**
1076+ * subclasses may envelope to monitor veto child property changes.
1077+ */
1078+
1079+ public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
1080+ String propertyName = pce.getPropertyName();
1081+ Object source = pce.getSource();
1082+
1083+ synchronized(children) {
1084+ if ("beanContext".equals(propertyName) &&
1085+ containsKey(source) &&
1086+ !getBeanContextPeer().equals(pce.getNewValue())
1087+ ) {
1088+ if (!validatePendingRemove(source)) {
1089+ throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce);
1090+ } else ((BCSChild)children.get(source)).setRemovePending(true);
1091+ }
1092+ }
1093+ }
1094+
1095+ /**
1096+ * subclasses may envelope to monitor child property changes.
1097+ */
1098+
1099+ public void propertyChange(PropertyChangeEvent pce) {
1100+ String propertyName = pce.getPropertyName();
1101+ Object source = pce.getSource();
1102+
1103+ synchronized(children) {
1104+ if ("beanContext".equals(propertyName) &&
1105+ containsKey(source) &&
1106+ ((BCSChild)children.get(source)).isRemovePending()) {
1107+ BeanContext bc = getBeanContextPeer();
1108+
1109+ if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {
1110+ remove(source, false);
1111+ } else {
1112+ ((BCSChild)children.get(source)).setRemovePending(false);
1113+ }
1114+ }
1115+ }
1116+ }
1117+
1118+ /**
1119+ * <p>
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.
1123+ * </p>
1124+ *
1125+ * @return true iff the child may be added to this BeanContext, otherwise false.
1126+ */
1127+
1128+ protected boolean validatePendingAdd(Object targetChild) {
1129+ return true;
1130+ }
1131+
1132+ /**
1133+ * <p>
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.
1137+ * </p>
1138+ *
1139+ * @return true iff the child may be removed from this BeanContext, otherwise false.
1140+ */
1141+
1142+ protected boolean validatePendingRemove(Object targetChild) {
1143+ return true;
1144+ }
1145+
1146+ /**
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.
1150+ */
1151+
1152+ protected void childJustAddedHook(Object child, BCSChild bcsc) {
1153+ }
1154+
1155+ /**
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.
1159+ */
1160+
1161+ protected void childJustRemovedHook(Object child, BCSChild bcsc) {
1162+ }
1163+
1164+ /**
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.
1168+ */
1169+ protected static final Visibility getChildVisibility(Object child) {
1170+ try {
1171+ return (Visibility)child;
1172+ } catch (ClassCastException cce) {
1173+ return null;
1174+ }
1175+ }
1176+
1177+ /**
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
1181+ */
1182+ protected static final Serializable getChildSerializable(Object child) {
1183+ try {
1184+ return (Serializable)child;
1185+ } catch (ClassCastException cce) {
1186+ return null;
1187+ }
1188+ }
1189+
1190+ /**
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
1195+ */
1196+ protected static final PropertyChangeListener getChildPropertyChangeListener(Object child) {
1197+ try {
1198+ return (PropertyChangeListener)child;
1199+ } catch (ClassCastException cce) {
1200+ return null;
1201+ }
1202+ }
1203+
1204+ /**
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
1209+ */
1210+ protected static final VetoableChangeListener getChildVetoableChangeListener(Object child) {
1211+ try {
1212+ return (VetoableChangeListener)child;
1213+ } catch (ClassCastException cce) {
1214+ return null;
1215+ }
1216+ }
1217+
1218+ /**
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
1223+ */
1224+ protected static final BeanContextMembershipListener getChildBeanContextMembershipListener(Object child) {
1225+ try {
1226+ return (BeanContextMembershipListener)child;
1227+ } catch (ClassCastException cce) {
1228+ return null;
1229+ }
1230+ }
1231+
1232+ /**
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
1237+ */
1238+ protected static final BeanContextChild getChildBeanContextChild(Object child) {
1239+ try {
1240+ BeanContextChild bcc = (BeanContextChild)child;
1241+
1242+ if (child instanceof BeanContextChild && child instanceof BeanContextProxy)
1243+ throw new IllegalArgumentException("child cannot implement both BeanContextChild and BeanContextProxy");
1244+ else
1245+ return bcc;
1246+ } catch (ClassCastException cce) {
1247+ try {
1248+ return ((BeanContextProxy)child).getBeanContextProxy();
1249+ } catch (ClassCastException cce1) {
1250+ return null;
1251+ }
1252+ }
1253+ }
1254+
1255+ /**
1256+ * Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
1257+ */
1258+
1259+ protected final void fireChildrenAdded(BeanContextMembershipEvent bcme) {
1260+ Object[] copy;
1261+
1262+ synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1263+
1264+ for (int i = 0; i < copy.length; i++)
1265+ ((BeanContextMembershipListener)copy[i]).childrenAdded(bcme);
1266+ }
1267+
1268+ /**
1269+ * Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
1270+ */
1271+
1272+ protected final void fireChildrenRemoved(BeanContextMembershipEvent bcme) {
1273+ Object[] copy;
1274+
1275+ synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1276+
1277+ for (int i = 0; i < copy.length; i++)
1278+ ((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme);
1279+ }
1280+
1281+ /**
1282+ * protected method called from constructor and readObject to initialize
1283+ * transient state of BeanContextSupport instance.
1284+ *
1285+ * This class uses this method to instantiate inner class listeners used
1286+ * to monitor PropertyChange and VetoableChange events on children.
1287+ *
1288+ * subclasses may envelope this method to add their own initialization
1289+ * behavior
1290+ */
1291+
1292+ protected synchronized void initialize() {
1293+ children = new HashMap(serializable + 1);
1294+ bcmListeners = new ArrayList(1);
1295+
1296+ childPCL = new PropertyChangeListener() {
1297+
1298+ /*
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.
1303+ */
1304+
1305+ public void propertyChange(PropertyChangeEvent pce) {
1306+ BeanContextSupport.this.propertyChange(pce);
1307+ }
1308+ };
1309+
1310+ childVCL = new VetoableChangeListener() {
1311+
1312+ /*
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.
1317+ */
1318+
1319+ public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
1320+ BeanContextSupport.this.vetoableChange(pce);
1321+ }
1322+ };
1323+ }
1324+
1325+ /**
1326+ * Gets a copy of the this BeanContext's children.
1327+ * @return a copy of the current nested children
1328+ */
1329+ protected final Object[] copyChildren() {
1330+ synchronized(children) { return children.keySet().toArray(); }
1331+ }
1332+
1333+ /**
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
1339+ */
1340+ protected static final boolean classEquals(Class first, Class second) {
1341+ return first.equals(second) || first.getName().equals(second.getName());
1342+ }
1343+
1344+
1345+ /*
1346+ * fields
1347+ */
1348+
1349+
1350+ /**
1351+ * all accesses to the <code> protected HashMap children </code> field
1352+ * shall be synchronized on that object.
1353+ */
1354+ protected transient HashMap children;
1355+
1356+ private int serializable = 0; // children serializable
1357+
1358+ /**
1359+ * all accesses to the <code> protected ArrayList bcmListeners </code> field
1360+ * shall be synchronized on that object.
1361+ */
1362+ protected transient ArrayList bcmListeners;
1363+
1364+ //
1365+
1366+ /**
1367+ * The current locale of this BeanContext.
1368+ */
1369+ protected Locale locale;
1370+
1371+ /**
1372+ * A <tt>boolean</tt> indicating if this
1373+ * instance may now render a GUI.
1374+ */
1375+ protected boolean okToUseGui;
1376+
1377+
1378+ /**
1379+ * A <tt>boolean</tt> indicating whether or not
1380+ * this object is currently in design time mode.
1381+ */
1382+ protected boolean designTime;
1383+
1384+ /*
1385+ * transient
1386+ */
1387+
1388+ private transient PropertyChangeListener childPCL;
1389+
1390+ private transient VetoableChangeListener childVCL;
1391+
1392+ private transient boolean serializing;
1393+}