Path: blob/master/src/java.desktop/share/classes/java/beans/beancontext/BeanContextSupport.java
41159 views
/*1* Copyright (c) 1997, 2021, 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;29import java.beans.Beans;30import java.beans.PropertyChangeEvent;31import java.beans.PropertyChangeListener;32import java.beans.PropertyVetoException;33import java.beans.VetoableChangeListener;34import java.beans.Visibility;35import java.io.IOException;36import java.io.InputStream;37import java.io.ObjectInputStream;38import java.io.ObjectOutputStream;39import java.io.Serial;40import java.io.Serializable;41import java.net.URL;42import java.util.ArrayList;43import java.util.Collection;44import java.util.HashMap;45import java.util.Iterator;46import java.util.Locale;47import java.util.Map;4849/**50* This helper class provides a utility implementation of the51* java.beans.beancontext.BeanContext interface.52* <p>53* Since this class directly implements the BeanContext interface, the class54* can, and is intended to be used either by subclassing this implementation,55* or via ad-hoc delegation of an instance of this class from another.56* </p>57*58* @author Laurence P. G. Cable59* @since 1.260*/61public class BeanContextSupport extends BeanContextChildSupport62implements BeanContext,63Serializable,64PropertyChangeListener,65VetoableChangeListener {6667/**68* Use serialVersionUID from JDK 1.3 for interoperability.69*/70@Serial71private static final long serialVersionUID = -4879613978649577204L;7273/**74*75* Construct a BeanContextSupport instance76*77*78* @param peer The peer {@code BeanContext} we are79* supplying an implementation for,80* or {@code null}81* if this object is its own peer82* @param lcle The current Locale for this BeanContext. If83* {@code lcle} is {@code null}, the default locale84* is assigned to the {@code BeanContext} instance.85* @param dTime The initial state,86* {@code true} if in design mode,87* {@code false} if runtime.88* @param visible The initial visibility.89* @see java.util.Locale#getDefault()90* @see java.util.Locale#setDefault(java.util.Locale)91*/92public BeanContextSupport(BeanContext peer, Locale lcle, boolean dTime, boolean visible) {93super(peer);9495locale = lcle != null ? lcle : Locale.getDefault();96designTime = dTime;97okToUseGui = visible;9899initialize();100}101102/**103* Create an instance using the specified Locale and design mode.104*105* @param peer The peer {@code BeanContext} we106* are supplying an implementation for,107* or {@code null} if this object is its own peer108* @param lcle The current Locale for this {@code BeanContext}. If109* {@code lcle} is {@code null}, the default locale110* is assigned to the {@code BeanContext} instance.111* @param dtime The initial state, {@code true}112* if in design mode,113* {@code false} if runtime.114* @see java.util.Locale#getDefault()115* @see java.util.Locale#setDefault(java.util.Locale)116*/117public BeanContextSupport(BeanContext peer, Locale lcle, boolean dtime) {118this (peer, lcle, dtime, true);119}120121/**122* Create an instance using the specified locale123*124* @param peer The peer BeanContext we are125* supplying an implementation for,126* or {@code null} if this object127* is its own peer128* @param lcle The current Locale for this129* {@code BeanContext}. If130* {@code lcle} is {@code null},131* the default locale132* is assigned to the {@code BeanContext}133* instance.134* @see java.util.Locale#getDefault()135* @see java.util.Locale#setDefault(java.util.Locale)136*/137public BeanContextSupport(BeanContext peer, Locale lcle) {138this (peer, lcle, false, true);139}140141/**142* Create an instance using with a default locale143*144* @param peer The peer {@code BeanContext} we are145* supplying an implementation for,146* or {@code null} if this object147* is its own peer148*/149public BeanContextSupport(BeanContext peer) {150this (peer, null, false, true);151}152153/**154* Create an instance that is not a delegate of another object155*/156157public BeanContextSupport() {158this (null, null, false, true);159}160161/**162* Gets the instance of {@code BeanContext} that163* this object is providing the implementation for.164* @return the BeanContext instance165*/166public BeanContext getBeanContextPeer() { return (BeanContext)getBeanContextChildPeer(); }167168/**169* <p>170* The instantiateChild method is a convenience hook171* in BeanContext to simplify172* the task of instantiating a Bean, nested,173* into a {@code BeanContext}.174* </p>175* <p>176* The semantics of the beanName parameter are defined by java.beans.Beans.instantiate.177* </p>178*179* @param beanName the name of the Bean to instantiate within this BeanContext180* @throws IOException if there is an I/O error when the bean is being deserialized181* @throws ClassNotFoundException if the class182* identified by the beanName parameter is not found183* @return the new object184*/185public Object instantiateChild(String beanName)186throws IOException, ClassNotFoundException {187BeanContext bc = getBeanContextPeer();188189return Beans.instantiate(bc.getClass().getClassLoader(), beanName, bc);190}191192/**193* Gets the number of children currently nested in194* this BeanContext.195*196* @return number of children197*/198public int size() {199synchronized(children) {200return children.size();201}202}203204/**205* Reports whether or not this206* {@code BeanContext} is empty.207* A {@code BeanContext} is considered208* empty when it contains zero209* nested children.210* @return if there are not children211*/212public boolean isEmpty() {213synchronized(children) {214return children.isEmpty();215}216}217218/**219* Determines whether or not the specified object220* is currently a child of this {@code BeanContext}.221* @param o the Object in question222* @return if this object is a child223*/224public boolean contains(Object o) {225synchronized(children) {226return children.containsKey(o);227}228}229230/**231* Determines whether or not the specified object232* is currently a child of this {@code BeanContext}.233* @param o the Object in question234* @return if this object is a child235*/236public boolean containsKey(Object o) {237synchronized(children) {238return children.containsKey(o);239}240}241242/**243* Gets all JavaBean or {@code BeanContext} instances244* currently nested in this {@code BeanContext}.245* @return an {@code Iterator} of the nested children246*/247public Iterator<Object> iterator() {248synchronized(children) {249return new BCSIterator(children.keySet().iterator());250}251}252253/**254* Gets all JavaBean or {@code BeanContext}255* instances currently nested in this BeanContext.256*/257public Object[] toArray() {258synchronized(children) {259return children.keySet().toArray();260}261}262263/**264* Gets an array containing all children of265* this {@code BeanContext} that match266* the types contained in arry.267* @param arry The array of object268* types that are of interest.269* @return an array of children270*/271public Object[] toArray(Object[] arry) {272synchronized(children) {273return children.keySet().toArray(arry);274}275}276277278/************************************************************************/279280/**281* protected final subclass that encapsulates an iterator but implements282* a noop remove() method.283*/284285protected static final class BCSIterator implements Iterator<Object> {286BCSIterator(Iterator<?> i) { super(); src = i; }287288public boolean hasNext() { return src.hasNext(); }289public Object next() { return src.next(); }290public void remove() { /* do nothing */ }291292private Iterator<?> src;293}294295/************************************************************************/296297/*298* protected nested class containing per child information, an instance299* of which is associated with each child in the "children" hashtable.300* subclasses can extend this class to include their own per-child state.301*302* Note that this 'value' is serialized with the corresponding child 'key'303* when the BeanContextSupport is serialized.304*/305306protected class BCSChild implements Serializable {307308/**309* Use serialVersionUID from JDK 1.7 for interoperability.310*/311@Serial312private static final long serialVersionUID = -5815286101609939109L;313314BCSChild(Object bcc, Object peer) {315super();316317child = bcc;318proxyPeer = peer;319}320321Object getChild() { return child; }322323void setRemovePending(boolean v) { removePending = v; }324325boolean isRemovePending() { return removePending; }326327boolean isProxyPeer() { return proxyPeer != null; }328329Object getProxyPeer() { return proxyPeer; }330/*331* fields332*/333334335/**336* The child.337*/338@SuppressWarnings("serial") // Not statically typed as Serializable339private Object child;340341/**342* The peer if the child and the peer are related by an implementation343* of BeanContextProxy344*/345@SuppressWarnings("serial") // Not statically typed as Serializable346private Object proxyPeer;347348private transient boolean removePending;349}350351/**352* <p>353* Subclasses can override this method to insert their own subclass354* of Child without having to override add() or the other Collection355* methods that add children to the set.356* </p>357* @param targetChild the child to create the Child on behalf of358* @param peer the peer if the tragetChild and the peer are related by an implementation of BeanContextProxy359* @return Subtype-specific subclass of Child without overriding collection methods360*/361362protected BCSChild createBCSChild(Object targetChild, Object peer) {363return new BCSChild(targetChild, peer);364}365366/************************************************************************/367368/**369* Adds/nests a child within this {@code BeanContext}.370* <p>371* Invoked as a side effect of java.beans.Beans.instantiate().372* If the child object is not valid for adding then this method373* throws an IllegalStateException.374* </p>375*376*377* @param targetChild The child objects to nest378* within this {@code BeanContext}379* @return true if the child was added successfully.380* @see #validatePendingAdd381*/382public boolean add(Object targetChild) {383384if (targetChild == null) throw new IllegalArgumentException();385386// The specification requires that we do nothing if the child387// is already nested herein.388389if (children.containsKey(targetChild)) return false; // test before locking390391synchronized(BeanContext.globalHierarchyLock) {392if (children.containsKey(targetChild)) return false; // check again393394if (!validatePendingAdd(targetChild)) {395throw new IllegalStateException();396}397398399// The specification requires that we invoke setBeanContext() on the400// newly added child if it implements the java.beans.beancontext.BeanContextChild interface401402BeanContextChild cbcc = getChildBeanContextChild(targetChild);403BeanContextChild bccp = null;404405synchronized(targetChild) {406407if (targetChild instanceof BeanContextProxy) {408bccp = ((BeanContextProxy)targetChild).getBeanContextProxy();409410if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()");411}412413BCSChild bcsc = createBCSChild(targetChild, bccp);414BCSChild pbcsc = null;415416synchronized (children) {417children.put(targetChild, bcsc);418419if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));420}421422if (cbcc != null) synchronized(cbcc) {423try {424cbcc.setBeanContext(getBeanContextPeer());425} catch (PropertyVetoException pve) {426427synchronized (children) {428children.remove(targetChild);429430if (bccp != null) children.remove(bccp);431}432433throw new IllegalStateException();434}435436cbcc.addPropertyChangeListener("beanContext", childPCL);437cbcc.addVetoableChangeListener("beanContext", childVCL);438}439440Visibility v = getChildVisibility(targetChild);441442if (v != null) {443if (okToUseGui)444v.okToUseGui();445else446v.dontUseGui();447}448449if (getChildSerializable(targetChild) != null) serializable++;450451childJustAddedHook(targetChild, bcsc);452453if (bccp != null) {454v = getChildVisibility(bccp);455456if (v != null) {457if (okToUseGui)458v.okToUseGui();459else460v.dontUseGui();461}462463if (getChildSerializable(bccp) != null) serializable++;464465childJustAddedHook(bccp, pbcsc);466}467468469}470471// The specification requires that we fire a notification of the change472473fireChildrenAdded(new BeanContextMembershipEvent(getBeanContextPeer(), bccp == null ? new Object[] { targetChild } : new Object[] { targetChild, bccp } ));474475}476477return true;478}479480/**481* Removes a child from this BeanContext. If the child object is not482* for adding then this method throws an IllegalStateException.483* @param targetChild The child objects to remove484* @see #validatePendingRemove485*/486public boolean remove(Object targetChild) {487return remove(targetChild, true);488}489490/**491* internal remove used when removal caused by492* unexpected {@code setBeanContext} or493* by {@code remove()} invocation.494* @param targetChild the JavaBean, BeanContext, or Object to be removed495* @param callChildSetBC used to indicate that496* the child should be notified that it is no497* longer nested in this {@code BeanContext}.498* @return whether or not was present before being removed499*/500protected boolean remove(Object targetChild, boolean callChildSetBC) {501502if (targetChild == null) throw new IllegalArgumentException();503504synchronized(BeanContext.globalHierarchyLock) {505if (!containsKey(targetChild)) return false;506507if (!validatePendingRemove(targetChild)) {508throw new IllegalStateException();509}510511BCSChild bcsc = children.get(targetChild);512BCSChild pbcsc = null;513Object peer = null;514515// we are required to notify the child that it is no longer nested here if516// it implements java.beans.beancontext.BeanContextChild517518synchronized(targetChild) {519if (callChildSetBC) {520BeanContextChild cbcc = getChildBeanContextChild(targetChild);521if (cbcc != null) synchronized(cbcc) {522cbcc.removePropertyChangeListener("beanContext", childPCL);523cbcc.removeVetoableChangeListener("beanContext", childVCL);524525try {526cbcc.setBeanContext(null);527} catch (PropertyVetoException pve1) {528cbcc.addPropertyChangeListener("beanContext", childPCL);529cbcc.addVetoableChangeListener("beanContext", childVCL);530throw new IllegalStateException();531}532533}534}535536synchronized (children) {537children.remove(targetChild);538539if (bcsc.isProxyPeer()) {540pbcsc = children.get(peer = bcsc.getProxyPeer());541children.remove(peer);542}543}544545if (getChildSerializable(targetChild) != null) serializable--;546547childJustRemovedHook(targetChild, bcsc);548549if (peer != null) {550if (getChildSerializable(peer) != null) serializable--;551552childJustRemovedHook(peer, pbcsc);553}554}555556fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } ));557558}559560return true;561}562563/**564* Tests to see if all objects in the565* specified {@code Collection} are children of566* this {@code BeanContext}.567* @param c the specified {@code Collection}568*569* @return {@code true} if all objects570* in the collection are children of571* this {@code BeanContext}, false if not.572*/573@SuppressWarnings("rawtypes")574public boolean containsAll(Collection c) {575synchronized(children) {576for (Object o : c)577if(!contains(o))578return false;579580return true;581}582}583584/**585* add Collection to set of Children (Unsupported)586* implementations must synchronized on the hierarchy lock and "children" protected field587* @throws UnsupportedOperationException thrown unconditionally by this implementation588* @return this implementation unconditionally throws {@code UnsupportedOperationException}589*/590@SuppressWarnings("rawtypes")591public boolean addAll(Collection c) {592throw new UnsupportedOperationException();593}594595/**596* remove all specified children (Unsupported)597* implementations must synchronized on the hierarchy lock and "children" protected field598* @throws UnsupportedOperationException thrown unconditionally by this implementation599* @return this implementation unconditionally throws {@code UnsupportedOperationException}600601*/602@SuppressWarnings("rawtypes")603public boolean removeAll(Collection c) {604throw new UnsupportedOperationException();605}606607608/**609* retain only specified children (Unsupported)610* implementations must synchronized on the hierarchy lock and "children" protected field611* @throws UnsupportedOperationException thrown unconditionally by this implementation612* @return this implementation unconditionally throws {@code UnsupportedOperationException}613*/614@SuppressWarnings("rawtypes")615public boolean retainAll(Collection c) {616throw new UnsupportedOperationException();617}618619/**620* clear the children (Unsupported)621* implementations must synchronized on the hierarchy lock and "children" protected field622* @throws UnsupportedOperationException thrown unconditionally by this implementation623*/624public void clear() {625throw new UnsupportedOperationException();626}627628/**629* Adds a BeanContextMembershipListener630*631* @param bcml the BeanContextMembershipListener to add632* @throws NullPointerException if the argument is null633*/634635public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) {636if (bcml == null) throw new NullPointerException("listener");637638synchronized(bcmListeners) {639if (bcmListeners.contains(bcml))640return;641else642bcmListeners.add(bcml);643}644}645646/**647* Removes a BeanContextMembershipListener648*649* @param bcml the BeanContextMembershipListener to remove650* @throws NullPointerException if the argument is null651*/652653public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) {654if (bcml == null) throw new NullPointerException("listener");655656synchronized(bcmListeners) {657if (!bcmListeners.contains(bcml))658return;659else660bcmListeners.remove(bcml);661}662}663664/**665* @param name the name of the resource requested.666* @param bcc the child object making the request.667*668* @return the requested resource as an InputStream669* @throws NullPointerException if the argument is null670*/671672public InputStream getResourceAsStream(String name, BeanContextChild bcc) {673if (name == null) throw new NullPointerException("name");674if (bcc == null) throw new NullPointerException("bcc");675676if (containsKey(bcc)) {677ClassLoader cl = bcc.getClass().getClassLoader();678679return cl != null ? cl.getResourceAsStream(name)680: ClassLoader.getSystemResourceAsStream(name);681} else throw new IllegalArgumentException("Not a valid child");682}683684/**685* @param name the name of the resource requested.686* @param bcc the child object making the request.687*688* @return the requested resource as an InputStream689*/690691public URL getResource(String name, BeanContextChild bcc) {692if (name == null) throw new NullPointerException("name");693if (bcc == null) throw new NullPointerException("bcc");694695if (containsKey(bcc)) {696ClassLoader cl = bcc.getClass().getClassLoader();697698return cl != null ? cl.getResource(name)699: ClassLoader.getSystemResource(name);700} else throw new IllegalArgumentException("Not a valid child");701}702703/**704* Sets the new design time value for this {@code BeanContext}.705* @param dTime the new designTime value706*/707public synchronized void setDesignTime(boolean dTime) {708if (designTime != dTime) {709designTime = dTime;710711firePropertyChange("designMode", Boolean.valueOf(!dTime), Boolean.valueOf(dTime));712}713}714715716/**717* Reports whether or not this object is in718* currently in design time mode.719* @return {@code true} if in design time mode,720* {@code false} if not721*/722public synchronized boolean isDesignTime() { return designTime; }723724/**725* Sets the locale of this BeanContext.726* @param newLocale the new locale. This method call will have727* no effect if newLocale is {@code null}.728* @throws PropertyVetoException if the new value is rejected729*/730public synchronized void setLocale(Locale newLocale) throws PropertyVetoException {731732if ((locale != null && !locale.equals(newLocale)) && newLocale != null) {733Locale old = locale;734735fireVetoableChange("locale", old, newLocale); // throws736737locale = newLocale;738739firePropertyChange("locale", old, newLocale);740}741}742743/**744* Gets the locale for this {@code BeanContext}.745*746* @return the current Locale of the {@code BeanContext}747*/748public synchronized Locale getLocale() { return locale; }749750/**751* <p>752* This method is typically called from the environment in order to determine753* if the implementor "needs" a GUI.754* </p>755* <p>756* The algorithm used herein tests the BeanContextPeer, and its current children757* to determine if they are either Containers, Components, or if they implement758* Visibility and return needsGui() == true.759* </p>760* @return {@code true} if the implementor needs a GUI761*/762public synchronized boolean needsGui() {763BeanContext bc = getBeanContextPeer();764765if (bc != this) {766if (bc instanceof Visibility) return ((Visibility)bc).needsGui();767768if (bc instanceof Container || bc instanceof Component)769return true;770}771772synchronized(children) {773for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {774Object c = i.next();775776try {777return ((Visibility)c).needsGui();778} catch (ClassCastException cce) {779// do nothing ...780}781782if (c instanceof Container || c instanceof Component)783return true;784}785}786787return false;788}789790/**791* notify this instance that it may no longer render a GUI.792*/793794public synchronized void dontUseGui() {795if (okToUseGui) {796okToUseGui = false;797798// lets also tell the Children that can that they may not use their GUI's799synchronized(children) {800for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {801Visibility v = getChildVisibility(i.next());802803if (v != null) v.dontUseGui();804}805}806}807}808809/**810* Notify this instance that it may now render a GUI811*/812813public synchronized void okToUseGui() {814if (!okToUseGui) {815okToUseGui = true;816817// lets also tell the Children that can that they may use their GUI's818synchronized(children) {819for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {820Visibility v = getChildVisibility(i.next());821822if (v != null) v.okToUseGui();823}824}825}826}827828/**829* Used to determine if the {@code BeanContext}830* child is avoiding using its GUI.831* @return is this instance avoiding using its GUI?832* @see Visibility833*/834public boolean avoidingGui() {835return !okToUseGui && needsGui();836}837838/**839* Is this {@code BeanContext} in the840* process of being serialized?841* @return if this {@code BeanContext} is842* currently being serialized843*/844public boolean isSerializing() { return serializing; }845846/**847* Returns an iterator of all children848* of this {@code BeanContext}.849* @return an iterator for all the current BCSChild values850*/851protected Iterator<BCSChild> bcsChildren() { synchronized(children) { return children.values().iterator(); } }852853/**854* called by writeObject after defaultWriteObject() but prior to855* serialization of currently serializable children.856*857* This method may be overridden by subclasses to perform custom858* serialization of their state prior to this superclass serializing859* the children.860*861* This method should not however be used by subclasses to replace their862* own implementation (if any) of writeObject().863* @param oos the {@code ObjectOutputStream} to use during serialization864* @throws IOException if serialization failed865*/866867protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {868}869870/**871* called by readObject after defaultReadObject() but prior to872* deserialization of any children.873*874* This method may be overridden by subclasses to perform custom875* deserialization of their state prior to this superclass deserializing876* the children.877*878* This method should not however be used by subclasses to replace their879* own implementation (if any) of readObject().880* @param ois the {@code ObjectInputStream} to use during deserialization881* @throws IOException if deserialization failed882* @throws ClassNotFoundException if needed classes are not found883*/884885protected void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {886}887888/**889* Called by readObject with the newly deserialized child and BCSChild.890* @param child the newly deserialized child891* @param bcsc the newly deserialized BCSChild892*/893protected void childDeserializedHook(Object child, BCSChild bcsc) {894synchronized(children) {895children.put(child, bcsc);896}897}898899/**900* Used by writeObject to serialize a Collection.901* @param oos the {@code ObjectOutputStream}902* to use during serialization903* @param coll the {@code Collection} to serialize904* @throws IOException if serialization failed905*/906protected final void serialize(ObjectOutputStream oos, Collection<?> coll) throws IOException {907int count = 0;908Object[] objects = coll.toArray();909910for (int i = 0; i < objects.length; i++) {911if (objects[i] instanceof Serializable)912count++;913else914objects[i] = null;915}916917oos.writeInt(count); // number of subsequent objects918919for (int i = 0; count > 0; i++) {920Object o = objects[i];921922if (o != null) {923oos.writeObject(o);924count--;925}926}927}928929/**930* used by readObject to deserialize a collection.931* @param ois the ObjectInputStream to use932* @param coll the Collection933* @throws IOException if deserialization failed934* @throws ClassNotFoundException if needed classes are not found935*/936@SuppressWarnings({"rawtypes", "unchecked"})937protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException {938int count = 0;939940count = ois.readInt();941942while (count-- > 0) {943coll.add(ois.readObject());944}945}946947/**948* Used to serialize all children of949* this {@code BeanContext}.950* @param oos the {@code ObjectOutputStream}951* to use during serialization952* @throws IOException if serialization failed953*/954public final void writeChildren(ObjectOutputStream oos) throws IOException {955if (serializable <= 0) return;956957boolean prev = serializing;958959serializing = true;960961int count = 0;962963synchronized(children) {964Iterator<Map.Entry<Object, BCSChild>> i = children.entrySet().iterator();965966while (i.hasNext() && count < serializable) {967Map.Entry<Object, BCSChild> entry = i.next();968969if (entry.getKey() instanceof Serializable) {970try {971oos.writeObject(entry.getKey()); // child972oos.writeObject(entry.getValue()); // BCSChild973} catch (IOException ioe) {974serializing = prev;975throw ioe;976}977count++;978}979}980}981982serializing = prev;983984if (count != serializable) {985throw new IOException("wrote different number of children than expected");986}987988}989990/**991* Serialize the BeanContextSupport, if this instance has a distinct992* peer (that is this object is acting as a delegate for another) then993* the children of this instance are not serialized here due to a994* 'chicken and egg' problem that occurs on deserialization of the995* children at the same time as this instance.996*997* Therefore in situations where there is a distinct peer to this instance998* it should always call writeObject() followed by writeChildren() and999* readObject() followed by readChildren().1000*1001* @param oos the {@code ObjectOutputStream} to write1002* @throws IOException if an I/O error occurs1003*/1004@Serial1005private synchronized void writeObject(ObjectOutputStream oos) throws IOException {1006serializing = true;10071008synchronized (BeanContext.globalHierarchyLock) {1009try {1010oos.defaultWriteObject(); // serialize the BeanContextSupport object10111012bcsPreSerializationHook(oos);10131014if (serializable > 0 && this.equals(getBeanContextPeer()))1015writeChildren(oos);10161017serialize(oos, (Collection)bcmListeners);1018} finally {1019serializing = false;1020}1021}1022}10231024/**1025* When an instance of this class is used as a delegate for the1026* implementation of the BeanContext protocols (and its subprotocols)1027* there exists a 'chicken and egg' problem during deserialization1028* @param ois the ObjectInputStream to use1029* @throws IOException if deserialization failed1030* @throws ClassNotFoundException if needed classes are not found1031*/10321033public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException {1034int count = serializable;10351036while (count-- > 0) {1037Object child = ois.readObject();1038BCSChild bscc = (BCSChild) ois.readObject();10391040synchronized(child) {1041BeanContextChild bcc = null;10421043try {1044bcc = (BeanContextChild)child;1045} catch (ClassCastException cce) {1046// do nothing;1047}10481049if (bcc != null) {1050try {1051bcc.setBeanContext(getBeanContextPeer());10521053bcc.addPropertyChangeListener("beanContext", childPCL);1054bcc.addVetoableChangeListener("beanContext", childVCL);10551056} catch (PropertyVetoException pve) {1057continue;1058}1059}10601061childDeserializedHook(child, bscc);1062}1063}1064}10651066/**1067* deserialize contents ... if this instance has a distinct peer the1068* children are *not* serialized here, the peer's readObject() must call1069* readChildren() after deserializing this instance.1070*1071* @param ois the {@code ObjectInputStream} to read1072* @throws ClassNotFoundException if the class of a serialized object could1073* not be found1074* @throws IOException if an I/O error occurs1075*/1076@Serial1077private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {10781079synchronized(BeanContext.globalHierarchyLock) {1080ois.defaultReadObject();10811082initialize();10831084bcsPreDeserializationHook(ois);10851086if (serializable > 0 && this.equals(getBeanContextPeer()))1087readChildren(ois);10881089deserialize(ois, bcmListeners = new ArrayList<>(1));1090}1091}10921093/**1094* subclasses may envelope to monitor veto child property changes.1095*/10961097public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {1098String propertyName = pce.getPropertyName();1099Object source = pce.getSource();11001101synchronized(children) {1102if ("beanContext".equals(propertyName) &&1103containsKey(source) &&1104!getBeanContextPeer().equals(pce.getNewValue())1105) {1106if (!validatePendingRemove(source)) {1107throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce);1108} else children.get(source).setRemovePending(true);1109}1110}1111}11121113/**1114* subclasses may envelope to monitor child property changes.1115*/11161117public void propertyChange(PropertyChangeEvent pce) {1118String propertyName = pce.getPropertyName();1119Object source = pce.getSource();11201121synchronized(children) {1122if ("beanContext".equals(propertyName) &&1123containsKey(source) &&1124children.get(source).isRemovePending()) {1125BeanContext bc = getBeanContextPeer();11261127if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {1128remove(source, false);1129} else {1130children.get(source).setRemovePending(false);1131}1132}1133}1134}11351136/**1137* <p>1138* Subclasses of this class may override, or envelope, this method to1139* add validation behavior for the BeanContext to examine child objects1140* immediately prior to their being added to the BeanContext.1141* </p>1142*1143* @param targetChild the child to create the Child on behalf of1144* @return true iff the child may be added to this BeanContext, otherwise false.1145*/11461147protected boolean validatePendingAdd(Object targetChild) {1148return true;1149}11501151/**1152* <p>1153* Subclasses of this class may override, or envelope, this method to1154* add validation behavior for the BeanContext to examine child objects1155* immediately prior to their being removed from the BeanContext.1156* </p>1157*1158* @param targetChild the child to create the Child on behalf of1159* @return true iff the child may be removed from this BeanContext, otherwise false.1160*/11611162protected boolean validatePendingRemove(Object targetChild) {1163return true;1164}11651166/**1167* subclasses may override this method to simply extend add() semantics1168* after the child has been added and before the event notification has1169* occurred. The method is called with the child synchronized.1170* @param child the child1171* @param bcsc the BCSChild1172*/11731174protected void childJustAddedHook(Object child, BCSChild bcsc) {1175}11761177/**1178* subclasses may override this method to simply extend remove() semantics1179* after the child has been removed and before the event notification has1180* occurred. The method is called with the child synchronized.1181* @param child the child1182* @param bcsc the BCSChild1183*/11841185protected void childJustRemovedHook(Object child, BCSChild bcsc) {1186}11871188/**1189* Gets the Component (if any) associated with the specified child.1190* @param child the specified child1191* @return the Component (if any) associated with the specified child.1192*/1193protected static final Visibility getChildVisibility(Object child) {1194try {1195return (Visibility)child;1196} catch (ClassCastException cce) {1197return null;1198}1199}12001201/**1202* Gets the Serializable (if any) associated with the specified Child1203* @param child the specified child1204* @return the Serializable (if any) associated with the specified Child1205*/1206protected static final Serializable getChildSerializable(Object child) {1207try {1208return (Serializable)child;1209} catch (ClassCastException cce) {1210return null;1211}1212}12131214/**1215* Gets the PropertyChangeListener1216* (if any) of the specified child1217* @param child the specified child1218* @return the PropertyChangeListener (if any) of the specified child1219*/1220protected static final PropertyChangeListener getChildPropertyChangeListener(Object child) {1221try {1222return (PropertyChangeListener)child;1223} catch (ClassCastException cce) {1224return null;1225}1226}12271228/**1229* Gets the VetoableChangeListener1230* (if any) of the specified child1231* @param child the specified child1232* @return the VetoableChangeListener (if any) of the specified child1233*/1234protected static final VetoableChangeListener getChildVetoableChangeListener(Object child) {1235try {1236return (VetoableChangeListener)child;1237} catch (ClassCastException cce) {1238return null;1239}1240}12411242/**1243* Gets the BeanContextMembershipListener1244* (if any) of the specified child1245* @param child the specified child1246* @return the BeanContextMembershipListener (if any) of the specified child1247*/1248protected static final BeanContextMembershipListener getChildBeanContextMembershipListener(Object child) {1249try {1250return (BeanContextMembershipListener)child;1251} catch (ClassCastException cce) {1252return null;1253}1254}12551256/**1257* Gets the BeanContextChild (if any) of the specified child1258* @param child the specified child1259* @return the BeanContextChild (if any) of the specified child1260* @throws IllegalArgumentException if child implements both BeanContextChild and BeanContextProxy1261*/1262protected static final BeanContextChild getChildBeanContextChild(Object child) {1263try {1264BeanContextChild bcc = (BeanContextChild)child;12651266if (child instanceof BeanContextChild && child instanceof BeanContextProxy)1267throw new IllegalArgumentException("child cannot implement both BeanContextChild and BeanContextProxy");1268else1269return bcc;1270} catch (ClassCastException cce) {1271try {1272return ((BeanContextProxy)child).getBeanContextProxy();1273} catch (ClassCastException cce1) {1274return null;1275}1276}1277}12781279/**1280* Fire a BeanContextshipEvent on the BeanContextMembershipListener interface1281* @param bcme the event to fire1282*/12831284protected final void fireChildrenAdded(BeanContextMembershipEvent bcme) {1285Object[] copy;12861287synchronized(bcmListeners) { copy = bcmListeners.toArray(); }12881289for (int i = 0; i < copy.length; i++)1290((BeanContextMembershipListener)copy[i]).childrenAdded(bcme);1291}12921293/**1294* Fire a BeanContextshipEvent on the BeanContextMembershipListener interface1295* @param bcme the event to fire1296*/12971298protected final void fireChildrenRemoved(BeanContextMembershipEvent bcme) {1299Object[] copy;13001301synchronized(bcmListeners) { copy = bcmListeners.toArray(); }13021303for (int i = 0; i < copy.length; i++)1304((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme);1305}13061307/**1308* protected method called from constructor and readObject to initialize1309* transient state of BeanContextSupport instance.1310*1311* This class uses this method to instantiate inner class listeners used1312* to monitor PropertyChange and VetoableChange events on children.1313*1314* subclasses may envelope this method to add their own initialization1315* behavior1316*/13171318protected synchronized void initialize() {1319children = new HashMap<>(serializable + 1);1320bcmListeners = new ArrayList<>(1);13211322childPCL = new PropertyChangeListener() {13231324/*1325* this adaptor is used by the BeanContextSupport class to forward1326* property changes from a child to the BeanContext, avoiding1327* accidential serialization of the BeanContext by a badly1328* behaved Serializable child.1329*/13301331public void propertyChange(PropertyChangeEvent pce) {1332BeanContextSupport.this.propertyChange(pce);1333}1334};13351336childVCL = new VetoableChangeListener() {13371338/*1339* this adaptor is used by the BeanContextSupport class to forward1340* vetoable changes from a child to the BeanContext, avoiding1341* accidential serialization of the BeanContext by a badly1342* behaved Serializable child.1343*/13441345public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {1346BeanContextSupport.this.vetoableChange(pce);1347}1348};1349}13501351/**1352* Gets a copy of the this BeanContext's children.1353* @return a copy of the current nested children1354*/1355protected final Object[] copyChildren() {1356synchronized(children) { return children.keySet().toArray(); }1357}13581359/**1360* Tests to see if two class objects,1361* or their names are equal.1362* @param first the first object1363* @param second the second object1364* @return true if equal, false if not1365*/1366protected static final boolean classEquals(Class<?> first, Class<?> second) {1367return first.equals(second) || first.getName().equals(second.getName());1368}136913701371/*1372* fields1373*/137413751376/**1377* all accesses to the {@code protected HashMap children} field1378* shall be synchronized on that object.1379*/1380protected transient HashMap<Object, BCSChild> children;13811382/**1383* Currently serializable children.1384*/1385private int serializable = 0; // children serializable13861387/**1388* all accesses to the {@code protected ArrayList bcmListeners} field1389* shall be synchronized on that object.1390*/1391protected transient ArrayList<BeanContextMembershipListener> bcmListeners;13921393//13941395/**1396* The current locale of this BeanContext.1397*/1398protected Locale locale;13991400/**1401* A {@code boolean} indicating if this1402* instance may now render a GUI.1403*/1404protected boolean okToUseGui;140514061407/**1408* A {@code boolean} indicating whether or not1409* this object is currently in design time mode.1410*/1411protected boolean designTime;14121413/*1414* transient1415*/14161417private transient PropertyChangeListener childPCL;14181419private transient VetoableChangeListener childVCL;14201421private transient boolean serializing;1422}142314241425