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