Source for java.beans.beancontext.BeanContextSupport

   1: /* BeanContextSupport.java --
   2:    Copyright (C) 2003, 2005, 2006  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.beans.beancontext;
  40: 
  41: import java.beans.Beans;
  42: import java.beans.DesignMode;
  43: import java.beans.PropertyChangeEvent;
  44: import java.beans.PropertyChangeListener;
  45: import java.beans.PropertyVetoException;
  46: import java.beans.VetoableChangeListener;
  47: import java.beans.Visibility;
  48: import java.io.IOException;
  49: import java.io.InputStream;
  50: import java.io.ObjectInputStream;
  51: import java.io.ObjectOutputStream;
  52: import java.io.Serializable;
  53: import java.net.URL;
  54: import java.util.ArrayList;
  55: import java.util.Collection;
  56: import java.util.HashMap;
  57: import java.util.Iterator;
  58: import java.util.List;
  59: import java.util.Locale;
  60: 
  61: /**
  62:  * This is a helper class for implementing a bean context.  It is
  63:  * intended to be used either by subclassing or by calling methods
  64:  * of this implementation from another.
  65:  *
  66:  * @author Michael Koch
  67:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  68:  * @since 1.2
  69:  */
  70: public class BeanContextSupport extends BeanContextChildSupport
  71:   implements BeanContext, Serializable, PropertyChangeListener,
  72:   VetoableChangeListener
  73: {
  74:   private static final long serialVersionUID = -4879613978649577204L;
  75: 
  76:   /**
  77:    * Deserializes a stored bean context.  Hook methods are provided to allow
  78:    * subclasses to perform their own deserialization after the default
  79:    * deserialization but prior to the deserialization of the children.  Note that
  80:    * {@link #readChildren(ObjectInputStream)} is only called if there
  81:    * is no distinct peer.  If there is, the peer is expected to call
  82:    * the method instead.
  83:    *
  84:    * @param s the stream to deserialize.
  85:    * @throws ClassNotFoundException if the class of an object being deserialized
  86:    *                                could not be found.
  87:    * @throws IOException if an I/O error occurs.
  88:    */
  89:   private void readObject (ObjectInputStream s)
  90:     throws ClassNotFoundException, IOException
  91:   {
  92:     s.defaultReadObject();
  93:     bcsPreDeserializationHook(s);
  94:     BeanContext peer = getBeanContextPeer();
  95:     if (peer == null || peer == this)
  96:       readChildren(s);
  97:   }
  98: 
  99:   /**
 100:    * Serializes a bean context.  Hook methods are provided to allow
 101:    * subclasses to perform their own serialization after the default
 102:    * serialization but prior to serialization of the children.  Note that
 103:    * {@link #writeChildren(ObjectOutputStream)} is only called if there
 104:    * is no distinct peer.  If there is, the peer is expected to call
 105:    * the method instead.
 106:    *
 107:    * @param s the stream to serialize.
 108:    * @throws ClassNotFoundException if the class of an object being deserialized
 109:    *                                could not be found.
 110:    * @throws IOException if an I/O error occurs.
 111:    */
 112:   private void writeObject (ObjectOutputStream s)
 113:     throws ClassNotFoundException, IOException
 114:   {
 115:     serializing = true;
 116:     s.defaultWriteObject();
 117:     bcsPreSerializationHook(s);
 118:     BeanContext peer = getBeanContextPeer();
 119:     if (peer == null || peer == this)
 120:       writeChildren(s);
 121:     serializing = false;
 122:   }
 123: 
 124:   protected class BCSChild implements Serializable
 125:   {
 126:     private static final long serialVersionUID = -5815286101609939109L;
 127: 
 128:     private Object targetChild;
 129:     private Object peer;
 130: 
 131:     BCSChild(Object targetChild, Object peer)
 132:     {
 133:       this.targetChild = targetChild;
 134:       this.peer = peer;
 135:     }
 136: 
 137:     private Object getTargetChild()
 138:     {
 139:       return targetChild;
 140:     }
 141: 
 142:   }
 143: 
 144:   protected static final class BCSIterator implements Iterator
 145:   {
 146:     private Iterator child;
 147: 
 148:     BCSIterator(Iterator child)
 149:     {
 150:       this.child = child;
 151:     }
 152: 
 153:     public boolean hasNext ()
 154:     {
 155:       return child.hasNext();
 156:     }
 157: 
 158:     public Object next ()
 159:     {
 160:       return child.next();
 161:     }
 162: 
 163:     public void remove ()
 164:     {
 165:       // This must be a noop remove operation.
 166:     }
 167:   }
 168: 
 169:   protected transient ArrayList bcmListeners;
 170: 
 171:   protected transient HashMap children;
 172: 
 173:   protected transient boolean designTime;
 174: 
 175:   protected transient Locale locale;
 176: 
 177:   protected transient boolean okToUseGui;
 178: 
 179:   private transient boolean serializing;
 180: 
 181:   /**
 182:    * Construct a BeanContextSupport instance.
 183:    */
 184:   public BeanContextSupport ()
 185:   {
 186:     this (null, null, false, true);
 187:   }
 188: 
 189:   /**
 190:    * Construct a BeanContextSupport instance.
 191:    *
 192:    * @param peer  the bean context peer (<code>null</code> permitted).
 193:    */
 194:   public BeanContextSupport(BeanContext peer)
 195:   {
 196:     this (peer, null, false, true);
 197:   }
 198: 
 199:   /**
 200:    * Construct a BeanContextSupport instance.
 201:    *
 202:    * @param peer  the bean context peer (<code>null</code> permitted).
 203:    * @param locale  the locale (<code>null</code> permitted, equivalent to
 204:    *     the default locale).
 205:    */
 206:   public BeanContextSupport (BeanContext peer, Locale locale)
 207:   {
 208:     this (peer, locale, false, true);
 209:   }
 210: 
 211:   /**
 212:    * Construct a BeanContextSupport instance.
 213:    *
 214:    * @param peer  the bean context peer (<code>null</code> permitted).
 215:    * @param locale  the locale (<code>null</code> permitted, equivalent to
 216:    *     the default locale).
 217:    * @param dtime  a flag indicating whether or not the bean context is in
 218:    *     design time mode.
 219:    */
 220:   public BeanContextSupport (BeanContext peer, Locale locale, boolean dtime)
 221:   {
 222:     this (peer, locale, dtime, true);
 223:   }
 224: 
 225:   /**
 226:    * Construct a BeanContextSupport instance.
 227:    *
 228:    * @param peer  the bean context peer (<code>null</code> permitted).
 229:    * @param locale  the locale (<code>null</code> permitted, equivalent to
 230:    *     the default locale).
 231:    * @param dtime  a flag indicating whether or not the bean context is in
 232:    *     design time mode.
 233:    * @param visible  initial value of the <code>okToUseGui</code> flag.
 234:    */
 235:   public BeanContextSupport (BeanContext peer, Locale locale, boolean dtime,
 236:                              boolean visible)
 237:   {
 238:     super(peer);
 239: 
 240:     this.locale = locale == null ? Locale.getDefault() : locale;
 241:     designTime = dtime;
 242:     okToUseGui = visible;
 243: 
 244:     initialize ();
 245:   }
 246: 
 247:   /**
 248:    * <p>
 249:    * Add a child to the bean context.  A child can be a simple
 250:    * <code>Object</code>, a <code>BeanContextChild</code>
 251:    * or another <code>BeanContext</code>.
 252:    * </p>
 253:    * <p>
 254:    * The children of a <code>BeanContext</code> form a set.  As
 255:    * a result, this method returns <code>false</code> if the given
 256:    * object is already a child of this context.
 257:    * </p>
 258:    * <p>
 259:    * If the child is a <code>BeanContextChild</code>, or a proxy
 260:    * for such a child, the <code>setBeanContext()</code> method
 261:    * is invoked on the child.  If this operation is vetoed by the
 262:    * child, via throwing a <code>PropertyVetoException</code>,
 263:    * then the current completion state of the <code>add()</code>
 264:    * operation is rolled back and a <code>IllegalStateException</code>
 265:    * is thrown.  If the <code>BeanContextChild</code> is successfully
 266:    * added, then the context registers with its
 267:    * <code>PropertyChangeListener</code> and
 268:    * <code>VetoableChangeListener</code> for "beanContext" events.
 269:    * </p>
 270:    * <p>
 271:    * If the child implements <code>java.beans.Visibility</code>,
 272:    * then its ability to use a GUI is set based on that of
 273:    * this context.
 274:    * </p>
 275:    * <p>
 276:    * A <code>BeanContextMembershipEvent</code> is fired when the
 277:    * child is successfully added to the bean context.
 278:    * </p>
 279:    * <p>
 280:    * This method is synchronized over the global hierarchy lock.
 281:    * </p>
 282:    *
 283:    * @param targetChild the child to add.
 284:    * @return false if the child has already been added.
 285:    * @throws IllegalArgumentException if the child is null.
 286:    * @throws IllegalStateException if the child vetos the setting
 287:    *                               of its context.
 288:    */
 289:   public boolean add(Object targetChild)
 290:   {
 291:     synchronized (globalHierarchyLock)
 292:       {
 293:         if (targetChild == null)
 294:           throw new IllegalArgumentException();
 295: 
 296:         BCSChild child;
 297:         synchronized (children)
 298:           {
 299:             if (children.containsKey(targetChild)
 300:                 || ! validatePendingAdd(targetChild))
 301:               return false;
 302:             child = createBCSChild(targetChild, beanContextChildPeer);
 303:             children.put(targetChild, child);
 304:           }
 305:         synchronized (targetChild)
 306:           {
 307:             BeanContextChild bcChild = null;
 308:             if (targetChild instanceof BeanContextChild)
 309:               bcChild = (BeanContextChild) targetChild;
 310:             if (targetChild instanceof BeanContextProxy)
 311:               bcChild = ((BeanContextProxy) targetChild).getBeanContextProxy();
 312:             if (bcChild != null)
 313:               try
 314:                 {
 315:                   bcChild.setBeanContext(this);
 316:                   bcChild.addVetoableChangeListener("beanContext", this);
 317:                   bcChild.addPropertyChangeListener("beanContext", this);
 318:                 }
 319:               catch (PropertyVetoException e)
 320:                 {
 321:                   synchronized (children)
 322:                     {
 323:                       children.remove(targetChild);
 324:                     }
 325:                   throw new IllegalStateException("The child refused to " +
 326:                                                   "associate itself with " +
 327:                                                   "this context.", e);
 328:                 }
 329:             if (targetChild instanceof Visibility)
 330:               {
 331:                 Visibility visibleChild = (Visibility) targetChild;
 332:                 if (okToUseGui)
 333:                   visibleChild.okToUseGui();
 334:                 else
 335:                   visibleChild.dontUseGui();
 336:               }
 337:             childJustAddedHook(targetChild, child);
 338:           }
 339:         fireChildrenAdded(new BeanContextMembershipEvent(this,
 340:                                                          new Object[]{ targetChild }));
 341:         return true;
 342:       }
 343:   }
 344: 
 345:   public boolean addAll (Collection c)
 346:   {
 347:     // Intentionally throws an exception.
 348:     throw new UnsupportedOperationException();
 349:   }
 350: 
 351:   public void addBeanContextMembershipListener
 352:     (BeanContextMembershipListener listener)
 353:   {
 354:     synchronized (bcmListeners)
 355:       {
 356:         if (! bcmListeners.contains(listener))
 357:           bcmListeners.add(listener);
 358:       }
 359:   }
 360: 
 361:   /**
 362:    * Returns true if this bean needs a GUI
 363:    * but is being prevented from using one.
 364:    *
 365:    * @return true if <code>needsGui()</code>
 366:    *              is true but the bean has been
 367:    *              told not to use it.
 368:    */
 369:   public boolean avoidingGui()
 370:   {
 371:     return needsGui() && (!okToUseGui);
 372:   }
 373: 
 374:   protected Iterator bcsChildren ()
 375:   {
 376:     synchronized (children)
 377:       {
 378:         return new BCSIterator(children.values().iterator());
 379:       }
 380:   }
 381: 
 382:   /**
 383:    * Subclasses may use this method to perform their own deserialization
 384:    * after the default deserialization process has taken place, but
 385:    * prior to the deserialization of the children.  It should not
 386:    * be used to replace the implementation of <code>readObject</code>
 387:    * in the subclass.
 388:    *
 389:    * @param ois the input stream.
 390:    * @throws ClassNotFoundException if the class of an object being deserialized
 391:    *                                could not be found.
 392:    * @throws IOException if an I/O error occurs.
 393:    */
 394:   protected void bcsPreDeserializationHook (ObjectInputStream ois)
 395:     throws ClassNotFoundException, IOException
 396:   {
 397:     /* Purposefully left empty */
 398:   }
 399: 
 400:   /**
 401:    * Subclasses may use this method to perform their own serialization
 402:    * after the default serialization process has taken place, but
 403:    * prior to the serialization of the children.  It should not
 404:    * be used to replace the implementation of <code>writeObject</code>
 405:    * in the subclass.
 406:    *
 407:    * @param oos the output stream.
 408:    * @throws IOException if an I/O error occurs.
 409:    */
 410:   protected void bcsPreSerializationHook (ObjectOutputStream oos)
 411:     throws IOException
 412:   {
 413:     /* Purposefully left empty */
 414:   }
 415: 
 416:   /**
 417:    * Called when a child is deserialized.
 418:    *
 419:    * @param child the deserialized child.
 420:    * @param bcsc the deserialized context wrapper for the child.
 421:    */
 422:   protected void childDeserializedHook (Object child, BeanContextSupport.BCSChild bcsc)
 423:   {
 424:     // Do nothing in the base class.
 425:   }
 426: 
 427:   protected void childJustAddedHook (Object child, BeanContextSupport.BCSChild bcsc)
 428:   {
 429:     // Do nothing in the base class.
 430:   }
 431: 
 432:   protected void childJustRemovedHook (Object child, BeanContextSupport.BCSChild bcsc)
 433:   {
 434:     // Do nothing in the base class.
 435:   }
 436: 
 437:   protected static final boolean classEquals (Class first, Class second)
 438:   {
 439:     // Lame function!
 440:     return (first == second || first.getName().equals(second.getName()));
 441:   }
 442: 
 443:   public void clear ()
 444:   {
 445:     // This is the right thing to do.
 446:     // The JDK docs are really bad here.
 447:     throw new UnsupportedOperationException();
 448:   }
 449: 
 450:   public boolean contains (Object o)
 451:   {
 452:     synchronized (children)
 453:       {
 454:         return children.containsKey(o);
 455:       }
 456:   }
 457: 
 458:   public boolean containsAll (Collection c)
 459:   {
 460:     synchronized (children)
 461:       {
 462:         Iterator it = c.iterator();
 463:         while (it.hasNext())
 464:           if (! children.containsKey(it.next()))
 465:             return false;
 466:       }
 467:     return true;
 468:   }
 469: 
 470:   public boolean containsKey (Object o)
 471:   {
 472:     synchronized (children)
 473:       {
 474:         return children.containsKey(o);
 475:       }
 476:   }
 477: 
 478:   protected final Object[] copyChildren ()
 479:   {
 480:     synchronized (children)
 481:       {
 482:         return children.keySet().toArray();
 483:       }
 484:   }
 485: 
 486:   protected BeanContextSupport.BCSChild createBCSChild (Object targetChild, Object peer)
 487:   {
 488:     return new BCSChild(targetChild, peer);
 489:   }
 490: 
 491:   /**
 492:    * Deserializes objects (written by {@link #serialize(ObjectOutputStream,
 493:    * Collection)}) and adds them to the specified collection.
 494:    *
 495:    * @param ois  the input stream (<code>null</code> not permitted).
 496:    * @param coll  the collection to add the objects to (<code>null</code> not
 497:    *     permitted).
 498:    *
 499:    * @throws ClassNotFoundException
 500:    * @throws IOException
 501:    *
 502:    * @see #serialize(ObjectOutputStream, Collection)
 503:    */
 504:   protected final void deserialize (ObjectInputStream ois, Collection coll)
 505:     throws ClassNotFoundException, IOException
 506:   {
 507:     int itemCount = ois.readInt();
 508:     for (int i = 0; i < itemCount; i++)
 509:       coll.add(ois.readObject());
 510:   }
 511: 
 512:   /**
 513:    * Informs this bean that is should not make
 514:    * use of the GUI.
 515:    */
 516:   public void dontUseGui()
 517:   {
 518:     okToUseGui = false;
 519:   }
 520: 
 521:   protected final void fireChildrenAdded (BeanContextMembershipEvent bcme)
 522:   {
 523:     synchronized (bcmListeners)
 524:       {
 525:         Iterator it = bcmListeners.iterator();
 526:         while (it.hasNext())
 527:           {
 528:             BeanContextMembershipListener l
 529:               = (BeanContextMembershipListener) it.next();
 530:             l.childrenAdded(bcme);
 531:           }
 532:       }
 533:   }
 534: 
 535:   protected final void fireChildrenRemoved (BeanContextMembershipEvent bcme)
 536:   {
 537:     synchronized (bcmListeners)
 538:       {
 539:         Iterator it = bcmListeners.iterator();
 540:         while (it.hasNext())
 541:           {
 542:             BeanContextMembershipListener l
 543:             = (BeanContextMembershipListener) it.next();
 544:             l.childrenRemoved(bcme);
 545:           }
 546:       }
 547:   }
 548: 
 549:   /**
 550:    * Returns the bean context peer.
 551:    *
 552:    * @return The bean context peer.
 553:    *
 554:    * @see BeanContextChildSupport#beanContextChildPeer
 555:    */
 556:   public BeanContext getBeanContextPeer()
 557:   {
 558:     return (BeanContext) beanContextChildPeer;
 559:   }
 560: 
 561:   /**
 562:    * Returns the {@link BeanContextChild} implementation for the given child.
 563:    *
 564:    * @param child  the child (<code>null</code> permitted).
 565:    *
 566:    * @return The bean context child.
 567:    *
 568:    * @throws IllegalArgumentException if <code>child</code> implements both
 569:    *     the {@link BeanContextChild} and {@link BeanContextProxy} interfaces.
 570:    */
 571:   protected static final BeanContextChild getChildBeanContextChild(Object child)
 572:   {
 573:     if (child == null)
 574:       return null;
 575:     if (child instanceof BeanContextChild && child instanceof BeanContextProxy)
 576:       throw new IllegalArgumentException("Child cannot implement "
 577:           + "BeanContextChild and BeanContextProxy simultaneously.");
 578:     if (child instanceof BeanContextChild)
 579:       return (BeanContextChild) child;
 580:     if (child instanceof BeanContextProxy)
 581:       return ((BeanContextProxy) child).getBeanContextProxy();
 582:     return null;
 583:   }
 584: 
 585:   /**
 586:    * Returns <code>child</code> as an instance of
 587:    * {@link BeanContextMembershipListener}, or <code>null</code> if
 588:    * <code>child</code> does not implement that interface.
 589:    *
 590:    * @param child  the child (<code>null</code> permitted).
 591:    *
 592:    * @return The child cast to {@link BeanContextMembershipListener}.
 593:    */
 594:   protected static final BeanContextMembershipListener
 595:       getChildBeanContextMembershipListener(Object child)
 596:   {
 597:     if (child instanceof BeanContextMembershipListener)
 598:       return (BeanContextMembershipListener) child;
 599:     else
 600:       return null;
 601:   }
 602: 
 603:   /**
 604:    * Returns <code>child</code> as an instance of
 605:    * {@link PropertyChangeListener}, or <code>null</code> if <code>child</code>
 606:    * does not implement that interface.
 607:    *
 608:    * @param child  the child (<code>null</code> permitted).
 609:    *
 610:    * @return The child cast to {@link PropertyChangeListener}.
 611:    */
 612:   protected static final PropertyChangeListener getChildPropertyChangeListener(
 613:       Object child)
 614:   {
 615:     if (child instanceof PropertyChangeListener)
 616:       return (PropertyChangeListener) child;
 617:     else
 618:       return null;
 619:   }
 620: 
 621:   /**
 622:    * Returns <code>child</code> as an instance of {@link Serializable}, or
 623:    * <code>null</code> if <code>child</code> does not implement that
 624:    * interface.
 625:    *
 626:    * @param child  the child (<code>null</code> permitted).
 627:    *
 628:    * @return The child cast to {@link Serializable}.
 629:    */
 630:   protected static final Serializable getChildSerializable(Object child)
 631:   {
 632:     if (child instanceof Serializable)
 633:       return (Serializable) child;
 634:     else
 635:       return null;
 636:   }
 637: 
 638:   /**
 639:    * Returns <code>child</code> as an instance of
 640:    * {@link VetoableChangeListener}, or <code>null</code> if <code>child</code>
 641:    * does not implement that interface.
 642:    *
 643:    * @param child  the child (<code>null</code> permitted).
 644:    *
 645:    * @return The child cast to {@link VetoableChangeListener}.
 646:    */
 647:   protected static final VetoableChangeListener getChildVetoableChangeListener(
 648:       Object child)
 649:   {
 650:     if (child instanceof VetoableChangeListener)
 651:       return (VetoableChangeListener) child;
 652:     else
 653:       return null;
 654:   }
 655: 
 656:   /**
 657:    * Returns <code>child</code> as an instance of {@link Visibility}, or
 658:    * <code>null</code> if <code>child</code> does not implement that interface.
 659:    *
 660:    * @param child  the child (<code>null</code> permitted).
 661:    *
 662:    * @return The child cast to {@link Visibility}.
 663:    */
 664:   protected static final Visibility getChildVisibility(Object child)
 665:   {
 666:     if (child instanceof Visibility)
 667:       return (Visibility) child;
 668:     else
 669:       return null;
 670:   }
 671: 
 672:   public Locale getLocale ()
 673:   {
 674:     return locale;
 675:   }
 676: 
 677:   public URL getResource (String name, BeanContextChild bcc)
 678:   {
 679:     if (! contains(bcc))
 680:       throw new IllegalArgumentException("argument not a child");
 681:     ClassLoader loader = bcc.getClass().getClassLoader();
 682:     return (loader == null ? ClassLoader.getSystemResource(name)
 683:             : loader.getResource(name));
 684:   }
 685: 
 686:   public InputStream getResourceAsStream (String name, BeanContextChild bcc)
 687:   {
 688:     if (! contains(bcc))
 689:       throw new IllegalArgumentException("argument not a child");
 690:     ClassLoader loader = bcc.getClass().getClassLoader();
 691:     return (loader == null ? ClassLoader.getSystemResourceAsStream(name)
 692:             : loader.getResourceAsStream(name));
 693:   }
 694: 
 695:   protected void initialize ()
 696:   {
 697:     bcmListeners = new ArrayList();
 698:     children = new HashMap();
 699:   }
 700: 
 701:   /**
 702:    * This is a convenience method for instantiating a bean inside this
 703:    * context.  It delegates to the appropriate method in
 704:    * <code>java.beans.Beans</code> using the context's classloader.
 705:    *
 706:    * @param beanName the name of the class of bean to instantiate.
 707:    * @throws IOException if an I/O error occurs in loading the class.
 708:    * @throws ClassNotFoundException if the class, <code>beanName</code>,
 709:    *                                can not be found.
 710:    */
 711:   public Object instantiateChild (String beanName)
 712:     throws IOException, ClassNotFoundException
 713:   {
 714:     return Beans.instantiate(getClass().getClassLoader(), beanName, this);
 715:   }
 716: 
 717:   /**
 718:    * Returns <code>true</code> if the <code>BeanContext</code> is in
 719:    * design time mode, and <code>false</code> if it is in runtime mode.
 720:    *
 721:    * @return A boolean.
 722:    *
 723:    * @see #setDesignTime(boolean)
 724:    */
 725:   public boolean isDesignTime()
 726:   {
 727:     return designTime;
 728:   }
 729: 
 730:   /**
 731:    * Returns true if this bean context has no children.
 732:    *
 733:    * @return true if there are no children.
 734:    */
 735:   public boolean isEmpty ()
 736:   {
 737:     synchronized (children)
 738:       {
 739:         return children.isEmpty();
 740:       }
 741:   }
 742: 
 743:   /**
 744:    * Returns true if the bean context is in the process
 745:    * of being serialized.
 746:    *
 747:    * @return true if the context is being serialized.
 748:    */
 749:   public boolean isSerializing()
 750:   {
 751:     return serializing;
 752:   }
 753: 
 754:   public Iterator iterator ()
 755:   {
 756:     synchronized (children)
 757:       {
 758:         return children.keySet().iterator();
 759:       }
 760:   }
 761: 
 762:   /**
 763:    * Returns false as this bean does not a
 764:    * GUI for its operation.
 765:    *
 766:    * @return false
 767:    */
 768:   public boolean needsGui()
 769:   {
 770:     return false;
 771:   }
 772: 
 773:   /**
 774:    * Informs this bean that it is okay to make use of
 775:    * the GUI.
 776:    */
 777:   public void okToUseGui ()
 778:   {
 779:     okToUseGui = true;
 780:   }
 781: 
 782:   /**
 783:    * Subclasses may use this method to catch property changes
 784:    * arising from the children of this context.  At present,
 785:    * we just listen for the beans being assigned to a different
 786:    * context and remove them from here if such an event occurs.
 787:    *
 788:    * @param pce the property change event.
 789:    */
 790:   public void propertyChange (PropertyChangeEvent pce)
 791:   {
 792:     if (pce.getNewValue() != this)
 793:       remove(pce.getSource(), false);
 794:   }
 795: 
 796:   /**
 797:    * Deserializes the children using the
 798:    * {@link #deserialize(ObjectInputStream, Collection} method
 799:    * and then calls {@link childDeserializedHook(Object, BCSChild)}
 800:    * for each child deserialized.
 801:    *
 802:    * @param ois the input stream.
 803:    * @throws IOException if an I/O error occurs.
 804:    */
 805:   public final void readChildren (ObjectInputStream ois)
 806:     throws IOException, ClassNotFoundException
 807:   {
 808:     List temp = new ArrayList();
 809:     deserialize(ois, temp);
 810:     Iterator i = temp.iterator();
 811:     synchronized (globalHierarchyLock)
 812:       {
 813:         synchronized (children)
 814:           {
 815:             while (i.hasNext())
 816:               {
 817:                 BCSChild bcs = (BCSChild) i.next();
 818:                 childDeserializedHook(bcs.getTargetChild(), bcs);
 819:                 children.put(bcs.getTargetChild(), bcs);
 820:               }
 821:           }
 822:       }
 823:   }
 824: 
 825:   /**
 826:    * Remove the specified child from the context.  This is
 827:    * the same as calling <code>remove(Object,boolean)</code>
 828:    * with a request for the <code>setBeanContext()</code> method
 829:    * of the child to be called (i.e. the second argument is true).
 830:    *
 831:    * @param targetChild the child to remove.
 832:    */
 833:   public boolean remove (Object targetChild)
 834:   {
 835:     return remove(targetChild, true);
 836:   }
 837: 
 838:   /**
 839:    * <p>
 840:    * Removes a child from the bean context.  A child can be a simple
 841:    * <code>Object</code>, a <code>BeanContextChild</code>
 842:    * or another <code>BeanContext</code>.  If the given child is not
 843:    * a child of this context, this method returns <code>false</code>.
 844:    * </p>
 845:    * <p>
 846:    * If the child is a <code>BeanContextChild</code>, or a proxy
 847:    * for such a child, the <code>setBeanContext()</code> method
 848:    * is invoked on the child (if specified).  If this operation is vetoed
 849:    * by the child, via throwing a <code>PropertyVetoException</code>,
 850:    * then the current completion state of the <code>remove()</code>
 851:    * operation is rolled back and a <code>IllegalStateException</code>
 852:    * is thrown.  If the <code>BeanContextChild</code> is successfully
 853:    * removed, then the context deregisters with its
 854:    * <code>PropertyChangeListener</code> and
 855:    * <code>VetoableChangeListener</code> for "beanContext" events.
 856:    * </p>
 857:    * <p>
 858:    * A <code>BeanContextMembershipEvent</code> is fired when the
 859:    * child is successfully removed from the bean context.
 860:    * </p>
 861:    * <p>
 862:    * This method is synchronized over the global hierarchy lock.
 863:    * </p>
 864:    *
 865:    * @param targetChild the child to remove.
 866:    * @param callChildSetBC true if the <code>setBeanContext()</code>
 867:    *                       method of the child should be called.
 868:    * @return false if the child doesn't exist.
 869:    * @throws IllegalArgumentException if the child is null.
 870:    * @throws IllegalStateException if the child vetos the setting
 871:    *                               of its context.
 872:    */
 873:   protected boolean remove (Object targetChild, boolean callChildSetBC)
 874:   {
 875:     synchronized (globalHierarchyLock)
 876:       {
 877:         if (targetChild == null)
 878:           throw new IllegalArgumentException();
 879: 
 880:         BCSChild child;
 881:         synchronized (children)
 882:           {
 883:             if (!children.containsKey(targetChild)
 884:                 || !validatePendingRemove(targetChild))
 885:               return false;
 886:             child = (BCSChild) children.remove(targetChild);
 887:           }
 888:         synchronized (targetChild)
 889:           {
 890:             BeanContextChild bcChild = null;
 891:             if (targetChild instanceof BeanContextChild)
 892:               bcChild = (BeanContextChild) targetChild;
 893:             if (targetChild instanceof BeanContextProxy)
 894:               bcChild = ((BeanContextProxy) targetChild).getBeanContextProxy();
 895:             if (bcChild != null)
 896:               try
 897:                 {
 898:                   if (callChildSetBC)
 899:                     bcChild.setBeanContext(null);
 900:                   bcChild.removeVetoableChangeListener("beanContext", this);
 901:                   bcChild.removePropertyChangeListener("beanContext", this);
 902:                 }
 903:               catch (PropertyVetoException e)
 904:                 {
 905:                   synchronized (children)
 906:                     {
 907:                       children.put(targetChild, child);
 908:                     }
 909:                   throw new IllegalStateException("The child refused to " +
 910:                                                   "disassociate itself with " +
 911:                                                   "this context.", e);
 912:                 }
 913:             childJustRemovedHook(targetChild, child);
 914:           }
 915:         fireChildrenRemoved(new BeanContextMembershipEvent(this,
 916:                                                          new Object[]{ targetChild }));
 917:         return true;
 918:       }
 919:   }
 920: 
 921:   public boolean removeAll (Collection c)
 922:   {
 923:     // Intentionally throws an exception.
 924:     throw new UnsupportedOperationException();
 925:   }
 926: 
 927:   public void removeBeanContextMembershipListener (BeanContextMembershipListener bcml)
 928:   {
 929:     synchronized (bcmListeners)
 930:       {
 931:         bcmListeners.remove(bcml);
 932:       }
 933:   }
 934: 
 935:   public boolean retainAll (Collection c)
 936:   {
 937:     // Intentionally throws an exception.
 938:     throw new UnsupportedOperationException();
 939:   }
 940: 
 941:   /**
 942:    * Writes the items in the collection to the specified output stream.  Items
 943:    * in the collection that are not instances of {@link Serializable}
 944:    * (this includes <code>null</code>) are simply ignored.
 945:    *
 946:    * @param oos  the output stream (<code>null</code> not permitted).
 947:    * @param coll  the collection (<code>null</code> not permitted).
 948:    *
 949:    * @throws IOException
 950:    *
 951:    * @see #deserialize(ObjectInputStream, Collection)
 952:    */
 953:   protected final void serialize(ObjectOutputStream oos, Collection coll)
 954:     throws IOException
 955:   {
 956:     Object[] items = coll.toArray();
 957:     int itemCount = 0;
 958:     for (int i = 0; i < items.length; i++)
 959:       {
 960:         if (items[i] instanceof Serializable)
 961:           itemCount++;
 962:       }
 963:     oos.writeInt(itemCount);
 964:     for (int i = 0; i < items.length; i++)
 965:       {
 966:         if (items[i] instanceof Serializable)
 967:           oos.writeObject(items[i]);
 968:       }
 969:   }
 970: 
 971:   /**
 972:    * Sets the flag that indicates whether or not the
 973:    * <code>BeanContext</code> is in design mode.  If the flag changes
 974:    * value, a {@link PropertyChangeEvent} (with the property name 'designMode')
 975:    * is sent to registered listeners.  Note that the property name used here
 976:    * does NOT match the specification in the {@link DesignMode} interface, we
 977:    * match the reference implementation instead - see bug parade entry 4295174.
 978:    *
 979:    * @param dtime  the new value for the flag.
 980:    *
 981:    * @see #isDesignTime()
 982:    */
 983:   public void setDesignTime(boolean dtime)
 984:   {
 985:     boolean save = designTime;
 986:     designTime = dtime;
 987:     // note that we use the same property name as Sun's implementation,
 988:     // even though this is a known bug: see bug parade entry 4295174
 989:     firePropertyChange("designMode", Boolean.valueOf(save),
 990:                        Boolean.valueOf(dtime));
 991:   }
 992: 
 993:   public void setLocale (Locale newLocale)
 994:     throws PropertyVetoException
 995:   {
 996:     if (newLocale == null || locale == newLocale)
 997:       return;
 998:     fireVetoableChange("locale", locale, newLocale);
 999:     Locale oldLocale = locale;
1000:     locale = newLocale;
1001:     firePropertyChange("locale", oldLocale, newLocale);
1002:   }
1003: 
1004:   public int size ()
1005:   {
1006:     synchronized (children)
1007:       {
1008:         return children.size();
1009:       }
1010:   }
1011: 
1012:   /**
1013:    * Returns an array containing the children of this <code>BeanContext</code>.
1014:    *
1015:    * @return An array containing the children.
1016:    */
1017:   public Object[] toArray()
1018:   {
1019:     synchronized (children)
1020:       {
1021:         return children.keySet().toArray();
1022:       }
1023:   }
1024: 
1025:   /**
1026:    * Populates, then returns, the supplied array with the children of this
1027:    * <code>BeanContext</code>.  If the array is too short to hold the
1028:    * children, a new array is allocated and returned.  If the array is too
1029:    * long, it is padded with <code>null</code> items at the end.
1030:    *
1031:    * @param array  an array to populate (<code>null</code> not permitted).
1032:    */
1033:   public Object[] toArray(Object[] array)
1034:   {
1035:     synchronized (children)
1036:       {
1037:         return children.keySet().toArray(array);
1038:       }
1039:   }
1040: 
1041:   protected boolean validatePendingAdd (Object targetChild)
1042:   {
1043:     return true;
1044:   }
1045: 
1046:   protected boolean validatePendingRemove (Object targetChild)
1047:   {
1048:     return true;
1049:   }
1050: 
1051:   /**
1052:    * Subclasses may use this method to veto changes arising
1053:    * from the children of this context.
1054:    *
1055:    * @param pce the vetoable property change event fired.
1056:    */
1057:   public void vetoableChange (PropertyChangeEvent pce)
1058:     throws PropertyVetoException
1059:   {
1060:     /* Purposefully left empty */
1061:   }
1062: 
1063:   /**
1064:    * Serializes the children using the
1065:    * {@link #serialize(ObjectOutputStream, Collection} method.
1066:    *
1067:    * @param oos the output stream.
1068:    * @throws IOException if an I/O error occurs.
1069:    */
1070:   public final void writeChildren (ObjectOutputStream oos)
1071:     throws IOException
1072:   {
1073:     synchronized (children)
1074:       {
1075:         serialize(oos, children.values());
1076:       }
1077:   }
1078: 
1079: }