src/share/classes/java/beans/beancontext/BeanContextSupport.java

Print this page




 237         }
 238     }
 239 
 240     /**
 241      * Determines whether or not the specified object
 242      * is currently a child of this <tt>BeanContext</tt>.
 243      * @param o the Object in question
 244      * @return if this object is a child
 245      */
 246     public boolean containsKey(Object o) {
 247         synchronized(children) {
 248             return children.containsKey(o);
 249         }
 250     }
 251 
 252     /**
 253      * Gets all JavaBean or <tt>BeanContext</tt> instances
 254      * currently nested in this <tt>BeanContext</tt>.
 255      * @return an <tt>Iterator</tt> of the nested children
 256      */
 257     public Iterator iterator() {
 258         synchronized(children) {
 259             return new BCSIterator(children.keySet().iterator());
 260         }
 261     }
 262 
 263     /**
 264      * Gets all JavaBean or <tt>BeanContext</tt>
 265      * instances currently nested in this BeanContext.
 266      */
 267     public Object[] toArray() {
 268         synchronized(children) {
 269             return children.keySet().toArray();
 270         }
 271     }
 272 
 273     /**
 274      * Gets an array containing all children of
 275      * this <tt>BeanContext</tt> that match
 276      * the types contained in arry.
 277      * @param arry The array of object
 278      * types that are of interest.
 279      * @return an array of children
 280      */
 281     public Object[] toArray(Object[] arry) {
 282         synchronized(children) {
 283             return children.keySet().toArray(arry);
 284         }
 285     }
 286 
 287 
 288     /************************************************************************/
 289 
 290     /**
 291      * protected final subclass that encapsulates an iterator but implements
 292      * a noop remove() method.
 293      */
 294 
 295     protected static final class BCSIterator implements Iterator {
 296         BCSIterator(Iterator i) { super(); src = i; }
 297 
 298         public boolean hasNext() { return src.hasNext(); }
 299         public Object  next()    { return src.next();    }
 300         public void    remove()  { /* do nothing */      }
 301 
 302         private Iterator src;
 303     }
 304 
 305     /************************************************************************/
 306 
 307     /*
 308      * protected nested class containing per child information, an instance
 309      * of which is associated with each child in the "children" hashtable.
 310      * subclasses can extend this class to include their own per-child state.
 311      *
 312      * Note that this 'value' is serialized with the corresponding child 'key'
 313      * when the BeanContextSupport is serialized.
 314      */
 315 
 316     protected class BCSChild implements Serializable {
 317 
 318     private static final long serialVersionUID = -5815286101609939109L;
 319 
 320         BCSChild(Object bcc, Object peer) {
 321             super();
 322 


 487      * internal remove used when removal caused by
 488      * unexpected <tt>setBeanContext</tt> or
 489      * by <tt>remove()</tt> invocation.
 490      * @param targetChild the JavaBean, BeanContext, or Object to be removed
 491      * @param callChildSetBC used to indicate that
 492      * the child should be notified that it is no
 493      * longer nested in this <tt>BeanContext</tt>.
 494      * @return whether or not was present before being removed
 495      */
 496     protected boolean remove(Object targetChild, boolean callChildSetBC) {
 497 
 498         if (targetChild == null) throw new IllegalArgumentException();
 499 
 500         synchronized(BeanContext.globalHierarchyLock) {
 501             if (!containsKey(targetChild)) return false;
 502 
 503             if (!validatePendingRemove(targetChild)) {
 504                 throw new IllegalStateException();
 505             }
 506 
 507             BCSChild bcsc  = (BCSChild)children.get(targetChild);
 508             BCSChild pbcsc = null;
 509             Object   peer  = null;
 510 
 511             // we are required to notify the child that it is no longer nested here if
 512             // it implements java.beans.beancontext.BeanContextChild
 513 
 514             synchronized(targetChild) {
 515                 if (callChildSetBC) {
 516                     BeanContextChild cbcc = getChildBeanContextChild(targetChild);
 517                     if (cbcc != null) synchronized(cbcc) {
 518                         cbcc.removePropertyChangeListener("beanContext", childPCL);
 519                         cbcc.removeVetoableChangeListener("beanContext", childVCL);
 520 
 521                         try {
 522                             cbcc.setBeanContext(null);
 523                         } catch (PropertyVetoException pve1) {
 524                             cbcc.addPropertyChangeListener("beanContext", childPCL);
 525                             cbcc.addVetoableChangeListener("beanContext", childVCL);
 526                             throw new IllegalStateException();
 527                         }
 528 
 529                     }
 530                 }
 531 
 532                 synchronized (children) {
 533                     children.remove(targetChild);
 534 
 535                     if (bcsc.isProxyPeer()) {
 536                         pbcsc = (BCSChild)children.get(peer = bcsc.getProxyPeer());
 537                         children.remove(peer);
 538                     }
 539                 }
 540 
 541                 if (getChildSerializable(targetChild) != null) serializable--;
 542 
 543                 childJustRemovedHook(targetChild, bcsc);
 544 
 545                 if (peer != null) {
 546                     if (getChildSerializable(peer) != null) serializable--;
 547 
 548                     childJustRemovedHook(peer, pbcsc);
 549                 }
 550             }
 551 
 552             fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } ));
 553 
 554         }
 555 
 556         return true;
 557     }
 558 
 559     /**
 560      * Tests to see if all objects in the
 561      * specified <tt>Collection</tt> are children of
 562      * this <tt>BeanContext</tt>.
 563      * @param c the specified <tt>Collection</tt>
 564      *
 565      * @return <tt>true</tt> if all objects
 566      * in the collection are children of
 567      * this <tt>BeanContext</tt>, false if not.
 568      */

 569     public boolean containsAll(Collection c) {
 570         synchronized(children) {
 571             Iterator i = c.iterator();
 572             while (i.hasNext())
 573                 if(!contains(i.next()))
 574                     return false;
 575 
 576             return true;
 577         }
 578     }
 579 
 580     /**
 581      * add Collection to set of Children (Unsupported)
 582      * implementations must synchronized on the hierarchy lock and "children" protected field
 583      * @throws UnsupportedOperationException thrown unconditionally by this implementation
 584      * @return this implementation unconditionally throws {@code UnsupportedOperationException}
 585      */

 586     public boolean addAll(Collection c) {
 587         throw new UnsupportedOperationException();
 588     }
 589 
 590     /**
 591      * remove all specified children (Unsupported)
 592      * implementations must synchronized on the hierarchy lock and "children" protected field
 593      * @throws UnsupportedOperationException thrown unconditionally by this implementation
 594      * @return this implementation unconditionally throws {@code UnsupportedOperationException}
 595 
 596      */

 597     public boolean removeAll(Collection c) {
 598         throw new UnsupportedOperationException();
 599     }
 600 
 601 
 602     /**
 603      * retain only specified children (Unsupported)
 604      * implementations must synchronized on the hierarchy lock and "children" protected field
 605      * @throws UnsupportedOperationException thrown unconditionally by this implementation
 606      * @return this implementation unconditionally throws {@code UnsupportedOperationException}
 607      */

 608     public boolean retainAll(Collection c) {
 609         throw new UnsupportedOperationException();
 610     }
 611 
 612     /**
 613      * clear the children (Unsupported)
 614      * implementations must synchronized on the hierarchy lock and "children" protected field
 615      * @throws UnsupportedOperationException thrown unconditionally by this implementation
 616      */
 617     public void clear() {
 618         throw new UnsupportedOperationException();
 619     }
 620 
 621     /**
 622      * Adds a BeanContextMembershipListener
 623      *
 624      * @param  bcml the BeanContextMembershipListener to add
 625      * @throws NullPointerException if the argument is null
 626      */
 627 


 746      * if the implementor "needs" a GUI.
 747      * </p>
 748      * <p>
 749      * The algorithm used herein tests the BeanContextPeer, and its current children
 750      * to determine if they are either Containers, Components, or if they implement
 751      * Visibility and return needsGui() == true.
 752      * </p>
 753      * @return <tt>true</tt> if the implementor needs a GUI
 754      */
 755     public synchronized boolean needsGui() {
 756         BeanContext bc = getBeanContextPeer();
 757 
 758         if (bc != this) {
 759             if (bc instanceof Visibility) return ((Visibility)bc).needsGui();
 760 
 761             if (bc instanceof Container || bc instanceof Component)
 762                 return true;
 763         }
 764 
 765         synchronized(children) {
 766             for (Iterator i = children.keySet().iterator(); i.hasNext();) {
 767                 Object c = i.next();
 768 
 769                 try {
 770                         return ((Visibility)c).needsGui();
 771                     } catch (ClassCastException cce) {
 772                         // do nothing ...
 773                     }
 774 
 775                     if (c instanceof Container || c instanceof Component)
 776                         return true;
 777             }
 778         }
 779 
 780         return false;
 781     }
 782 
 783     /**
 784      * notify this instance that it may no longer render a GUI.
 785      */
 786 
 787     public synchronized void dontUseGui() {
 788         if (okToUseGui) {
 789             okToUseGui = false;
 790 
 791             // lets also tell the Children that can that they may not use their GUI's
 792             synchronized(children) {
 793                 for (Iterator i = children.keySet().iterator(); i.hasNext();) {
 794                     Visibility v = getChildVisibility(i.next());
 795 
 796                     if (v != null) v.dontUseGui();
 797                }
 798             }
 799         }
 800     }
 801 
 802     /**
 803      * Notify this instance that it may now render a GUI
 804      */
 805 
 806     public synchronized void okToUseGui() {
 807         if (!okToUseGui) {
 808             okToUseGui = true;
 809 
 810             // lets also tell the Children that can that they may use their GUI's
 811             synchronized(children) {
 812                 for (Iterator i = children.keySet().iterator(); i.hasNext();) {
 813                     Visibility v = getChildVisibility(i.next());
 814 
 815                     if (v != null) v.okToUseGui();
 816                 }
 817             }
 818         }
 819     }
 820 
 821     /**
 822      * Used to determine if the <tt>BeanContext</tt>
 823      * child is avoiding using its GUI.
 824      * @return is this instance avoiding using its GUI?
 825      * @see Visibility
 826      */
 827     public boolean avoidingGui() {
 828         return !okToUseGui && needsGui();
 829     }
 830 
 831     /**
 832      * Is this <tt>BeanContext</tt> in the
 833      * process of being serialized?
 834      * @return if this <tt>BeanContext</tt> is
 835      * currently being serialized
 836      */
 837     public boolean isSerializing() { return serializing; }
 838 
 839     /**
 840      * Returns an iterator of all children
 841      * of this <tt>BeanContext</tt>.
 842      * @return an iterator for all the current BCSChild values
 843      */
 844     protected Iterator bcsChildren() { synchronized(children) { return children.values().iterator();  } }
 845 
 846     /**
 847      * called by writeObject after defaultWriteObject() but prior to
 848      * serialization of currently serializable children.
 849      *
 850      * This method may be overridden by subclasses to perform custom
 851      * serialization of their state prior to this superclass serializing
 852      * the children.
 853      *
 854      * This method should not however be used by subclasses to replace their
 855      * own implementation (if any) of writeObject().
 856      * @param oos the {@code ObjectOutputStream} to use during serialization
 857      * @throws IOException if serialization failed
 858      */
 859 
 860     protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {
 861     }
 862 
 863     /**
 864      * called by readObject after defaultReadObject() but prior to


 879     }
 880 
 881     /**
 882      * Called by readObject with the newly deserialized child and BCSChild.
 883      * @param child the newly deserialized child
 884      * @param bcsc the newly deserialized BCSChild
 885      */
 886     protected void childDeserializedHook(Object child, BCSChild bcsc) {
 887         synchronized(children) {
 888             children.put(child, bcsc);
 889         }
 890     }
 891 
 892     /**
 893      * Used by writeObject to serialize a Collection.
 894      * @param oos the <tt>ObjectOutputStream</tt>
 895      * to use during serialization
 896      * @param coll the <tt>Collection</tt> to serialize
 897      * @throws IOException if serialization failed
 898      */
 899     protected final void serialize(ObjectOutputStream oos, Collection coll) throws IOException {
 900         int      count   = 0;
 901         Object[] objects = coll.toArray();
 902 
 903         for (int i = 0; i < objects.length; i++) {
 904             if (objects[i] instanceof Serializable)
 905                 count++;
 906             else
 907                 objects[i] = null;
 908         }
 909 
 910         oos.writeInt(count); // number of subsequent objects
 911 
 912         for (int i = 0; count > 0; i++) {
 913             Object o = objects[i];
 914 
 915             if (o != null) {
 916                 oos.writeObject(o);
 917                 count--;
 918             }
 919         }
 920     }
 921 
 922     /**
 923      * used by readObject to deserialize a collection.
 924      * @param ois the ObjectInputStream to use
 925      * @param coll the Collection
 926      * @throws IOException if deserialization failed
 927      * @throws ClassNotFoundException if needed classes are not found
 928      */

 929     protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException {
 930         int count = 0;
 931 
 932         count = ois.readInt();
 933 
 934         while (count-- > 0) {
 935             coll.add(ois.readObject());
 936         }
 937     }
 938 
 939     /**
 940      * Used to serialize all children of
 941      * this <tt>BeanContext</tt>.
 942      * @param oos the <tt>ObjectOutputStream</tt>
 943      * to use during serialization
 944      * @throws IOException if serialization failed
 945      */
 946     public final void writeChildren(ObjectOutputStream oos) throws IOException {
 947         if (serializable <= 0) return;
 948 
 949         boolean prev = serializing;
 950 
 951         serializing = true;
 952 
 953         int count = 0;
 954 
 955         synchronized(children) {
 956             Iterator i = children.entrySet().iterator();
 957 
 958             while (i.hasNext() && count < serializable) {
 959                 Map.Entry entry = (Map.Entry)i.next();
 960 
 961                 if (entry.getKey() instanceof Serializable) {
 962                     try {
 963                         oos.writeObject(entry.getKey());   // child
 964                         oos.writeObject(entry.getValue()); // BCSChild
 965                     } catch (IOException ioe) {
 966                         serializing = prev;
 967                         throw ioe;
 968                     }
 969                     count++;
 970                 }
 971             }
 972         }
 973 
 974         serializing = prev;
 975 
 976         if (count != serializable) {
 977             throw new IOException("wrote different number of children than expected");
 978         }
 979 


1065     }
1066 
1067     /**
1068      * deserialize contents ... if this instance has a distinct peer the
1069      * children are *not* serialized here, the peer's readObject() must call
1070      * readChildren() after deserializing this instance.
1071      */
1072 
1073     private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1074 
1075         synchronized(BeanContext.globalHierarchyLock) {
1076             ois.defaultReadObject();
1077 
1078             initialize();
1079 
1080             bcsPreDeserializationHook(ois);
1081 
1082             if (serializable > 0 && this.equals(getBeanContextPeer()))
1083                 readChildren(ois);
1084 
1085             deserialize(ois, bcmListeners = new ArrayList(1));
1086         }
1087     }
1088 
1089     /**
1090      * subclasses may envelope to monitor veto child property changes.
1091      */
1092 
1093     public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
1094         String propertyName = pce.getPropertyName();
1095         Object source       = pce.getSource();
1096 
1097         synchronized(children) {
1098             if ("beanContext".equals(propertyName) &&
1099                 containsKey(source)                    &&
1100                 !getBeanContextPeer().equals(pce.getNewValue())
1101             ) {
1102                 if (!validatePendingRemove(source)) {
1103                     throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce);
1104                 } else ((BCSChild)children.get(source)).setRemovePending(true);
1105             }
1106         }
1107     }
1108 
1109     /**
1110      * subclasses may envelope to monitor child property changes.
1111      */
1112 
1113     public void propertyChange(PropertyChangeEvent pce) {
1114         String propertyName = pce.getPropertyName();
1115         Object source       = pce.getSource();
1116 
1117         synchronized(children) {
1118             if ("beanContext".equals(propertyName) &&
1119                 containsKey(source)                    &&
1120                 ((BCSChild)children.get(source)).isRemovePending()) {
1121                 BeanContext bc = getBeanContextPeer();
1122 
1123                 if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {
1124                     remove(source, false);
1125                 } else {
1126                     ((BCSChild)children.get(source)).setRemovePending(false);
1127                 }
1128             }
1129         }
1130     }
1131 
1132     /**
1133      * <p>
1134      * Subclasses of this class may override, or envelope, this method to
1135      * add validation behavior for the BeanContext to examine child objects
1136      * immediately prior to their being added to the BeanContext.
1137      * </p>
1138      *
1139      * @param targetChild the child to create the Child on behalf of
1140      * @return true iff the child may be added to this BeanContext, otherwise false.
1141      */
1142 
1143     protected boolean validatePendingAdd(Object targetChild) {
1144         return true;
1145     }
1146 


1295         Object[] copy;
1296 
1297         synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1298 
1299         for (int i = 0; i < copy.length; i++)
1300             ((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme);
1301     }
1302 
1303     /**
1304      * protected method called from constructor and readObject to initialize
1305      * transient state of BeanContextSupport instance.
1306      *
1307      * This class uses this method to instantiate inner class listeners used
1308      * to monitor PropertyChange and VetoableChange events on children.
1309      *
1310      * subclasses may envelope this method to add their own initialization
1311      * behavior
1312      */
1313 
1314     protected synchronized void initialize() {
1315         children     = new HashMap(serializable + 1);
1316         bcmListeners = new ArrayList(1);
1317 
1318         childPCL = new PropertyChangeListener() {
1319 
1320             /*
1321              * this adaptor is used by the BeanContextSupport class to forward
1322              * property changes from a child to the BeanContext, avoiding
1323              * accidential serialization of the BeanContext by a badly
1324              * behaved Serializable child.
1325              */
1326 
1327             public void propertyChange(PropertyChangeEvent pce) {
1328                 BeanContextSupport.this.propertyChange(pce);
1329             }
1330         };
1331 
1332         childVCL = new VetoableChangeListener() {
1333 
1334             /*
1335              * this adaptor is used by the BeanContextSupport class to forward
1336              * vetoable changes from a child to the BeanContext, avoiding


1342                 BeanContextSupport.this.vetoableChange(pce);
1343              }
1344         };
1345     }
1346 
1347     /**
1348      * Gets a copy of the this BeanContext's children.
1349      * @return a copy of the current nested children
1350      */
1351     protected final Object[] copyChildren() {
1352         synchronized(children) { return children.keySet().toArray(); }
1353     }
1354 
1355     /**
1356      * Tests to see if two class objects,
1357      * or their names are equal.
1358      * @param first the first object
1359      * @param second the second object
1360      * @return true if equal, false if not
1361      */
1362     protected static final boolean classEquals(Class first, Class second) {
1363         return first.equals(second) || first.getName().equals(second.getName());
1364     }
1365 
1366 
1367     /*
1368      * fields
1369      */
1370 
1371 
1372     /**
1373      * all accesses to the <code> protected HashMap children </code> field
1374      * shall be synchronized on that object.
1375      */
1376     protected transient HashMap         children;
1377 
1378     private             int             serializable  = 0; // children serializable
1379 
1380     /**
1381      * all accesses to the <code> protected ArrayList bcmListeners </code> field
1382      * shall be synchronized on that object.
1383      */
1384     protected transient ArrayList       bcmListeners;
1385 
1386     //
1387 
1388     /**
1389      * The current locale of this BeanContext.
1390      */
1391     protected           Locale          locale;
1392 
1393     /**
1394      * A <tt>boolean</tt> indicating if this
1395      * instance may now render a GUI.
1396      */
1397     protected           boolean         okToUseGui;
1398 
1399 
1400     /**
1401      * A <tt>boolean</tt> indicating whether or not
1402      * this object is currently in design time mode.
1403      */
1404     protected           boolean         designTime;


 237         }
 238     }
 239 
 240     /**
 241      * Determines whether or not the specified object
 242      * is currently a child of this <tt>BeanContext</tt>.
 243      * @param o the Object in question
 244      * @return if this object is a child
 245      */
 246     public boolean containsKey(Object o) {
 247         synchronized(children) {
 248             return children.containsKey(o);
 249         }
 250     }
 251 
 252     /**
 253      * Gets all JavaBean or <tt>BeanContext</tt> instances
 254      * currently nested in this <tt>BeanContext</tt>.
 255      * @return an <tt>Iterator</tt> of the nested children
 256      */
 257     public Iterator<Object> iterator() {
 258         synchronized(children) {
 259             return new BCSIterator(children.keySet().iterator());
 260         }
 261     }
 262 
 263     /**
 264      * Gets all JavaBean or <tt>BeanContext</tt>
 265      * instances currently nested in this BeanContext.
 266      */
 267     public Object[] toArray() {
 268         synchronized(children) {
 269             return children.keySet().toArray();
 270         }
 271     }
 272 
 273     /**
 274      * Gets an array containing all children of
 275      * this <tt>BeanContext</tt> that match
 276      * the types contained in arry.
 277      * @param arry The array of object
 278      * types that are of interest.
 279      * @return an array of children
 280      */
 281     public Object[] toArray(Object[] arry) {
 282         synchronized(children) {
 283             return children.keySet().toArray(arry);
 284         }
 285     }
 286 
 287 
 288     /************************************************************************/
 289 
 290     /**
 291      * protected final subclass that encapsulates an iterator but implements
 292      * a noop remove() method.
 293      */
 294 
 295     protected static final class BCSIterator implements Iterator<Object> {
 296         BCSIterator(Iterator<?> i) { super(); src = i; }
 297 
 298         public boolean hasNext() { return src.hasNext(); }
 299         public Object       next()    { return src.next();    }
 300         public void    remove()  { /* do nothing */      }
 301 
 302         private Iterator<?> src;
 303     }
 304 
 305     /************************************************************************/
 306 
 307     /*
 308      * protected nested class containing per child information, an instance
 309      * of which is associated with each child in the "children" hashtable.
 310      * subclasses can extend this class to include their own per-child state.
 311      *
 312      * Note that this 'value' is serialized with the corresponding child 'key'
 313      * when the BeanContextSupport is serialized.
 314      */
 315 
 316     protected class BCSChild implements Serializable {
 317 
 318     private static final long serialVersionUID = -5815286101609939109L;
 319 
 320         BCSChild(Object bcc, Object peer) {
 321             super();
 322 


 487      * internal remove used when removal caused by
 488      * unexpected <tt>setBeanContext</tt> or
 489      * by <tt>remove()</tt> invocation.
 490      * @param targetChild the JavaBean, BeanContext, or Object to be removed
 491      * @param callChildSetBC used to indicate that
 492      * the child should be notified that it is no
 493      * longer nested in this <tt>BeanContext</tt>.
 494      * @return whether or not was present before being removed
 495      */
 496     protected boolean remove(Object targetChild, boolean callChildSetBC) {
 497 
 498         if (targetChild == null) throw new IllegalArgumentException();
 499 
 500         synchronized(BeanContext.globalHierarchyLock) {
 501             if (!containsKey(targetChild)) return false;
 502 
 503             if (!validatePendingRemove(targetChild)) {
 504                 throw new IllegalStateException();
 505             }
 506 
 507             BCSChild bcsc  = children.get(targetChild);
 508             BCSChild pbcsc = null;
 509             Object   peer  = null;
 510 
 511             // we are required to notify the child that it is no longer nested here if
 512             // it implements java.beans.beancontext.BeanContextChild
 513 
 514             synchronized(targetChild) {
 515                 if (callChildSetBC) {
 516                     BeanContextChild cbcc = getChildBeanContextChild(targetChild);
 517                     if (cbcc != null) synchronized(cbcc) {
 518                         cbcc.removePropertyChangeListener("beanContext", childPCL);
 519                         cbcc.removeVetoableChangeListener("beanContext", childVCL);
 520 
 521                         try {
 522                             cbcc.setBeanContext(null);
 523                         } catch (PropertyVetoException pve1) {
 524                             cbcc.addPropertyChangeListener("beanContext", childPCL);
 525                             cbcc.addVetoableChangeListener("beanContext", childVCL);
 526                             throw new IllegalStateException();
 527                         }
 528 
 529                     }
 530                 }
 531 
 532                 synchronized (children) {
 533                     children.remove(targetChild);
 534 
 535                     if (bcsc.isProxyPeer()) {
 536                         pbcsc = children.get(peer = bcsc.getProxyPeer());
 537                         children.remove(peer);
 538                     }
 539                 }
 540 
 541                 if (getChildSerializable(targetChild) != null) serializable--;
 542 
 543                 childJustRemovedHook(targetChild, bcsc);
 544 
 545                 if (peer != null) {
 546                     if (getChildSerializable(peer) != null) serializable--;
 547 
 548                     childJustRemovedHook(peer, pbcsc);
 549                 }
 550             }
 551 
 552             fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } ));
 553 
 554         }
 555 
 556         return true;
 557     }
 558 
 559     /**
 560      * Tests to see if all objects in the
 561      * specified <tt>Collection</tt> are children of
 562      * this <tt>BeanContext</tt>.
 563      * @param c the specified <tt>Collection</tt>
 564      *
 565      * @return <tt>true</tt> if all objects
 566      * in the collection are children of
 567      * this <tt>BeanContext</tt>, false if not.
 568      */
 569     @SuppressWarnings("rawtypes")
 570     public boolean containsAll(Collection c) {
 571         synchronized(children) {
 572             Iterator<?> i = c.iterator();
 573             while (i.hasNext())
 574                 if(!contains(i.next()))
 575                     return false;
 576 
 577             return true;
 578         }
 579     }
 580 
 581     /**
 582      * add Collection to set of Children (Unsupported)
 583      * implementations must synchronized on the hierarchy lock and "children" protected field
 584      * @throws UnsupportedOperationException thrown unconditionally by this implementation
 585      * @return this implementation unconditionally throws {@code UnsupportedOperationException}
 586      */
 587     @SuppressWarnings("rawtypes")
 588     public boolean addAll(Collection c) {
 589         throw new UnsupportedOperationException();
 590     }
 591 
 592     /**
 593      * remove all specified children (Unsupported)
 594      * implementations must synchronized on the hierarchy lock and "children" protected field
 595      * @throws UnsupportedOperationException thrown unconditionally by this implementation
 596      * @return this implementation unconditionally throws {@code UnsupportedOperationException}
 597 
 598      */
 599     @SuppressWarnings("rawtypes")
 600     public boolean removeAll(Collection c) {
 601         throw new UnsupportedOperationException();
 602     }
 603 
 604 
 605     /**
 606      * retain only specified children (Unsupported)
 607      * implementations must synchronized on the hierarchy lock and "children" protected field
 608      * @throws UnsupportedOperationException thrown unconditionally by this implementation
 609      * @return this implementation unconditionally throws {@code UnsupportedOperationException}
 610      */
 611     @SuppressWarnings("rawtypes")
 612     public boolean retainAll(Collection c) {
 613         throw new UnsupportedOperationException();
 614     }
 615 
 616     /**
 617      * clear the children (Unsupported)
 618      * implementations must synchronized on the hierarchy lock and "children" protected field
 619      * @throws UnsupportedOperationException thrown unconditionally by this implementation
 620      */
 621     public void clear() {
 622         throw new UnsupportedOperationException();
 623     }
 624 
 625     /**
 626      * Adds a BeanContextMembershipListener
 627      *
 628      * @param  bcml the BeanContextMembershipListener to add
 629      * @throws NullPointerException if the argument is null
 630      */
 631 


 750      * if the implementor "needs" a GUI.
 751      * </p>
 752      * <p>
 753      * The algorithm used herein tests the BeanContextPeer, and its current children
 754      * to determine if they are either Containers, Components, or if they implement
 755      * Visibility and return needsGui() == true.
 756      * </p>
 757      * @return <tt>true</tt> if the implementor needs a GUI
 758      */
 759     public synchronized boolean needsGui() {
 760         BeanContext bc = getBeanContextPeer();
 761 
 762         if (bc != this) {
 763             if (bc instanceof Visibility) return ((Visibility)bc).needsGui();
 764 
 765             if (bc instanceof Container || bc instanceof Component)
 766                 return true;
 767         }
 768 
 769         synchronized(children) {
 770             for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {
 771                 Object c = i.next();
 772 
 773                 try {
 774                         return ((Visibility)c).needsGui();
 775                     } catch (ClassCastException cce) {
 776                         // do nothing ...
 777                     }
 778 
 779                     if (c instanceof Container || c instanceof Component)
 780                         return true;
 781             }
 782         }
 783 
 784         return false;
 785     }
 786 
 787     /**
 788      * notify this instance that it may no longer render a GUI.
 789      */
 790 
 791     public synchronized void dontUseGui() {
 792         if (okToUseGui) {
 793             okToUseGui = false;
 794 
 795             // lets also tell the Children that can that they may not use their GUI's
 796             synchronized(children) {
 797                 for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {
 798                     Visibility v = getChildVisibility(i.next());
 799 
 800                     if (v != null) v.dontUseGui();
 801                }
 802             }
 803         }
 804     }
 805 
 806     /**
 807      * Notify this instance that it may now render a GUI
 808      */
 809 
 810     public synchronized void okToUseGui() {
 811         if (!okToUseGui) {
 812             okToUseGui = true;
 813 
 814             // lets also tell the Children that can that they may use their GUI's
 815             synchronized(children) {
 816                 for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {
 817                     Visibility v = getChildVisibility(i.next());
 818 
 819                     if (v != null) v.okToUseGui();
 820                 }
 821             }
 822         }
 823     }
 824 
 825     /**
 826      * Used to determine if the <tt>BeanContext</tt>
 827      * child is avoiding using its GUI.
 828      * @return is this instance avoiding using its GUI?
 829      * @see Visibility
 830      */
 831     public boolean avoidingGui() {
 832         return !okToUseGui && needsGui();
 833     }
 834 
 835     /**
 836      * Is this <tt>BeanContext</tt> in the
 837      * process of being serialized?
 838      * @return if this <tt>BeanContext</tt> is
 839      * currently being serialized
 840      */
 841     public boolean isSerializing() { return serializing; }
 842 
 843     /**
 844      * Returns an iterator of all children
 845      * of this <tt>BeanContext</tt>.
 846      * @return an iterator for all the current BCSChild values
 847      */
 848     protected Iterator<BCSChild> bcsChildren() { synchronized(children) { return children.values().iterator();  } }
 849 
 850     /**
 851      * called by writeObject after defaultWriteObject() but prior to
 852      * serialization of currently serializable children.
 853      *
 854      * This method may be overridden by subclasses to perform custom
 855      * serialization of their state prior to this superclass serializing
 856      * the children.
 857      *
 858      * This method should not however be used by subclasses to replace their
 859      * own implementation (if any) of writeObject().
 860      * @param oos the {@code ObjectOutputStream} to use during serialization
 861      * @throws IOException if serialization failed
 862      */
 863 
 864     protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {
 865     }
 866 
 867     /**
 868      * called by readObject after defaultReadObject() but prior to


 883     }
 884 
 885     /**
 886      * Called by readObject with the newly deserialized child and BCSChild.
 887      * @param child the newly deserialized child
 888      * @param bcsc the newly deserialized BCSChild
 889      */
 890     protected void childDeserializedHook(Object child, BCSChild bcsc) {
 891         synchronized(children) {
 892             children.put(child, bcsc);
 893         }
 894     }
 895 
 896     /**
 897      * Used by writeObject to serialize a Collection.
 898      * @param oos the <tt>ObjectOutputStream</tt>
 899      * to use during serialization
 900      * @param coll the <tt>Collection</tt> to serialize
 901      * @throws IOException if serialization failed
 902      */
 903     protected final void serialize(ObjectOutputStream oos, Collection<?> coll) throws IOException {
 904         int      count   = 0;
 905         Object[] objects = coll.toArray();
 906 
 907         for (int i = 0; i < objects.length; i++) {
 908             if (objects[i] instanceof Serializable)
 909                 count++;
 910             else
 911                 objects[i] = null;
 912         }
 913 
 914         oos.writeInt(count); // number of subsequent objects
 915 
 916         for (int i = 0; count > 0; i++) {
 917             Object o = objects[i];
 918 
 919             if (o != null) {
 920                 oos.writeObject(o);
 921                 count--;
 922             }
 923         }
 924     }
 925 
 926     /**
 927      * used by readObject to deserialize a collection.
 928      * @param ois the ObjectInputStream to use
 929      * @param coll the Collection
 930      * @throws IOException if deserialization failed
 931      * @throws ClassNotFoundException if needed classes are not found
 932      */
 933     @SuppressWarnings({"rawtypes", "unchecked"})
 934     protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException {
 935         int count = 0;
 936 
 937         count = ois.readInt();
 938 
 939         while (count-- > 0) {
 940             coll.add(ois.readObject());
 941         }
 942     }
 943 
 944     /**
 945      * Used to serialize all children of
 946      * this <tt>BeanContext</tt>.
 947      * @param oos the <tt>ObjectOutputStream</tt>
 948      * to use during serialization
 949      * @throws IOException if serialization failed
 950      */
 951     public final void writeChildren(ObjectOutputStream oos) throws IOException {
 952         if (serializable <= 0) return;
 953 
 954         boolean prev = serializing;
 955 
 956         serializing = true;
 957 
 958         int count = 0;
 959 
 960         synchronized(children) {
 961             Iterator<Map.Entry<Object, BCSChild>> i = children.entrySet().iterator();
 962 
 963             while (i.hasNext() && count < serializable) {
 964                 Map.Entry<Object, BCSChild> entry = i.next();
 965 
 966                 if (entry.getKey() instanceof Serializable) {
 967                     try {
 968                         oos.writeObject(entry.getKey());   // child
 969                         oos.writeObject(entry.getValue()); // BCSChild
 970                     } catch (IOException ioe) {
 971                         serializing = prev;
 972                         throw ioe;
 973                     }
 974                     count++;
 975                 }
 976             }
 977         }
 978 
 979         serializing = prev;
 980 
 981         if (count != serializable) {
 982             throw new IOException("wrote different number of children than expected");
 983         }
 984 


1070     }
1071 
1072     /**
1073      * deserialize contents ... if this instance has a distinct peer the
1074      * children are *not* serialized here, the peer's readObject() must call
1075      * readChildren() after deserializing this instance.
1076      */
1077 
1078     private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1079 
1080         synchronized(BeanContext.globalHierarchyLock) {
1081             ois.defaultReadObject();
1082 
1083             initialize();
1084 
1085             bcsPreDeserializationHook(ois);
1086 
1087             if (serializable > 0 && this.equals(getBeanContextPeer()))
1088                 readChildren(ois);
1089 
1090             deserialize(ois, bcmListeners = new ArrayList<>(1));
1091         }
1092     }
1093 
1094     /**
1095      * subclasses may envelope to monitor veto child property changes.
1096      */
1097 
1098     public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
1099         String propertyName = pce.getPropertyName();
1100         Object source       = pce.getSource();
1101 
1102         synchronized(children) {
1103             if ("beanContext".equals(propertyName) &&
1104                 containsKey(source)                    &&
1105                 !getBeanContextPeer().equals(pce.getNewValue())
1106             ) {
1107                 if (!validatePendingRemove(source)) {
1108                     throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce);
1109                 } else children.get(source).setRemovePending(true);
1110             }
1111         }
1112     }
1113 
1114     /**
1115      * subclasses may envelope to monitor child property changes.
1116      */
1117 
1118     public void propertyChange(PropertyChangeEvent pce) {
1119         String propertyName = pce.getPropertyName();
1120         Object source       = pce.getSource();
1121 
1122         synchronized(children) {
1123             if ("beanContext".equals(propertyName) &&
1124                 containsKey(source)                    &&
1125                 children.get(source).isRemovePending()) {
1126                 BeanContext bc = getBeanContextPeer();
1127 
1128                 if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {
1129                     remove(source, false);
1130                 } else {
1131                     children.get(source).setRemovePending(false);
1132                 }
1133             }
1134         }
1135     }
1136 
1137     /**
1138      * <p>
1139      * Subclasses of this class may override, or envelope, this method to
1140      * add validation behavior for the BeanContext to examine child objects
1141      * immediately prior to their being added to the BeanContext.
1142      * </p>
1143      *
1144      * @param targetChild the child to create the Child on behalf of
1145      * @return true iff the child may be added to this BeanContext, otherwise false.
1146      */
1147 
1148     protected boolean validatePendingAdd(Object targetChild) {
1149         return true;
1150     }
1151 


1300         Object[] copy;
1301 
1302         synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1303 
1304         for (int i = 0; i < copy.length; i++)
1305             ((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme);
1306     }
1307 
1308     /**
1309      * protected method called from constructor and readObject to initialize
1310      * transient state of BeanContextSupport instance.
1311      *
1312      * This class uses this method to instantiate inner class listeners used
1313      * to monitor PropertyChange and VetoableChange events on children.
1314      *
1315      * subclasses may envelope this method to add their own initialization
1316      * behavior
1317      */
1318 
1319     protected synchronized void initialize() {
1320         children     = new HashMap<>(serializable + 1);
1321         bcmListeners = new ArrayList<>(1);
1322 
1323         childPCL = new PropertyChangeListener() {
1324 
1325             /*
1326              * this adaptor is used by the BeanContextSupport class to forward
1327              * property changes from a child to the BeanContext, avoiding
1328              * accidential serialization of the BeanContext by a badly
1329              * behaved Serializable child.
1330              */
1331 
1332             public void propertyChange(PropertyChangeEvent pce) {
1333                 BeanContextSupport.this.propertyChange(pce);
1334             }
1335         };
1336 
1337         childVCL = new VetoableChangeListener() {
1338 
1339             /*
1340              * this adaptor is used by the BeanContextSupport class to forward
1341              * vetoable changes from a child to the BeanContext, avoiding


1347                 BeanContextSupport.this.vetoableChange(pce);
1348              }
1349         };
1350     }
1351 
1352     /**
1353      * Gets a copy of the this BeanContext's children.
1354      * @return a copy of the current nested children
1355      */
1356     protected final Object[] copyChildren() {
1357         synchronized(children) { return children.keySet().toArray(); }
1358     }
1359 
1360     /**
1361      * Tests to see if two class objects,
1362      * or their names are equal.
1363      * @param first the first object
1364      * @param second the second object
1365      * @return true if equal, false if not
1366      */
1367     protected static final boolean classEquals(Class<?> first, Class<?> second) {
1368         return first.equals(second) || first.getName().equals(second.getName());
1369     }
1370 
1371 
1372     /*
1373      * fields
1374      */
1375 
1376 
1377     /**
1378      * all accesses to the <code> protected HashMap children </code> field
1379      * shall be synchronized on that object.
1380      */
1381     protected transient HashMap<Object, BCSChild>         children;
1382 
1383     private             int             serializable  = 0; // children serializable
1384 
1385     /**
1386      * all accesses to the <code> protected ArrayList bcmListeners </code> field
1387      * shall be synchronized on that object.
1388      */
1389     protected transient ArrayList<BeanContextMembershipListener> bcmListeners;
1390 
1391     //
1392 
1393     /**
1394      * The current locale of this BeanContext.
1395      */
1396     protected           Locale          locale;
1397 
1398     /**
1399      * A <tt>boolean</tt> indicating if this
1400      * instance may now render a GUI.
1401      */
1402     protected           boolean         okToUseGui;
1403 
1404 
1405     /**
1406      * A <tt>boolean</tt> indicating whether or not
1407      * this object is currently in design time mode.
1408      */
1409     protected           boolean         designTime;