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