src/share/classes/java/beans/beancontext/BeanContextSupport.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 16 Jun 2009 17:53:32 +0200
changeset 1238 57914fd9382f
parent 0 37a05a11f281
child 1240 4b353465cd30
permissions -rw-r--r--
Separatelly compiling Beans and Applet modules. Using 'code injection' to allow Beans class to perform its Applet related functionality if Applet module is around.
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
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
duke@0
   196
        return Beans.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
}