| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.beans.beancontext; |
| |
| import java.awt.Component; |
| import java.beans.Beans; |
| 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.Locale; |
| |
| import org.apache.harmony.beans.internal.nls.Messages; |
| |
| /** |
| * This support class implements <code>BeanContext</code> interface. |
| * This class can be used directly, or be a super class of your class, |
| * or be a delegate of your implementation that needs to support |
| * <code>BeanContext</code> interface. |
| * |
| */ |
| public class BeanContextSupport extends BeanContextChildSupport implements |
| BeanContext, PropertyChangeListener, VetoableChangeListener, |
| Serializable { |
| |
| /** |
| * Every child of context is companied with a <code>BCSChild</code> |
| * instance. It can hold implementation specific information about |
| * each child. |
| * <p> |
| * This class holds references of the child and its peer if there is one.</p> |
| * |
| */ |
| protected class BCSChild implements Serializable { |
| |
| private static final long serialVersionUID = -5815286101609939109L; |
| |
| Object child; |
| |
| Object proxyPeer; |
| |
| BCSChild(Object child, Object proxyPeer) { |
| this.child = child; |
| this.proxyPeer = proxyPeer; |
| } |
| } |
| |
| /** |
| * This implementation wraps an iterator and override |
| * <code>remove()</code> with a noop method. |
| * |
| */ |
| protected static final class BCSIterator implements Iterator { |
| |
| private Iterator backIter; |
| |
| BCSIterator(Iterator backIter) { |
| this.backIter = backIter; |
| } |
| |
| public boolean hasNext() { |
| return backIter.hasNext(); |
| } |
| |
| public Object next() { |
| return backIter.next(); |
| } |
| |
| public void remove() { |
| // no-op |
| } |
| } |
| |
| private static final long serialVersionUID = -4879613978649577204L; //J2SE 1.4.2 |
| |
| /** |
| * A list of registered membership listeners. |
| * All access to this object should be synchronized on itself. |
| */ |
| @SuppressWarnings("unchecked") |
| transient protected ArrayList bcmListeners; |
| |
| /** |
| * A map of children - key is child instance, value is <code>BCSChild</code> instance. |
| * All access to this object should be synchronized on itself. |
| */ |
| @SuppressWarnings("unchecked") |
| transient protected HashMap children; |
| |
| transient private boolean serializing; |
| |
| transient private boolean inNeedsGui; |
| |
| transient private PropertyChangeListener nonSerPCL; |
| |
| private int serializable; |
| |
| /** |
| * The locale of this context. |
| */ |
| protected Locale locale; |
| |
| /** |
| * A flag indicating whether this context is allowed to use GUI. |
| */ |
| protected boolean okToUseGui; |
| |
| /** |
| * A flag indicating whether this context is in design mode. |
| */ |
| protected boolean designTime; |
| |
| /** |
| * Constructs a standload <code>BeanContextSupport</code>. |
| */ |
| public BeanContextSupport() { |
| this(null, Locale.getDefault(), false, true); |
| } |
| |
| /** |
| * Constructs a <code>BeanContextSupport</code> which is a delegate |
| * of the given peer. |
| * |
| * @param peer the peer of this context |
| */ |
| public BeanContextSupport(BeanContext peer) { |
| this(peer, Locale.getDefault(), false, true); |
| } |
| |
| /** |
| * Constructs a <code>BeanContextSupport</code> which is a delegate |
| * of the given peer. |
| * |
| * @param peer the peer of this context |
| * @param locale the locale of this context |
| */ |
| public BeanContextSupport(BeanContext peer, Locale locale) { |
| this(peer, locale, false, true); |
| } |
| |
| /** |
| * Constructs a <code>BeanContextSupport</code> which is a delegate |
| * of the given peer. |
| * |
| * @param peer the peer of this context |
| * @param locale the locale of this context |
| * @param designTime whether in design mode or not |
| */ |
| public BeanContextSupport(BeanContext peer, Locale locale, |
| boolean designTime) { |
| this(peer, locale, designTime, true); |
| } |
| |
| /** |
| * Constructs a <code>BeanContextSupport</code> which is a delegate |
| * of the given peer. |
| * |
| * @param peer the peer of this context |
| * @param locale the locale of this context |
| * @param designTime whether in design mode or not |
| * @param okToUseGui whether GUI is usable or not |
| */ |
| public BeanContextSupport(BeanContext peer, Locale locale, |
| boolean designTime, boolean okToUseGui) { |
| super(peer); |
| if (locale == null) { |
| locale = Locale.getDefault(); |
| } |
| this.locale = locale; |
| this.designTime = designTime; |
| this.okToUseGui = okToUseGui; |
| |
| initialize(); |
| } |
| |
| /** |
| * Add a child to this context. |
| * <p> |
| * If the child already exists in this context, simply returns false. |
| * Otherwise, it is validated by calling <code>validatePendingAdd()</code>. |
| * If the add is valid, the child and its proxy (if the child implements |
| * <code>BeanContextProxy</code>) is then added, and <code>setBeanContext()</code> |
| * is called on it (if the child implements <code>BeanContextChild</code> |
| * or it has a proxy). Last, the <code>childJustAddedHook()</code> is |
| * called and all registered <code>BeanContextMembershipListener</code>s |
| * are notified.</p> |
| * |
| * @param child the child to add |
| * @return true if the child is added to this context; otherwise false |
| * @throws IllegalStateException if the child is not valid to add |
| * @see java.util.Collection#add(java.lang.Object) |
| */ |
| @SuppressWarnings("unchecked") |
| public boolean add(Object child) { |
| if (child == null) { |
| throw new IllegalArgumentException(Messages.getString("beans.67")); |
| } |
| |
| BeanContextChild proxy = null; |
| |
| synchronized (globalHierarchyLock) { |
| // check existence |
| if (contains(child)) { |
| return false; |
| } |
| |
| // check serializing state |
| if (serializing) { |
| throw new IllegalStateException( |
| Messages.getString("beans.68")); |
| } |
| |
| // validate |
| boolean valid = validatePendingAdd(child); |
| if (!valid) { |
| throw new IllegalStateException( |
| Messages.getString("beans.69")); |
| } |
| |
| // find the proxy, if there's one |
| if (child instanceof BeanContextProxy) { |
| proxy = ((BeanContextProxy) child).getBeanContextProxy(); |
| if (proxy == null) { |
| throw new NullPointerException( |
| Messages.getString("beans.6A")); |
| } |
| } |
| BeanContextChild beanContextChild = getChildBeanContextChild(child); |
| |
| // add to children |
| BCSChild childBCSC = null, proxyBCSC = null; |
| synchronized (children) { |
| childBCSC = createBCSChild(child, proxy); |
| children.put(child, childBCSC); |
| if (proxy != null) { |
| proxyBCSC = createBCSChild(proxy, child); |
| children.put(proxy, proxyBCSC); |
| } |
| } |
| |
| // set child's beanContext property |
| if (beanContextChild != null) { |
| try { |
| beanContextChild.setBeanContext(getBeanContextPeer()); |
| } catch (PropertyVetoException e) { |
| synchronized (children) { |
| children.remove(child); |
| if (proxy != null) { |
| children.remove(proxy); |
| } |
| } |
| throw new IllegalStateException( |
| Messages.getString("beans.6B")); |
| } |
| // ensure no duplicate listener |
| beanContextChild.removePropertyChangeListener("beanContext", |
| nonSerPCL); |
| // listen to child's beanContext change |
| beanContextChild.addPropertyChangeListener("beanContext", |
| nonSerPCL); |
| } |
| |
| // trigger hook |
| synchronized (child) { |
| addSerializable(childBCSC); |
| childJustAddedHook(child, childBCSC); |
| } |
| if (proxy != null) { |
| synchronized (proxy) { |
| addSerializable(proxyBCSC); |
| childJustAddedHook(proxy, proxyBCSC); |
| } |
| } |
| } |
| |
| // notify listeners |
| fireChildrenAdded(new BeanContextMembershipEvent(getBeanContextPeer(), |
| proxy == null ? new Object[] { child } : new Object[] { child, |
| proxy })); |
| return true; |
| } |
| |
| /** |
| * This method is unsupported, throws <code>UnsupportedOperationException</code>. |
| * |
| * @see java.util.Collection#addAll(java.util.Collection) |
| */ |
| public boolean addAll(Collection collection) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.beancontext.BeanContext#addBeanContextMembershipListener(java.beans.beancontext.BeanContextMembershipListener) |
| */ |
| public void addBeanContextMembershipListener( |
| BeanContextMembershipListener listener) { |
| if (listener == null) { |
| throw new NullPointerException(); |
| } |
| synchronized (bcmListeners) { |
| if (!bcmListeners.contains(listener)) { |
| bcmListeners.add(listener); |
| } |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.Visibility#avoidingGui() |
| */ |
| public boolean avoidingGui() { |
| // Avoiding GUI means that |
| // GUI is needed but not allowed to use at this time |
| return (needsGui() && !this.okToUseGui); |
| } |
| |
| /** |
| * Returns an iterator of all <code>BCSChild</code> instances, |
| * with <code>remove()</code> disabled. |
| * |
| * @return an iterator of all <code>BCSChild</code> instances |
| */ |
| protected Iterator bcsChildren() { |
| synchronized (children) { |
| return new BCSIterator(children.values().iterator()); |
| } |
| } |
| |
| /** |
| * This method is called by <code>readObject()</code> after |
| * <code>defaultReadObject()</code> and before deserializing any |
| * children or listeners. Subclass can insert its specific |
| * deserialization behavior by overrideing this method. |
| * <p> |
| * The default implementation does nothing.</p> |
| * |
| * @param ois the object input stream |
| * @throws IOException |
| * @throws ClassNotFoundException |
| */ |
| protected void bcsPreDeserializationHook(ObjectInputStream ois) |
| throws IOException, ClassNotFoundException { |
| // to be overridden |
| } |
| |
| /** |
| * This method is called by <code>writeObject()</code> after |
| * <code>defaultWriteObject()</code> and before serializing any |
| * children or listeners. Subclass can insert its specific |
| * serialization behavior by overrideing this method. |
| * <p> |
| * The default implementation does nothing.</p> |
| * |
| * @param oos the object output stream |
| * @throws IOException |
| */ |
| protected void bcsPreSerializationHook(ObjectOutputStream oos) |
| throws IOException { |
| // to be overridden |
| } |
| |
| /** |
| * This method is called during deserialization everytime a child is read. |
| * <p> |
| * The default implementation does nothing.</p> |
| * |
| * @param child the child just deserialized |
| * @param bcsChild the <code>BCSChild</code> just deserialized |
| */ |
| protected void childDeserializedHook(Object child, BCSChild bcsChild) { |
| // to be overridden |
| } |
| |
| /** |
| * This method is called everytime a child is added to this context. |
| * This method is called with child synchronized. |
| * <p> |
| * The default implementation does nothing.</p> |
| * |
| * @param child the child just added |
| * @param bcsChild the <code>BCSChild</code> just added |
| */ |
| protected void childJustAddedHook(Object child, BCSChild bcsChild) { |
| // to be overridden |
| } |
| |
| /** |
| * This method is called everytime a child is removed from this context. |
| * This method is called with child synchronized. |
| * <p> |
| * The default implementation does nothing.</p> |
| * |
| * @param child the child just removed |
| * @param bcsChild the <code>BCSChild</code> just removed |
| */ |
| protected void childJustRemovedHook(Object child, BCSChild bcsChild) { |
| // to be overridden |
| } |
| |
| /** |
| * Compares if two classes are equal or their class names are equal. |
| * |
| * @param clz1 a class |
| * @param clz2 another class |
| * @return true if two class objects are equal or their class names are equal. |
| */ |
| protected static final boolean classEquals(Class clz1, Class clz2) { |
| if (clz1 == null || clz2 == null) { |
| throw new NullPointerException(); |
| } |
| return clz1 == clz2 || clz1.getName().equals(clz2.getName()); |
| } |
| |
| /** |
| * This method is unsupported, throws <code>UnsupportedOperationException</code>. |
| * |
| * @see java.util.Collection#clear() |
| */ |
| public void clear() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Returns true if the given object is a child of this context. |
| * |
| * @param child the object to test |
| * @return true if the given object is a child of this context |
| * @see java.util.Collection#contains(java.lang.Object) |
| */ |
| public boolean contains(Object child) { |
| synchronized (children) { |
| return children.containsKey(child); |
| } |
| } |
| |
| /** |
| * Returns true if given objects are children of this context. |
| * |
| * @param collection a collection of objects |
| * @return true if given objects are children of this context |
| * @see java.util.Collection#containsAll(java.util.Collection) |
| */ |
| @SuppressWarnings("unchecked") |
| public boolean containsAll(Collection collection) { |
| synchronized (children) { |
| return children.keySet().containsAll(collection); |
| } |
| } |
| |
| /** |
| * Returns true if the given object is a child of this context. |
| * |
| * @param child the object to test |
| * @return true if the given object is a child of this context |
| */ |
| public boolean containsKey(Object child) { |
| synchronized (children) { |
| return children.containsKey(child); |
| } |
| } |
| |
| /** |
| * Returns an array containing all children of this context. |
| * |
| * @return an array containing all children of this context |
| */ |
| protected final Object[] copyChildren() { |
| synchronized (children) { |
| return children.keySet().toArray(); |
| } |
| } |
| |
| /** |
| * Creates a <code>BCSChild</code> object to company the given child. |
| * |
| * @param child the child |
| * @param proxyPeer the proxy peer of the child if there is one |
| * @return a <code>BCSChild</code> object to company the given child |
| */ |
| protected BCSChild createBCSChild(Object child, Object proxyPeer) { |
| return new BCSChild(child, proxyPeer); |
| } |
| |
| /** |
| * Deserialize a collection. |
| * <p> |
| * First read a <code>int</code> indicating of number of rest objects, |
| * then read the objects one by one.</p> |
| * |
| * @param ois the stream where the collection is read from |
| * @param collection the collection to hold read objects |
| * @throws IOException if I/O exception occurs |
| * @throws ClassNotFoundException if class of any read object is not found |
| */ |
| @SuppressWarnings("unchecked") |
| protected final void deserialize(ObjectInputStream ois, |
| Collection collection) throws IOException, ClassNotFoundException { |
| int size = ois.readInt(); |
| for (int i = 0; i < size; i++) { |
| collection.add(ois.readObject()); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.Visibility#dontUseGui() |
| */ |
| public void dontUseGui() { |
| okToUseGui = false; |
| } |
| |
| /** |
| * Notifies registered <code>BeanContextMembershipListener</code>s that |
| * a new child has been added. |
| * |
| * @param event the <code>BeanContextMembershipEvent</code> |
| */ |
| protected final void fireChildrenAdded(BeanContextMembershipEvent event) { |
| Object listeners[]; |
| synchronized (bcmListeners) { |
| listeners = bcmListeners.toArray(); |
| } |
| for (int i = 0; i < listeners.length; i++) { |
| BeanContextMembershipListener l = (BeanContextMembershipListener) listeners[i]; |
| l.childrenAdded(event); |
| } |
| } |
| |
| /** |
| * Notifies registered <code>BeanContextMembershipListener</code>s that |
| * a child has been removed. |
| * |
| * @param event the <code>BeanContextMembershipEvent</code> |
| */ |
| protected final void fireChildrenRemoved(BeanContextMembershipEvent event) { |
| Object listeners[]; |
| synchronized (bcmListeners) { |
| listeners = bcmListeners.toArray(); |
| } |
| for (int i = 0; i < listeners.length; i++) { |
| BeanContextMembershipListener l = (BeanContextMembershipListener) listeners[i]; |
| l.childrenRemoved(event); |
| } |
| } |
| |
| /** |
| * Returns the peer of this context casted as <code>BeanContext</code>. |
| * |
| * @return the peer of this context casted as <code>BeanContext</code> |
| */ |
| public BeanContext getBeanContextPeer() { |
| return (BeanContext) beanContextChildPeer; |
| } |
| |
| /** |
| * Returns the <code>BeanContextChild</code> related with the given child. |
| * <p> |
| * If the child implements <code>BeanContextChild</code>, it is returned. |
| * If the child implements <code>BeanContextProxy</code>, the proxy is returned. |
| * Otherwise, null is returned.</p> |
| * |
| * @param child a child |
| * @return the <code>BeanContextChild</code> related with the given child |
| * @throws IllegalStateException if the child implements both <code>BeanContextChild</code> and <code>BeanContextProxy</code> |
| */ |
| protected static final BeanContextChild getChildBeanContextChild( |
| Object child) { |
| if (child instanceof BeanContextChild) { |
| if (child instanceof BeanContextProxy) { |
| throw new IllegalArgumentException( |
| Messages.getString("beans.6C")); |
| } |
| return (BeanContextChild) child; |
| } |
| if (child instanceof BeanContextProxy) { |
| if (child instanceof BeanContextChild) { |
| throw new IllegalArgumentException( |
| Messages.getString("beans.6C")); |
| } |
| return ((BeanContextProxy) child).getBeanContextProxy(); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the given child casted to <code>BeanContextMembershipListener</code>, |
| * or null if it does not implements the interface. |
| * |
| * @param child a child |
| * @return the given child casted to <code>BeanContextMembershipListener</code>, |
| * or null if it does not implements the interface |
| */ |
| protected static final BeanContextMembershipListener getChildBeanContextMembershipListener( |
| Object child) { |
| if (child instanceof BeanContextMembershipListener) { |
| return (BeanContextMembershipListener) child; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the given child casted to <code>PropertyChangeListener</code>, |
| * or null if it does not implements the interface. |
| * |
| * @param child a child |
| * @return the given child casted to <code>PropertyChangeListener</code>, |
| * or null if it does not implements the interface |
| */ |
| protected static final PropertyChangeListener getChildPropertyChangeListener( |
| Object child) { |
| if (child instanceof PropertyChangeListener) { |
| return (PropertyChangeListener) child; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the given child casted to <code>Serializable</code>, |
| * or null if it does not implements the interface. |
| * |
| * @param child a child |
| * @return the given child casted to <code>Serializable</code>, |
| * or null if it does not implements the interface |
| */ |
| protected static final Serializable getChildSerializable(Object child) { |
| if (child instanceof Serializable) { |
| return (Serializable) child; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the given child casted to <code>VetoableChangeListener</code>, |
| * or null if it does not implements the interface. |
| * |
| * @param child a child |
| * @return the given child casted to <code>VetoableChangeListener</code>, |
| * or null if it does not implements the interface |
| */ |
| protected static final VetoableChangeListener getChildVetoableChangeListener( |
| Object child) { |
| if (child instanceof VetoableChangeListener) { |
| return (VetoableChangeListener) child; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the given child casted to <code>Visibility</code>, |
| * or null if it does not implements the interface. |
| * |
| * @param child a child |
| * @return the given child casted to <code>Visibility</code>, |
| * or null if it does not implements the interface |
| */ |
| protected static final Visibility getChildVisibility(Object child) { |
| if (child instanceof Visibility) { |
| return (Visibility) child; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the locale of this context. |
| * |
| * @return the locale of this context |
| */ |
| public Locale getLocale() { |
| return locale; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.beancontext.BeanContext#getResource(java.lang.String, java.beans.beancontext.BeanContextChild) |
| */ |
| public URL getResource(String resourceName, BeanContextChild child) { |
| if (resourceName == null || child == null) { |
| throw new NullPointerException(); |
| } |
| if (!contains(child)) { |
| throw new IllegalArgumentException(Messages.getString("beans.6D")); |
| } |
| |
| return ClassLoader.getSystemResource(resourceName); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.beancontext.BeanContext#getResourceAsStream(java.lang.String, java.beans.beancontext.BeanContextChild) |
| */ |
| public InputStream getResourceAsStream(String resourceName, |
| BeanContextChild child) throws IllegalArgumentException { |
| if (resourceName == null || child == null) { |
| throw new NullPointerException(); |
| } |
| if (!contains(child)) { |
| throw new IllegalArgumentException(Messages.getString("beans.6D")); |
| } |
| |
| return ClassLoader.getSystemResourceAsStream(resourceName); |
| } |
| |
| /** |
| * Initializes all transient fields of this instance, called by |
| * constructors and <code>readObject()</code>. |
| */ |
| protected void initialize() { |
| // init transient fields |
| bcmListeners = new ArrayList<BeanContextMembershipListener>(); |
| children = new HashMap(); |
| serializing = false; |
| inNeedsGui = false; |
| nonSerPCL = new PropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| BeanContextSupport.this.propertyChange(event); |
| } |
| }; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.beancontext.BeanContext#instantiateChild(java.lang.String) |
| */ |
| public Object instantiateChild(String beanName) throws IOException, |
| ClassNotFoundException { |
| return Beans.instantiate(getClass().getClassLoader(), beanName, |
| getBeanContextPeer()); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.DesignMode#isDesignTime() |
| */ |
| public boolean isDesignTime() { |
| return designTime; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Collection#isEmpty() |
| */ |
| public boolean isEmpty() { |
| synchronized (children) { |
| return children.isEmpty(); |
| } |
| } |
| |
| /** |
| * Returns true if this context is currently being serialized |
| * (by another thread). |
| * |
| * @return true if this context is currently being serialized |
| * (by another thread) |
| */ |
| public boolean isSerializing() { |
| return serializing; |
| } |
| |
| /** |
| * Returns an iterator of children of this context, |
| * with <code>remove()</code> disabled. |
| * |
| * @see java.util.Collection#iterator() |
| */ |
| public Iterator iterator() { |
| synchronized (children) { |
| return new BCSIterator(children.keySet().iterator()); |
| } |
| } |
| |
| /** |
| * Returns true if this context or its children needs GUI to work properly. |
| * <p> |
| * The implementation checks the peer and all the children that implement |
| * <code>Visibility</code> to see if any of their <code>needsGui()</code> |
| * returns true, and if any of the children extends |
| * <code>java.awt.Component</code>.</p> |
| * |
| * @see java.beans.Visibility#needsGui() |
| */ |
| public boolean needsGui() { |
| if (inNeedsGui) { |
| return false; |
| } |
| inNeedsGui = true; |
| |
| try { |
| if (getBeanContextPeer() != this) { |
| if (getBeanContextPeer().needsGui()) { |
| return true; |
| } |
| } |
| Object childs[] = copyChildren(); |
| for (int i = 0; i < childs.length; i++) { |
| if (childs[i] instanceof Component) { |
| return true; |
| } |
| Visibility v = getChildVisibility(childs[i]); |
| if (v != null && v.needsGui()) { |
| return true; |
| } |
| } |
| return false; |
| } finally { |
| inNeedsGui = false; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.Visibility#okToUseGui() |
| */ |
| public void okToUseGui() { |
| okToUseGui = true; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) |
| */ |
| public void propertyChange(PropertyChangeEvent event) { |
| if (contains(event.getSource()) |
| && "beanContext".equals(event.getPropertyName()) |
| && event.getOldValue() == getBeanContextPeer()) { |
| remove(event.getSource(), false); |
| } |
| } |
| |
| /** |
| * Deserializes children from the given object input stream. |
| * <p> |
| * The implementation reads pairs of child object and <code>BCSChild</code> |
| * object according to <code>serializable</code> property. For each pair, |
| * it is added to the <code>children</code> map and the |
| * <code>childDeserializedHook()</code> is called. If the child implements |
| * <code>BeanContextChild</code>, its <code>setBeanContext()</code> is |
| * also called. |
| * </p> |
| * <p> |
| * This method is called by <code>readObject()</code> if the context works |
| * standalone. Or if this support object is a delegate of another |
| * <code>BeanContext</code> implementation, then this method should be |
| * called by the peer. Doing this means that derialization can proceed |
| * without any circular dependency problems. |
| * |
| * @param ois |
| * the object input stream |
| * @throws IOException |
| * if I/O exception occurs |
| * @throws ClassNotFoundException |
| * if class of read object is not found |
| */ |
| @SuppressWarnings("unchecked") |
| public final void readChildren(ObjectInputStream ois) throws IOException, |
| ClassNotFoundException { |
| synchronized (children) { |
| for (int i = 0; i < serializable; i++) { |
| Object child = ois.readObject(); |
| BCSChild childBCSC = (BCSChild) ois.readObject(); |
| children.put(child, childBCSC); |
| |
| childDeserializedHook(child, childBCSC); |
| |
| // set child's beanContext property |
| BeanContextChild beanContextChild = getChildBeanContextChild(child); |
| if (beanContextChild != null) { |
| try { |
| beanContextChild.setBeanContext(getBeanContextPeer()); |
| } catch (PropertyVetoException e) { |
| throw new IOException( |
| Messages.getString("beans.6B")); |
| } |
| // ensure no duplicate listener |
| beanContextChild.removePropertyChangeListener( |
| "beanContext", nonSerPCL); |
| // listen to child's beanContext change |
| beanContextChild.addPropertyChangeListener("beanContext", |
| nonSerPCL); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Removes the given child from this context. |
| * <p> |
| * Delegates to <code>remove(child, true)</code>.</p> |
| * |
| * @param child a child of this context |
| * @return true if the child is removed; or false if it is not a child of this context |
| * @throws IllegalArgumentException if the child is null |
| * @throws IllegalStateException if the child is not valid to remove |
| * @see java.util.Collection#remove(java.lang.Object) |
| */ |
| public boolean remove(Object child) { |
| return remove(child, true); |
| } |
| |
| /** |
| * Removes the given child from this context. |
| * <p> |
| * If the given child is not a child of this context, simply returns false. |
| * Otherwise, <code>validatePendingRemove()</code> is called. If the |
| * removal is valid, the child's <code>beanContext</code> property is |
| * updated (if required) and the child and its proxy peer (if there is one) |
| * is removed. Last, <code>childJustRemovedHook()</code> is called and |
| * listeners are notified.</p> |
| * |
| * @param child a child of this context |
| * @param setChildBC whether to call <code>setBeanContext()</code> on the child or not |
| * @return true if the child is removed; or false if it is not a child of this context |
| * @throws IllegalArgumentException if the child is null |
| * @throws IllegalStateException if the child is not valid to remove |
| */ |
| protected boolean remove(Object child, boolean setChildBC) { |
| if (child == null) { |
| throw new IllegalArgumentException(Messages.getString("beans.67")); |
| } |
| |
| Object peer = null; |
| |
| synchronized (globalHierarchyLock) { |
| // check existence |
| if (!contains(child)) { |
| return false; |
| } |
| |
| // check serializing state |
| if (serializing) { |
| throw new IllegalStateException( |
| Messages.getString("beans.68")); |
| } |
| |
| // validate |
| boolean valid = validatePendingRemove(child); |
| if (!valid) { |
| throw new IllegalStateException( |
| Messages.getString("beans.6E")); |
| } |
| |
| // set child's beanContext property |
| BeanContextChild beanContextChild = getChildBeanContextChild(child); |
| if (beanContextChild != null && setChildBC) { |
| // remove listener, first |
| beanContextChild.removePropertyChangeListener("beanContext", |
| nonSerPCL); |
| try { |
| beanContextChild.setBeanContext(null); |
| } catch (PropertyVetoException e) { |
| // rollback the listener change |
| beanContextChild.addPropertyChangeListener("beanContext", |
| nonSerPCL); |
| throw new IllegalStateException( |
| Messages.getString("beans.6B")); |
| } |
| } |
| |
| // remove from children |
| BCSChild childBCSC = null, peerBCSC = null; |
| synchronized (children) { |
| childBCSC = (BCSChild) children.remove(child); |
| peer = childBCSC.proxyPeer; |
| if (peer != null) { |
| peerBCSC = (BCSChild) children.remove(peer); |
| } |
| } |
| |
| // trigger hook |
| synchronized (child) { |
| removeSerializable(childBCSC); |
| childJustRemovedHook(child, childBCSC); |
| } |
| if (peer != null) { |
| synchronized (peer) { |
| removeSerializable(peerBCSC); |
| childJustRemovedHook(peer, peerBCSC); |
| } |
| } |
| } |
| |
| // notify listeners |
| fireChildrenRemoved(new BeanContextMembershipEvent( |
| getBeanContextPeer(), peer == null ? new Object[] { child } |
| : new Object[] { child, peer })); |
| return true; |
| } |
| |
| /** |
| * This method is unsupported, throws <code>UnsupportedOperationException</code>. |
| * |
| * @see java.util.Collection#removeAll(java.util.Collection) |
| */ |
| public boolean removeAll(Collection collection) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.beancontext.BeanContext#removeBeanContextMembershipListener(java.beans.beancontext.BeanContextMembershipListener) |
| */ |
| public void removeBeanContextMembershipListener( |
| BeanContextMembershipListener listener) { |
| if (listener == null) { |
| throw new NullPointerException(); |
| } |
| synchronized (bcmListeners) { |
| bcmListeners.remove(listener); |
| } |
| } |
| |
| /** |
| * This method is unsupported, throws <code>UnsupportedOperationException</code>. |
| * |
| * @see java.util.Collection#retainAll(java.util.Collection) |
| */ |
| public boolean retainAll(Collection collection) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Serializes the given collection. |
| * <p> |
| * First writes a <code>int</code> indicating the number of all |
| * serializable elements (implements <code>Serializable</code>, then |
| * objects are writtern one by one.</p> |
| * |
| * @param oos the stream where the collection is writtern to |
| * @param collection the collection to serialize |
| * @throws IOException if I/O exception occurs |
| */ |
| protected final void serialize(ObjectOutputStream oos, Collection collection) |
| throws IOException { |
| Object array[] = collection.toArray(); |
| int serCount = 0; |
| for (int i = 0; i < array.length; i++) { |
| if (array[i] instanceof Serializable) { |
| serCount++; |
| } |
| } |
| |
| oos.writeInt(serCount); |
| for (int i = 0; i < array.length; i++) { |
| if (array[i] instanceof Serializable) { |
| oos.writeObject(array[i]); |
| } |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.DesignMode#setDesignTime(boolean) |
| */ |
| public void setDesignTime(boolean designTime) { |
| this.designTime = designTime; |
| } |
| |
| /** |
| * Sets the locale of this context. <code>VetoableChangeListener</code>s |
| * and <code>PropertyChangeListener</code>s are notified. |
| * |
| * @param newLocale the new locale to set |
| * @throws PropertyVetoException if any <code>VetoableChangeListener</code> vetos this change |
| */ |
| public void setLocale(Locale newLocale) throws PropertyVetoException { |
| if (newLocale == null || newLocale == locale) { |
| return; // ignore null locale |
| } |
| |
| PropertyChangeEvent event = new PropertyChangeEvent( |
| beanContextChildPeer, "locale", locale, newLocale); |
| |
| // apply change |
| Locale oldLocale = locale; |
| locale = newLocale; |
| |
| try { |
| // notify vetoable listeners |
| vcSupport.fireVetoableChange(event); |
| } catch (PropertyVetoException e) { |
| // rollback change |
| locale = oldLocale; |
| throw e; |
| } |
| // Notify BeanContext about this change |
| this.pcSupport.firePropertyChange(event); |
| } |
| |
| /** |
| * Returns the number children of this context. |
| * |
| * @return the number children of this context |
| * @see java.util.Collection#size() |
| */ |
| public int size() { |
| synchronized (children) { |
| return children.size(); |
| } |
| } |
| |
| /** |
| * Returns an array of children of this context. |
| * |
| * @return an array of children of this context |
| * @see java.util.Collection#toArray() |
| */ |
| public Object[] toArray() { |
| synchronized (children) { |
| return children.keySet().toArray(); |
| } |
| } |
| |
| /** |
| * Returns an array of children of this context. |
| * |
| * @return an array of children of this context |
| * @see java.util.Collection#toArray(java.lang.Object[]) |
| */ |
| @SuppressWarnings("unchecked") |
| public Object[] toArray(Object[] array) { |
| synchronized (children) { |
| return children.keySet().toArray(array); |
| } |
| } |
| |
| /** |
| * Validates the pending add of child. |
| * <p> |
| * Default implementation always returns true.</p> |
| * |
| * @param child the child to be added |
| * @return true if it is valid to add the child |
| */ |
| protected boolean validatePendingAdd(Object child) { |
| // to be overridden |
| return true; |
| } |
| |
| /** |
| * Validates the pending removal of child. |
| * <p> |
| * Default implementation always returns true.</p> |
| * |
| * @param child the child to be removed |
| * @return true if it is valid to remove the child |
| */ |
| protected boolean validatePendingRemove(Object child) { |
| // to be overridden |
| return true; |
| } |
| |
| /* (non-Javadoc) |
| * @see java.beans.VetoableChangeListener#vetoableChange(java.beans.PropertyChangeEvent) |
| */ |
| public void vetoableChange(PropertyChangeEvent pce) |
| throws PropertyVetoException { |
| if (pce == null) { |
| throw new NullPointerException(Messages.getString("beans.1C")); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Serializes children to the given object input stream. |
| * <p> |
| * The implementation iterates through all children and writes out pairs |
| * of child object and <code>BCSChild</code> object if the child is |
| * serializable (implements <code>Serialization</code>.</p> |
| * <p> |
| * This method is called by <code>writeObject()</code> if the context |
| * works standalone. Or if this support object is a delegate of another |
| * <code>BeanContext</code> implementation, then this method should be |
| * called by the peer to avoid the 'chicken and egg' problem during |
| * deserialization.</p> |
| * |
| * @param oos the stream to write |
| * @throws IOException if I/O exception occurs |
| */ |
| public final void writeChildren(ObjectOutputStream oos) throws IOException { |
| boolean origSer = serializing; |
| serializing = true; |
| |
| try { |
| int count = 0; |
| synchronized (children) { |
| for (Iterator iter = children.values().iterator(); iter |
| .hasNext();) { |
| BCSChild bcsc = (BCSChild) iter.next(); |
| if (bcsc.child instanceof Serializable |
| && (bcsc.proxyPeer == null || bcsc.proxyPeer instanceof Serializable)) { |
| oos.writeObject(bcsc.child); |
| oos.writeObject(bcsc); |
| count++; |
| } |
| } |
| } |
| |
| // what if count not equals to serializable? |
| if (count != serializable) { |
| throw new IOException(Messages.getString("beans.6F")); |
| } |
| } finally { |
| serializing = origSer; |
| } |
| } |
| |
| /** |
| * The implementation goes through following steps: |
| * <p> |
| * <ol> |
| * <li>Writes out non-transient properties by calling |
| * <code>defaultWriteObject()</code>, especially the |
| * <code>serializable</code> indicating the number of serializable |
| * children.</li> |
| * <li>Calls <code>bcsPreSerializationHook()</code>.</li> |
| * <li>Writes out children by calling <code>writeChildren()</code> if |
| * this context works standalone. Otherwise it is the peer's |
| * responsibility to call <code>writeChildren()</code> after this object |
| * is serialized.</li> |
| * <li>Writes out serializable membership listeners.</li> |
| * </ol> |
| * </p> |
| * |
| * @param oos the object output stream |
| * @throws IOException if I/O exception occurs |
| */ |
| private void writeObject(ObjectOutputStream oos) throws IOException { |
| boolean origSer = serializing; |
| serializing = true; |
| |
| try { |
| oos.defaultWriteObject(); |
| |
| bcsPreSerializationHook(oos); |
| |
| if (this == getBeanContextPeer()) { |
| writeChildren(oos); |
| } |
| |
| synchronized (bcmListeners) { |
| serialize(oos, bcmListeners); |
| } |
| } finally { |
| serializing = origSer; |
| } |
| } |
| |
| /** |
| * The implementation goes through following steps: |
| * <p> |
| * <ol> |
| * <li>Reads non-transient properties by calling |
| * <code>defaultReadObject()</code>.</li> |
| * <li>Calls <code>bcsPreDeserializationHook()</code>.</li> |
| * <li>Reads children by calling <code>readChildren()</code> if |
| * this context works standalone. Otherwise it is the peer's |
| * responsibility to call <code>readChildren()</code> after this object |
| * is deserialized.</li> |
| * <li>Reads serializable membership listeners.</li> |
| * </ol> |
| * </p> |
| * |
| * @param ois the object input stream |
| * @throws IOException if I/O error occurs |
| * @throws ClassNotFoundException if class of read object is not found |
| */ |
| private void readObject(ObjectInputStream ois) throws IOException, |
| ClassNotFoundException { |
| |
| ois.defaultReadObject(); |
| |
| initialize(); // init transient fields |
| |
| bcsPreDeserializationHook(ois); |
| |
| if (this == getBeanContextPeer()) { |
| readChildren(ois); |
| } |
| |
| deserialize(ois, bcmListeners); |
| } |
| |
| /* |
| * Increase variable serializable if child and proxyPeer fields of the given |
| * BCSChild object are serializable |
| */ |
| private void addSerializable(BCSChild bcsc) { |
| if (bcsc.child instanceof Serializable |
| && (bcsc.proxyPeer == null || bcsc.proxyPeer instanceof Serializable)) { |
| serializable++; |
| } |
| } |
| |
| /* |
| * Decrease variable serializable if child and proxyPeer fields of the given |
| * BCSChild object are serializable |
| */ |
| private void removeSerializable(BCSChild bcsc) { |
| if (serializable > 0 |
| && bcsc.child instanceof Serializable |
| && (bcsc.proxyPeer == null || bcsc.proxyPeer instanceof Serializable)) { |
| serializable--; |
| } |
| } |
| |
| } |
| |
| |