|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package java.beans.beancontext; |
|
|
|
import java.awt.Component; |
|
import java.awt.Container; |
|
|
|
import java.beans.Beans; |
|
import java.beans.AppletInitializer; |
|
|
|
import java.beans.DesignMode; |
|
|
|
import java.beans.PropertyChangeEvent; |
|
import java.beans.PropertyChangeListener; |
|
import java.beans.PropertyChangeSupport; |
|
|
|
import java.beans.VetoableChangeListener; |
|
import java.beans.VetoableChangeSupport; |
|
import java.beans.PropertyVetoException; |
|
|
|
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.Locale; |
|
import java.util.Map; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class BeanContextSupport extends BeanContextChildSupport |
|
implements BeanContext, |
|
Serializable, |
|
PropertyChangeListener, |
|
VetoableChangeListener { |
|
|
|
|
|
static final long serialVersionUID = -4879613978649577204L; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public BeanContextSupport(BeanContext peer, Locale lcle, boolean dTime, boolean visible) { |
|
super(peer); |
|
|
|
locale = lcle != null ? lcle : Locale.getDefault(); |
|
designTime = dTime; |
|
okToUseGui = visible; |
|
|
|
initialize(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public BeanContextSupport(BeanContext peer, Locale lcle, boolean dtime) { |
|
this (peer, lcle, dtime, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public BeanContextSupport(BeanContext peer, Locale lcle) { |
|
this (peer, lcle, false, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public BeanContextSupport(BeanContext peer) { |
|
this (peer, null, false, true); |
|
} |
|
|
|
/** |
|
* Create an instance that is not a delegate of another object |
|
*/ |
|
|
|
public BeanContextSupport() { |
|
this (null, null, false, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public BeanContext getBeanContextPeer() { return (BeanContext)getBeanContextChildPeer(); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Object instantiateChild(String beanName) |
|
throws IOException, ClassNotFoundException { |
|
BeanContext bc = getBeanContextPeer(); |
|
|
|
return Beans.instantiate(bc.getClass().getClassLoader(), beanName, bc); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public int size() { |
|
synchronized(children) { |
|
return children.size(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isEmpty() { |
|
synchronized(children) { |
|
return children.isEmpty(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean contains(Object o) { |
|
synchronized(children) { |
|
return children.containsKey(o); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean containsKey(Object o) { |
|
synchronized(children) { |
|
return children.containsKey(o); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Iterator iterator() { |
|
synchronized(children) { |
|
return new BCSIterator(children.keySet().iterator()); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Object[] toArray() { |
|
synchronized(children) { |
|
return children.keySet().toArray(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Object[] toArray(Object[] arry) { |
|
synchronized(children) { |
|
return children.keySet().toArray(arry); |
|
} |
|
} |
|
|
|
|
|
/************************************************************************/ |
|
|
|
/** |
|
* protected final subclass that encapsulates an iterator but implements |
|
* a noop remove() method. |
|
*/ |
|
|
|
protected static final class BCSIterator implements Iterator { |
|
BCSIterator(Iterator i) { super(); src = i; } |
|
|
|
public boolean hasNext() { return src.hasNext(); } |
|
public Object next() { return src.next(); } |
|
public void remove() { /* do nothing */ } |
|
|
|
private Iterator src; |
|
} |
|
|
|
/************************************************************************/ |
|
|
|
/* |
|
* protected nested class containing per child information, an instance |
|
* of which is associated with each child in the "children" hashtable. |
|
* subclasses can extend this class to include their own per-child state. |
|
* |
|
* Note that this 'value' is serialized with the corresponding child 'key' |
|
* when the BeanContextSupport is serialized. |
|
*/ |
|
|
|
protected class BCSChild implements Serializable { |
|
|
|
private static final long serialVersionUID = -5815286101609939109L; |
|
|
|
BCSChild(Object bcc, Object peer) { |
|
super(); |
|
|
|
child = bcc; |
|
proxyPeer = peer; |
|
} |
|
|
|
Object getChild() { return child; } |
|
|
|
void setRemovePending(boolean v) { removePending = v; } |
|
|
|
boolean isRemovePending() { return removePending; } |
|
|
|
boolean isProxyPeer() { return proxyPeer != null; } |
|
|
|
Object getProxyPeer() { return proxyPeer; } |
|
/* |
|
* fields |
|
*/ |
|
|
|
|
|
private Object child; |
|
private Object proxyPeer; |
|
|
|
private transient boolean removePending; |
|
} |
|
|
|
/** |
|
* <p> |
|
* Subclasses can override this method to insert their own subclass |
|
* of Child without having to override add() or the other Collection |
|
* methods that add children to the set. |
|
* </p> |
|
* @param targetChild the child to create the Child on behalf of |
|
* @param peer the peer if the tragetChild and the peer are related by an implementation of BeanContextProxy * @return Subtype-specific subclass of Child without overriding collection methods |
|
*/ |
|
|
|
protected BCSChild createBCSChild(Object targetChild, Object peer) { |
|
return new BCSChild(targetChild, peer); |
|
} |
|
|
|
/************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean add(Object targetChild) { |
|
|
|
if (targetChild == null) throw new IllegalArgumentException(); |
|
|
|
// The specification requires that we do nothing if the child |
|
// is already nested herein. |
|
|
|
if (children.containsKey(targetChild)) return false; |
|
|
|
synchronized(BeanContext.globalHierarchyLock) { |
|
if (children.containsKey(targetChild)) return false; |
|
|
|
if (!validatePendingAdd(targetChild)) { |
|
throw new IllegalStateException(); |
|
} |
|
|
|
|
|
// The specification requires that we invoke setBeanContext() on the |
|
// newly added child if it implements the java.beans.beancontext.BeanContextChild interface |
|
|
|
BeanContextChild cbcc = getChildBeanContextChild(targetChild); |
|
BeanContextChild bccp = null; |
|
|
|
synchronized(targetChild) { |
|
|
|
if (targetChild instanceof BeanContextProxy) { |
|
bccp = ((BeanContextProxy)targetChild).getBeanContextProxy(); |
|
|
|
if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()"); |
|
} |
|
|
|
BCSChild bcsc = createBCSChild(targetChild, bccp); |
|
BCSChild pbcsc = null; |
|
|
|
synchronized (children) { |
|
children.put(targetChild, bcsc); |
|
|
|
if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild)); |
|
} |
|
|
|
if (cbcc != null) synchronized(cbcc) { |
|
try { |
|
cbcc.setBeanContext(getBeanContextPeer()); |
|
} catch (PropertyVetoException pve) { |
|
|
|
synchronized (children) { |
|
children.remove(targetChild); |
|
|
|
if (bccp != null) children.remove(bccp); |
|
} |
|
|
|
throw new IllegalStateException(); |
|
} |
|
|
|
cbcc.addPropertyChangeListener("beanContext", childPCL); |
|
cbcc.addVetoableChangeListener("beanContext", childVCL); |
|
} |
|
|
|
Visibility v = getChildVisibility(targetChild); |
|
|
|
if (v != null) { |
|
if (okToUseGui) |
|
v.okToUseGui(); |
|
else |
|
v.dontUseGui(); |
|
} |
|
|
|
if (getChildSerializable(targetChild) != null) serializable++; |
|
|
|
childJustAddedHook(targetChild, bcsc); |
|
|
|
if (bccp != null) { |
|
v = getChildVisibility(bccp); |
|
|
|
if (v != null) { |
|
if (okToUseGui) |
|
v.okToUseGui(); |
|
else |
|
v.dontUseGui(); |
|
} |
|
|
|
if (getChildSerializable(bccp) != null) serializable++; |
|
|
|
childJustAddedHook(bccp, pbcsc); |
|
} |
|
|
|
|
|
} |
|
|
|
// The specification requires that we fire a notification of the change |
|
|
|
fireChildrenAdded(new BeanContextMembershipEvent(getBeanContextPeer(), bccp == null ? new Object[] { targetChild } : new Object[] { targetChild, bccp } )); |
|
|
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean remove(Object targetChild) { |
|
return remove(targetChild, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected boolean remove(Object targetChild, boolean callChildSetBC) { |
|
|
|
if (targetChild == null) throw new IllegalArgumentException(); |
|
|
|
synchronized(BeanContext.globalHierarchyLock) { |
|
if (!containsKey(targetChild)) return false; |
|
|
|
if (!validatePendingRemove(targetChild)) { |
|
throw new IllegalStateException(); |
|
} |
|
|
|
BCSChild bcsc = (BCSChild)children.get(targetChild); |
|
BCSChild pbcsc = null; |
|
Object peer = null; |
|
|
|
// we are required to notify the child that it is no longer nested here if |
|
// it implements java.beans.beancontext.BeanContextChild |
|
|
|
synchronized(targetChild) { |
|
if (callChildSetBC) { |
|
BeanContextChild cbcc = getChildBeanContextChild(targetChild); |
|
if (cbcc != null) synchronized(cbcc) { |
|
cbcc.removePropertyChangeListener("beanContext", childPCL); |
|
cbcc.removeVetoableChangeListener("beanContext", childVCL); |
|
|
|
try { |
|
cbcc.setBeanContext(null); |
|
} catch (PropertyVetoException pve1) { |
|
cbcc.addPropertyChangeListener("beanContext", childPCL); |
|
cbcc.addVetoableChangeListener("beanContext", childVCL); |
|
throw new IllegalStateException(); |
|
} |
|
|
|
} |
|
} |
|
|
|
synchronized (children) { |
|
children.remove(targetChild); |
|
|
|
if (bcsc.isProxyPeer()) { |
|
pbcsc = (BCSChild)children.get(peer = bcsc.getProxyPeer()); |
|
children.remove(peer); |
|
} |
|
} |
|
|
|
if (getChildSerializable(targetChild) != null) serializable--; |
|
|
|
childJustRemovedHook(targetChild, bcsc); |
|
|
|
if (peer != null) { |
|
if (getChildSerializable(peer) != null) serializable--; |
|
|
|
childJustRemovedHook(peer, pbcsc); |
|
} |
|
} |
|
|
|
fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } )); |
|
|
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean containsAll(Collection c) { |
|
synchronized(children) { |
|
Iterator i = c.iterator(); |
|
while (i.hasNext()) |
|
if(!contains(i.next())) |
|
return false; |
|
|
|
return true; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean addAll(Collection c) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean removeAll(Collection c) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean retainAll(Collection c) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void clear() { |
|
throw new UnsupportedOperationException(); |
|
} |
|
|
|
/** |
|
* Adds a BeanContextMembershipListener |
|
* |
|
* @param bcml the BeanContextMembershipListener to add |
|
* @throws NullPointerException if the argument is null |
|
*/ |
|
|
|
public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) { |
|
if (bcml == null) throw new NullPointerException("listener"); |
|
|
|
synchronized(bcmListeners) { |
|
if (bcmListeners.contains(bcml)) |
|
return; |
|
else |
|
bcmListeners.add(bcml); |
|
} |
|
} |
|
|
|
/** |
|
* Removes a BeanContextMembershipListener |
|
* |
|
* @param bcml the BeanContextMembershipListener to remove |
|
* @throws NullPointerException if the argument is null |
|
*/ |
|
|
|
public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) { |
|
if (bcml == null) throw new NullPointerException("listener"); |
|
|
|
synchronized(bcmListeners) { |
|
if (!bcmListeners.contains(bcml)) |
|
return; |
|
else |
|
bcmListeners.remove(bcml); |
|
} |
|
} |
|
|
|
/** |
|
* @param name the name of the resource requested. |
|
* @param bcc the child object making the request. |
|
* |
|
* @return the requested resource as an InputStream |
|
* @throws NullPointerException if the argument is null |
|
*/ |
|
|
|
public InputStream getResourceAsStream(String name, BeanContextChild bcc) { |
|
if (name == null) throw new NullPointerException("name"); |
|
if (bcc == null) throw new NullPointerException("bcc"); |
|
|
|
if (containsKey(bcc)) { |
|
ClassLoader cl = bcc.getClass().getClassLoader(); |
|
|
|
return cl != null ? cl.getResourceAsStream(name) |
|
: ClassLoader.getSystemResourceAsStream(name); |
|
} else throw new IllegalArgumentException("Not a valid child"); |
|
} |
|
|
|
/** |
|
* @param name the name of the resource requested. |
|
* @param bcc the child object making the request. |
|
* |
|
* @return the requested resource as an InputStream |
|
*/ |
|
|
|
public URL getResource(String name, BeanContextChild bcc) { |
|
if (name == null) throw new NullPointerException("name"); |
|
if (bcc == null) throw new NullPointerException("bcc"); |
|
|
|
if (containsKey(bcc)) { |
|
ClassLoader cl = bcc.getClass().getClassLoader(); |
|
|
|
return cl != null ? cl.getResource(name) |
|
: ClassLoader.getSystemResource(name); |
|
} else throw new IllegalArgumentException("Not a valid child"); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized void setDesignTime(boolean dTime) { |
|
if (designTime != dTime) { |
|
designTime = dTime; |
|
|
|
firePropertyChange("designMode", Boolean.valueOf(!dTime), Boolean.valueOf(dTime)); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized boolean isDesignTime() { return designTime; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized void setLocale(Locale newLocale) throws PropertyVetoException { |
|
|
|
if ((locale != null && !locale.equals(newLocale)) && newLocale != null) { |
|
Locale old = locale; |
|
|
|
fireVetoableChange("locale", old, newLocale); |
|
|
|
locale = newLocale; |
|
|
|
firePropertyChange("locale", old, newLocale); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized Locale getLocale() { return locale; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public synchronized boolean needsGui() { |
|
BeanContext bc = getBeanContextPeer(); |
|
|
|
if (bc != this) { |
|
if (bc instanceof Visibility) return ((Visibility)bc).needsGui(); |
|
|
|
if (bc instanceof Container || bc instanceof Component) |
|
return true; |
|
} |
|
|
|
synchronized(children) { |
|
for (Iterator i = children.keySet().iterator(); i.hasNext();) { |
|
Object c = i.next(); |
|
|
|
try { |
|
return ((Visibility)c).needsGui(); |
|
} catch (ClassCastException cce) { |
|
// do nothing ... |
|
} |
|
|
|
if (c instanceof Container || c instanceof Component) |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
/** |
|
* notify this instance that it may no longer render a GUI. |
|
*/ |
|
|
|
public synchronized void dontUseGui() { |
|
if (okToUseGui) { |
|
okToUseGui = false; |
|
|
|
|
|
synchronized(children) { |
|
for (Iterator i = children.keySet().iterator(); i.hasNext();) { |
|
Visibility v = getChildVisibility(i.next()); |
|
|
|
if (v != null) v.dontUseGui(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Notify this instance that it may now render a GUI |
|
*/ |
|
|
|
public synchronized void okToUseGui() { |
|
if (!okToUseGui) { |
|
okToUseGui = true; |
|
|
|
|
|
synchronized(children) { |
|
for (Iterator i = children.keySet().iterator(); i.hasNext();) { |
|
Visibility v = getChildVisibility(i.next()); |
|
|
|
if (v != null) v.okToUseGui(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean avoidingGui() { |
|
return !okToUseGui && needsGui(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isSerializing() { return serializing; } |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected Iterator bcsChildren() { synchronized(children) { return children.values().iterator(); } } |
|
|
|
/** |
|
* called by writeObject after defaultWriteObject() but prior to |
|
* serialization of currently serializable children. |
|
* |
|
* This method may be overridden by subclasses to perform custom |
|
* serialization of their state prior to this superclass serializing |
|
* the children. |
|
* |
|
* This method should not however be used by subclasses to replace their |
|
* own implementation (if any) of writeObject(). |
|
* @param oos the {@code ObjectOutputStream} to use during serialization |
|
* @throws IOException if serialization failed |
|
*/ |
|
|
|
protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException { |
|
} |
|
|
|
/** |
|
* called by readObject after defaultReadObject() but prior to |
|
* deserialization of any children. |
|
* |
|
* This method may be overridden by subclasses to perform custom |
|
* deserialization of their state prior to this superclass deserializing |
|
* the children. |
|
* |
|
* This method should not however be used by subclasses to replace their |
|
* own implementation (if any) of readObject(). |
|
* @param ois the {@code ObjectInputStream} to use during deserialization |
|
* @throws IOException if deserialization failed |
|
* @throws ClassNotFoundException if needed classes are not found |
|
*/ |
|
|
|
protected void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException { |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void childDeserializedHook(Object child, BCSChild bcsc) { |
|
synchronized(children) { |
|
children.put(child, bcsc); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected final void serialize(ObjectOutputStream oos, Collection coll) throws IOException { |
|
int count = 0; |
|
Object[] objects = coll.toArray(); |
|
|
|
for (int i = 0; i < objects.length; i++) { |
|
if (objects[i] instanceof Serializable) |
|
count++; |
|
else |
|
objects[i] = null; |
|
} |
|
|
|
oos.writeInt(count); |
|
|
|
for (int i = 0; count > 0; i++) { |
|
Object o = objects[i]; |
|
|
|
if (o != null) { |
|
oos.writeObject(o); |
|
count--; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException { |
|
int count = 0; |
|
|
|
count = ois.readInt(); |
|
|
|
while (count-- > 0) { |
|
coll.add(ois.readObject()); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final void writeChildren(ObjectOutputStream oos) throws IOException { |
|
if (serializable <= 0) return; |
|
|
|
boolean prev = serializing; |
|
|
|
serializing = true; |
|
|
|
int count = 0; |
|
|
|
synchronized(children) { |
|
Iterator i = children.entrySet().iterator(); |
|
|
|
while (i.hasNext() && count < serializable) { |
|
Map.Entry entry = (Map.Entry)i.next(); |
|
|
|
if (entry.getKey() instanceof Serializable) { |
|
try { |
|
oos.writeObject(entry.getKey()); |
|
oos.writeObject(entry.getValue()); |
|
} catch (IOException ioe) { |
|
serializing = prev; |
|
throw ioe; |
|
} |
|
count++; |
|
} |
|
} |
|
} |
|
|
|
serializing = prev; |
|
|
|
if (count != serializable) { |
|
throw new IOException("wrote different number of children than expected"); |
|
} |
|
|
|
} |
|
|
|
/** |
|
* Serialize the BeanContextSupport, if this instance has a distinct |
|
* peer (that is this object is acting as a delegate for another) then |
|
* the children of this instance are not serialized here due to a |
|
* 'chicken and egg' problem that occurs on deserialization of the |
|
* children at the same time as this instance. |
|
* |
|
* Therefore in situations where there is a distinct peer to this instance |
|
* it should always call writeObject() followed by writeChildren() and |
|
* readObject() followed by readChildren(). |
|
* |
|
* @param oos the ObjectOutputStream |
|
*/ |
|
|
|
private synchronized void writeObject(ObjectOutputStream oos) throws IOException, ClassNotFoundException { |
|
serializing = true; |
|
|
|
synchronized (BeanContext.globalHierarchyLock) { |
|
try { |
|
oos.defaultWriteObject(); |
|
|
|
bcsPreSerializationHook(oos); |
|
|
|
if (serializable > 0 && this.equals(getBeanContextPeer())) |
|
writeChildren(oos); |
|
|
|
serialize(oos, (Collection)bcmListeners); |
|
} finally { |
|
serializing = false; |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* When an instance of this class is used as a delegate for the |
|
* implementation of the BeanContext protocols (and its subprotocols) |
|
* there exists a 'chicken and egg' problem during deserialization |
|
* @param ois the ObjectInputStream to use |
|
* @throws IOException if deserialization failed |
|
* @throws ClassNotFoundException if needed classes are not found |
|
*/ |
|
|
|
public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException { |
|
int count = serializable; |
|
|
|
while (count-- > 0) { |
|
Object child = ois.readObject(); |
|
BCSChild bscc = (BCSChild) ois.readObject(); |
|
|
|
synchronized(child) { |
|
BeanContextChild bcc = null; |
|
|
|
try { |
|
bcc = (BeanContextChild)child; |
|
} catch (ClassCastException cce) { |
|
// do nothing; |
|
} |
|
|
|
if (bcc != null) { |
|
try { |
|
bcc.setBeanContext(getBeanContextPeer()); |
|
|
|
bcc.addPropertyChangeListener("beanContext", childPCL); |
|
bcc.addVetoableChangeListener("beanContext", childVCL); |
|
|
|
} catch (PropertyVetoException pve) { |
|
continue; |
|
} |
|
} |
|
|
|
childDeserializedHook(child, bscc); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* deserialize contents ... if this instance has a distinct peer the |
|
* children are *not* serialized here, the peer's readObject() must call |
|
* readChildren() after deserializing this instance. |
|
*/ |
|
|
|
private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { |
|
|
|
synchronized(BeanContext.globalHierarchyLock) { |
|
ois.defaultReadObject(); |
|
|
|
initialize(); |
|
|
|
bcsPreDeserializationHook(ois); |
|
|
|
if (serializable > 0 && this.equals(getBeanContextPeer())) |
|
readChildren(ois); |
|
|
|
deserialize(ois, bcmListeners = new ArrayList(1)); |
|
} |
|
} |
|
|
|
/** |
|
* subclasses may envelope to monitor veto child property changes. |
|
*/ |
|
|
|
public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException { |
|
String propertyName = pce.getPropertyName(); |
|
Object source = pce.getSource(); |
|
|
|
synchronized(children) { |
|
if ("beanContext".equals(propertyName) && |
|
containsKey(source) && |
|
!getBeanContextPeer().equals(pce.getNewValue()) |
|
) { |
|
if (!validatePendingRemove(source)) { |
|
throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce); |
|
} else ((BCSChild)children.get(source)).setRemovePending(true); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* subclasses may envelope to monitor child property changes. |
|
*/ |
|
|
|
public void propertyChange(PropertyChangeEvent pce) { |
|
String propertyName = pce.getPropertyName(); |
|
Object source = pce.getSource(); |
|
|
|
synchronized(children) { |
|
if ("beanContext".equals(propertyName) && |
|
containsKey(source) && |
|
((BCSChild)children.get(source)).isRemovePending()) { |
|
BeanContext bc = getBeanContextPeer(); |
|
|
|
if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) { |
|
remove(source, false); |
|
} else { |
|
((BCSChild)children.get(source)).setRemovePending(false); |
|
} |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* <p> |
|
* Subclasses of this class may override, or envelope, this method to |
|
* add validation behavior for the BeanContext to examine child objects |
|
* immediately prior to their being added to the BeanContext. |
|
* </p> |
|
* |
|
* @param targetChild the child to create the Child on behalf of |
|
* @return true iff the child may be added to this BeanContext, otherwise false. |
|
*/ |
|
|
|
protected boolean validatePendingAdd(Object targetChild) { |
|
return true; |
|
} |
|
|
|
/** |
|
* <p> |
|
* Subclasses of this class may override, or envelope, this method to |
|
* add validation behavior for the BeanContext to examine child objects |
|
* immediately prior to their being removed from the BeanContext. |
|
* </p> |
|
* |
|
* @param targetChild the child to create the Child on behalf of |
|
* @return true iff the child may be removed from this BeanContext, otherwise false. |
|
*/ |
|
|
|
protected boolean validatePendingRemove(Object targetChild) { |
|
return true; |
|
} |
|
|
|
/** |
|
* subclasses may override this method to simply extend add() semantics |
|
* after the child has been added and before the event notification has |
|
* occurred. The method is called with the child synchronized. |
|
* @param child the child |
|
* @param bcsc the BCSChild |
|
*/ |
|
|
|
protected void childJustAddedHook(Object child, BCSChild bcsc) { |
|
} |
|
|
|
/** |
|
* subclasses may override this method to simply extend remove() semantics |
|
* after the child has been removed and before the event notification has |
|
* occurred. The method is called with the child synchronized. |
|
* @param child the child |
|
* @param bcsc the BCSChild |
|
*/ |
|
|
|
protected void childJustRemovedHook(Object child, BCSChild bcsc) { |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected static final Visibility getChildVisibility(Object child) { |
|
try { |
|
return (Visibility)child; |
|
} catch (ClassCastException cce) { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected static final Serializable getChildSerializable(Object child) { |
|
try { |
|
return (Serializable)child; |
|
} catch (ClassCastException cce) { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected static final PropertyChangeListener getChildPropertyChangeListener(Object child) { |
|
try { |
|
return (PropertyChangeListener)child; |
|
} catch (ClassCastException cce) { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected static final VetoableChangeListener getChildVetoableChangeListener(Object child) { |
|
try { |
|
return (VetoableChangeListener)child; |
|
} catch (ClassCastException cce) { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected static final BeanContextMembershipListener getChildBeanContextMembershipListener(Object child) { |
|
try { |
|
return (BeanContextMembershipListener)child; |
|
} catch (ClassCastException cce) { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected static final BeanContextChild getChildBeanContextChild(Object child) { |
|
try { |
|
BeanContextChild bcc = (BeanContextChild)child; |
|
|
|
if (child instanceof BeanContextChild && child instanceof BeanContextProxy) |
|
throw new IllegalArgumentException("child cannot implement both BeanContextChild and BeanContextProxy"); |
|
else |
|
return bcc; |
|
} catch (ClassCastException cce) { |
|
try { |
|
return ((BeanContextProxy)child).getBeanContextProxy(); |
|
} catch (ClassCastException cce1) { |
|
return null; |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Fire a BeanContextshipEvent on the BeanContextMembershipListener interface |
|
* @param bcme the event to fire |
|
*/ |
|
|
|
protected final void fireChildrenAdded(BeanContextMembershipEvent bcme) { |
|
Object[] copy; |
|
|
|
synchronized(bcmListeners) { copy = bcmListeners.toArray(); } |
|
|
|
for (int i = 0; i < copy.length; i++) |
|
((BeanContextMembershipListener)copy[i]).childrenAdded(bcme); |
|
} |
|
|
|
/** |
|
* Fire a BeanContextshipEvent on the BeanContextMembershipListener interface |
|
* @param bcme the event to fire |
|
*/ |
|
|
|
protected final void fireChildrenRemoved(BeanContextMembershipEvent bcme) { |
|
Object[] copy; |
|
|
|
synchronized(bcmListeners) { copy = bcmListeners.toArray(); } |
|
|
|
for (int i = 0; i < copy.length; i++) |
|
((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme); |
|
} |
|
|
|
/** |
|
* protected method called from constructor and readObject to initialize |
|
* transient state of BeanContextSupport instance. |
|
* |
|
* This class uses this method to instantiate inner class listeners used |
|
* to monitor PropertyChange and VetoableChange events on children. |
|
* |
|
* subclasses may envelope this method to add their own initialization |
|
* behavior |
|
*/ |
|
|
|
protected synchronized void initialize() { |
|
children = new HashMap(serializable + 1); |
|
bcmListeners = new ArrayList(1); |
|
|
|
childPCL = new PropertyChangeListener() { |
|
|
|
/* |
|
* this adaptor is used by the BeanContextSupport class to forward |
|
* property changes from a child to the BeanContext, avoiding |
|
* accidential serialization of the BeanContext by a badly |
|
* behaved Serializable child. |
|
*/ |
|
|
|
public void propertyChange(PropertyChangeEvent pce) { |
|
BeanContextSupport.this.propertyChange(pce); |
|
} |
|
}; |
|
|
|
childVCL = new VetoableChangeListener() { |
|
|
|
/* |
|
* this adaptor is used by the BeanContextSupport class to forward |
|
* vetoable changes from a child to the BeanContext, avoiding |
|
* accidential serialization of the BeanContext by a badly |
|
* behaved Serializable child. |
|
*/ |
|
|
|
public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException { |
|
BeanContextSupport.this.vetoableChange(pce); |
|
} |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
protected final Object[] copyChildren() { |
|
synchronized(children) { return children.keySet().toArray(); } |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected static final boolean classEquals(Class first, Class second) { |
|
return first.equals(second) || first.getName().equals(second.getName()); |
|
} |
|
|
|
|
|
/* |
|
* fields |
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected transient HashMap children; |
|
|
|
private int serializable = 0; |
|
|
|
|
|
|
|
|
|
*/ |
|
protected transient ArrayList bcmListeners; |
|
|
|
// |
|
|
|
|
|
|
|
*/ |
|
protected Locale locale; |
|
|
|
|
|
|
|
|
|
*/ |
|
protected boolean okToUseGui; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected boolean designTime; |
|
|
|
/* |
|
* transient |
|
*/ |
|
|
|
private transient PropertyChangeListener childPCL; |
|
|
|
private transient VetoableChangeListener childVCL; |
|
|
|
private transient boolean serializing; |
|
} |