1. /*
  2. * @(#)BeanContextServicesSupport.java 1.16 00/02/02
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.beans.beancontext;
  11. import java.util.ArrayList;
  12. import java.util.Collection;
  13. import java.util.HashMap;
  14. import java.util.HashSet;
  15. import java.util.Iterator;
  16. import java.util.Map;
  17. import java.util.Map.Entry;
  18. import java.io.IOException;
  19. import java.io.ObjectInputStream;
  20. import java.io.ObjectOutputStream;
  21. import java.io.Serializable;
  22. import java.util.TooManyListenersException;
  23. import java.util.Locale;
  24. /**
  25. * <p>
  26. * This helper class provides a utility implementation of the
  27. * java.beans.beancontext.BeanContextServices interface.
  28. * </p>
  29. * <p>
  30. * Since this class directly implements the BeanContextServices interface,
  31. * the class can, and is intended to be used either by subclassing this
  32. * implementation, or via delegation of an instance of this class
  33. * from another through the BeanContextProxy interface.
  34. * </p>
  35. *
  36. * @author Laurence P. G. Cable
  37. * @version 1.16, 02/02/00
  38. * @since 1.2
  39. */
  40. public class BeanContextServicesSupport extends BeanContextSupport
  41. implements BeanContextServices {
  42. /**
  43. * <p>
  44. * Construct a BeanContextServicesSupport instance
  45. * </p>
  46. *
  47. * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
  48. * @param lcle The current Locale for this BeanContext.
  49. * @param dtime The initial state, true if in design mode, false if runtime.
  50. * @param visible The initial visibility.
  51. *
  52. */
  53. public BeanContextServicesSupport(BeanContextServices peer, Locale lcle, boolean dTime, boolean visible) {
  54. super(peer, lcle, dTime, visible);
  55. }
  56. /**
  57. * Create an instance using the specified Locale and design mode.
  58. *
  59. * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
  60. * @param lcle The current Locale for this BeanContext.
  61. * @param dtime The initial state, true if in design mode, false if runtime.
  62. */
  63. public BeanContextServicesSupport(BeanContextServices peer, Locale lcle, boolean dtime) {
  64. this (peer, lcle, dtime, true);
  65. }
  66. /**
  67. * Create an instance using the specified locale
  68. *
  69. * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
  70. * @param lcle The current Locale for this BeanContext.
  71. */
  72. public BeanContextServicesSupport(BeanContextServices peer, Locale lcle) {
  73. this (peer, lcle, false, true);
  74. }
  75. /**
  76. * Create an instance with a peer
  77. *
  78. * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
  79. */
  80. public BeanContextServicesSupport(BeanContextServices peer) {
  81. this (peer, null, false, true);
  82. }
  83. /**
  84. * Create an instance that is not a delegate of another object
  85. */
  86. public BeanContextServicesSupport() {
  87. this (null, null, false, true);
  88. }
  89. /**
  90. * called by BeanContextSupport superclass during construction and
  91. * deserialization to initialize subclass transient state.
  92. *
  93. * subclasses may envelope this method, but should not override it or
  94. * call it directly.
  95. */
  96. public void initialize() {
  97. super.initialize();
  98. services = new HashMap(serializable + 1);
  99. bcsListeners = new ArrayList(1);
  100. }
  101. /**
  102. * Gets the <tt>BeanContextServices</tt> associated with this
  103. * <tt>BeanContextServicesSupport</tt>.
  104. *
  105. * @return the instance of <tt>BeanContext</tt>
  106. * this object is providing the implementation for.
  107. */
  108. public BeanContextServices getBeanContextServicesPeer() {
  109. return (BeanContextServices)getBeanContextChildPeer();
  110. }
  111. /************************************************************************/
  112. /*
  113. * protected nested class containing per child information, an instance
  114. * of which is associated with each child in the "children" hashtable.
  115. * subclasses can extend this class to include their own per-child state.
  116. *
  117. * Note that this 'value' is serialized with the corresponding child 'key'
  118. * when the BeanContextSupport is serialized.
  119. */
  120. protected class BCSSChild extends BeanContextSupport.BCSChild {
  121. /*
  122. * private nested class to map serviceClass to Provider and requestors
  123. * listeners.
  124. */
  125. class BCSSCServiceClassRef {
  126. // create an instance of a service ref
  127. BCSSCServiceClassRef(Class sc, BeanContextServiceProvider bcsp, boolean delegated) {
  128. super();
  129. serviceClass = sc;
  130. if (delegated)
  131. delegateProvider = bcsp;
  132. else
  133. serviceProvider = bcsp;
  134. }
  135. // add a requestor and assoc listener
  136. void addRequestor(Object requestor, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {
  137. BeanContextServiceRevokedListener cbcsrl = (BeanContextServiceRevokedListener)requestors.get(requestor);
  138. if (cbcsrl != null && !cbcsrl.equals(bcsrl))
  139. throw new TooManyListenersException();
  140. requestors.put(requestor, bcsrl);
  141. }
  142. // remove a requestor
  143. void removeRequestor(Object requestor) {
  144. requestors.remove(requestor);
  145. }
  146. // check a requestors listener
  147. void verifyRequestor(Object requestor, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {
  148. BeanContextServiceRevokedListener cbcsrl = (BeanContextServiceRevokedListener)requestors.get(requestor);
  149. if (cbcsrl != null && !cbcsrl.equals(bcsrl))
  150. throw new TooManyListenersException();
  151. }
  152. void verifyAndMaybeSetProvider(BeanContextServiceProvider bcsp, boolean isDelegated) {
  153. BeanContextServiceProvider current;
  154. if (isDelegated) { // the provider is delegated
  155. current = delegateProvider;
  156. if (current == null || bcsp == null) {
  157. delegateProvider = bcsp;
  158. return;
  159. }
  160. } else { // the provider is registered with this BCS
  161. current = serviceProvider;
  162. if (current == null || bcsp == null) {
  163. serviceProvider = bcsp;
  164. return;
  165. }
  166. }
  167. if (!current.equals(bcsp))
  168. throw new UnsupportedOperationException("existing service reference obtained from different BeanContextServiceProvider not supported");
  169. }
  170. Iterator cloneOfEntries() {
  171. return ((HashMap)requestors.clone()).entrySet().iterator();
  172. }
  173. Iterator entries() { return requestors.entrySet().iterator(); }
  174. boolean isEmpty() { return requestors.isEmpty(); }
  175. Class getServiceClass() { return serviceClass; }
  176. BeanContextServiceProvider getServiceProvider() {
  177. return serviceProvider;
  178. }
  179. BeanContextServiceProvider getDelegateProvider() {
  180. return delegateProvider;
  181. }
  182. boolean isDelegated() { return delegateProvider != null; }
  183. void addRef(boolean delegated) {
  184. if (delegated)
  185. delegateRefs++;
  186. else
  187. serviceRefs++;
  188. }
  189. void releaseRef(boolean delegated) {
  190. if (delegated)
  191. if (--delegateRefs == 0) delegateProvider = null;
  192. else
  193. if (--serviceRefs <= 0) serviceProvider = null;
  194. }
  195. int getRefs() { return serviceRefs + delegateRefs; }
  196. int getDelegateRefs() { return delegateRefs; }
  197. int getServiceRefs() { return serviceRefs; }
  198. /*
  199. * fields
  200. */
  201. Class serviceClass;
  202. BeanContextServiceProvider serviceProvider;
  203. int serviceRefs;
  204. BeanContextServiceProvider delegateProvider; // proxy
  205. int delegateRefs;
  206. HashMap requestors = new HashMap(1);
  207. }
  208. /*
  209. * per service reference info ...
  210. */
  211. class BCSSCServiceRef {
  212. BCSSCServiceRef(BCSSCServiceClassRef scref, boolean isDelegated) {
  213. serviceClassRef = scref;
  214. delegated = isDelegated;
  215. }
  216. void addRef() { refCnt++; }
  217. int release() { return --refCnt; }
  218. BCSSCServiceClassRef getServiceClassRef() { return serviceClassRef; }
  219. boolean isDelegated() { return delegated; }
  220. /*
  221. * fields
  222. */
  223. BCSSCServiceClassRef serviceClassRef;
  224. int refCnt = 1;
  225. boolean delegated = false;
  226. }
  227. BCSSChild(Object bcc, Object peer) { super(bcc, peer); }
  228. // note usage of service per requestor, per service
  229. synchronized void usingService(Object requestor, Object service, Class serviceClass, BeanContextServiceProvider bcsp, boolean isDelegated, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException, UnsupportedOperationException {
  230. // first, process mapping from serviceClass to requestor(s)
  231. BCSSCServiceClassRef serviceClassRef = null;
  232. if (serviceClasses == null)
  233. serviceClasses = new HashMap(1);
  234. else
  235. serviceClassRef = (BCSSCServiceClassRef)serviceClasses.get(serviceClass);
  236. if (serviceClassRef == null) { // new service being used ...
  237. serviceClassRef = new BCSSCServiceClassRef(serviceClass, bcsp, isDelegated);
  238. serviceClasses.put(serviceClass, serviceClassRef);
  239. } else { // existing service ...
  240. serviceClassRef.verifyAndMaybeSetProvider(bcsp, isDelegated); // throws
  241. serviceClassRef.verifyRequestor(requestor, bcsrl); // throws
  242. }
  243. serviceClassRef.addRequestor(requestor, bcsrl);
  244. serviceClassRef.addRef(isDelegated);
  245. // now handle mapping from requestor to service(s)
  246. BCSSCServiceRef serviceRef = null;
  247. Map services = null;
  248. if (serviceRequestors == null) {
  249. serviceRequestors = new HashMap(1);
  250. } else {
  251. services = (Map)serviceRequestors.get(requestor);
  252. }
  253. if (services == null) {
  254. services = new HashMap(1);
  255. serviceRequestors.put(requestor, services);
  256. } else
  257. serviceRef = (BCSSCServiceRef)services.get(service);
  258. if (serviceRef == null) {
  259. serviceRef = new BCSSCServiceRef(serviceClassRef, isDelegated);
  260. services.put(service, serviceRef);
  261. } else {
  262. serviceRef.addRef();
  263. }
  264. }
  265. // release a service reference
  266. synchronized void releaseService(Object requestor, Object service) {
  267. if (serviceRequestors == null) return;
  268. Map services = (Map)serviceRequestors.get(requestor);
  269. if (services == null) return; // oops its not there anymore!
  270. BCSSCServiceRef serviceRef = (BCSSCServiceRef)services.get(service);
  271. if (serviceRef == null) return; // oops its not there anymore!
  272. BCSSCServiceClassRef serviceClassRef = serviceRef.getServiceClassRef();
  273. boolean isDelegated = serviceRef.isDelegated();
  274. BeanContextServiceProvider bcsp = isDelegated ? serviceClassRef.getDelegateProvider() : serviceClassRef.getServiceProvider();
  275. bcsp.releaseService(BeanContextServicesSupport.this.getBeanContextServicesPeer(), requestor, service);
  276. serviceClassRef.releaseRef(isDelegated);
  277. if (serviceRef.release() == 0) {
  278. services.remove(service);
  279. if (services.isEmpty()) {
  280. serviceRequestors.remove(requestor);
  281. serviceClassRef.removeRequestor(requestor);
  282. }
  283. if (serviceRequestors.isEmpty()) {
  284. serviceRequestors = null;
  285. }
  286. if (serviceClassRef.isEmpty()) {
  287. serviceClasses.remove(serviceClassRef.getServiceClass());
  288. }
  289. if (serviceClasses.isEmpty())
  290. serviceClasses = null;
  291. }
  292. }
  293. // revoke a service
  294. synchronized void revokeService(Class serviceClass, boolean isDelegated, boolean revokeNow) {
  295. if (serviceClasses == null) return;
  296. BCSSCServiceClassRef serviceClassRef = (BCSSCServiceClassRef)serviceClasses.get(serviceClass);
  297. if (serviceClassRef == null) return;
  298. Iterator i = serviceClassRef.cloneOfEntries();
  299. BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(BeanContextServicesSupport.this.getBeanContextServicesPeer(), serviceClass, revokeNow);
  300. boolean noMoreRefs = false;
  301. while (i.hasNext()) {
  302. Map.Entry entry = (Map.Entry)i.next();
  303. BeanContextServiceRevokedListener listener = (BeanContextServiceRevokedListener)entry.getValue();
  304. if (revokeNow) {
  305. Object requestor = entry.getKey();
  306. Map services = (Map)serviceRequestors.get(requestor);
  307. if (services != null) {
  308. Iterator i1 = services.entrySet().iterator();
  309. while (i1.hasNext()) {
  310. Map.Entry tmp = (Map.Entry)i1.next();
  311. BCSSCServiceRef serviceRef = (BCSSCServiceRef)tmp.getValue();
  312. if (serviceRef.getServiceClassRef().equals(serviceClassRef) && isDelegated == serviceRef.isDelegated()) {
  313. i1.remove();
  314. }
  315. }
  316. if (noMoreRefs = services.isEmpty()) {
  317. serviceRequestors.remove(requestor);
  318. }
  319. }
  320. if (noMoreRefs) serviceClassRef.removeRequestor(requestor);
  321. }
  322. listener.serviceRevoked(bcsre);
  323. }
  324. if (revokeNow && serviceClasses != null) {
  325. if (serviceClassRef.isEmpty())
  326. serviceClasses.remove(serviceClass);
  327. if (serviceClasses.isEmpty())
  328. serviceClasses = null;
  329. }
  330. if (serviceRequestors != null && serviceRequestors.isEmpty())
  331. serviceRequestors = null;
  332. }
  333. // release all references for this child since it has been unnested.
  334. void cleanupReferences() {
  335. if (serviceRequestors == null) return;
  336. Iterator requestors = serviceRequestors.entrySet().iterator();
  337. while(requestors.hasNext()) {
  338. Map.Entry tmp = (Map.Entry)requestors.next();
  339. Object requestor = tmp.getKey();
  340. Iterator services = ((Map)tmp.getValue()).entrySet().iterator();
  341. requestors.remove();
  342. while (services.hasNext()) {
  343. Map.Entry entry = (Map.Entry)services.next();
  344. Object service = entry.getKey();
  345. BCSSCServiceRef sref = (BCSSCServiceRef)entry.getValue();
  346. BCSSCServiceClassRef scref = sref.getServiceClassRef();
  347. BeanContextServiceProvider bcsp = sref.isDelegated() ? scref.getDelegateProvider() : scref.getServiceProvider();
  348. scref.removeRequestor(requestor);
  349. services.remove();
  350. while (sref.release() >= 0) {
  351. bcsp.releaseService(BeanContextServicesSupport.this.getBeanContextServicesPeer(), requestor, service);
  352. }
  353. }
  354. }
  355. serviceRequestors = null;
  356. serviceClasses = null;
  357. }
  358. void revokeAllDelegatedServicesNow() {
  359. if (serviceClasses == null) return;
  360. Iterator serviceClassRefs =
  361. new HashSet(serviceClasses.values()).iterator();
  362. while (serviceClassRefs.hasNext()) {
  363. BCSSCServiceClassRef serviceClassRef = (BCSSCServiceClassRef)serviceClassRefs.next();
  364. if (!serviceClassRef.isDelegated()) continue;
  365. Iterator i = serviceClassRef.cloneOfEntries();
  366. BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(BeanContextServicesSupport.this.getBeanContextServicesPeer(), serviceClassRef.getServiceClass(), true);
  367. boolean noMoreRefs = false;
  368. while (i.hasNext()) {
  369. Map.Entry entry = (Map.Entry)i.next();
  370. BeanContextServiceRevokedListener listener = (BeanContextServiceRevokedListener)entry.getValue();
  371. Object requestor = entry.getKey();
  372. Map services = (Map)serviceRequestors.get(requestor);
  373. if (services != null) {
  374. Iterator i1 = services.entrySet().iterator();
  375. while (i1.hasNext()) {
  376. Map.Entry tmp = (Map.Entry)i1.next();
  377. BCSSCServiceRef serviceRef = (BCSSCServiceRef)tmp.getValue();
  378. if (serviceRef.getServiceClassRef().equals(serviceClassRef) && serviceRef.isDelegated()) {
  379. i1.remove();
  380. }
  381. }
  382. if (noMoreRefs = services.isEmpty()) {
  383. serviceRequestors.remove(requestor);
  384. }
  385. }
  386. if (noMoreRefs) serviceClassRef.removeRequestor(requestor);
  387. listener.serviceRevoked(bcsre);
  388. if (serviceClassRef.isEmpty())
  389. serviceClasses.remove(serviceClassRef.getServiceClass());
  390. }
  391. }
  392. if (serviceClasses.isEmpty()) serviceClasses = null;
  393. if (serviceRequestors != null && serviceRequestors.isEmpty())
  394. serviceRequestors = null;
  395. }
  396. /*
  397. * fields
  398. */
  399. private transient HashMap serviceClasses;
  400. private transient HashMap serviceRequestors;
  401. }
  402. /**
  403. * <p>
  404. * Subclasses can override this method to insert their own subclass
  405. * of Child without having to override add() or the other Collection
  406. * methods that add children to the set.
  407. * </p>
  408. *
  409. * @param targetChild the child to create the Child on behalf of
  410. * @param peer the peer if the targetChild and peer are related by BeanContextProxy
  411. */
  412. protected BCSChild createBCSChild(Object targetChild, Object peer) {
  413. return new BCSSChild(targetChild, peer);
  414. }
  415. /************************************************************************/
  416. /**
  417. * subclasses may subclass this nested class to add behaviors for
  418. * each BeanContextServicesProvider.
  419. */
  420. protected static class BCSSServiceProvider implements Serializable {
  421. BCSSServiceProvider(Class sc, BeanContextServiceProvider bcsp) {
  422. super();
  423. serviceProvider = bcsp;
  424. }
  425. protected BeanContextServiceProvider getServiceProvider() {
  426. return serviceProvider;
  427. }
  428. /*
  429. * fields
  430. */
  431. protected BeanContextServiceProvider serviceProvider;
  432. }
  433. /**
  434. * subclasses can override this method to create new subclasses of
  435. * BCSSServiceProvider without having to overrride addService() in
  436. * order to instantiate.
  437. */
  438. protected BCSSServiceProvider createBCSSServiceProvider(Class sc, BeanContextServiceProvider bcsp) {
  439. return new BCSSServiceProvider(sc, bcsp);
  440. }
  441. /************************************************************************/
  442. /**
  443. * add a BeanContextServicesListener
  444. *
  445. * @throw new NullPointerException
  446. */
  447. public void addBeanContextServicesListener(BeanContextServicesListener bcsl) {
  448. if (bcsl == null) throw new NullPointerException("bcsl");
  449. synchronized(bcsListeners) {
  450. if (bcsListeners.contains(bcsl))
  451. return;
  452. else
  453. bcsListeners.add(bcsl);
  454. }
  455. }
  456. /**
  457. * remove a BeanContextServicesListener
  458. */
  459. public void removeBeanContextServicesListener(BeanContextServicesListener bcsl) {
  460. if (bcsl == null) throw new NullPointerException("bcsl");
  461. synchronized(bcsListeners) {
  462. if (!bcsListeners.contains(bcsl))
  463. return;
  464. else
  465. bcsListeners.remove(bcsl);
  466. }
  467. }
  468. /**
  469. * add a service
  470. */
  471. public boolean addService(Class serviceClass, BeanContextServiceProvider bcsp) {
  472. return addService(serviceClass, bcsp, true);
  473. }
  474. /**
  475. * add a service
  476. */
  477. protected boolean addService(Class serviceClass, BeanContextServiceProvider bcsp, boolean fireEvent) {
  478. if (serviceClass == null) throw new NullPointerException("serviceClass");
  479. if (bcsp == null) throw new NullPointerException("bcsp");
  480. synchronized(BeanContext.globalHierarchyLock) {
  481. if (services.containsKey(serviceClass))
  482. return false;
  483. else {
  484. services.put(serviceClass, createBCSSServiceProvider(serviceClass, bcsp));
  485. if (bcsp instanceof Serializable) serializable++;
  486. if (!fireEvent) return true;
  487. BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent(getBeanContextServicesPeer(), serviceClass);
  488. fireServiceAdded(bcssae);
  489. synchronized(children) {
  490. Iterator i = children.keySet().iterator();
  491. while (i.hasNext()) {
  492. Object c = i.next();
  493. if (c instanceof BeanContextServices) {
  494. ((BeanContextServicesListener)c).serviceAvailable(bcssae);
  495. }
  496. }
  497. }
  498. return true;
  499. }
  500. }
  501. }
  502. /**
  503. * remove a service
  504. */
  505. public void revokeService(Class serviceClass, BeanContextServiceProvider bcsp, boolean revokeCurrentServicesNow) {
  506. if (serviceClass == null) throw new NullPointerException("serviceClass");
  507. if (bcsp == null) throw new NullPointerException("bcsp");
  508. synchronized(BeanContext.globalHierarchyLock) {
  509. if (!services.containsKey(serviceClass)) return;
  510. BCSSServiceProvider bcsssp = (BCSSServiceProvider)services.get(serviceClass);
  511. if (!bcsssp.getServiceProvider().equals(bcsp))
  512. throw new IllegalArgumentException("service provider mismatch");
  513. services.remove(serviceClass);
  514. if (bcsp instanceof Serializable) serializable--;
  515. Iterator i = bcsChildren(); // get the BCSChild values.
  516. while (i.hasNext()) {
  517. ((BCSSChild)i.next()).revokeService(serviceClass, false, revokeCurrentServicesNow);
  518. }
  519. fireServiceRevoked(serviceClass, revokeCurrentServicesNow);
  520. }
  521. }
  522. /**
  523. * has a service, which may be delegated
  524. */
  525. public synchronized boolean hasService(Class serviceClass) {
  526. if (serviceClass == null) throw new NullPointerException("serviceClass");
  527. synchronized(BeanContext.globalHierarchyLock) {
  528. if (services.containsKey(serviceClass)) return true;
  529. BeanContextServices bcs = null;
  530. try {
  531. bcs = (BeanContextServices)getBeanContext();
  532. } catch (ClassCastException cce) {
  533. return false;
  534. }
  535. return bcs == null ? false : bcs.hasService(serviceClass);
  536. }
  537. }
  538. /************************************************************************/
  539. /*
  540. * a nested subclass used to represent a proxy for serviceClasses delegated
  541. * to an enclosing BeanContext.
  542. */
  543. protected class BCSSProxyServiceProvider implements BeanContextServiceProvider, BeanContextServiceRevokedListener {
  544. BCSSProxyServiceProvider(BeanContextServices bcs) {
  545. super();
  546. nestingCtxt = bcs;
  547. }
  548. public Object getService(BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector) {
  549. Object service = null;
  550. try {
  551. service = nestingCtxt.getService(bcs, requestor, serviceClass, serviceSelector, this);
  552. } catch (TooManyListenersException tmle) {
  553. return null;
  554. }
  555. return service;
  556. }
  557. public void releaseService(BeanContextServices bcs, Object requestor, Object service) {
  558. nestingCtxt.releaseService(bcs, requestor, service);
  559. }
  560. public Iterator getCurrentServiceSelectors(BeanContextServices bcs, Class serviceClass) {
  561. return nestingCtxt.getCurrentServiceSelectors(serviceClass);
  562. }
  563. public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) {
  564. Iterator i = bcsChildren(); // get the BCSChild values.
  565. while (i.hasNext()) {
  566. ((BCSSChild)i.next()).revokeService(bcsre.getServiceClass(), true, bcsre.isCurrentServiceInvalidNow());
  567. }
  568. }
  569. /*
  570. * fields
  571. */
  572. private BeanContextServices nestingCtxt;
  573. }
  574. /************************************************************************/
  575. /**
  576. * obtain a service which may be delegated
  577. */
  578. public Object getService(BeanContextChild child, Object requestor, Class serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {
  579. if (child == null) throw new NullPointerException("child");
  580. if (serviceClass == null) throw new NullPointerException("serviceClass");
  581. if (requestor == null) throw new NullPointerException("requestor");
  582. if (bcsrl == null) throw new NullPointerException("bcsrl");
  583. Object service = null;
  584. BCSSChild bcsc;
  585. BeanContextServices bcssp = getBeanContextServicesPeer();
  586. synchronized(BeanContext.globalHierarchyLock) {
  587. synchronized(children) { bcsc = (BCSSChild)children.get(child); }
  588. if (bcsc == null) throw new IllegalArgumentException("not a child of this context"); // not a child ...
  589. BCSSServiceProvider bcsssp = (BCSSServiceProvider)services.get(serviceClass);
  590. if (bcsssp != null) {
  591. BeanContextServiceProvider bcsp = bcsssp.getServiceProvider();
  592. service = bcsp.getService(bcssp, requestor, serviceClass, serviceSelector);
  593. if (service != null) { // do bookkeeping ...
  594. try {
  595. bcsc.usingService(requestor, service, serviceClass, bcsp, false, bcsrl);
  596. } catch (TooManyListenersException tmle) {
  597. bcsp.releaseService(bcssp, requestor, service);
  598. throw tmle;
  599. } catch (UnsupportedOperationException uope) {
  600. bcsp.releaseService(bcssp, requestor, service);
  601. throw uope; // unchecked rt exception
  602. }
  603. return service;
  604. }
  605. }
  606. if (proxy != null) {
  607. // try to delegate ...
  608. service = proxy.getService(bcssp, requestor, serviceClass, serviceSelector);
  609. if (service != null) { // do bookkeeping ...
  610. try {
  611. bcsc.usingService(requestor, service, serviceClass, proxy, true, bcsrl);
  612. } catch (TooManyListenersException tmle) {
  613. proxy.releaseService(bcssp, requestor, service);
  614. throw tmle;
  615. } catch (UnsupportedOperationException uope) {
  616. proxy.releaseService(bcssp, requestor, service);
  617. throw uope; // unchecked rt exception
  618. }
  619. return service;
  620. }
  621. }
  622. }
  623. return null;
  624. }
  625. /**
  626. * release a service
  627. */
  628. public void releaseService(BeanContextChild child, Object requestor, Object service) {
  629. if (child == null) throw new NullPointerException("child");
  630. if (requestor == null) throw new NullPointerException("requestor");
  631. if (service == null) throw new NullPointerException("service");
  632. BCSSChild bcsc;
  633. synchronized(BeanContext.globalHierarchyLock) {
  634. synchronized(children) { bcsc = (BCSSChild)children.get(child); }
  635. if (bcsc != null)
  636. bcsc.releaseService(requestor, service);
  637. else
  638. throw new IllegalArgumentException("child actual is not a child of this BeanContext");
  639. }
  640. }
  641. /**
  642. * @return an iterator for all the currently registered service classes.
  643. */
  644. public Iterator getCurrentServiceClasses() {
  645. return new BCSIterator(services.keySet().iterator());
  646. }
  647. /**
  648. * @return an iterator for all the currently available service selectors
  649. * (if any) available for the specified service.
  650. */
  651. public Iterator getCurrentServiceSelectors(Class serviceClass) {
  652. BCSSServiceProvider bcsssp = (BCSSServiceProvider)services.get(serviceClass);
  653. return bcsssp != null ? new BCSIterator(bcsssp.getServiceProvider().getCurrentServiceSelectors(getBeanContextServicesPeer(), serviceClass)) : null;
  654. }
  655. /**
  656. * BeanContextServicesListener callback, propagates event to all
  657. * currently registered listeners and BeanContextServices children,
  658. * if this BeanContextService does not already implement this service
  659. * itself.
  660. *
  661. * subclasses may override or envelope this method to implement their
  662. * own propagation semantics.
  663. */
  664. public void serviceAvailable(BeanContextServiceAvailableEvent bcssae) {
  665. synchronized(BeanContext.globalHierarchyLock) {
  666. if (services.containsKey(bcssae.getServiceClass())) return;
  667. fireServiceAdded(bcssae);
  668. Iterator i;
  669. synchronized(children) {
  670. i = children.keySet().iterator();
  671. }
  672. while (i.hasNext()) {
  673. Object c = i.next();
  674. if (c instanceof BeanContextServices) {
  675. ((BeanContextServicesListener)c).serviceAvailable(bcssae);
  676. }
  677. }
  678. }
  679. }
  680. /**
  681. * BeanContextServicesListener callback, propagates event to all
  682. * currently registered listeners and BeanContextServices children,
  683. * if this BeanContextService does not already implement this service
  684. * itself.
  685. *
  686. * subclasses may override or envelope this method to implement their
  687. * own propagation semantics.
  688. */
  689. public void serviceRevoked(BeanContextServiceRevokedEvent bcssre) {
  690. synchronized(BeanContext.globalHierarchyLock) {
  691. if (services.containsKey(bcssre.getServiceClass())) return;
  692. fireServiceRevoked(bcssre);
  693. Iterator i;
  694. synchronized(children) {
  695. i = children.keySet().iterator();
  696. }
  697. while (i.hasNext()) {
  698. Object c = i.next();
  699. if (c instanceof BeanContextServices) {
  700. ((BeanContextServicesListener)c).serviceRevoked(bcssre);
  701. }
  702. }
  703. }
  704. }
  705. /**
  706. * Gets the <tt>BeanContextServicesListener</tt> (if any) of the specified
  707. * child.
  708. *
  709. * @param child the specified child
  710. * @return the BeanContextServicesListener (if any) of the specified child
  711. */
  712. protected static final BeanContextServicesListener getChildBeanContextServicesListener(Object child) {
  713. try {
  714. return (BeanContextServicesListener)child;
  715. } catch (ClassCastException cce) {
  716. return null;
  717. }
  718. }
  719. /**
  720. * called from superclass child removal operations after a child
  721. * has been successfully removed. called with child synchronized.
  722. *
  723. * This subclass uses this hook to immediately revoke any services
  724. * being used by this child if it is a BeanContextChild.
  725. *
  726. * subclasses may envelope this method in order to implement their
  727. * own child removal side-effects.
  728. */
  729. protected void childJustRemovedHook(Object child, BCSChild bcsc) {
  730. BCSSChild bcssc = (BCSSChild)bcsc;
  731. bcssc.cleanupReferences();
  732. }
  733. /**
  734. * called from setBeanContext to notify a BeanContextChild
  735. * to release resources obtained from the nesting BeanContext.
  736. *
  737. * This method revokes any services obtained from its parent.
  738. *
  739. * subclasses may envelope this method to implement their own semantics.
  740. */
  741. protected synchronized void releaseBeanContextResources() {
  742. Object[] bcssc;
  743. super.releaseBeanContextResources();
  744. synchronized(children) {
  745. if (children.isEmpty()) return;
  746. bcssc = children.values().toArray();
  747. }
  748. for (int i = 0; i < bcssc.length; i++) {
  749. ((BCSSChild)bcssc[i]).revokeAllDelegatedServicesNow();
  750. }
  751. proxy = null;
  752. }
  753. /**
  754. * called from setBeanContext to notify a BeanContextChild
  755. * to allocate resources obtained from the nesting BeanContext.
  756. *
  757. * subclasses may envelope this method to implement their own semantics.
  758. */
  759. protected synchronized void initializeBeanContextResources() {
  760. super.initializeBeanContextResources();
  761. BeanContext nbc = getBeanContext();
  762. if (nbc == null) return;
  763. try {
  764. BeanContextServices bcs = (BeanContextServices)nbc;
  765. proxy = new BCSSProxyServiceProvider(bcs);
  766. } catch (ClassCastException cce) {
  767. // do nothing ...
  768. }
  769. }
  770. /**
  771. * Fires a <tt>BeanContextServiceEvent</tt> notifying of a new service.
  772. */
  773. protected final void fireServiceAdded(Class serviceClass) {
  774. BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent(getBeanContextServicesPeer(), serviceClass);
  775. fireServiceAdded(bcssae);
  776. }
  777. /**
  778. * Fires a <tt>BeanContextServiceAvailableEvent</tt> indicating that a new
  779. * service has become available.
  780. *
  781. * @param bcssae the <tt>BeanContextServiceAvailableEvent</tt>
  782. */
  783. protected final void fireServiceAdded(BeanContextServiceAvailableEvent bcssae) {
  784. Object[] copy;
  785. synchronized (bcsListeners) { copy = bcsListeners.toArray(); }
  786. for (int i = 0; i < copy.length; i++) {
  787. ((BeanContextServicesListener)copy[i]).serviceAvailable(bcssae);
  788. }
  789. }
  790. /**
  791. * Fires a <tt>BeanContextServiceEvent</tt> notifying of a service being revoked.
  792. *
  793. * @param bcsre the <tt>BeanContextServiceRevokedEvent</tt>
  794. */
  795. protected final void fireServiceRevoked(BeanContextServiceRevokedEvent bcsre) {
  796. Object[] copy;
  797. synchronized (bcsListeners) { copy = bcsListeners.toArray(); }
  798. for (int i = 0; i < copy.length; i++) {
  799. ((BeanContextServiceRevokedListener)copy[i]).serviceRevoked(bcsre);
  800. }
  801. }
  802. /**
  803. * Fires a <tt>BeanContextServiceRevokedEvent</tt>
  804. * indicating that a particular service is
  805. * no longer available.
  806. */
  807. protected final void fireServiceRevoked(Class serviceClass, boolean revokeNow) {
  808. Object[] copy;
  809. BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(getBeanContextServicesPeer(), serviceClass, revokeNow);
  810. synchronized (bcsListeners) { copy = bcsListeners.toArray(); }
  811. for (int i = 0; i < copy.length; i++) {
  812. ((BeanContextServicesListener)copy[i]).serviceRevoked(bcsre);
  813. }
  814. }
  815. /**
  816. * called from BeanContextSupport writeObject before it serializes the
  817. * children ...
  818. *
  819. * This class will serialize any Serializable BeanContextServiceProviders
  820. * herein.
  821. *
  822. * subclasses may envelope this method to insert their own serialization
  823. * processing that has to occur prior to serialization of the children
  824. */
  825. protected synchronized void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {
  826. oos.writeInt(serializable);
  827. if (serializable <= 0) return;
  828. int count = 0;
  829. Iterator i = services.entrySet().iterator();
  830. while (i.hasNext() && count < serializable) {
  831. Map.Entry entry = (Map.Entry)i.next();
  832. BCSSServiceProvider bcsp = null;
  833. try {
  834. bcsp = (BCSSServiceProvider)entry.getValue();
  835. } catch (ClassCastException cce) {
  836. continue;
  837. }
  838. if (bcsp.getServiceProvider() instanceof Serializable) {
  839. oos.writeObject(entry.getKey());
  840. oos.writeObject(bcsp);
  841. count++;
  842. }
  843. }
  844. if (count != serializable)
  845. throw new IOException("wrote different number of service providers than expected");
  846. }
  847. /**
  848. * called from BeanContextSupport readObject before it deserializes the
  849. * children ...
  850. *
  851. * This class will deserialize any Serializable BeanContextServiceProviders
  852. * serialized earlier thus making them available to the children when they
  853. * deserialized.
  854. *
  855. * subclasses may envelope this method to insert their own serialization
  856. * processing that has to occur prior to serialization of the children
  857. */
  858. protected synchronized void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  859. serializable = ois.readInt();
  860. int count = serializable;
  861. while (count > 0) {
  862. services.put(ois.readObject(), ois.readObject());
  863. count--;
  864. }
  865. }
  866. /**
  867. * serialize the instance
  868. */
  869. private synchronized void writeObject(ObjectOutputStream oos) throws IOException {
  870. oos.defaultWriteObject();
  871. serialize(oos, (Collection)bcsListeners);
  872. }
  873. /**
  874. * deserialize the instance
  875. */
  876. private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
  877. ois.defaultReadObject();
  878. deserialize(ois, (Collection)bcsListeners);
  879. }
  880. /*
  881. * fields
  882. */
  883. /**
  884. * all accesses to the <code> protected transient HashMap services </code>
  885. * field should be synchronized on that object
  886. */
  887. protected transient HashMap services;
  888. /**
  889. * The number of instances of a serializable <tt>BeanContextServceProvider</tt>.
  890. */
  891. protected transient int serializable = 0;
  892. /**
  893. * Delegate for the <tt>BeanContextServiceProvider</tt>.
  894. */
  895. protected transient BCSSProxyServiceProvider proxy;
  896. /**
  897. * List of <tt>BeanContextServicesListener</tt> objects.
  898. */
  899. protected transient ArrayList bcsListeners;
  900. }