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