mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
1080 lines
31 KiB
Java
1080 lines
31 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);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Deerializes the children using the
|
||
|
* {@link #deserialize(ObjectInputStream, Collection} method
|
||
|
* and then calls {@link childDeserializedHook(Object, BCSChild)}
|
||
|
* for each child deserialized.
|
||
|
*
|
||
|
* @param oos the output 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());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|