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