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

Save This Page
Home » openjdk-7 » java » beans » beancontext » [javadoc | source]