Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/beans/beancontext/BeanContextSupport.java
38918 views
/*1* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.beans.beancontext;2627import java.awt.Component;28import java.awt.Container;2930import java.beans.Beans;31import java.beans.AppletInitializer;3233import java.beans.DesignMode;3435import java.beans.PropertyChangeEvent;36import java.beans.PropertyChangeListener;37import java.beans.PropertyChangeSupport;3839import java.beans.VetoableChangeListener;40import java.beans.VetoableChangeSupport;41import java.beans.PropertyVetoException;4243import java.beans.Visibility;4445import java.io.IOException;46import java.io.InputStream;47import java.io.ObjectInputStream;48import java.io.ObjectOutputStream;49import java.io.Serializable;5051import java.net.URL;5253import java.util.ArrayList;54import java.util.Collection;55import java.util.HashMap;56import java.util.Iterator;57import java.util.Locale;58import java.util.Map;596061/**62* This helper class provides a utility implementation of the63* java.beans.beancontext.BeanContext interface.64* <p>65* Since this class directly implements the BeanContext interface, the class66* can, and is intended to be used either by subclassing this implementation,67* or via ad-hoc delegation of an instance of this class from another.68* </p>69*70* @author Laurence P. G. Cable71* @since 1.272*/73public class BeanContextSupport extends BeanContextChildSupport74implements BeanContext,75Serializable,76PropertyChangeListener,77VetoableChangeListener {7879// Fix for bug 4282900 to pass JCK regression test80static final long serialVersionUID = -4879613978649577204L;8182/**83*84* Construct a BeanContextSupport instance85*86*87* @param peer The peer <tt>BeanContext</tt> we are88* supplying an implementation for,89* or <tt>null</tt>90* if this object is its own peer91* @param lcle The current Locale for this BeanContext. If92* <tt>lcle</tt> is <tt>null</tt>, the default locale93* is assigned to the <tt>BeanContext</tt> instance.94* @param dTime The initial state,95* <tt>true</tt> if in design mode,96* <tt>false</tt> if runtime.97* @param visible The initial visibility.98* @see java.util.Locale#getDefault()99* @see java.util.Locale#setDefault(java.util.Locale)100*/101public BeanContextSupport(BeanContext peer, Locale lcle, boolean dTime, boolean visible) {102super(peer);103104locale = lcle != null ? lcle : Locale.getDefault();105designTime = dTime;106okToUseGui = visible;107108initialize();109}110111/**112* Create an instance using the specified Locale and design mode.113*114* @param peer The peer <tt>BeanContext</tt> we115* are supplying an implementation for,116* or <tt>null</tt> if this object is its own peer117* @param lcle The current Locale for this <tt>BeanContext</tt>. If118* <tt>lcle</tt> is <tt>null</tt>, the default locale119* is assigned to the <tt>BeanContext</tt> instance.120* @param dtime The initial state, <tt>true</tt>121* if in design mode,122* <tt>false</tt> if runtime.123* @see java.util.Locale#getDefault()124* @see java.util.Locale#setDefault(java.util.Locale)125*/126public BeanContextSupport(BeanContext peer, Locale lcle, boolean dtime) {127this (peer, lcle, dtime, true);128}129130/**131* Create an instance using the specified locale132*133* @param peer The peer BeanContext we are134* supplying an implementation for,135* or <tt>null</tt> if this object136* is its own peer137* @param lcle The current Locale for this138* <tt>BeanContext</tt>. If139* <tt>lcle</tt> is <tt>null</tt>,140* the default locale141* is assigned to the <tt>BeanContext</tt>142* instance.143* @see java.util.Locale#getDefault()144* @see java.util.Locale#setDefault(java.util.Locale)145*/146public BeanContextSupport(BeanContext peer, Locale lcle) {147this (peer, lcle, false, true);148}149150/**151* Create an instance using with a default locale152*153* @param peer The peer <tt>BeanContext</tt> we are154* supplying an implementation for,155* or <tt>null</tt> if this object156* is its own peer157*/158public BeanContextSupport(BeanContext peer) {159this (peer, null, false, true);160}161162/**163* Create an instance that is not a delegate of another object164*/165166public BeanContextSupport() {167this (null, null, false, true);168}169170/**171* Gets the instance of <tt>BeanContext</tt> that172* this object is providing the implementation for.173* @return the BeanContext instance174*/175public BeanContext getBeanContextPeer() { return (BeanContext)getBeanContextChildPeer(); }176177/**178* <p>179* The instantiateChild method is a convenience hook180* in BeanContext to simplify181* the task of instantiating a Bean, nested,182* into a <tt>BeanContext</tt>.183* </p>184* <p>185* The semantics of the beanName parameter are defined by java.beans.Beans.instantiate.186* </p>187*188* @param beanName the name of the Bean to instantiate within this BeanContext189* @throws IOException if there is an I/O error when the bean is being deserialized190* @throws ClassNotFoundException if the class191* identified by the beanName parameter is not found192* @return the new object193*/194public Object instantiateChild(String beanName)195throws IOException, ClassNotFoundException {196BeanContext bc = getBeanContextPeer();197198return Beans.instantiate(bc.getClass().getClassLoader(), beanName, bc);199}200201/**202* Gets the number of children currently nested in203* this BeanContext.204*205* @return number of children206*/207public int size() {208synchronized(children) {209return children.size();210}211}212213/**214* Reports whether or not this215* <tt>BeanContext</tt> is empty.216* A <tt>BeanContext</tt> is considered217* empty when it contains zero218* nested children.219* @return if there are not children220*/221public boolean isEmpty() {222synchronized(children) {223return children.isEmpty();224}225}226227/**228* Determines whether or not the specified object229* is currently a child of this <tt>BeanContext</tt>.230* @param o the Object in question231* @return if this object is a child232*/233public boolean contains(Object o) {234synchronized(children) {235return children.containsKey(o);236}237}238239/**240* Determines whether or not the specified object241* is currently a child of this <tt>BeanContext</tt>.242* @param o the Object in question243* @return if this object is a child244*/245public boolean containsKey(Object o) {246synchronized(children) {247return children.containsKey(o);248}249}250251/**252* Gets all JavaBean or <tt>BeanContext</tt> instances253* currently nested in this <tt>BeanContext</tt>.254* @return an <tt>Iterator</tt> of the nested children255*/256public Iterator iterator() {257synchronized(children) {258return new BCSIterator(children.keySet().iterator());259}260}261262/**263* Gets all JavaBean or <tt>BeanContext</tt>264* instances currently nested in this BeanContext.265*/266public Object[] toArray() {267synchronized(children) {268return children.keySet().toArray();269}270}271272/**273* Gets an array containing all children of274* this <tt>BeanContext</tt> that match275* the types contained in arry.276* @param arry The array of object277* types that are of interest.278* @return an array of children279*/280public Object[] toArray(Object[] arry) {281synchronized(children) {282return children.keySet().toArray(arry);283}284}285286287/************************************************************************/288289/**290* protected final subclass that encapsulates an iterator but implements291* a noop remove() method.292*/293294protected static final class BCSIterator implements Iterator {295BCSIterator(Iterator i) { super(); src = i; }296297public boolean hasNext() { return src.hasNext(); }298public Object next() { return src.next(); }299public void remove() { /* do nothing */ }300301private Iterator src;302}303304/************************************************************************/305306/*307* protected nested class containing per child information, an instance308* of which is associated with each child in the "children" hashtable.309* subclasses can extend this class to include their own per-child state.310*311* Note that this 'value' is serialized with the corresponding child 'key'312* when the BeanContextSupport is serialized.313*/314315protected class BCSChild implements Serializable {316317private static final long serialVersionUID = -5815286101609939109L;318319BCSChild(Object bcc, Object peer) {320super();321322child = bcc;323proxyPeer = peer;324}325326Object getChild() { return child; }327328void setRemovePending(boolean v) { removePending = v; }329330boolean isRemovePending() { return removePending; }331332boolean isProxyPeer() { return proxyPeer != null; }333334Object getProxyPeer() { return proxyPeer; }335/*336* fields337*/338339340private Object child;341private Object proxyPeer;342343private transient boolean removePending;344}345346/**347* <p>348* Subclasses can override this method to insert their own subclass349* of Child without having to override add() or the other Collection350* methods that add children to the set.351* </p>352* @param targetChild the child to create the Child on behalf of353* @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 methods354*/355356protected BCSChild createBCSChild(Object targetChild, Object peer) {357return new BCSChild(targetChild, peer);358}359360/************************************************************************/361362/**363* Adds/nests a child within this <tt>BeanContext</tt>.364* <p>365* Invoked as a side effect of java.beans.Beans.instantiate().366* If the child object is not valid for adding then this method367* throws an IllegalStateException.368* </p>369*370*371* @param targetChild The child objects to nest372* within this <tt>BeanContext</tt>373* @return true if the child was added successfully.374* @see #validatePendingAdd375*/376public boolean add(Object targetChild) {377378if (targetChild == null) throw new IllegalArgumentException();379380// The specification requires that we do nothing if the child381// is already nested herein.382383if (children.containsKey(targetChild)) return false; // test before locking384385synchronized(BeanContext.globalHierarchyLock) {386if (children.containsKey(targetChild)) return false; // check again387388if (!validatePendingAdd(targetChild)) {389throw new IllegalStateException();390}391392393// The specification requires that we invoke setBeanContext() on the394// newly added child if it implements the java.beans.beancontext.BeanContextChild interface395396BeanContextChild cbcc = getChildBeanContextChild(targetChild);397BeanContextChild bccp = null;398399synchronized(targetChild) {400401if (targetChild instanceof BeanContextProxy) {402bccp = ((BeanContextProxy)targetChild).getBeanContextProxy();403404if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()");405}406407BCSChild bcsc = createBCSChild(targetChild, bccp);408BCSChild pbcsc = null;409410synchronized (children) {411children.put(targetChild, bcsc);412413if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));414}415416if (cbcc != null) synchronized(cbcc) {417try {418cbcc.setBeanContext(getBeanContextPeer());419} catch (PropertyVetoException pve) {420421synchronized (children) {422children.remove(targetChild);423424if (bccp != null) children.remove(bccp);425}426427throw new IllegalStateException();428}429430cbcc.addPropertyChangeListener("beanContext", childPCL);431cbcc.addVetoableChangeListener("beanContext", childVCL);432}433434Visibility v = getChildVisibility(targetChild);435436if (v != null) {437if (okToUseGui)438v.okToUseGui();439else440v.dontUseGui();441}442443if (getChildSerializable(targetChild) != null) serializable++;444445childJustAddedHook(targetChild, bcsc);446447if (bccp != null) {448v = getChildVisibility(bccp);449450if (v != null) {451if (okToUseGui)452v.okToUseGui();453else454v.dontUseGui();455}456457if (getChildSerializable(bccp) != null) serializable++;458459childJustAddedHook(bccp, pbcsc);460}461462463}464465// The specification requires that we fire a notification of the change466467fireChildrenAdded(new BeanContextMembershipEvent(getBeanContextPeer(), bccp == null ? new Object[] { targetChild } : new Object[] { targetChild, bccp } ));468469}470471return true;472}473474/**475* Removes a child from this BeanContext. If the child object is not476* for adding then this method throws an IllegalStateException.477* @param targetChild The child objects to remove478* @see #validatePendingRemove479*/480public boolean remove(Object targetChild) {481return remove(targetChild, true);482}483484/**485* internal remove used when removal caused by486* unexpected <tt>setBeanContext</tt> or487* by <tt>remove()</tt> invocation.488* @param targetChild the JavaBean, BeanContext, or Object to be removed489* @param callChildSetBC used to indicate that490* the child should be notified that it is no491* longer nested in this <tt>BeanContext</tt>.492* @return whether or not was present before being removed493*/494protected boolean remove(Object targetChild, boolean callChildSetBC) {495496if (targetChild == null) throw new IllegalArgumentException();497498synchronized(BeanContext.globalHierarchyLock) {499if (!containsKey(targetChild)) return false;500501if (!validatePendingRemove(targetChild)) {502throw new IllegalStateException();503}504505BCSChild bcsc = (BCSChild)children.get(targetChild);506BCSChild pbcsc = null;507Object peer = null;508509// we are required to notify the child that it is no longer nested here if510// it implements java.beans.beancontext.BeanContextChild511512synchronized(targetChild) {513if (callChildSetBC) {514BeanContextChild cbcc = getChildBeanContextChild(targetChild);515if (cbcc != null) synchronized(cbcc) {516cbcc.removePropertyChangeListener("beanContext", childPCL);517cbcc.removeVetoableChangeListener("beanContext", childVCL);518519try {520cbcc.setBeanContext(null);521} catch (PropertyVetoException pve1) {522cbcc.addPropertyChangeListener("beanContext", childPCL);523cbcc.addVetoableChangeListener("beanContext", childVCL);524throw new IllegalStateException();525}526527}528}529530synchronized (children) {531children.remove(targetChild);532533if (bcsc.isProxyPeer()) {534pbcsc = (BCSChild)children.get(peer = bcsc.getProxyPeer());535children.remove(peer);536}537}538539if (getChildSerializable(targetChild) != null) serializable--;540541childJustRemovedHook(targetChild, bcsc);542543if (peer != null) {544if (getChildSerializable(peer) != null) serializable--;545546childJustRemovedHook(peer, pbcsc);547}548}549550fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } ));551552}553554return true;555}556557/**558* Tests to see if all objects in the559* specified <tt>Collection</tt> are children of560* this <tt>BeanContext</tt>.561* @param c the specified <tt>Collection</tt>562*563* @return <tt>true</tt> if all objects564* in the collection are children of565* this <tt>BeanContext</tt>, false if not.566*/567public boolean containsAll(Collection c) {568synchronized(children) {569Iterator i = c.iterator();570while (i.hasNext())571if(!contains(i.next()))572return false;573574return true;575}576}577578/**579* add Collection to set of Children (Unsupported)580* implementations must synchronized on the hierarchy lock and "children" protected field581* @throws UnsupportedOperationException thrown unconditionally by this implementation582* @return this implementation unconditionally throws {@code UnsupportedOperationException}583*/584public boolean addAll(Collection c) {585throw new UnsupportedOperationException();586}587588/**589* remove all specified children (Unsupported)590* implementations must synchronized on the hierarchy lock and "children" protected field591* @throws UnsupportedOperationException thrown unconditionally by this implementation592* @return this implementation unconditionally throws {@code UnsupportedOperationException}593594*/595public boolean removeAll(Collection c) {596throw new UnsupportedOperationException();597}598599600/**601* retain only specified children (Unsupported)602* implementations must synchronized on the hierarchy lock and "children" protected field603* @throws UnsupportedOperationException thrown unconditionally by this implementation604* @return this implementation unconditionally throws {@code UnsupportedOperationException}605*/606public boolean retainAll(Collection c) {607throw new UnsupportedOperationException();608}609610/**611* clear the children (Unsupported)612* implementations must synchronized on the hierarchy lock and "children" protected field613* @throws UnsupportedOperationException thrown unconditionally by this implementation614*/615public void clear() {616throw new UnsupportedOperationException();617}618619/**620* Adds a BeanContextMembershipListener621*622* @param bcml the BeanContextMembershipListener to add623* @throws NullPointerException if the argument is null624*/625626public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) {627if (bcml == null) throw new NullPointerException("listener");628629synchronized(bcmListeners) {630if (bcmListeners.contains(bcml))631return;632else633bcmListeners.add(bcml);634}635}636637/**638* Removes a BeanContextMembershipListener639*640* @param bcml the BeanContextMembershipListener to remove641* @throws NullPointerException if the argument is null642*/643644public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) {645if (bcml == null) throw new NullPointerException("listener");646647synchronized(bcmListeners) {648if (!bcmListeners.contains(bcml))649return;650else651bcmListeners.remove(bcml);652}653}654655/**656* @param name the name of the resource requested.657* @param bcc the child object making the request.658*659* @return the requested resource as an InputStream660* @throws NullPointerException if the argument is null661*/662663public InputStream getResourceAsStream(String name, BeanContextChild bcc) {664if (name == null) throw new NullPointerException("name");665if (bcc == null) throw new NullPointerException("bcc");666667if (containsKey(bcc)) {668ClassLoader cl = bcc.getClass().getClassLoader();669670return cl != null ? cl.getResourceAsStream(name)671: ClassLoader.getSystemResourceAsStream(name);672} else throw new IllegalArgumentException("Not a valid child");673}674675/**676* @param name the name of the resource requested.677* @param bcc the child object making the request.678*679* @return the requested resource as an InputStream680*/681682public URL getResource(String name, BeanContextChild bcc) {683if (name == null) throw new NullPointerException("name");684if (bcc == null) throw new NullPointerException("bcc");685686if (containsKey(bcc)) {687ClassLoader cl = bcc.getClass().getClassLoader();688689return cl != null ? cl.getResource(name)690: ClassLoader.getSystemResource(name);691} else throw new IllegalArgumentException("Not a valid child");692}693694/**695* Sets the new design time value for this <tt>BeanContext</tt>.696* @param dTime the new designTime value697*/698public synchronized void setDesignTime(boolean dTime) {699if (designTime != dTime) {700designTime = dTime;701702firePropertyChange("designMode", Boolean.valueOf(!dTime), Boolean.valueOf(dTime));703}704}705706707/**708* Reports whether or not this object is in709* currently in design time mode.710* @return <tt>true</tt> if in design time mode,711* <tt>false</tt> if not712*/713public synchronized boolean isDesignTime() { return designTime; }714715/**716* Sets the locale of this BeanContext.717* @param newLocale the new locale. This method call will have718* no effect if newLocale is <CODE>null</CODE>.719* @throws PropertyVetoException if the new value is rejected720*/721public synchronized void setLocale(Locale newLocale) throws PropertyVetoException {722723if ((locale != null && !locale.equals(newLocale)) && newLocale != null) {724Locale old = locale;725726fireVetoableChange("locale", old, newLocale); // throws727728locale = newLocale;729730firePropertyChange("locale", old, newLocale);731}732}733734/**735* Gets the locale for this <tt>BeanContext</tt>.736*737* @return the current Locale of the <tt>BeanContext</tt>738*/739public synchronized Locale getLocale() { return locale; }740741/**742* <p>743* This method is typically called from the environment in order to determine744* if the implementor "needs" a GUI.745* </p>746* <p>747* The algorithm used herein tests the BeanContextPeer, and its current children748* to determine if they are either Containers, Components, or if they implement749* Visibility and return needsGui() == true.750* </p>751* @return <tt>true</tt> if the implementor needs a GUI752*/753public synchronized boolean needsGui() {754BeanContext bc = getBeanContextPeer();755756if (bc != this) {757if (bc instanceof Visibility) return ((Visibility)bc).needsGui();758759if (bc instanceof Container || bc instanceof Component)760return true;761}762763synchronized(children) {764for (Iterator i = children.keySet().iterator(); i.hasNext();) {765Object c = i.next();766767try {768return ((Visibility)c).needsGui();769} catch (ClassCastException cce) {770// do nothing ...771}772773if (c instanceof Container || c instanceof Component)774return true;775}776}777778return false;779}780781/**782* notify this instance that it may no longer render a GUI.783*/784785public synchronized void dontUseGui() {786if (okToUseGui) {787okToUseGui = false;788789// lets also tell the Children that can that they may not use their GUI's790synchronized(children) {791for (Iterator i = children.keySet().iterator(); i.hasNext();) {792Visibility v = getChildVisibility(i.next());793794if (v != null) v.dontUseGui();795}796}797}798}799800/**801* Notify this instance that it may now render a GUI802*/803804public synchronized void okToUseGui() {805if (!okToUseGui) {806okToUseGui = true;807808// lets also tell the Children that can that they may use their GUI's809synchronized(children) {810for (Iterator i = children.keySet().iterator(); i.hasNext();) {811Visibility v = getChildVisibility(i.next());812813if (v != null) v.okToUseGui();814}815}816}817}818819/**820* Used to determine if the <tt>BeanContext</tt>821* child is avoiding using its GUI.822* @return is this instance avoiding using its GUI?823* @see Visibility824*/825public boolean avoidingGui() {826return !okToUseGui && needsGui();827}828829/**830* Is this <tt>BeanContext</tt> in the831* process of being serialized?832* @return if this <tt>BeanContext</tt> is833* currently being serialized834*/835public boolean isSerializing() { return serializing; }836837/**838* Returns an iterator of all children839* of this <tt>BeanContext</tt>.840* @return an iterator for all the current BCSChild values841*/842protected Iterator bcsChildren() { synchronized(children) { return children.values().iterator(); } }843844/**845* called by writeObject after defaultWriteObject() but prior to846* serialization of currently serializable children.847*848* This method may be overridden by subclasses to perform custom849* serialization of their state prior to this superclass serializing850* the children.851*852* This method should not however be used by subclasses to replace their853* own implementation (if any) of writeObject().854* @param oos the {@code ObjectOutputStream} to use during serialization855* @throws IOException if serialization failed856*/857858protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {859}860861/**862* called by readObject after defaultReadObject() but prior to863* deserialization of any children.864*865* This method may be overridden by subclasses to perform custom866* deserialization of their state prior to this superclass deserializing867* the children.868*869* This method should not however be used by subclasses to replace their870* own implementation (if any) of readObject().871* @param ois the {@code ObjectInputStream} to use during deserialization872* @throws IOException if deserialization failed873* @throws ClassNotFoundException if needed classes are not found874*/875876protected void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {877}878879/**880* Called by readObject with the newly deserialized child and BCSChild.881* @param child the newly deserialized child882* @param bcsc the newly deserialized BCSChild883*/884protected void childDeserializedHook(Object child, BCSChild bcsc) {885synchronized(children) {886children.put(child, bcsc);887}888}889890/**891* Used by writeObject to serialize a Collection.892* @param oos the <tt>ObjectOutputStream</tt>893* to use during serialization894* @param coll the <tt>Collection</tt> to serialize895* @throws IOException if serialization failed896*/897protected final void serialize(ObjectOutputStream oos, Collection coll) throws IOException {898int count = 0;899Object[] objects = coll.toArray();900901for (int i = 0; i < objects.length; i++) {902if (objects[i] instanceof Serializable)903count++;904else905objects[i] = null;906}907908oos.writeInt(count); // number of subsequent objects909910for (int i = 0; count > 0; i++) {911Object o = objects[i];912913if (o != null) {914oos.writeObject(o);915count--;916}917}918}919920/**921* used by readObject to deserialize a collection.922* @param ois the ObjectInputStream to use923* @param coll the Collection924* @throws IOException if deserialization failed925* @throws ClassNotFoundException if needed classes are not found926*/927protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException {928int count = 0;929930count = ois.readInt();931932while (count-- > 0) {933coll.add(ois.readObject());934}935}936937/**938* Used to serialize all children of939* this <tt>BeanContext</tt>.940* @param oos the <tt>ObjectOutputStream</tt>941* to use during serialization942* @throws IOException if serialization failed943*/944public final void writeChildren(ObjectOutputStream oos) throws IOException {945if (serializable <= 0) return;946947boolean prev = serializing;948949serializing = true;950951int count = 0;952953synchronized(children) {954Iterator i = children.entrySet().iterator();955956while (i.hasNext() && count < serializable) {957Map.Entry entry = (Map.Entry)i.next();958959if (entry.getKey() instanceof Serializable) {960try {961oos.writeObject(entry.getKey()); // child962oos.writeObject(entry.getValue()); // BCSChild963} catch (IOException ioe) {964serializing = prev;965throw ioe;966}967count++;968}969}970}971972serializing = prev;973974if (count != serializable) {975throw new IOException("wrote different number of children than expected");976}977978}979980/**981* Serialize the BeanContextSupport, if this instance has a distinct982* peer (that is this object is acting as a delegate for another) then983* the children of this instance are not serialized here due to a984* 'chicken and egg' problem that occurs on deserialization of the985* children at the same time as this instance.986*987* Therefore in situations where there is a distinct peer to this instance988* it should always call writeObject() followed by writeChildren() and989* readObject() followed by readChildren().990*991* @param oos the ObjectOutputStream992*/993994private synchronized void writeObject(ObjectOutputStream oos) throws IOException, ClassNotFoundException {995serializing = true;996997synchronized (BeanContext.globalHierarchyLock) {998try {999oos.defaultWriteObject(); // serialize the BeanContextSupport object10001001bcsPreSerializationHook(oos);10021003if (serializable > 0 && this.equals(getBeanContextPeer()))1004writeChildren(oos);10051006serialize(oos, (Collection)bcmListeners);1007} finally {1008serializing = false;1009}1010}1011}10121013/**1014* When an instance of this class is used as a delegate for the1015* implementation of the BeanContext protocols (and its subprotocols)1016* there exists a 'chicken and egg' problem during deserialization1017* @param ois the ObjectInputStream to use1018* @throws IOException if deserialization failed1019* @throws ClassNotFoundException if needed classes are not found1020*/10211022public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException {1023int count = serializable;10241025while (count-- > 0) {1026Object child = ois.readObject();1027BCSChild bscc = (BCSChild) ois.readObject();10281029synchronized(child) {1030BeanContextChild bcc = null;10311032try {1033bcc = (BeanContextChild)child;1034} catch (ClassCastException cce) {1035// do nothing;1036}10371038if (bcc != null) {1039try {1040bcc.setBeanContext(getBeanContextPeer());10411042bcc.addPropertyChangeListener("beanContext", childPCL);1043bcc.addVetoableChangeListener("beanContext", childVCL);10441045} catch (PropertyVetoException pve) {1046continue;1047}1048}10491050childDeserializedHook(child, bscc);1051}1052}1053}10541055/**1056* deserialize contents ... if this instance has a distinct peer the1057* children are *not* serialized here, the peer's readObject() must call1058* readChildren() after deserializing this instance.1059*/10601061private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {10621063synchronized(BeanContext.globalHierarchyLock) {1064ois.defaultReadObject();10651066initialize();10671068bcsPreDeserializationHook(ois);10691070if (serializable > 0 && this.equals(getBeanContextPeer()))1071readChildren(ois);10721073deserialize(ois, bcmListeners = new ArrayList(1));1074}1075}10761077/**1078* subclasses may envelope to monitor veto child property changes.1079*/10801081public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {1082String propertyName = pce.getPropertyName();1083Object source = pce.getSource();10841085synchronized(children) {1086if ("beanContext".equals(propertyName) &&1087containsKey(source) &&1088!getBeanContextPeer().equals(pce.getNewValue())1089) {1090if (!validatePendingRemove(source)) {1091throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce);1092} else ((BCSChild)children.get(source)).setRemovePending(true);1093}1094}1095}10961097/**1098* subclasses may envelope to monitor child property changes.1099*/11001101public void propertyChange(PropertyChangeEvent pce) {1102String propertyName = pce.getPropertyName();1103Object source = pce.getSource();11041105synchronized(children) {1106if ("beanContext".equals(propertyName) &&1107containsKey(source) &&1108((BCSChild)children.get(source)).isRemovePending()) {1109BeanContext bc = getBeanContextPeer();11101111if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {1112remove(source, false);1113} else {1114((BCSChild)children.get(source)).setRemovePending(false);1115}1116}1117}1118}11191120/**1121* <p>1122* Subclasses of this class may override, or envelope, this method to1123* add validation behavior for the BeanContext to examine child objects1124* immediately prior to their being added to the BeanContext.1125* </p>1126*1127* @param targetChild the child to create the Child on behalf of1128* @return true iff the child may be added to this BeanContext, otherwise false.1129*/11301131protected boolean validatePendingAdd(Object targetChild) {1132return true;1133}11341135/**1136* <p>1137* Subclasses of this class may override, or envelope, this method to1138* add validation behavior for the BeanContext to examine child objects1139* immediately prior to their being removed from the BeanContext.1140* </p>1141*1142* @param targetChild the child to create the Child on behalf of1143* @return true iff the child may be removed from this BeanContext, otherwise false.1144*/11451146protected boolean validatePendingRemove(Object targetChild) {1147return true;1148}11491150/**1151* subclasses may override this method to simply extend add() semantics1152* after the child has been added and before the event notification has1153* occurred. The method is called with the child synchronized.1154* @param child the child1155* @param bcsc the BCSChild1156*/11571158protected void childJustAddedHook(Object child, BCSChild bcsc) {1159}11601161/**1162* subclasses may override this method to simply extend remove() semantics1163* after the child has been removed and before the event notification has1164* occurred. The method is called with the child synchronized.1165* @param child the child1166* @param bcsc the BCSChild1167*/11681169protected void childJustRemovedHook(Object child, BCSChild bcsc) {1170}11711172/**1173* Gets the Component (if any) associated with the specified child.1174* @param child the specified child1175* @return the Component (if any) associated with the specified child.1176*/1177protected static final Visibility getChildVisibility(Object child) {1178try {1179return (Visibility)child;1180} catch (ClassCastException cce) {1181return null;1182}1183}11841185/**1186* Gets the Serializable (if any) associated with the specified Child1187* @param child the specified child1188* @return the Serializable (if any) associated with the specified Child1189*/1190protected static final Serializable getChildSerializable(Object child) {1191try {1192return (Serializable)child;1193} catch (ClassCastException cce) {1194return null;1195}1196}11971198/**1199* Gets the PropertyChangeListener1200* (if any) of the specified child1201* @param child the specified child1202* @return the PropertyChangeListener (if any) of the specified child1203*/1204protected static final PropertyChangeListener getChildPropertyChangeListener(Object child) {1205try {1206return (PropertyChangeListener)child;1207} catch (ClassCastException cce) {1208return null;1209}1210}12111212/**1213* Gets the VetoableChangeListener1214* (if any) of the specified child1215* @param child the specified child1216* @return the VetoableChangeListener (if any) of the specified child1217*/1218protected static final VetoableChangeListener getChildVetoableChangeListener(Object child) {1219try {1220return (VetoableChangeListener)child;1221} catch (ClassCastException cce) {1222return null;1223}1224}12251226/**1227* Gets the BeanContextMembershipListener1228* (if any) of the specified child1229* @param child the specified child1230* @return the BeanContextMembershipListener (if any) of the specified child1231*/1232protected static final BeanContextMembershipListener getChildBeanContextMembershipListener(Object child) {1233try {1234return (BeanContextMembershipListener)child;1235} catch (ClassCastException cce) {1236return null;1237}1238}12391240/**1241* Gets the BeanContextChild (if any) of the specified child1242* @param child the specified child1243* @return the BeanContextChild (if any) of the specified child1244* @throws IllegalArgumentException if child implements both BeanContextChild and BeanContextProxy1245*/1246protected static final BeanContextChild getChildBeanContextChild(Object child) {1247try {1248BeanContextChild bcc = (BeanContextChild)child;12491250if (child instanceof BeanContextChild && child instanceof BeanContextProxy)1251throw new IllegalArgumentException("child cannot implement both BeanContextChild and BeanContextProxy");1252else1253return bcc;1254} catch (ClassCastException cce) {1255try {1256return ((BeanContextProxy)child).getBeanContextProxy();1257} catch (ClassCastException cce1) {1258return null;1259}1260}1261}12621263/**1264* Fire a BeanContextshipEvent on the BeanContextMembershipListener interface1265* @param bcme the event to fire1266*/12671268protected final void fireChildrenAdded(BeanContextMembershipEvent bcme) {1269Object[] copy;12701271synchronized(bcmListeners) { copy = bcmListeners.toArray(); }12721273for (int i = 0; i < copy.length; i++)1274((BeanContextMembershipListener)copy[i]).childrenAdded(bcme);1275}12761277/**1278* Fire a BeanContextshipEvent on the BeanContextMembershipListener interface1279* @param bcme the event to fire1280*/12811282protected final void fireChildrenRemoved(BeanContextMembershipEvent bcme) {1283Object[] copy;12841285synchronized(bcmListeners) { copy = bcmListeners.toArray(); }12861287for (int i = 0; i < copy.length; i++)1288((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme);1289}12901291/**1292* protected method called from constructor and readObject to initialize1293* transient state of BeanContextSupport instance.1294*1295* This class uses this method to instantiate inner class listeners used1296* to monitor PropertyChange and VetoableChange events on children.1297*1298* subclasses may envelope this method to add their own initialization1299* behavior1300*/13011302protected synchronized void initialize() {1303children = new HashMap(serializable + 1);1304bcmListeners = new ArrayList(1);13051306childPCL = new PropertyChangeListener() {13071308/*1309* this adaptor is used by the BeanContextSupport class to forward1310* property changes from a child to the BeanContext, avoiding1311* accidential serialization of the BeanContext by a badly1312* behaved Serializable child.1313*/13141315public void propertyChange(PropertyChangeEvent pce) {1316BeanContextSupport.this.propertyChange(pce);1317}1318};13191320childVCL = new VetoableChangeListener() {13211322/*1323* this adaptor is used by the BeanContextSupport class to forward1324* vetoable changes from a child to the BeanContext, avoiding1325* accidential serialization of the BeanContext by a badly1326* behaved Serializable child.1327*/13281329public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {1330BeanContextSupport.this.vetoableChange(pce);1331}1332};1333}13341335/**1336* Gets a copy of the this BeanContext's children.1337* @return a copy of the current nested children1338*/1339protected final Object[] copyChildren() {1340synchronized(children) { return children.keySet().toArray(); }1341}13421343/**1344* Tests to see if two class objects,1345* or their names are equal.1346* @param first the first object1347* @param second the second object1348* @return true if equal, false if not1349*/1350protected static final boolean classEquals(Class first, Class second) {1351return first.equals(second) || first.getName().equals(second.getName());1352}135313541355/*1356* fields1357*/135813591360/**1361* all accesses to the <code> protected HashMap children </code> field1362* shall be synchronized on that object.1363*/1364protected transient HashMap children;13651366private int serializable = 0; // children serializable13671368/**1369* all accesses to the <code> protected ArrayList bcmListeners </code> field1370* shall be synchronized on that object.1371*/1372protected transient ArrayList bcmListeners;13731374//13751376/**1377* The current locale of this BeanContext.1378*/1379protected Locale locale;13801381/**1382* A <tt>boolean</tt> indicating if this1383* instance may now render a GUI.1384*/1385protected boolean okToUseGui;138613871388/**1389* A <tt>boolean</tt> indicating whether or not1390* this object is currently in design time mode.1391*/1392protected boolean designTime;13931394/*1395* transient1396*/13971398private transient PropertyChangeListener childPCL;13991400private transient VetoableChangeListener childVCL;14011402private transient boolean serializing;1403}140414051406