mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1080 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1080 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* BeanContextSupport.java --
 | |
|    Copyright (C) 2003, 2005, 2006  Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package java.beans.beancontext;
 | |
| 
 | |
| import java.beans.Beans;
 | |
| import java.beans.DesignMode;
 | |
| import java.beans.PropertyChangeEvent;
 | |
| import java.beans.PropertyChangeListener;
 | |
| import java.beans.PropertyVetoException;
 | |
| import java.beans.VetoableChangeListener;
 | |
| import java.beans.Visibility;
 | |
| import java.io.IOException;
 | |
| import java.io.InputStream;
 | |
| import java.io.ObjectInputStream;
 | |
| import java.io.ObjectOutputStream;
 | |
| import java.io.Serializable;
 | |
| import java.net.URL;
 | |
| import java.util.ArrayList;
 | |
| import java.util.Collection;
 | |
| import java.util.HashMap;
 | |
| import java.util.Iterator;
 | |
| import java.util.List;
 | |
| import java.util.Locale;
 | |
| 
 | |
| /**
 | |
|  * This is a helper class for implementing a bean context.  It is
 | |
|  * intended to be used either by subclassing or by calling methods
 | |
|  * of this implementation from another.
 | |
|  *
 | |
|  * @author Michael Koch
 | |
|  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 | |
|  * @since 1.2
 | |
|  */
 | |
| public class BeanContextSupport extends BeanContextChildSupport
 | |
|   implements BeanContext, Serializable, PropertyChangeListener,
 | |
|   VetoableChangeListener
 | |
| {
 | |
|   private static final long serialVersionUID = -4879613978649577204L;
 | |
| 
 | |
|   /**
 | |
|    * Deserializes a stored bean context.  Hook methods are provided to allow
 | |
|    * subclasses to perform their own deserialization after the default
 | |
|    * deserialization but prior to the deserialization of the children.  Note that
 | |
|    * {@link #readChildren(ObjectInputStream)} is only called if there
 | |
|    * is no distinct peer.  If there is, the peer is expected to call
 | |
|    * the method instead.
 | |
|    *
 | |
|    * @param s the stream to deserialize.
 | |
|    * @throws ClassNotFoundException if the class of an object being deserialized
 | |
|    *                                could not be found.
 | |
|    * @throws IOException if an I/O error occurs.
 | |
|    */
 | |
|   private void readObject (ObjectInputStream s)
 | |
|     throws ClassNotFoundException, IOException
 | |
|   {
 | |
|     s.defaultReadObject();
 | |
|     bcsPreDeserializationHook(s);
 | |
|     BeanContext peer = getBeanContextPeer();
 | |
|     if (peer == null || peer == this)
 | |
|       readChildren(s);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Serializes a bean context.  Hook methods are provided to allow
 | |
|    * subclasses to perform their own serialization after the default
 | |
|    * serialization but prior to serialization of the children.  Note that
 | |
|    * {@link #writeChildren(ObjectOutputStream)} is only called if there
 | |
|    * is no distinct peer.  If there is, the peer is expected to call
 | |
|    * the method instead.
 | |
|    *
 | |
|    * @param s the stream to serialize.
 | |
|    * @throws ClassNotFoundException if the class of an object being deserialized
 | |
|    *                                could not be found.
 | |
|    * @throws IOException if an I/O error occurs.
 | |
|    */
 | |
|   private void writeObject (ObjectOutputStream s)
 | |
|     throws ClassNotFoundException, IOException
 | |
|   {
 | |
|     serializing = true;
 | |
|     s.defaultWriteObject();
 | |
|     bcsPreSerializationHook(s);
 | |
|     BeanContext peer = getBeanContextPeer();
 | |
|     if (peer == null || peer == this)
 | |
|       writeChildren(s);
 | |
|     serializing = false;
 | |
|   }
 | |
| 
 | |
|   protected class BCSChild implements Serializable
 | |
|   {
 | |
|     private static final long serialVersionUID = -5815286101609939109L;
 | |
| 
 | |
|     private Object targetChild;
 | |
|     private Object peer;
 | |
| 
 | |
|     BCSChild(Object targetChild, Object peer)
 | |
|     {
 | |
|       this.targetChild = targetChild;
 | |
|       this.peer = peer;
 | |
|     }
 | |
| 
 | |
|     private Object getTargetChild()
 | |
|     {
 | |
|       return targetChild;
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   protected static final class BCSIterator implements Iterator
 | |
|   {
 | |
|     private Iterator child;
 | |
| 
 | |
|     BCSIterator(Iterator child)
 | |
|     {
 | |
|       this.child = child;
 | |
|     }
 | |
| 
 | |
|     public boolean hasNext ()
 | |
|     {
 | |
|       return child.hasNext();
 | |
|     }
 | |
| 
 | |
|     public Object next ()
 | |
|     {
 | |
|       return child.next();
 | |
|     }
 | |
| 
 | |
|     public void remove ()
 | |
|     {
 | |
|       // This must be a noop remove operation.
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   protected transient ArrayList bcmListeners;
 | |
| 
 | |
|   protected transient HashMap children;
 | |
| 
 | |
|   protected transient boolean designTime;
 | |
| 
 | |
|   protected transient Locale locale;
 | |
| 
 | |
|   protected transient boolean okToUseGui;
 | |
| 
 | |
|   private transient boolean serializing;
 | |
| 
 | |
|   /**
 | |
|    * Construct a BeanContextSupport instance.
 | |
|    */
 | |
|   public BeanContextSupport ()
 | |
|   {
 | |
|     this (null, null, false, true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Construct a BeanContextSupport instance.
 | |
|    *
 | |
|    * @param peer  the bean context peer (<code>null</code> permitted).
 | |
|    */
 | |
|   public BeanContextSupport(BeanContext peer)
 | |
|   {
 | |
|     this (peer, null, false, true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Construct a BeanContextSupport instance.
 | |
|    *
 | |
|    * @param peer  the bean context peer (<code>null</code> permitted).
 | |
|    * @param locale  the locale (<code>null</code> permitted, equivalent to
 | |
|    *     the default locale).
 | |
|    */
 | |
|   public BeanContextSupport (BeanContext peer, Locale locale)
 | |
|   {
 | |
|     this (peer, locale, false, true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Construct a BeanContextSupport instance.
 | |
|    *
 | |
|    * @param peer  the bean context peer (<code>null</code> permitted).
 | |
|    * @param locale  the locale (<code>null</code> permitted, equivalent to
 | |
|    *     the default locale).
 | |
|    * @param dtime  a flag indicating whether or not the bean context is in
 | |
|    *     design time mode.
 | |
|    */
 | |
|   public BeanContextSupport (BeanContext peer, Locale locale, boolean dtime)
 | |
|   {
 | |
|     this (peer, locale, dtime, true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Construct a BeanContextSupport instance.
 | |
|    *
 | |
|    * @param peer  the bean context peer (<code>null</code> permitted).
 | |
|    * @param locale  the locale (<code>null</code> permitted, equivalent to
 | |
|    *     the default locale).
 | |
|    * @param dtime  a flag indicating whether or not the bean context is in
 | |
|    *     design time mode.
 | |
|    * @param visible  initial value of the <code>okToUseGui</code> flag.
 | |
|    */
 | |
|   public BeanContextSupport (BeanContext peer, Locale locale, boolean dtime,
 | |
|                              boolean visible)
 | |
|   {
 | |
|     super(peer);
 | |
| 
 | |
|     this.locale = locale == null ? Locale.getDefault() : locale;
 | |
|     designTime = dtime;
 | |
|     okToUseGui = visible;
 | |
| 
 | |
|     initialize ();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * <p>
 | |
|    * Add a child to the bean context.  A child can be a simple
 | |
|    * <code>Object</code>, a <code>BeanContextChild</code>
 | |
|    * or another <code>BeanContext</code>.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * The children of a <code>BeanContext</code> form a set.  As
 | |
|    * a result, this method returns <code>false</code> if the given
 | |
|    * object is already a child of this context.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * If the child is a <code>BeanContextChild</code>, or a proxy
 | |
|    * for such a child, the <code>setBeanContext()</code> method
 | |
|    * is invoked on the child.  If this operation is vetoed by the
 | |
|    * child, via throwing a <code>PropertyVetoException</code>,
 | |
|    * then the current completion state of the <code>add()</code>
 | |
|    * operation is rolled back and a <code>IllegalStateException</code>
 | |
|    * is thrown.  If the <code>BeanContextChild</code> is successfully
 | |
|    * added, then the context registers with its
 | |
|    * <code>PropertyChangeListener</code> and
 | |
|    * <code>VetoableChangeListener</code> for "beanContext" events.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * If the child implements <code>java.beans.Visibility</code>,
 | |
|    * then its ability to use a GUI is set based on that of
 | |
|    * this context.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * A <code>BeanContextMembershipEvent</code> is fired when the
 | |
|    * child is successfully added to the bean context.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * This method is synchronized over the global hierarchy lock.
 | |
|    * </p>
 | |
|    *
 | |
|    * @param targetChild the child to add.
 | |
|    * @return false if the child has already been added.
 | |
|    * @throws IllegalArgumentException if the child is null.
 | |
|    * @throws IllegalStateException if the child vetos the setting
 | |
|    *                               of its context.
 | |
|    */
 | |
|   public boolean add(Object targetChild)
 | |
|   {
 | |
|     synchronized (globalHierarchyLock)
 | |
|       {
 | |
|         if (targetChild == null)
 | |
|           throw new IllegalArgumentException();
 | |
| 
 | |
|         BCSChild child;
 | |
|         synchronized (children)
 | |
|           {
 | |
|             if (children.containsKey(targetChild)
 | |
|                 || ! validatePendingAdd(targetChild))
 | |
|               return false;
 | |
|             child = createBCSChild(targetChild, beanContextChildPeer);
 | |
|             children.put(targetChild, child);
 | |
|           }
 | |
|         synchronized (targetChild)
 | |
|           {
 | |
|             BeanContextChild bcChild = null;
 | |
|             if (targetChild instanceof BeanContextChild)
 | |
|               bcChild = (BeanContextChild) targetChild;
 | |
|             if (targetChild instanceof BeanContextProxy)
 | |
|               bcChild = ((BeanContextProxy) targetChild).getBeanContextProxy();
 | |
|             if (bcChild != null)
 | |
|               try
 | |
|                 {
 | |
|                   bcChild.setBeanContext(this);
 | |
|                   bcChild.addVetoableChangeListener("beanContext", this);
 | |
|                   bcChild.addPropertyChangeListener("beanContext", this);
 | |
|                 }
 | |
|               catch (PropertyVetoException e)
 | |
|                 {
 | |
|                   synchronized (children)
 | |
|                     {
 | |
|                       children.remove(targetChild);
 | |
|                     }
 | |
|                   throw new IllegalStateException("The child refused to " +
 | |
|                                                   "associate itself with " +
 | |
|                                                   "this context.", e);
 | |
|                 }
 | |
|             if (targetChild instanceof Visibility)
 | |
|               {
 | |
|                 Visibility visibleChild = (Visibility) targetChild;
 | |
|                 if (okToUseGui)
 | |
|                   visibleChild.okToUseGui();
 | |
|                 else
 | |
|                   visibleChild.dontUseGui();
 | |
|               }
 | |
|             childJustAddedHook(targetChild, child);
 | |
|           }
 | |
|         fireChildrenAdded(new BeanContextMembershipEvent(this,
 | |
|                                                          new Object[]{ targetChild }));
 | |
|         return true;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public boolean addAll (Collection c)
 | |
|   {
 | |
|     // Intentionally throws an exception.
 | |
|     throw new UnsupportedOperationException();
 | |
|   }
 | |
| 
 | |
|   public void addBeanContextMembershipListener
 | |
|     (BeanContextMembershipListener listener)
 | |
|   {
 | |
|     synchronized (bcmListeners)
 | |
|       {
 | |
|         if (! bcmListeners.contains(listener))
 | |
|           bcmListeners.add(listener);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns true if this bean needs a GUI
 | |
|    * but is being prevented from using one.
 | |
|    *
 | |
|    * @return true if <code>needsGui()</code>
 | |
|    *              is true but the bean has been
 | |
|    *              told not to use it.
 | |
|    */
 | |
|   public boolean avoidingGui()
 | |
|   {
 | |
|     return needsGui() && (!okToUseGui);
 | |
|   }
 | |
| 
 | |
|   protected Iterator bcsChildren ()
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return new BCSIterator(children.values().iterator());
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Subclasses may use this method to perform their own deserialization
 | |
|    * after the default deserialization process has taken place, but
 | |
|    * prior to the deserialization of the children.  It should not
 | |
|    * be used to replace the implementation of <code>readObject</code>
 | |
|    * in the subclass.
 | |
|    *
 | |
|    * @param ois the input stream.
 | |
|    * @throws ClassNotFoundException if the class of an object being deserialized
 | |
|    *                                could not be found.
 | |
|    * @throws IOException if an I/O error occurs.
 | |
|    */
 | |
|   protected void bcsPreDeserializationHook (ObjectInputStream ois)
 | |
|     throws ClassNotFoundException, IOException
 | |
|   {
 | |
|     /* Purposefully left empty */
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Subclasses may use this method to perform their own serialization
 | |
|    * after the default serialization process has taken place, but
 | |
|    * prior to the serialization of the children.  It should not
 | |
|    * be used to replace the implementation of <code>writeObject</code>
 | |
|    * in the subclass.
 | |
|    *
 | |
|    * @param oos the output stream.
 | |
|    * @throws IOException if an I/O error occurs.
 | |
|    */
 | |
|   protected void bcsPreSerializationHook (ObjectOutputStream oos)
 | |
|     throws IOException
 | |
|   {
 | |
|     /* Purposefully left empty */
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Called when a child is deserialized.
 | |
|    *
 | |
|    * @param child the deserialized child.
 | |
|    * @param bcsc the deserialized context wrapper for the child.
 | |
|    */
 | |
|   protected void childDeserializedHook (Object child, BeanContextSupport.BCSChild bcsc)
 | |
|   {
 | |
|     // Do nothing in the base class.
 | |
|   }
 | |
| 
 | |
|   protected void childJustAddedHook (Object child, BeanContextSupport.BCSChild bcsc)
 | |
|   {
 | |
|     // Do nothing in the base class.
 | |
|   }
 | |
| 
 | |
|   protected void childJustRemovedHook (Object child, BeanContextSupport.BCSChild bcsc)
 | |
|   {
 | |
|     // Do nothing in the base class.
 | |
|   }
 | |
| 
 | |
|   protected static final boolean classEquals (Class first, Class second)
 | |
|   {
 | |
|     // Lame function!
 | |
|     return (first == second || first.getName().equals(second.getName()));
 | |
|   }
 | |
| 
 | |
|   public void clear ()
 | |
|   {
 | |
|     // This is the right thing to do.
 | |
|     // The JDK docs are really bad here.
 | |
|     throw new UnsupportedOperationException();
 | |
|   }
 | |
| 
 | |
|   public boolean contains (Object o)
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return children.containsKey(o);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public boolean containsAll (Collection c)
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         Iterator it = c.iterator();
 | |
|         while (it.hasNext())
 | |
|           if (! children.containsKey(it.next()))
 | |
|             return false;
 | |
|       }
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   public boolean containsKey (Object o)
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return children.containsKey(o);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   protected final Object[] copyChildren ()
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return children.keySet().toArray();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   protected BeanContextSupport.BCSChild createBCSChild (Object targetChild, Object peer)
 | |
|   {
 | |
|     return new BCSChild(targetChild, peer);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Deserializes objects (written by {@link #serialize(ObjectOutputStream,
 | |
|    * Collection)}) and adds them to the specified collection.
 | |
|    *
 | |
|    * @param ois  the input stream (<code>null</code> not permitted).
 | |
|    * @param coll  the collection to add the objects to (<code>null</code> not
 | |
|    *     permitted).
 | |
|    *
 | |
|    * @throws ClassNotFoundException
 | |
|    * @throws IOException
 | |
|    *
 | |
|    * @see #serialize(ObjectOutputStream, Collection)
 | |
|    */
 | |
|   protected final void deserialize (ObjectInputStream ois, Collection coll)
 | |
|     throws ClassNotFoundException, IOException
 | |
|   {
 | |
|     int itemCount = ois.readInt();
 | |
|     for (int i = 0; i < itemCount; i++)
 | |
|       coll.add(ois.readObject());
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Informs this bean that is should not make
 | |
|    * use of the GUI.
 | |
|    */
 | |
|   public void dontUseGui()
 | |
|   {
 | |
|     okToUseGui = false;
 | |
|   }
 | |
| 
 | |
|   protected final void fireChildrenAdded (BeanContextMembershipEvent bcme)
 | |
|   {
 | |
|     synchronized (bcmListeners)
 | |
|       {
 | |
|         Iterator it = bcmListeners.iterator();
 | |
|         while (it.hasNext())
 | |
|           {
 | |
|             BeanContextMembershipListener l
 | |
|               = (BeanContextMembershipListener) it.next();
 | |
|             l.childrenAdded(bcme);
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   protected final void fireChildrenRemoved (BeanContextMembershipEvent bcme)
 | |
|   {
 | |
|     synchronized (bcmListeners)
 | |
|       {
 | |
|         Iterator it = bcmListeners.iterator();
 | |
|         while (it.hasNext())
 | |
|           {
 | |
|             BeanContextMembershipListener l
 | |
|             = (BeanContextMembershipListener) it.next();
 | |
|             l.childrenRemoved(bcme);
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the bean context peer.
 | |
|    *
 | |
|    * @return The bean context peer.
 | |
|    *
 | |
|    * @see BeanContextChildSupport#beanContextChildPeer
 | |
|    */
 | |
|   public BeanContext getBeanContextPeer()
 | |
|   {
 | |
|     return (BeanContext) beanContextChildPeer;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the {@link BeanContextChild} implementation for the given child.
 | |
|    *
 | |
|    * @param child  the child (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return The bean context child.
 | |
|    *
 | |
|    * @throws IllegalArgumentException if <code>child</code> implements both
 | |
|    *     the {@link BeanContextChild} and {@link BeanContextProxy} interfaces.
 | |
|    */
 | |
|   protected static final BeanContextChild getChildBeanContextChild(Object child)
 | |
|   {
 | |
|     if (child == null)
 | |
|       return null;
 | |
|     if (child instanceof BeanContextChild && child instanceof BeanContextProxy)
 | |
|       throw new IllegalArgumentException("Child cannot implement "
 | |
|           + "BeanContextChild and BeanContextProxy simultaneously.");
 | |
|     if (child instanceof BeanContextChild)
 | |
|       return (BeanContextChild) child;
 | |
|     if (child instanceof BeanContextProxy)
 | |
|       return ((BeanContextProxy) child).getBeanContextProxy();
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>child</code> as an instance of
 | |
|    * {@link BeanContextMembershipListener}, or <code>null</code> if
 | |
|    * <code>child</code> does not implement that interface.
 | |
|    *
 | |
|    * @param child  the child (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return The child cast to {@link BeanContextMembershipListener}.
 | |
|    */
 | |
|   protected static final BeanContextMembershipListener
 | |
|       getChildBeanContextMembershipListener(Object child)
 | |
|   {
 | |
|     if (child instanceof BeanContextMembershipListener)
 | |
|       return (BeanContextMembershipListener) child;
 | |
|     else
 | |
|       return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>child</code> as an instance of
 | |
|    * {@link PropertyChangeListener}, or <code>null</code> if <code>child</code>
 | |
|    * does not implement that interface.
 | |
|    *
 | |
|    * @param child  the child (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return The child cast to {@link PropertyChangeListener}.
 | |
|    */
 | |
|   protected static final PropertyChangeListener getChildPropertyChangeListener(
 | |
|       Object child)
 | |
|   {
 | |
|     if (child instanceof PropertyChangeListener)
 | |
|       return (PropertyChangeListener) child;
 | |
|     else
 | |
|       return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>child</code> as an instance of {@link Serializable}, or
 | |
|    * <code>null</code> if <code>child</code> does not implement that
 | |
|    * interface.
 | |
|    *
 | |
|    * @param child  the child (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return The child cast to {@link Serializable}.
 | |
|    */
 | |
|   protected static final Serializable getChildSerializable(Object child)
 | |
|   {
 | |
|     if (child instanceof Serializable)
 | |
|       return (Serializable) child;
 | |
|     else
 | |
|       return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>child</code> as an instance of
 | |
|    * {@link VetoableChangeListener}, or <code>null</code> if <code>child</code>
 | |
|    * does not implement that interface.
 | |
|    *
 | |
|    * @param child  the child (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return The child cast to {@link VetoableChangeListener}.
 | |
|    */
 | |
|   protected static final VetoableChangeListener getChildVetoableChangeListener(
 | |
|       Object child)
 | |
|   {
 | |
|     if (child instanceof VetoableChangeListener)
 | |
|       return (VetoableChangeListener) child;
 | |
|     else
 | |
|       return null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>child</code> as an instance of {@link Visibility}, or
 | |
|    * <code>null</code> if <code>child</code> does not implement that interface.
 | |
|    *
 | |
|    * @param child  the child (<code>null</code> permitted).
 | |
|    *
 | |
|    * @return The child cast to {@link Visibility}.
 | |
|    */
 | |
|   protected static final Visibility getChildVisibility(Object child)
 | |
|   {
 | |
|     if (child instanceof Visibility)
 | |
|       return (Visibility) child;
 | |
|     else
 | |
|       return null;
 | |
|   }
 | |
| 
 | |
|   public Locale getLocale ()
 | |
|   {
 | |
|     return locale;
 | |
|   }
 | |
| 
 | |
|   public URL getResource (String name, BeanContextChild bcc)
 | |
|   {
 | |
|     if (! contains(bcc))
 | |
|       throw new IllegalArgumentException("argument not a child");
 | |
|     ClassLoader loader = bcc.getClass().getClassLoader();
 | |
|     return (loader == null ? ClassLoader.getSystemResource(name)
 | |
|             : loader.getResource(name));
 | |
|   }
 | |
| 
 | |
|   public InputStream getResourceAsStream (String name, BeanContextChild bcc)
 | |
|   {
 | |
|     if (! contains(bcc))
 | |
|       throw new IllegalArgumentException("argument not a child");
 | |
|     ClassLoader loader = bcc.getClass().getClassLoader();
 | |
|     return (loader == null ? ClassLoader.getSystemResourceAsStream(name)
 | |
|             : loader.getResourceAsStream(name));
 | |
|   }
 | |
| 
 | |
|   protected void initialize ()
 | |
|   {
 | |
|     bcmListeners = new ArrayList();
 | |
|     children = new HashMap();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This is a convenience method for instantiating a bean inside this
 | |
|    * context.  It delegates to the appropriate method in
 | |
|    * <code>java.beans.Beans</code> using the context's classloader.
 | |
|    *
 | |
|    * @param beanName the name of the class of bean to instantiate.
 | |
|    * @throws IOException if an I/O error occurs in loading the class.
 | |
|    * @throws ClassNotFoundException if the class, <code>beanName</code>,
 | |
|    *                                can not be found.
 | |
|    */
 | |
|   public Object instantiateChild (String beanName)
 | |
|     throws IOException, ClassNotFoundException
 | |
|   {
 | |
|     return Beans.instantiate(getClass().getClassLoader(), beanName, this);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns <code>true</code> if the <code>BeanContext</code> is in
 | |
|    * design time mode, and <code>false</code> if it is in runtime mode.
 | |
|    *
 | |
|    * @return A boolean.
 | |
|    *
 | |
|    * @see #setDesignTime(boolean)
 | |
|    */
 | |
|   public boolean isDesignTime()
 | |
|   {
 | |
|     return designTime;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns true if this bean context has no children.
 | |
|    *
 | |
|    * @return true if there are no children.
 | |
|    */
 | |
|   public boolean isEmpty ()
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return children.isEmpty();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns true if the bean context is in the process
 | |
|    * of being serialized.
 | |
|    *
 | |
|    * @return true if the context is being serialized.
 | |
|    */
 | |
|   public boolean isSerializing()
 | |
|   {
 | |
|     return serializing;
 | |
|   }
 | |
| 
 | |
|   public Iterator iterator ()
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return children.keySet().iterator();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns false as this bean does not a
 | |
|    * GUI for its operation.
 | |
|    *
 | |
|    * @return false
 | |
|    */
 | |
|   public boolean needsGui()
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Informs this bean that it is okay to make use of
 | |
|    * the GUI.
 | |
|    */
 | |
|   public void okToUseGui ()
 | |
|   {
 | |
|     okToUseGui = true;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Subclasses may use this method to catch property changes
 | |
|    * arising from the children of this context.  At present,
 | |
|    * we just listen for the beans being assigned to a different
 | |
|    * context and remove them from here if such an event occurs.
 | |
|    *
 | |
|    * @param pce the property change event.
 | |
|    */
 | |
|   public void propertyChange (PropertyChangeEvent pce)
 | |
|   {
 | |
|     if (pce.getNewValue() != this)
 | |
|       remove(pce.getSource(), false);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Deserializes the children using the
 | |
|    * {@link #deserialize(ObjectInputStream, Collection} method
 | |
|    * and then calls {@link childDeserializedHook(Object, BCSChild)}
 | |
|    * for each child deserialized.
 | |
|    *
 | |
|    * @param ois the input stream.
 | |
|    * @throws IOException if an I/O error occurs.
 | |
|    */
 | |
|   public final void readChildren (ObjectInputStream ois)
 | |
|     throws IOException, ClassNotFoundException
 | |
|   {
 | |
|     List temp = new ArrayList();
 | |
|     deserialize(ois, temp);
 | |
|     Iterator i = temp.iterator();
 | |
|     synchronized (globalHierarchyLock)
 | |
|       {
 | |
|         synchronized (children)
 | |
|           {
 | |
|             while (i.hasNext())
 | |
|               {
 | |
|                 BCSChild bcs = (BCSChild) i.next();
 | |
|                 childDeserializedHook(bcs.getTargetChild(), bcs);
 | |
|                 children.put(bcs.getTargetChild(), bcs);
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Remove the specified child from the context.  This is
 | |
|    * the same as calling <code>remove(Object,boolean)</code>
 | |
|    * with a request for the <code>setBeanContext()</code> method
 | |
|    * of the child to be called (i.e. the second argument is true).
 | |
|    *
 | |
|    * @param targetChild the child to remove.
 | |
|    */
 | |
|   public boolean remove (Object targetChild)
 | |
|   {
 | |
|     return remove(targetChild, true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * <p>
 | |
|    * Removes a child from the bean context.  A child can be a simple
 | |
|    * <code>Object</code>, a <code>BeanContextChild</code>
 | |
|    * or another <code>BeanContext</code>.  If the given child is not
 | |
|    * a child of this context, this method returns <code>false</code>.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * If the child is a <code>BeanContextChild</code>, or a proxy
 | |
|    * for such a child, the <code>setBeanContext()</code> method
 | |
|    * is invoked on the child (if specified).  If this operation is vetoed
 | |
|    * by the child, via throwing a <code>PropertyVetoException</code>,
 | |
|    * then the current completion state of the <code>remove()</code>
 | |
|    * operation is rolled back and a <code>IllegalStateException</code>
 | |
|    * is thrown.  If the <code>BeanContextChild</code> is successfully
 | |
|    * removed, then the context deregisters with its
 | |
|    * <code>PropertyChangeListener</code> and
 | |
|    * <code>VetoableChangeListener</code> for "beanContext" events.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * A <code>BeanContextMembershipEvent</code> is fired when the
 | |
|    * child is successfully removed from the bean context.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * This method is synchronized over the global hierarchy lock.
 | |
|    * </p>
 | |
|    *
 | |
|    * @param targetChild the child to remove.
 | |
|    * @param callChildSetBC true if the <code>setBeanContext()</code>
 | |
|    *                       method of the child should be called.
 | |
|    * @return false if the child doesn't exist.
 | |
|    * @throws IllegalArgumentException if the child is null.
 | |
|    * @throws IllegalStateException if the child vetos the setting
 | |
|    *                               of its context.
 | |
|    */
 | |
|   protected boolean remove (Object targetChild, boolean callChildSetBC)
 | |
|   {
 | |
|     synchronized (globalHierarchyLock)
 | |
|       {
 | |
|         if (targetChild == null)
 | |
|           throw new IllegalArgumentException();
 | |
| 
 | |
|         BCSChild child;
 | |
|         synchronized (children)
 | |
|           {
 | |
|             if (!children.containsKey(targetChild)
 | |
|                 || !validatePendingRemove(targetChild))
 | |
|               return false;
 | |
|             child = (BCSChild) children.remove(targetChild);
 | |
|           }
 | |
|         synchronized (targetChild)
 | |
|           {
 | |
|             BeanContextChild bcChild = null;
 | |
|             if (targetChild instanceof BeanContextChild)
 | |
|               bcChild = (BeanContextChild) targetChild;
 | |
|             if (targetChild instanceof BeanContextProxy)
 | |
|               bcChild = ((BeanContextProxy) targetChild).getBeanContextProxy();
 | |
|             if (bcChild != null)
 | |
|               try
 | |
|                 {
 | |
|                   if (callChildSetBC)
 | |
|                     bcChild.setBeanContext(null);
 | |
|                   bcChild.removeVetoableChangeListener("beanContext", this);
 | |
|                   bcChild.removePropertyChangeListener("beanContext", this);
 | |
|                 }
 | |
|               catch (PropertyVetoException e)
 | |
|                 {
 | |
|                   synchronized (children)
 | |
|                     {
 | |
|                       children.put(targetChild, child);
 | |
|                     }
 | |
|                   throw new IllegalStateException("The child refused to " +
 | |
|                                                   "disassociate itself with " +
 | |
|                                                   "this context.", e);
 | |
|                 }
 | |
|             childJustRemovedHook(targetChild, child);
 | |
|           }
 | |
|         fireChildrenRemoved(new BeanContextMembershipEvent(this,
 | |
|                                                          new Object[]{ targetChild }));
 | |
|         return true;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public boolean removeAll (Collection c)
 | |
|   {
 | |
|     // Intentionally throws an exception.
 | |
|     throw new UnsupportedOperationException();
 | |
|   }
 | |
| 
 | |
|   public void removeBeanContextMembershipListener (BeanContextMembershipListener bcml)
 | |
|   {
 | |
|     synchronized (bcmListeners)
 | |
|       {
 | |
|         bcmListeners.remove(bcml);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public boolean retainAll (Collection c)
 | |
|   {
 | |
|     // Intentionally throws an exception.
 | |
|     throw new UnsupportedOperationException();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Writes the items in the collection to the specified output stream.  Items
 | |
|    * in the collection that are not instances of {@link Serializable}
 | |
|    * (this includes <code>null</code>) are simply ignored.
 | |
|    *
 | |
|    * @param oos  the output stream (<code>null</code> not permitted).
 | |
|    * @param coll  the collection (<code>null</code> not permitted).
 | |
|    *
 | |
|    * @throws IOException
 | |
|    *
 | |
|    * @see #deserialize(ObjectInputStream, Collection)
 | |
|    */
 | |
|   protected final void serialize(ObjectOutputStream oos, Collection coll)
 | |
|     throws IOException
 | |
|   {
 | |
|     Object[] items = coll.toArray();
 | |
|     int itemCount = 0;
 | |
|     for (int i = 0; i < items.length; i++)
 | |
|       {
 | |
|         if (items[i] instanceof Serializable)
 | |
|           itemCount++;
 | |
|       }
 | |
|     oos.writeInt(itemCount);
 | |
|     for (int i = 0; i < items.length; i++)
 | |
|       {
 | |
|         if (items[i] instanceof Serializable)
 | |
|           oos.writeObject(items[i]);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the flag that indicates whether or not the
 | |
|    * <code>BeanContext</code> is in design mode.  If the flag changes
 | |
|    * value, a {@link PropertyChangeEvent} (with the property name 'designMode')
 | |
|    * is sent to registered listeners.  Note that the property name used here
 | |
|    * does NOT match the specification in the {@link DesignMode} interface, we
 | |
|    * match the reference implementation instead - see bug parade entry 4295174.
 | |
|    *
 | |
|    * @param dtime  the new value for the flag.
 | |
|    *
 | |
|    * @see #isDesignTime()
 | |
|    */
 | |
|   public void setDesignTime(boolean dtime)
 | |
|   {
 | |
|     boolean save = designTime;
 | |
|     designTime = dtime;
 | |
|     // note that we use the same property name as Sun's implementation,
 | |
|     // even though this is a known bug: see bug parade entry 4295174
 | |
|     firePropertyChange("designMode", Boolean.valueOf(save),
 | |
|                        Boolean.valueOf(dtime));
 | |
|   }
 | |
| 
 | |
|   public void setLocale (Locale newLocale)
 | |
|     throws PropertyVetoException
 | |
|   {
 | |
|     if (newLocale == null || locale == newLocale)
 | |
|       return;
 | |
|     fireVetoableChange("locale", locale, newLocale);
 | |
|     Locale oldLocale = locale;
 | |
|     locale = newLocale;
 | |
|     firePropertyChange("locale", oldLocale, newLocale);
 | |
|   }
 | |
| 
 | |
|   public int size ()
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return children.size();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns an array containing the children of this <code>BeanContext</code>.
 | |
|    *
 | |
|    * @return An array containing the children.
 | |
|    */
 | |
|   public Object[] toArray()
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return children.keySet().toArray();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Populates, then returns, the supplied array with the children of this
 | |
|    * <code>BeanContext</code>.  If the array is too short to hold the
 | |
|    * children, a new array is allocated and returned.  If the array is too
 | |
|    * long, it is padded with <code>null</code> items at the end.
 | |
|    *
 | |
|    * @param array  an array to populate (<code>null</code> not permitted).
 | |
|    */
 | |
|   public Object[] toArray(Object[] array)
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         return children.keySet().toArray(array);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   protected boolean validatePendingAdd (Object targetChild)
 | |
|   {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   protected boolean validatePendingRemove (Object targetChild)
 | |
|   {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Subclasses may use this method to veto changes arising
 | |
|    * from the children of this context.
 | |
|    *
 | |
|    * @param pce the vetoable property change event fired.
 | |
|    */
 | |
|   public void vetoableChange (PropertyChangeEvent pce)
 | |
|     throws PropertyVetoException
 | |
|   {
 | |
|     /* Purposefully left empty */
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Serializes the children using the
 | |
|    * {@link #serialize(ObjectOutputStream, Collection} method.
 | |
|    *
 | |
|    * @param oos the output stream.
 | |
|    * @throws IOException if an I/O error occurs.
 | |
|    */
 | |
|   public final void writeChildren (ObjectOutputStream oos)
 | |
|     throws IOException
 | |
|   {
 | |
|     synchronized (children)
 | |
|       {
 | |
|         serialize(oos, children.values());
 | |
|       }
 | |
|   }
 | |
| 
 | |
| }
 |