/**
   * When an instance of this class is used as a delegate for the implementation of the BeanContext
   * protocols (and its subprotocols) there exists a 'chicken and egg' problem during
   * deserialization
   */
  public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    int count = serializable;

    while (count-- > 0) {
      Object child = null;
      BeanContextSupport.BCSChild bscc = null;

      try {
        child = ois.readObject();
        bscc = (BeanContextSupport.BCSChild) ois.readObject();
      } catch (IOException ioe) {
        continue;
      } catch (ClassNotFoundException cnfe) {
        continue;
      }

      synchronized (child) {
        BeanContextChild bcc = null;

        try {
          bcc = (BeanContextChild) child;
        } catch (ClassCastException cce) {
          // do nothing;
        }

        if (bcc != null) {
          try {
            bcc.setBeanContext(getBeanContextPeer());

            bcc.addPropertyChangeListener("beanContext", childPCL);
            bcc.addVetoableChangeListener("beanContext", childVCL);

          } catch (PropertyVetoException pve) {
            continue;
          }
        }

        childDeserializedHook(child, bscc);
      }
    }
  }
  /**
   * internal remove used when removal caused by unexpected <tt>setBeanContext</tt> or by
   * <tt>remove()</tt> invocation.
   *
   * @param targetChild the JavaBean, BeanContext, or Object to be removed
   * @param callChildSetBC used to indicate that the child should be notified that it is no longer
   *     nested in this <tt>BeanContext</tt>.
   */
  protected boolean remove(Object targetChild, boolean callChildSetBC) {

    if (targetChild == null) throw new IllegalArgumentException();

    synchronized (BeanContext.globalHierarchyLock) {
      if (!containsKey(targetChild)) return false;

      if (!validatePendingRemove(targetChild)) {
        throw new IllegalStateException();
      }

      BCSChild bcsc = (BCSChild) children.get(targetChild);
      BCSChild pbcsc = null;
      Object peer = null;

      // we are required to notify the child that it is no longer nested here if
      // it implements java.beans.beancontext.BeanContextChild

      synchronized (targetChild) {
        if (callChildSetBC) {
          BeanContextChild cbcc = getChildBeanContextChild(targetChild);
          if (cbcc != null)
            synchronized (cbcc) {
              cbcc.removePropertyChangeListener("beanContext", childPCL);
              cbcc.removeVetoableChangeListener("beanContext", childVCL);

              try {
                cbcc.setBeanContext(null);
              } catch (PropertyVetoException pve1) {
                cbcc.addPropertyChangeListener("beanContext", childPCL);
                cbcc.addVetoableChangeListener("beanContext", childVCL);
                throw new IllegalStateException();
              }
            }
        }

        synchronized (children) {
          children.remove(targetChild);

          if (bcsc.isProxyPeer()) {
            pbcsc = (BCSChild) children.get(peer = bcsc.getProxyPeer());
            children.remove(peer);
          }
        }

        if (getChildSerializable(targetChild) != null) serializable--;

        childJustRemovedHook(targetChild, bcsc);

        if (peer != null) {
          if (getChildSerializable(peer) != null) serializable--;

          childJustRemovedHook(peer, pbcsc);
        }
      }

      fireChildrenRemoved(
          new BeanContextMembershipEvent(
              getBeanContextPeer(),
              peer == null ? new Object[] {targetChild} : new Object[] {targetChild, peer}));
    }

    return true;
  }
  /**
   * Adds/nests a child within this <tt>BeanContext</tt>.
   *
   * <p>Invoked as a side effect of java.beans.Beans.instantiate(). If the child object is not valid
   * for adding then this method throws an IllegalStateException.
   *
   * @param targetChild The child objects to nest within this <tt>BeanContext</tt>
   * @return true if the child was added successfully.
   * @see #validatePendingAdd
   */
  public boolean add(Object targetChild) {

    if (targetChild == null) throw new IllegalArgumentException();

    // The specification requires that we do nothing if the child
    // is already nested herein.

    if (children.containsKey(targetChild)) return false; // test before locking

    synchronized (BeanContext.globalHierarchyLock) {
      if (children.containsKey(targetChild)) return false; // check again

      if (!validatePendingAdd(targetChild)) {
        throw new IllegalStateException();
      }

      // The specification requires that we invoke setBeanContext() on the
      // newly added child if it implements the java.beans.beancontext.BeanContextChild interface

      BeanContextChild cbcc = getChildBeanContextChild(targetChild);
      BeanContextChild bccp = null;

      synchronized (targetChild) {
        if (targetChild instanceof BeanContextProxy) {
          bccp = ((BeanContextProxy) targetChild).getBeanContextProxy();

          if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()");
        }

        BCSChild bcsc = createBCSChild(targetChild, bccp);
        BCSChild pbcsc = null;

        synchronized (children) {
          children.put(targetChild, bcsc);

          if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));
        }

        if (cbcc != null)
          synchronized (cbcc) {
            try {
              cbcc.setBeanContext(getBeanContextPeer());
            } catch (PropertyVetoException pve) {

              synchronized (children) {
                children.remove(targetChild);

                if (bccp != null) children.remove(bccp);
              }

              throw new IllegalStateException();
            }

            cbcc.addPropertyChangeListener("beanContext", childPCL);
            cbcc.addVetoableChangeListener("beanContext", childVCL);
          }

        Visibility v = getChildVisibility(targetChild);

        if (v != null) {
          if (okToUseGui) v.okToUseGui();
          else v.dontUseGui();
        }

        if (getChildSerializable(targetChild) != null) serializable++;

        childJustAddedHook(targetChild, bcsc);

        if (bccp != null) {
          v = getChildVisibility(bccp);

          if (v != null) {
            if (okToUseGui) v.okToUseGui();
            else v.dontUseGui();
          }

          if (getChildSerializable(bccp) != null) serializable++;

          childJustAddedHook(bccp, pbcsc);
        }
      }

      // The specification requires that we fire a notification of the change

      fireChildrenAdded(
          new BeanContextMembershipEvent(
              getBeanContextPeer(),
              bccp == null ? new Object[] {targetChild} : new Object[] {targetChild, bccp}));
    }

    return true;
  }