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