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