1. /*
  2. * @(#)BeanContextSupport.java 1.30 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.beans.beancontext;
  8. import java.awt.Component;
  9. import java.awt.Container;
  10. import java.beans.Beans;
  11. import java.beans.AppletInitializer;
  12. import java.beans.DesignMode;
  13. import java.beans.PropertyChangeEvent;
  14. import java.beans.PropertyChangeListener;
  15. import java.beans.PropertyChangeSupport;
  16. import java.beans.VetoableChangeListener;
  17. import java.beans.VetoableChangeSupport;
  18. import java.beans.PropertyVetoException;
  19. import java.beans.Visibility;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.io.ObjectInputStream;
  23. import java.io.ObjectOutputStream;
  24. import java.io.Serializable;
  25. import java.net.URL;
  26. import java.util.ArrayList;
  27. import java.util.Collection;
  28. import java.util.HashMap;
  29. import java.util.Iterator;
  30. import java.util.Locale;
  31. import java.util.Map;
  32. /**
  33. * <p>
  34. * This helper class provides a utility implementation of the
  35. * java.beans.beancontext.BeanContext interface.
  36. * </p>
  37. * <p>
  38. * Since this class directly implements the BeanContext interface, the class
  39. * can, and is intended to be used either by subclassing this implementation,
  40. * or via ad-hoc delegation of an instance of this class from another.
  41. * </p>
  42. *
  43. * @author Laurence P. G. Cable
  44. * @version 1.30
  45. * @since JDK1.2
  46. */
  47. public class BeanContextSupport extends BeanContextChildSupport
  48. implements BeanContext,
  49. Serializable,
  50. PropertyChangeListener,
  51. VetoableChangeListener {
  52. /**
  53. * <p>
  54. * Construct a BeanContextSupport instance
  55. * </p>
  56. *
  57. * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
  58. * @param lcle The current Locale for this BeanContext. If
  59. * <tt>lcle</tt> is <tt>null</tt>, the default locale
  60. * is assigned to the BeanContext instance.
  61. * @param dtime The initial state, true if in design mode, false if runtime.
  62. * @param visible The initial visibility.
  63. * @see java.util.Locale#getDefault()
  64. * @see java.util.Locale@setDefault(java.util.Locale)
  65. *
  66. */
  67. public BeanContextSupport(BeanContext peer, Locale lcle, boolean dTime, boolean visible) {
  68. super(peer);
  69. locale = lcle != null ? lcle : Locale.getDefault();
  70. designTime = dTime;
  71. okToUseGui = visible;
  72. initialize();
  73. }
  74. /**
  75. * Create an instance using the specified Locale and design mode.
  76. *
  77. * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
  78. * @param lcle The current Locale for this BeanContext. If
  79. * <tt>lcle</tt> is <tt>null</tt>, the default locale
  80. * is assigned to the BeanContext instance.
  81. * @param dtime The initial state, true if in design mode, false if runtime.
  82. * @see java.util.Locale#getDefault()
  83. * @see java.util.Locale@setDefault(java.util.Locale)
  84. *
  85. */
  86. public BeanContextSupport(BeanContext peer, Locale lcle, boolean dtime) {
  87. this (peer, lcle, dtime, true);
  88. }
  89. /**
  90. * Create an instance using the specified locale
  91. *
  92. * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
  93. * @param lcle The current Locale for this BeanContext. If
  94. * <tt>lcle</tt> is <tt>null</tt>, the default locale
  95. * is assigned to the BeanContext instance.
  96. * @see java.util.Locale#getDefault()
  97. * @see java.util.Locale@setDefault(java.util.Locale)
  98. *
  99. */
  100. public BeanContextSupport(BeanContext peer, Locale lcle) {
  101. this (peer, lcle, false, true);
  102. }
  103. /**
  104. * Create an instance using with a default locale
  105. *
  106. * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
  107. */
  108. public BeanContextSupport(BeanContext peer) {
  109. this (peer, null, false, true);
  110. }
  111. /**
  112. * Create an instance that is not a delegate of another object
  113. */
  114. public BeanContextSupport() {
  115. this (null, null, false, true);
  116. }
  117. /**
  118. * @return the instance of BeanContext this object is providing the implemen
  119. tation for.
  120. */
  121. public BeanContext getBeanContextPeer() { return (BeanContext)getBeanContextChildPeer(); }
  122. /**
  123. * <p>
  124. * The instantiateChild method is a convenience hook in BeanContext to simplify
  125. * the task of instantiating a Bean, nested, into a BeanContext.
  126. * </p>
  127. * <p>
  128. * The semantics of the beanName parameter are defined by java.beans.Beans.instantate.
  129. * </p>
  130. *
  131. * @param beanName the name of the Bean to instantiate within this BeanContext
  132. */
  133. public Object instantiateChild(String beanName)
  134. throws IOException, ClassNotFoundException {
  135. BeanContext bc = getBeanContextPeer();
  136. return Beans.instantiate(bc.getClass().getClassLoader(), beanName, bc);
  137. }
  138. /**
  139. * @return number of children
  140. */
  141. public int size() {
  142. synchronized(children) {
  143. return children.size();
  144. }
  145. }
  146. /**
  147. * @return if there are not children
  148. */
  149. public boolean isEmpty() {
  150. synchronized(children) {
  151. return children.isEmpty();
  152. }
  153. }
  154. /**
  155. * @return if this object is a child
  156. */
  157. public boolean contains(Object o) {
  158. synchronized(children) {
  159. return children.containsKey(o);
  160. }
  161. }
  162. /**
  163. * @return if this object is a child
  164. */
  165. public boolean containsKey(Object o) {
  166. synchronized(children) {
  167. return children.containsKey(o);
  168. }
  169. }
  170. /**
  171. * @return the iterator
  172. */
  173. public Iterator iterator() {
  174. synchronized(children) {
  175. return new BCSIterator(children.keySet().iterator());
  176. }
  177. }
  178. /**
  179. * @return an array of children
  180. */
  181. public Object[] toArray() {
  182. synchronized(children) {
  183. return children.keySet().toArray();
  184. }
  185. }
  186. /**
  187. * @return an array of children
  188. */
  189. public Object[] toArray(Object[] arry) {
  190. synchronized(children) {
  191. return children.keySet().toArray(arry);
  192. }
  193. }
  194. /************************************************************************/
  195. /**
  196. * protected final subclass that encapsulates an iterator but implements
  197. * a noop remove() method.
  198. */
  199. protected static final class BCSIterator implements Iterator {
  200. BCSIterator(Iterator i) { super(); src = i; }
  201. public boolean hasNext() { return src.hasNext(); }
  202. public Object next() { return src.next(); }
  203. public void remove() { /* do nothing */ }
  204. private Iterator src;
  205. }
  206. /************************************************************************/
  207. /*
  208. * protected nested class containing per child information, an instance
  209. * of which is associated with each child in the "children" hashtable.
  210. * subclasses can extend this class to include their own per-child state.
  211. *
  212. * Note that this 'value' is serialized with the corresponding child 'key'
  213. * when the BeanContextSupport is serialized.
  214. */
  215. protected class BCSChild implements Serializable {
  216. BCSChild(Object bcc, Object peer) {
  217. super();
  218. child = bcc;
  219. proxyPeer = peer;
  220. }
  221. Object getChild() { return child; }
  222. void setRemovePending(boolean v) { removePending = v; }
  223. boolean isRemovePending() { return removePending; }
  224. boolean isProxyPeer() { return proxyPeer != null; }
  225. Object getProxyPeer() { return proxyPeer; }
  226. /*
  227. * fields
  228. */
  229. private Object child;
  230. private Object proxyPeer;
  231. private transient boolean removePending;
  232. }
  233. /**
  234. * <p>
  235. * Subclasses can override this method to insert their own subclass
  236. * of Child without having to override add() or the other Collection
  237. * methods that add children to the set.
  238. * </p>
  239. *
  240. * @param targetChild the child to create the Child on behalf of
  241. * @param peer the peer if the tragetChild and the peer are related by an implementation of BeanContextProxy
  242. */
  243. protected BCSChild createBCSChild(Object targetChild, Object peer) {
  244. return new BCSChild(targetChild, peer);
  245. }
  246. /************************************************************************/
  247. /**
  248. * <p>
  249. * Adds/nests a child within this BeanContext
  250. * </p>
  251. * <p>
  252. * Invoked as a side effect of java.beans.Beans.instantiate().
  253. * </p>
  254. *
  255. * @param targetChildren The child objects to nest within this BeanContext
  256. */
  257. public boolean add(Object targetChild) {
  258. if (targetChild == null) throw new IllegalArgumentException();
  259. // The specification requires that we do nothing if the child
  260. // is already nested herein.
  261. if (children.containsKey(targetChild)) return false; // test before locking
  262. synchronized(BeanContext.globalHierarchyLock) {
  263. if (children.containsKey(targetChild)) return false; // check again
  264. if (!validatePendingAdd(targetChild)) {
  265. throw new IllegalStateException();
  266. }
  267. // The specification requires that we invoke setBeanContext() on the
  268. // newly added child if it implements the java.beans.beancontext.BeanContextChild interface
  269. BeanContextChild cbcc = getChildBeanContextChild(targetChild);
  270. BeanContextChild bccp = null;
  271. synchronized(targetChild) {
  272. if (targetChild instanceof BeanContextProxy) {
  273. bccp = ((BeanContextProxy)targetChild).getBeanContextProxy();
  274. if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()");
  275. }
  276. BCSChild bcsc = createBCSChild(targetChild, bccp);
  277. BCSChild pbcsc = null;
  278. synchronized (children) {
  279. children.put(targetChild, bcsc);
  280. if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));
  281. }
  282. if (cbcc != null) synchronized(cbcc) {
  283. try {
  284. cbcc.setBeanContext(getBeanContextPeer());
  285. } catch (PropertyVetoException pve) {
  286. synchronized (children) {
  287. children.remove(targetChild);
  288. if (bccp != null) children.remove(bccp);
  289. }
  290. throw new IllegalStateException();
  291. }
  292. cbcc.addPropertyChangeListener("beanContext", childPCL);
  293. cbcc.addVetoableChangeListener("beanContext", childVCL);
  294. }
  295. Visibility v = getChildVisibility(targetChild);
  296. if (v != null) {
  297. if (okToUseGui)
  298. v.okToUseGui();
  299. else
  300. v.dontUseGui();
  301. }
  302. if (getChildSerializable(targetChild) != null) serializable++;
  303. childJustAddedHook(targetChild, bcsc);
  304. if (bccp != null) {
  305. v = getChildVisibility(bccp);
  306. if (v != null) {
  307. if (okToUseGui)
  308. v.okToUseGui();
  309. else
  310. v.dontUseGui();
  311. }
  312. if (getChildSerializable(bccp) != null) serializable++;
  313. childJustAddedHook(bccp, pbcsc);
  314. }
  315. }
  316. // The specification requires that we fire a notification of the change
  317. fireChildrenAdded(new BeanContextMembershipEvent(getBeanContextPeer(), bccp == null ? new Object[] { targetChild } : new Object[] { targetChild, bccp } ));
  318. }
  319. return true;
  320. }
  321. /**
  322. * @param targetChildren The child objects to remove
  323. */
  324. public boolean remove(Object targetChild) {
  325. return remove(targetChild, true);
  326. }
  327. /*
  328. * internal remove used when removal caused by unexpected setBeanContext or
  329. * by remove() invocation
  330. */
  331. protected boolean remove(Object targetChild, boolean callChildSetBC) {
  332. if (targetChild == null) throw new IllegalArgumentException();
  333. synchronized(BeanContext.globalHierarchyLock) {
  334. if (!containsKey(targetChild)) return false;
  335. if (!validatePendingRemove(targetChild)) {
  336. throw new IllegalStateException();
  337. }
  338. BCSChild bcsc = (BCSChild)children.get(targetChild);
  339. BCSChild pbcsc = null;
  340. Object peer = null;
  341. // we are required to notify the child that it is no longer nested here if
  342. // it implements java.beans.beancontext.BeanContextChild
  343. synchronized(targetChild) {
  344. if (callChildSetBC) {
  345. BeanContextChild cbcc = getChildBeanContextChild(targetChild);
  346. if (cbcc != null) synchronized(cbcc) {
  347. cbcc.removePropertyChangeListener("beanContext", childPCL);
  348. cbcc.removeVetoableChangeListener("beanContext", childVCL);
  349. try {
  350. cbcc.setBeanContext(null);
  351. } catch (PropertyVetoException pve1) {
  352. cbcc.addPropertyChangeListener("beanContext", childPCL);
  353. cbcc.addVetoableChangeListener("beanContext", childVCL);
  354. throw new IllegalStateException();
  355. }
  356. }
  357. }
  358. synchronized (children) {
  359. children.remove(targetChild);
  360. if (bcsc.isProxyPeer()) {
  361. pbcsc = (BCSChild)children.get(peer = bcsc.getProxyPeer());
  362. children.remove(peer);
  363. }
  364. }
  365. if (getChildSerializable(targetChild) != null) serializable--;
  366. childJustRemovedHook(targetChild, bcsc);
  367. if (peer != null) {
  368. if (getChildSerializable(peer) != null) serializable--;
  369. childJustRemovedHook(peer, pbcsc);
  370. }
  371. }
  372. fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } ));
  373. }
  374. return true;
  375. }
  376. /**
  377. * @return if all object objects in specified Collection are children.
  378. */
  379. public boolean containsAll(Collection c) {
  380. synchronized(children) {
  381. Iterator i = c.iterator();
  382. while (i.hasNext())
  383. if(!contains(i.next()))
  384. return false;
  385. return true;
  386. }
  387. }
  388. /**
  389. * add Collection to set of Children (Unsupported)
  390. * implementations must synchronized on the hierarchy lock and "children" protected field
  391. */
  392. public boolean addAll(Collection c) {
  393. throw new UnsupportedOperationException();
  394. }
  395. /**
  396. * remove all specified children (Unsupported)
  397. * implementations must synchronized on the hierarchy lock and "children" protected field
  398. */
  399. public boolean removeAll(Collection c) {
  400. throw new UnsupportedOperationException();
  401. }
  402. /**
  403. * retain only specified children (Unsupported)
  404. * implementations must synchronized on the hierarchy lock and "children" protected field
  405. */
  406. public boolean retainAll(Collection c) {
  407. throw new UnsupportedOperationException();
  408. }
  409. /**
  410. * clear the children (Unsupported)
  411. * implementations must synchronized on the hierarchy lock and "children" protected field
  412. */
  413. public void clear() {
  414. throw new UnsupportedOperationException();
  415. }
  416. /**
  417. * Adds a BeanContextMembershipListener
  418. *
  419. * @param bcml the BeanContextMembershipListener to add
  420. * @throw NullPointerException
  421. */
  422. public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) {
  423. if (bcml == null) throw new NullPointerException("listener");
  424. synchronized(bcmListeners) {
  425. if (bcmListeners.contains(bcml))
  426. return;
  427. else
  428. bcmListeners.add(bcml);
  429. }
  430. }
  431. /**
  432. * Removes a BeanContextMembershipListener
  433. *
  434. * @param bcml the BeanContextMembershipListener to remove
  435. * @throw NullPointerException
  436. */
  437. public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) {
  438. if (bcml == null) throw new NullPointerException("listener");
  439. synchronized(bcmListeners) {
  440. if (!bcmListeners.contains(bcml))
  441. return;
  442. else
  443. bcmListeners.remove(bcml);
  444. }
  445. }
  446. /**
  447. * @param name the name of the resource requested.
  448. * @param child the child object making the request.
  449. *
  450. * @return the requested resource as an InputStream
  451. * @throw NullPointerException
  452. */
  453. public InputStream getResourceAsStream(String name, BeanContextChild bcc) {
  454. if (name == null) throw new NullPointerException("name");
  455. if (bcc == null) throw new NullPointerException("bcc");
  456. boolean isChild;
  457. synchronized(children) {
  458. isChild = children.containsValue(bcc);
  459. }
  460. if (isChild) {
  461. ClassLoader cl = bcc.getClass().getClassLoader();
  462. return cl != null ? cl.getResourceAsStream(name)
  463. : ClassLoader.getSystemResourceAsStream(name);
  464. } else throw new IllegalArgumentException("Not a valid child");
  465. }
  466. /**
  467. * @param name the name of the resource requested.
  468. * @param child the child object making the request.
  469. *
  470. * @return the requested resource as an InputStream
  471. */
  472. public URL getResource(String name, BeanContextChild bcc) {
  473. if (name == null) throw new NullPointerException("name");
  474. if (bcc == null) throw new NullPointerException("bcc");
  475. boolean isChild;
  476. synchronized(children) {
  477. isChild = children.containsValue(bcc);
  478. }
  479. if (isChild) {
  480. ClassLoader cl = bcc.getClass().getClassLoader();
  481. return cl != null ? cl.getResource(name)
  482. : ClassLoader.getSystemResource(name);
  483. } else throw new IllegalArgumentException("Not a valid child");
  484. }
  485. /**
  486. * @param dTime the new designTime value
  487. */
  488. public synchronized void setDesignTime(boolean dTime) {
  489. if (designTime != dTime) {
  490. designTime = dTime;
  491. firePropertyChange("designMode", new Boolean(!dTime), new Boolean(dTime));
  492. }
  493. }
  494. /**
  495. * @return Design time
  496. */
  497. public synchronized boolean isDesignTime() { return designTime; }
  498. /**
  499. * @param newLocale the new locale
  500. */
  501. public synchronized void setLocale(Locale newLocale) throws PropertyVetoException {
  502. if ((locale != null && !locale.equals(newLocale)) || newLocale != null) {
  503. Locale old = locale;
  504. fireVetoableChange("locale", old, newLocale); // throws
  505. locale = newLocale;
  506. firePropertyChange("locale", old, newLocale);
  507. }
  508. }
  509. /**
  510. * @return the current Locale of the BeanContext
  511. */
  512. public synchronized Locale getLocale() { return locale; }
  513. /*
  514. * <p>
  515. * This method is typically called from the environment in order to determine
  516. * if the implementor "needs" a GUI.
  517. * </p>
  518. * <p>
  519. * The algorithm used herein tests the BeanContextPeer, and its current children
  520. * to determine if they are either Containers, Components, or if they implement
  521. * Visibility and return needsGui() == true.
  522. * </p>
  523. */
  524. public synchronized boolean needsGui() {
  525. BeanContext bc = getBeanContextPeer();
  526. if (bc != this) {
  527. if (bc instanceof Visibility) return ((Visibility)bc).needsGui();
  528. if (bc instanceof Container || bc instanceof Component)
  529. return true;
  530. }
  531. synchronized(children) {
  532. for (Iterator i = children.keySet().iterator(); i.hasNext();) {
  533. Object c = i.next();
  534. try {
  535. return ((Visibility)c).needsGui();
  536. } catch (ClassCastException cce) {
  537. // do nothing ...
  538. }
  539. if (c instanceof Container || c instanceof Component)
  540. return true;
  541. }
  542. }
  543. return false;
  544. }
  545. /**
  546. * notify this instance that it may no longer render a GUI.
  547. */
  548. public synchronized void dontUseGui() {
  549. if (okToUseGui) {
  550. okToUseGui = false;
  551. // lets also tell the Children that can that they may not use their GUI's
  552. synchronized(children) {
  553. for (Iterator i = children.keySet().iterator(); i.hasNext();) {
  554. Visibility v = getChildVisibility(i.next());
  555. if (v != null) v.dontUseGui();
  556. }
  557. }
  558. }
  559. }
  560. /**
  561. * Notify this instance that it may now render a GUI
  562. */
  563. public synchronized void okToUseGui() {
  564. if (!okToUseGui) {
  565. okToUseGui = true;
  566. // lets also tell the Children that can that they may use their GUI's
  567. synchronized(children) {
  568. for (Iterator i = children.keySet().iterator(); i.hasNext();) {
  569. Visibility v = getChildVisibility(i.next());
  570. if (v != null) v.okToUseGui();
  571. }
  572. }
  573. }
  574. }
  575. /**
  576. * @return is this instance avoiding using its GUI?
  577. */
  578. public boolean avoidingGui() {
  579. return !okToUseGui && needsGui();
  580. }
  581. /**
  582. * @return if this BeanContext is currently being serialized
  583. */
  584. public boolean isSerializing() { return serializing; }
  585. /**
  586. * @return an iterator for all the current BCSChild values
  587. */
  588. protected Iterator bcsChildren() { synchronized(children) { return children.values().iterator(); } }
  589. /**
  590. * called by writeObject after defaultWriteObject() but prior to
  591. * serialization of currently serializable children.
  592. *
  593. * This method may be overridden by subclasses to perform custom
  594. * serialization of their state prior to this superclass serializing
  595. * the children.
  596. *
  597. * This method should not however be used by subclasses to replace their
  598. * own implementation (if any) of writeObject().
  599. */
  600. protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {
  601. }
  602. /**
  603. * called by readObject after defaultReadObject() but prior to
  604. * deserialization of any children.
  605. *
  606. * This method may be overridden by subclasses to perform custom
  607. * deserialization of their state prior to this superclass deserializing
  608. * the children.
  609. *
  610. * This method should not however be used by subclasses to replace their
  611. * own implementation (if any) of readObject().
  612. */
  613. protected void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  614. }
  615. /**
  616. * called by readObject with the newly deserialized child and BCSChild
  617. */
  618. protected void childDeserializedHook(Object child, BCSChild bcsc) {
  619. synchronized(children) {
  620. children.put(child, bcsc);
  621. }
  622. }
  623. /*
  624. * used by writeObject to serialize a Collection
  625. */
  626. protected final void serialize(ObjectOutputStream oos, Collection coll) throws IOException {
  627. int count = 0;
  628. Object[] objects = coll.toArray();
  629. for (int i = 0; i < objects.length; i++) {
  630. if (objects[i] instanceof Serializable)
  631. count++;
  632. else
  633. objects[i] = null;
  634. }
  635. oos.writeInt(count); // number of subsequent objects
  636. for (int i = 0; count > 0; i++) {
  637. Object o = objects[i];
  638. if (o != null) {
  639. oos.writeObject(o);
  640. count--;
  641. }
  642. }
  643. }
  644. /**
  645. * used by readObject to deserialize a collection
  646. */
  647. protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException {
  648. int count = 0;
  649. count = ois.readInt();
  650. while (count-- > 0) {
  651. coll.add(ois.readObject());
  652. }
  653. }
  654. /**
  655. *
  656. */
  657. public final void writeChildren(ObjectOutputStream oos) throws IOException {
  658. if (serializable <= 0) return;
  659. boolean prev = serializing;
  660. serializing = true;
  661. int count = 0;
  662. synchronized(children) {
  663. Iterator i = children.entrySet().iterator();
  664. while (i.hasNext() && count < serializable) {
  665. Map.Entry entry = (Map.Entry)i.next();
  666. if (entry.getKey() instanceof Serializable) {
  667. try {
  668. oos.writeObject(entry.getKey()); // child
  669. oos.writeObject(entry.getValue()); // BCSChild
  670. } catch (IOException ioe) {
  671. serializing = prev;
  672. throw ioe;
  673. }
  674. count++;
  675. }
  676. }
  677. }
  678. serializing = prev;
  679. if (count != serializable) {
  680. throw new IOException("wrote different number of children than expected");
  681. }
  682. }
  683. /**
  684. * Serialize the BeanContextSupport, if this instance has a distinct
  685. * peer (that is this object is acting as a delegate for another) then
  686. * the children of this instance are not serialized here due to a
  687. * 'chicken and egg' problem that occurs on deserialization of the
  688. * children at the same time as this instance.
  689. *
  690. * Therefore in situations where there is a distinct peer to this instance
  691. * it should always call writeObject() followed by writeChildren() and
  692. * readObject() followed by readChildren().
  693. *
  694. * @param oos the ObjectOutputStream
  695. */
  696. private synchronized void writeObject(ObjectOutputStream oos) throws IOException, ClassNotFoundException {
  697. serializing = true;
  698. synchronized (BeanContext.globalHierarchyLock) {
  699. try {
  700. oos.defaultWriteObject(); // serialize the BeanContextSupport object
  701. bcsPreSerializationHook(oos);
  702. if (serializable > 0 && this.equals(getBeanContextPeer()))
  703. writeChildren(oos);
  704. serialize(oos, (Collection)bcmListeners);
  705. } finally {
  706. serializing = false;
  707. }
  708. }
  709. }
  710. /**
  711. * When an instance of this class is used as a delegate for the
  712. * implementation of the BeanContext protocols (and its subprotocols)
  713. * there exists a 'chicken and egg' problem during deserialization
  714. */
  715. public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  716. int count = serializable;
  717. while (count-- > 0) {
  718. Object child = null;
  719. BeanContextSupport.BCSChild bscc = null;
  720. try {
  721. child = ois.readObject();
  722. bscc = (BeanContextSupport.BCSChild)ois.readObject();
  723. } catch (IOException ioe) {
  724. continue;
  725. } catch (ClassNotFoundException cnfe) {
  726. continue;
  727. }
  728. synchronized(child) {
  729. BeanContextChild bcc = null;
  730. try {
  731. bcc = (BeanContextChild)child;
  732. } catch (ClassCastException cce) {
  733. // do nothing;
  734. }
  735. if (bcc != null) {
  736. try {
  737. bcc.setBeanContext(getBeanContextPeer());
  738. bcc.addPropertyChangeListener("beanContext", childPCL);
  739. bcc.addVetoableChangeListener("beanContext", childVCL);
  740. } catch (PropertyVetoException pve) {
  741. continue;
  742. }
  743. }
  744. childDeserializedHook(child, bscc);
  745. }
  746. }
  747. }
  748. /**
  749. * deserialize contents ... if this instance has a distinct peer the
  750. * children are *not* serialized here, the peer's readObject() must call
  751. * readChildren() after deserializing this instance.
  752. */
  753. private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  754. synchronized(BeanContext.globalHierarchyLock) {
  755. ois.defaultReadObject();
  756. initialize();
  757. bcsPreDeserializationHook(ois);
  758. if (serializable > 0 && this.equals(getBeanContextPeer()))
  759. readChildren(ois);
  760. deserialize(ois, bcmListeners = new ArrayList(1));
  761. }
  762. }
  763. /**
  764. * subclasses may envelope to monitor veto child property changes.
  765. */
  766. public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
  767. String propertyName = pce.getPropertyName();
  768. Object source = pce.getSource();
  769. synchronized(children) {
  770. if ("beanContext".equals(propertyName) &&
  771. containsKey(source) &&
  772. !getBeanContextPeer().equals(pce.getNewValue())
  773. ) {
  774. if (!validatePendingRemove(source)) {
  775. throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce);
  776. } else ((BCSChild)children.get(source)).setRemovePending(true);
  777. }
  778. }
  779. }
  780. /**
  781. * subclasses may envelope to monitor child property changes.
  782. */
  783. public void propertyChange(PropertyChangeEvent pce) {
  784. String propertyName = pce.getPropertyName();
  785. Object source = pce.getSource();
  786. synchronized(children) {
  787. if ("beanContext".equals(propertyName) &&
  788. containsKey(source) &&
  789. ((BCSChild)children.get(source)).isRemovePending()) {
  790. BeanContext bc = getBeanContextPeer();
  791. if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {
  792. remove(source, false);
  793. } else {
  794. ((BCSChild)children.get(source)).setRemovePending(false);
  795. }
  796. }
  797. }
  798. }
  799. /**
  800. * <p>
  801. * Subclasses of this class may override, or envelope, this method to
  802. * add validation behavior for the BeanContext to examine child objects
  803. * immediately prior to their being added to the BeanContext.
  804. * </p>
  805. *
  806. * @returns true iff the child may be added to this BeanContext, otherwise false.
  807. */
  808. protected boolean validatePendingAdd(Object targetChild) {
  809. return true;
  810. }
  811. /**
  812. * <p>
  813. * Subclasses of this class may override, or envelope, this method to
  814. * add validation behavior for the BeanContext to examine child objects
  815. * immediately prior to their being removed from the BeanContext.
  816. * </p>
  817. *
  818. * @returns true iff the child may be removed from this BeanContext, otherwise false.
  819. */
  820. protected boolean validatePendingRemove(Object targetChild) {
  821. return true;
  822. }
  823. /**
  824. * subclasses may override this method to simply extend add() semantics
  825. * after the child has been added and before the event notification has
  826. * occurred. The method is called with the child synchronized.
  827. */
  828. protected void childJustAddedHook(Object child, BCSChild bcsc) {
  829. }
  830. /**
  831. * subclasses may override this method to simply extend remove() semantics
  832. * after the child has been removed and before the event notification has
  833. * occurred. The method is called with the child synchronized.
  834. */
  835. protected void childJustRemovedHook(Object child, BCSChild bcsc) {
  836. }
  837. /**
  838. * @return the Component (if any) associated with the specified Child
  839. */
  840. protected static final Visibility getChildVisibility(Object child) {
  841. try {
  842. return (Visibility)child;
  843. } catch (ClassCastException cce) {
  844. return null;
  845. }
  846. }
  847. /**
  848. * @return the Serializable (if any) associated with the specified Child
  849. */
  850. protected static final Serializable getChildSerializable(Object child) {
  851. try {
  852. return (Serializable)child;
  853. } catch (ClassCastException cce) {
  854. return null;
  855. }
  856. }
  857. /**
  858. * @return the PropertyChangeListener (if any) of the specified child
  859. */
  860. protected static final PropertyChangeListener getChildPropertyChangeListener(Object child) {
  861. try {
  862. return (PropertyChangeListener)child;
  863. } catch (ClassCastException cce) {
  864. return null;
  865. }
  866. }
  867. /**
  868. * @return the VetoableChangeListener (if any) of the specified child
  869. */
  870. protected static final VetoableChangeListener getChildVetoableChangeListener(Object child) {
  871. try {
  872. return (VetoableChangeListener)child;
  873. } catch (ClassCastException cce) {
  874. return null;
  875. }
  876. }
  877. /**
  878. * @return the BeanContextMembershipListener (if any) of the specified child
  879. */
  880. protected static final BeanContextMembershipListener getChildBeanContextMembershipListener(Object child) {
  881. try {
  882. return (BeanContextMembershipListener)child;
  883. } catch (ClassCastException cce) {
  884. return null;
  885. }
  886. }
  887. /**
  888. * @return the BeanContextChild (if any) of the specified child
  889. * @throw IllegalArgumentException if child implements both BeanContextChild and BeanContextProxy
  890. */
  891. protected static final BeanContextChild getChildBeanContextChild(Object child) {
  892. try {
  893. BeanContextChild bcc = (BeanContextChild)child;
  894. if (child instanceof BeanContextChild && child instanceof BeanContextProxy)
  895. throw new IllegalArgumentException("child cannot implement both BeanContextChild and BeanContextProxy");
  896. else
  897. return bcc;
  898. } catch (ClassCastException cce) {
  899. try {
  900. return ((BeanContextProxy)child).getBeanContextProxy();
  901. } catch (ClassCastException cce1) {
  902. return null;
  903. }
  904. }
  905. }
  906. /**
  907. * Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
  908. */
  909. protected final void fireChildrenAdded(BeanContextMembershipEvent bcme) {
  910. Object[] copy;
  911. synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
  912. for (int i = 0; i < copy.length; i++)
  913. ((BeanContextMembershipListener)copy[i]).childrenAdded(bcme);
  914. }
  915. /**
  916. * Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
  917. */
  918. protected final void fireChildrenRemoved(BeanContextMembershipEvent bcme) {
  919. Object[] copy;
  920. synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
  921. for (int i = 0; i < copy.length; i++)
  922. ((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme);
  923. }
  924. /**
  925. * protected method called from constructor and readObject to initialize
  926. * transient state of BeanContextSupport instance.
  927. *
  928. * This class uses this method to instantiate inner class listeners used
  929. * to monitor PropertyChange and VetoableChange events on children.
  930. *
  931. * subclasses may envelope this method to add their own initialization
  932. * behavior
  933. */
  934. protected synchronized void initialize() {
  935. children = new HashMap(serializable + 1);
  936. bcmListeners = new ArrayList(1);
  937. childPCL = new PropertyChangeListener() {
  938. /*
  939. * this adaptor is used by the BeanContextSupport class to forward
  940. * property changes from a child to the BeanContext, avoiding
  941. * accidential serialization of the BeanContext by a badly
  942. * behaved Serializable child.
  943. */
  944. public void propertyChange(PropertyChangeEvent pce) {
  945. BeanContextSupport.this.propertyChange(pce);
  946. }
  947. };
  948. childVCL = new VetoableChangeListener() {
  949. /*
  950. * this adaptor is used by the BeanContextSupport class to forward
  951. * vetoable changes from a child to the BeanContext, avoiding
  952. * accidential serialization of the BeanContext by a badly
  953. * behaved Serializable child.
  954. */
  955. public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
  956. BeanContextSupport.this.vetoableChange(pce);
  957. }
  958. };
  959. }
  960. /**
  961. * @returns a copy of the current nested children
  962. */
  963. protected final Object[] copyChildren() {
  964. synchronized(children) { return children.keySet().toArray(); }
  965. }
  966. /**
  967. * @return if two class objects, or their names are equal.
  968. */
  969. protected static final boolean classEquals(Class first, Class second) {
  970. return first.equals(second) || first.getName().equals(second.getName());
  971. }
  972. /*
  973. * fields
  974. */
  975. /**
  976. * all accesses to the <code> protected HashMap children </code> field
  977. * shall be synchronized on that object.
  978. */
  979. protected transient HashMap children;
  980. private int serializable = 0; // children serializable
  981. /**
  982. * all accesses to the <code> protected ArrayList bcmListeners </code> field
  983. * shall be synchronized on that object.
  984. */
  985. protected transient ArrayList bcmListeners;
  986. //
  987. protected Locale locale;
  988. protected boolean okToUseGui;
  989. protected boolean designTime;
  990. /*
  991. * transient
  992. */
  993. private transient PropertyChangeListener childPCL;
  994. private transient VetoableChangeListener childVCL;
  995. private transient boolean serializing;
  996. }