Path: blob/master/src/java.desktop/share/classes/java/beans/beancontext/BeanContextServicesSupport.java
41159 views
/*1* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.beans.beancontext;2627import java.io.IOException;28import java.io.ObjectInputStream;29import java.io.ObjectOutputStream;30import java.io.Serial;31import java.io.Serializable;32import java.util.ArrayList;33import java.util.Collection;34import java.util.HashMap;35import java.util.HashSet;36import java.util.Iterator;37import java.util.Locale;38import java.util.Map;39import java.util.TooManyListenersException;4041/**42* <p>43* This helper class provides a utility implementation of the44* java.beans.beancontext.BeanContextServices interface.45* </p>46* <p>47* Since this class directly implements the BeanContextServices interface,48* the class can, and is intended to be used either by subclassing this49* implementation, or via delegation of an instance of this class50* from another through the BeanContextProxy interface.51* </p>52*53* @author Laurence P. G. Cable54* @since 1.255*/5657public class BeanContextServicesSupport extends BeanContextSupport58implements BeanContextServices {5960/**61* Use serialVersionUID from JDK 1.7 for interoperability.62*/63@Serial64private static final long serialVersionUID = -8494482757288719206L;6566/**67* <p>68* Construct a BeanContextServicesSupport instance69* </p>70*71* @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer72* @param lcle The current Locale for this BeanContext.73* @param dTime The initial state, true if in design mode, false if runtime.74* @param visible The initial visibility.75*76*/7778public BeanContextServicesSupport(BeanContextServices peer, Locale lcle, boolean dTime, boolean visible) {79super(peer, lcle, dTime, visible);80}8182/**83* Create an instance using the specified Locale and design mode.84*85* @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer86* @param lcle The current Locale for this BeanContext.87* @param dtime The initial state, true if in design mode, false if runtime.88*/8990public BeanContextServicesSupport(BeanContextServices peer, Locale lcle, boolean dtime) {91this (peer, lcle, dtime, true);92}9394/**95* Create an instance using the specified locale96*97* @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer98* @param lcle The current Locale for this BeanContext.99*/100101public BeanContextServicesSupport(BeanContextServices peer, Locale lcle) {102this (peer, lcle, false, true);103}104105/**106* Create an instance with a peer107*108* @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer109*/110111public BeanContextServicesSupport(BeanContextServices peer) {112this (peer, null, false, true);113}114115/**116* Create an instance that is not a delegate of another object117*/118119public BeanContextServicesSupport() {120this (null, null, false, true);121}122123/**124* called by BeanContextSupport superclass during construction and125* deserialization to initialize subclass transient state.126*127* subclasses may envelope this method, but should not override it or128* call it directly.129*/130131public void initialize() {132super.initialize();133services = new HashMap<>(serializable + 1);134bcsListeners = new ArrayList<>(1);135}136137/**138* Gets the {@code BeanContextServices} associated with this139* {@code BeanContextServicesSupport}.140*141* @return the instance of {@code BeanContext}142* this object is providing the implementation for.143*/144public BeanContextServices getBeanContextServicesPeer() {145return (BeanContextServices)getBeanContextChildPeer();146}147148/************************************************************************/149150/*151* protected nested class containing per child information, an instance152* of which is associated with each child in the "children" hashtable.153* subclasses can extend this class to include their own per-child state.154*155* Note that this 'value' is serialized with the corresponding child 'key'156* when the BeanContextSupport is serialized.157*/158159protected class BCSSChild extends BeanContextSupport.BCSChild {160161/**162* Use serialVersionUID from JDK 1.7 for interoperability.163*/164@Serial165private static final long serialVersionUID = -3263851306889194873L;166167/*168* private nested class to map serviceClass to Provider and requestors169* listeners.170*/171172class BCSSCServiceClassRef {173174// create an instance of a service ref175176BCSSCServiceClassRef(Class<?> sc, BeanContextServiceProvider bcsp, boolean delegated) {177super();178179serviceClass = sc;180181if (delegated)182delegateProvider = bcsp;183else184serviceProvider = bcsp;185}186187// add a requestor and assoc listener188189void addRequestor(Object requestor, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {190BeanContextServiceRevokedListener cbcsrl = requestors.get(requestor);191192if (cbcsrl != null && !cbcsrl.equals(bcsrl))193throw new TooManyListenersException();194195requestors.put(requestor, bcsrl);196}197198// remove a requestor199200void removeRequestor(Object requestor) {201requestors.remove(requestor);202}203204// check a requestors listener205206void verifyRequestor(Object requestor, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {207BeanContextServiceRevokedListener cbcsrl = requestors.get(requestor);208209if (cbcsrl != null && !cbcsrl.equals(bcsrl))210throw new TooManyListenersException();211}212213void verifyAndMaybeSetProvider(BeanContextServiceProvider bcsp, boolean isDelegated) {214BeanContextServiceProvider current;215216if (isDelegated) { // the provider is delegated217current = delegateProvider;218219if (current == null || bcsp == null) {220delegateProvider = bcsp;221return;222}223} else { // the provider is registered with this BCS224current = serviceProvider;225226if (current == null || bcsp == null) {227serviceProvider = bcsp;228return;229}230}231232if (!current.equals(bcsp))233throw new UnsupportedOperationException("existing service reference obtained from different BeanContextServiceProvider not supported");234235}236237@SuppressWarnings("unchecked") // Cast from clone238Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> cloneOfEntries() {239return ((HashMap<Object, BeanContextServiceRevokedListener>)requestors.clone()).entrySet().iterator();240}241242Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> entries() {243return requestors.entrySet().iterator();244}245246boolean isEmpty() { return requestors.isEmpty(); }247248Class<?> getServiceClass() { return serviceClass; }249250BeanContextServiceProvider getServiceProvider() {251return serviceProvider;252}253254BeanContextServiceProvider getDelegateProvider() {255return delegateProvider;256}257258boolean isDelegated() { return delegateProvider != null; }259260void addRef(boolean delegated) {261if (delegated) {262delegateRefs++;263} else {264serviceRefs++;265}266}267268269void releaseRef(boolean delegated) {270if (delegated) {271if (--delegateRefs == 0) {272delegateProvider = null;273}274} else {275if (--serviceRefs <= 0) {276serviceProvider = null;277}278}279}280281int getRefs() { return serviceRefs + delegateRefs; }282283int getDelegateRefs() { return delegateRefs; }284285int getServiceRefs() { return serviceRefs; }286287/*288* fields289*/290291Class<?> serviceClass;292293BeanContextServiceProvider serviceProvider;294int serviceRefs;295296BeanContextServiceProvider delegateProvider; // proxy297int delegateRefs;298299HashMap<Object, BeanContextServiceRevokedListener> requestors = new HashMap<>(1);300}301302/*303* per service reference info ...304*/305306class BCSSCServiceRef {307BCSSCServiceRef(BCSSCServiceClassRef scref, boolean isDelegated) {308serviceClassRef = scref;309delegated = isDelegated;310}311312void addRef() { refCnt++; }313int release() { return --refCnt; }314315BCSSCServiceClassRef getServiceClassRef() { return serviceClassRef; }316317boolean isDelegated() { return delegated; }318319/*320* fields321*/322323BCSSCServiceClassRef serviceClassRef;324int refCnt = 1;325boolean delegated = false;326}327328BCSSChild(Object bcc, Object peer) { super(bcc, peer); }329330// note usage of service per requestor, per service331332synchronized void usingService(Object requestor, Object service, Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean isDelegated, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException, UnsupportedOperationException {333334// first, process mapping from serviceClass to requestor(s)335336BCSSCServiceClassRef serviceClassRef = null;337338if (serviceClasses == null)339serviceClasses = new HashMap<>(1);340else341serviceClassRef = serviceClasses.get(serviceClass);342343if (serviceClassRef == null) { // new service being used ...344serviceClassRef = new BCSSCServiceClassRef(serviceClass, bcsp, isDelegated);345serviceClasses.put(serviceClass, serviceClassRef);346347} else { // existing service ...348serviceClassRef.verifyAndMaybeSetProvider(bcsp, isDelegated); // throws349serviceClassRef.verifyRequestor(requestor, bcsrl); // throws350}351352serviceClassRef.addRequestor(requestor, bcsrl);353serviceClassRef.addRef(isDelegated);354355// now handle mapping from requestor to service(s)356357BCSSCServiceRef serviceRef = null;358Map<Object , BCSSCServiceRef> services = null;359360if (serviceRequestors == null) {361serviceRequestors = new HashMap<>(1);362} else {363services = serviceRequestors.get(requestor);364}365366if (services == null) {367services = new HashMap<>(1);368369serviceRequestors.put(requestor, services);370} else371serviceRef = services.get(service);372373if (serviceRef == null) {374serviceRef = new BCSSCServiceRef(serviceClassRef, isDelegated);375376services.put(service, serviceRef);377} else {378serviceRef.addRef();379}380}381382// release a service reference383384synchronized void releaseService(Object requestor, Object service) {385if (serviceRequestors == null) return;386387Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor);388389if (services == null) return; // oops its not there anymore!390391BCSSCServiceRef serviceRef = services.get(service);392393if (serviceRef == null) return; // oops its not there anymore!394395BCSSCServiceClassRef serviceClassRef = serviceRef.getServiceClassRef();396boolean isDelegated = serviceRef.isDelegated();397BeanContextServiceProvider bcsp = isDelegated ? serviceClassRef.getDelegateProvider() : serviceClassRef.getServiceProvider();398399bcsp.releaseService(BeanContextServicesSupport.this.getBeanContextServicesPeer(), requestor, service);400401serviceClassRef.releaseRef(isDelegated);402serviceClassRef.removeRequestor(requestor);403404if (serviceRef.release() == 0) {405406services.remove(service);407408if (services.isEmpty()) {409serviceRequestors.remove(requestor);410serviceClassRef.removeRequestor(requestor);411}412413if (serviceRequestors.isEmpty()) {414serviceRequestors = null;415}416417if (serviceClassRef.isEmpty()) {418serviceClasses.remove(serviceClassRef.getServiceClass());419}420421if (serviceClasses.isEmpty())422serviceClasses = null;423}424}425426// revoke a service427428synchronized void revokeService(Class<?> serviceClass, boolean isDelegated, boolean revokeNow) {429if (serviceClasses == null) return;430431BCSSCServiceClassRef serviceClassRef = serviceClasses.get(serviceClass);432433if (serviceClassRef == null) return;434435Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> i = serviceClassRef.cloneOfEntries();436437BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(BeanContextServicesSupport.this.getBeanContextServicesPeer(), serviceClass, revokeNow);438boolean noMoreRefs = false;439440while (i.hasNext() && serviceRequestors != null) {441Map.Entry<Object,BeanContextServiceRevokedListener> entry = i.next();442BeanContextServiceRevokedListener listener = entry.getValue();443444if (revokeNow) {445Object requestor = entry.getKey();446Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor);447448if (services != null) {449Iterator<Map.Entry<Object, BCSSCServiceRef>> i1 = services.entrySet().iterator();450451while (i1.hasNext()) {452Map.Entry<Object, BCSSCServiceRef> tmp = i1.next();453454BCSSCServiceRef serviceRef = tmp.getValue();455if (serviceRef.getServiceClassRef().equals(serviceClassRef) && isDelegated == serviceRef.isDelegated()) {456i1.remove();457}458}459460if (noMoreRefs = services.isEmpty()) {461serviceRequestors.remove(requestor);462}463}464465if (noMoreRefs) serviceClassRef.removeRequestor(requestor);466}467468listener.serviceRevoked(bcsre);469}470471if (revokeNow && serviceClasses != null) {472if (serviceClassRef.isEmpty())473serviceClasses.remove(serviceClass);474475if (serviceClasses.isEmpty())476serviceClasses = null;477}478479if (serviceRequestors != null && serviceRequestors.isEmpty())480serviceRequestors = null;481}482483// release all references for this child since it has been unnested.484485void cleanupReferences() {486487if (serviceRequestors == null) return;488489Iterator<Map.Entry<Object, Map<Object, BCSSCServiceRef>>> requestors = serviceRequestors.entrySet().iterator();490491while(requestors.hasNext()) {492Map.Entry<Object, Map<Object, BCSSCServiceRef>> tmp = requestors.next();493Object requestor = tmp.getKey();494Iterator<Map.Entry<Object, BCSSCServiceRef>> services = tmp.getValue().entrySet().iterator();495496requestors.remove();497498while (services.hasNext()) {499Map.Entry<Object, BCSSCServiceRef> entry = services.next();500Object service = entry.getKey();501BCSSCServiceRef sref = entry.getValue();502503BCSSCServiceClassRef scref = sref.getServiceClassRef();504505BeanContextServiceProvider bcsp = sref.isDelegated() ? scref.getDelegateProvider() : scref.getServiceProvider();506507scref.removeRequestor(requestor);508services.remove();509510while (sref.release() >= 0) {511bcsp.releaseService(BeanContextServicesSupport.this.getBeanContextServicesPeer(), requestor, service);512}513}514}515516serviceRequestors = null;517serviceClasses = null;518}519520void revokeAllDelegatedServicesNow() {521if (serviceClasses == null) return;522523for (BCSSCServiceClassRef serviceClassRef : new HashSet<>(serviceClasses.values())) {524if (!serviceClassRef.isDelegated()) continue;525526Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> i = serviceClassRef.cloneOfEntries();527BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(BeanContextServicesSupport.this.getBeanContextServicesPeer(), serviceClassRef.getServiceClass(), true);528boolean noMoreRefs = false;529530while (i.hasNext()) {531Map.Entry<Object, BeanContextServiceRevokedListener> entry = i.next();532BeanContextServiceRevokedListener listener = entry.getValue();533534Object requestor = entry.getKey();535Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor);536537if (services != null) {538Iterator<Map.Entry<Object, BCSSCServiceRef>> i1 = services.entrySet().iterator();539540while (i1.hasNext()) {541Map.Entry<Object, BCSSCServiceRef> tmp = i1.next();542543BCSSCServiceRef serviceRef = tmp.getValue();544if (serviceRef.getServiceClassRef().equals(serviceClassRef) && serviceRef.isDelegated()) {545i1.remove();546}547}548549if (noMoreRefs = services.isEmpty()) {550serviceRequestors.remove(requestor);551}552}553554if (noMoreRefs) serviceClassRef.removeRequestor(requestor);555556listener.serviceRevoked(bcsre);557558if (serviceClassRef.isEmpty())559serviceClasses.remove(serviceClassRef.getServiceClass());560}561}562563if (serviceClasses.isEmpty()) serviceClasses = null;564565if (serviceRequestors != null && serviceRequestors.isEmpty())566serviceRequestors = null;567}568569/*570* fields571*/572573private transient HashMap<Class<?>, BCSSCServiceClassRef> serviceClasses;574private transient HashMap<Object, Map<Object, BeanContextServicesSupport.BCSSChild.BCSSCServiceRef>> serviceRequestors;575}576577/**578* <p>579* Subclasses can override this method to insert their own subclass580* of Child without having to override add() or the other Collection581* methods that add children to the set.582* </p>583*584* @param targetChild the child to create the Child on behalf of585* @param peer the peer if the targetChild and peer are related by BeanContextProxy586*/587588protected BCSChild createBCSChild(Object targetChild, Object peer) {589return new BCSSChild(targetChild, peer);590}591592/************************************************************************/593594/**595* subclasses may subclass this nested class to add behaviors for596* each BeanContextServicesProvider.597*/598599protected static class BCSSServiceProvider implements Serializable {600601/**602* Use serialVersionUID from JDK 1.7 for interoperability.603*/604@Serial605private static final long serialVersionUID = 861278251667444782L;606607BCSSServiceProvider(Class<?> sc, BeanContextServiceProvider bcsp) {608super();609610serviceProvider = bcsp;611}612613/**614* Returns the service provider.615* @return the service provider616*/617protected BeanContextServiceProvider getServiceProvider() {618return serviceProvider;619}620621/**622* The service provider.623*/624@SuppressWarnings("serial") // Not statically typed as Serializable625protected BeanContextServiceProvider serviceProvider;626}627628/**629* subclasses can override this method to create new subclasses of630* BCSSServiceProvider without having to override addService() in631* order to instantiate.632* @param sc the class633* @param bcsp the service provider634* @return a service provider without overriding addService()635*/636637protected BCSSServiceProvider createBCSSServiceProvider(Class<?> sc, BeanContextServiceProvider bcsp) {638return new BCSSServiceProvider(sc, bcsp);639}640641/************************************************************************/642643/**644* add a BeanContextServicesListener645*646* @throws NullPointerException if the argument is null647*/648649public void addBeanContextServicesListener(BeanContextServicesListener bcsl) {650if (bcsl == null) throw new NullPointerException("bcsl");651652synchronized(bcsListeners) {653if (bcsListeners.contains(bcsl))654return;655else656bcsListeners.add(bcsl);657}658}659660/**661* remove a BeanContextServicesListener662*/663664public void removeBeanContextServicesListener(BeanContextServicesListener bcsl) {665if (bcsl == null) throw new NullPointerException("bcsl");666667synchronized(bcsListeners) {668if (!bcsListeners.contains(bcsl))669return;670else671bcsListeners.remove(bcsl);672}673}674675/**676* add a service677* @param serviceClass the service class678* @param bcsp the service provider679*/680681public boolean addService(Class<?> serviceClass, BeanContextServiceProvider bcsp) {682return addService(serviceClass, bcsp, true);683}684685/**686* add a service687* @param serviceClass the service class688* @param bcsp the service provider689* @param fireEvent whether or not an event should be fired690* @return true if the service was successfully added691*/692693protected boolean addService(Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean fireEvent) {694695if (serviceClass == null) throw new NullPointerException("serviceClass");696if (bcsp == null) throw new NullPointerException("bcsp");697698synchronized(BeanContext.globalHierarchyLock) {699if (services.containsKey(serviceClass))700return false;701else {702services.put(serviceClass, createBCSSServiceProvider(serviceClass, bcsp));703704if (bcsp instanceof Serializable) serializable++;705706if (!fireEvent) return true;707708709BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent(getBeanContextServicesPeer(), serviceClass);710711fireServiceAdded(bcssae);712713synchronized(children) {714for (Object c : children.keySet()) {715if (c instanceof BeanContextServices) {716((BeanContextServicesListener)c).serviceAvailable(bcssae);717}718}719}720721return true;722}723}724}725726/**727* remove a service728* @param serviceClass the service class729* @param bcsp the service provider730* @param revokeCurrentServicesNow whether or not to revoke the service731*/732733public void revokeService(Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean revokeCurrentServicesNow) {734735if (serviceClass == null) throw new NullPointerException("serviceClass");736if (bcsp == null) throw new NullPointerException("bcsp");737738synchronized(BeanContext.globalHierarchyLock) {739if (!services.containsKey(serviceClass)) return;740741BCSSServiceProvider bcsssp = services.get(serviceClass);742743if (!bcsssp.getServiceProvider().equals(bcsp))744throw new IllegalArgumentException("service provider mismatch");745746services.remove(serviceClass);747748if (bcsp instanceof Serializable) serializable--;749750Iterator<BeanContextSupport.BCSChild> i = bcsChildren(); // get the BCSChild values.751752while (i.hasNext()) {753((BCSSChild)i.next()).revokeService(serviceClass, false, revokeCurrentServicesNow);754}755756fireServiceRevoked(serviceClass, revokeCurrentServicesNow);757}758}759760/**761* has a service, which may be delegated762*/763764public synchronized boolean hasService(Class<?> serviceClass) {765if (serviceClass == null) throw new NullPointerException("serviceClass");766767synchronized(BeanContext.globalHierarchyLock) {768if (services.containsKey(serviceClass)) return true;769770BeanContextServices bcs = null;771772try {773bcs = (BeanContextServices)getBeanContext();774} catch (ClassCastException cce) {775return false;776}777778return bcs == null ? false : bcs.hasService(serviceClass);779}780}781782/************************************************************************/783784/*785* a nested subclass used to represent a proxy for serviceClasses delegated786* to an enclosing BeanContext.787*/788789protected class BCSSProxyServiceProvider implements BeanContextServiceProvider, BeanContextServiceRevokedListener {790791BCSSProxyServiceProvider(BeanContextServices bcs) {792super();793794nestingCtxt = bcs;795}796797public Object getService(BeanContextServices bcs, Object requestor, Class<?> serviceClass, Object serviceSelector) {798Object service = null;799800try {801service = nestingCtxt.getService(bcs, requestor, serviceClass, serviceSelector, this);802} catch (TooManyListenersException tmle) {803return null;804}805806return service;807}808809public void releaseService(BeanContextServices bcs, Object requestor, Object service) {810nestingCtxt.releaseService(bcs, requestor, service);811}812813public Iterator<?> getCurrentServiceSelectors(BeanContextServices bcs, Class<?> serviceClass) {814return nestingCtxt.getCurrentServiceSelectors(serviceClass);815}816817public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) {818Iterator<BeanContextSupport.BCSChild> i = bcsChildren(); // get the BCSChild values.819820while (i.hasNext()) {821((BCSSChild)i.next()).revokeService(bcsre.getServiceClass(), true, bcsre.isCurrentServiceInvalidNow());822}823}824825/*826* fields827*/828829private BeanContextServices nestingCtxt;830}831832/************************************************************************/833834/**835* obtain a service which may be delegated836*/837838public Object getService(BeanContextChild child, Object requestor, Class<?> serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {839if (child == null) throw new NullPointerException("child");840if (serviceClass == null) throw new NullPointerException("serviceClass");841if (requestor == null) throw new NullPointerException("requestor");842if (bcsrl == null) throw new NullPointerException("bcsrl");843844Object service = null;845BCSSChild bcsc;846BeanContextServices bcssp = getBeanContextServicesPeer();847848synchronized(BeanContext.globalHierarchyLock) {849synchronized(children) { bcsc = (BCSSChild)children.get(child); }850851if (bcsc == null) throw new IllegalArgumentException("not a child of this context"); // not a child ...852853BCSSServiceProvider bcsssp = services.get(serviceClass);854855if (bcsssp != null) {856BeanContextServiceProvider bcsp = bcsssp.getServiceProvider();857service = bcsp.getService(bcssp, requestor, serviceClass, serviceSelector);858if (service != null) { // do bookkeeping ...859try {860bcsc.usingService(requestor, service, serviceClass, bcsp, false, bcsrl);861} catch (TooManyListenersException tmle) {862bcsp.releaseService(bcssp, requestor, service);863throw tmle;864} catch (UnsupportedOperationException uope) {865bcsp.releaseService(bcssp, requestor, service);866throw uope; // unchecked rt exception867}868869return service;870}871}872873874if (proxy != null) {875876// try to delegate ...877878service = proxy.getService(bcssp, requestor, serviceClass, serviceSelector);879880if (service != null) { // do bookkeeping ...881try {882bcsc.usingService(requestor, service, serviceClass, proxy, true, bcsrl);883} catch (TooManyListenersException tmle) {884proxy.releaseService(bcssp, requestor, service);885throw tmle;886} catch (UnsupportedOperationException uope) {887proxy.releaseService(bcssp, requestor, service);888throw uope; // unchecked rt exception889}890891return service;892}893}894}895896return null;897}898899/**900* release a service901*/902903public void releaseService(BeanContextChild child, Object requestor, Object service) {904if (child == null) throw new NullPointerException("child");905if (requestor == null) throw new NullPointerException("requestor");906if (service == null) throw new NullPointerException("service");907908BCSSChild bcsc;909910synchronized(BeanContext.globalHierarchyLock) {911synchronized(children) { bcsc = (BCSSChild)children.get(child); }912913if (bcsc != null)914bcsc.releaseService(requestor, service);915else916throw new IllegalArgumentException("child actual is not a child of this BeanContext");917}918}919920/**921* @return an iterator for all the currently registered service classes.922*/923924public Iterator<Object> getCurrentServiceClasses() {925return new BCSIterator(services.keySet().iterator());926}927928/**929* @return an iterator for all the currently available service selectors930* (if any) available for the specified service.931*/932933public Iterator<?> getCurrentServiceSelectors(Class<?> serviceClass) {934935BCSSServiceProvider bcsssp = services.get(serviceClass);936937return bcsssp != null ? new BCSIterator(bcsssp.getServiceProvider().getCurrentServiceSelectors(getBeanContextServicesPeer(), serviceClass)) : null;938}939940/**941* BeanContextServicesListener callback, propagates event to all942* currently registered listeners and BeanContextServices children,943* if this BeanContextService does not already implement this service944* itself.945*946* subclasses may override or envelope this method to implement their947* own propagation semantics.948*/949950public void serviceAvailable(BeanContextServiceAvailableEvent bcssae) {951synchronized(BeanContext.globalHierarchyLock) {952if (services.containsKey(bcssae.getServiceClass())) return;953954fireServiceAdded(bcssae);955956Iterator<Object> i;957958synchronized(children) {959i = children.keySet().iterator();960}961962while (i.hasNext()) {963Object c = i.next();964965if (c instanceof BeanContextServices) {966((BeanContextServicesListener)c).serviceAvailable(bcssae);967}968}969}970}971972/**973* BeanContextServicesListener callback, propagates event to all974* currently registered listeners and BeanContextServices children,975* if this BeanContextService does not already implement this service976* itself.977*978* subclasses may override or envelope this method to implement their979* own propagation semantics.980*/981982public void serviceRevoked(BeanContextServiceRevokedEvent bcssre) {983synchronized(BeanContext.globalHierarchyLock) {984if (services.containsKey(bcssre.getServiceClass())) return;985986fireServiceRevoked(bcssre);987988Iterator<Object> i;989990synchronized(children) {991i = children.keySet().iterator();992}993994while (i.hasNext()) {995Object c = i.next();996997if (c instanceof BeanContextServices) {998((BeanContextServicesListener)c).serviceRevoked(bcssre);999}1000}1001}1002}10031004/**1005* Gets the {@code BeanContextServicesListener} (if any) of the specified1006* child.1007*1008* @param child the specified child1009* @return the BeanContextServicesListener (if any) of the specified child1010*/1011protected static final BeanContextServicesListener getChildBeanContextServicesListener(Object child) {1012try {1013return (BeanContextServicesListener)child;1014} catch (ClassCastException cce) {1015return null;1016}1017}10181019/**1020* called from superclass child removal operations after a child1021* has been successfully removed. called with child synchronized.1022*1023* This subclass uses this hook to immediately revoke any services1024* being used by this child if it is a BeanContextChild.1025*1026* subclasses may envelope this method in order to implement their1027* own child removal side-effects.1028*/10291030protected void childJustRemovedHook(Object child, BCSChild bcsc) {1031BCSSChild bcssc = (BCSSChild)bcsc;10321033bcssc.cleanupReferences();1034}10351036/**1037* called from setBeanContext to notify a BeanContextChild1038* to release resources obtained from the nesting BeanContext.1039*1040* This method revokes any services obtained from its parent.1041*1042* subclasses may envelope this method to implement their own semantics.1043*/10441045protected synchronized void releaseBeanContextResources() {1046Object[] bcssc;10471048super.releaseBeanContextResources();10491050synchronized(children) {1051if (children.isEmpty()) return;10521053bcssc = children.values().toArray();1054}105510561057for (int i = 0; i < bcssc.length; i++) {1058((BCSSChild)bcssc[i]).revokeAllDelegatedServicesNow();1059}10601061proxy = null;1062}10631064/**1065* called from setBeanContext to notify a BeanContextChild1066* to allocate resources obtained from the nesting BeanContext.1067*1068* subclasses may envelope this method to implement their own semantics.1069*/10701071protected synchronized void initializeBeanContextResources() {1072super.initializeBeanContextResources();10731074BeanContext nbc = getBeanContext();10751076if (nbc == null) return;10771078try {1079BeanContextServices bcs = (BeanContextServices)nbc;10801081proxy = new BCSSProxyServiceProvider(bcs);1082} catch (ClassCastException cce) {1083// do nothing ...1084}1085}10861087/**1088* Fires a {@code BeanContextServiceEvent} notifying of a new service.1089* @param serviceClass the service class1090*/1091protected final void fireServiceAdded(Class<?> serviceClass) {1092BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent(getBeanContextServicesPeer(), serviceClass);10931094fireServiceAdded(bcssae);1095}10961097/**1098* Fires a {@code BeanContextServiceAvailableEvent} indicating that a new1099* service has become available.1100*1101* @param bcssae the {@code BeanContextServiceAvailableEvent}1102*/1103protected final void fireServiceAdded(BeanContextServiceAvailableEvent bcssae) {1104Object[] copy;11051106synchronized (bcsListeners) { copy = bcsListeners.toArray(); }11071108for (int i = 0; i < copy.length; i++) {1109((BeanContextServicesListener)copy[i]).serviceAvailable(bcssae);1110}1111}11121113/**1114* Fires a {@code BeanContextServiceEvent} notifying of a service being revoked.1115*1116* @param bcsre the {@code BeanContextServiceRevokedEvent}1117*/1118protected final void fireServiceRevoked(BeanContextServiceRevokedEvent bcsre) {1119Object[] copy;11201121synchronized (bcsListeners) { copy = bcsListeners.toArray(); }11221123for (int i = 0; i < copy.length; i++) {1124((BeanContextServiceRevokedListener)copy[i]).serviceRevoked(bcsre);1125}1126}11271128/**1129* Fires a {@code BeanContextServiceRevokedEvent}1130* indicating that a particular service is1131* no longer available.1132* @param serviceClass the service class1133* @param revokeNow whether or not the event should be revoked now1134*/1135protected final void fireServiceRevoked(Class<?> serviceClass, boolean revokeNow) {1136Object[] copy;1137BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(getBeanContextServicesPeer(), serviceClass, revokeNow);11381139synchronized (bcsListeners) { copy = bcsListeners.toArray(); }11401141for (int i = 0; i < copy.length; i++) {1142((BeanContextServicesListener)copy[i]).serviceRevoked(bcsre);1143}1144}11451146/**1147* called from BeanContextSupport writeObject before it serializes the1148* children ...1149*1150* This class will serialize any Serializable BeanContextServiceProviders1151* herein.1152*1153* subclasses may envelope this method to insert their own serialization1154* processing that has to occur prior to serialization of the children1155*/11561157protected synchronized void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {11581159oos.writeInt(serializable);11601161if (serializable <= 0) return;11621163int count = 0;11641165Iterator<Map.Entry<Object, BCSSServiceProvider>> i = services.entrySet().iterator();11661167while (i.hasNext() && count < serializable) {1168Map.Entry<Object, BCSSServiceProvider> entry = i.next();1169BCSSServiceProvider bcsp = null;11701171try {1172bcsp = entry.getValue();1173} catch (ClassCastException cce) {1174continue;1175}11761177if (bcsp.getServiceProvider() instanceof Serializable) {1178oos.writeObject(entry.getKey());1179oos.writeObject(bcsp);1180count++;1181}1182}11831184if (count != serializable)1185throw new IOException("wrote different number of service providers than expected");1186}11871188/**1189* called from BeanContextSupport readObject before it deserializes the1190* children ...1191*1192* This class will deserialize any Serializable BeanContextServiceProviders1193* serialized earlier thus making them available to the children when they1194* deserialized.1195*1196* subclasses may envelope this method to insert their own serialization1197* processing that has to occur prior to serialization of the children1198*/11991200protected synchronized void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {12011202serializable = ois.readInt();12031204int count = serializable;12051206while (count > 0) {1207services.put(ois.readObject(), (BCSSServiceProvider)ois.readObject());1208count--;1209}1210}12111212/**1213* Serialize the instance.1214*1215* @param oos the {@code ObjectOutputStream} to write1216* @throws IOException if an I/O error occurs1217*/1218@Serial1219private synchronized void writeObject(ObjectOutputStream oos) throws IOException {1220oos.defaultWriteObject();12211222serialize(oos, (Collection)bcsListeners);1223}12241225/**1226* Deserialize the instance.1227*1228* @param ois the {@code ObjectInputStream} to read1229* @throws ClassNotFoundException if the class of a serialized object could1230* not be found1231* @throws IOException if an I/O error occurs1232*/1233@Serial1234private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {12351236ois.defaultReadObject();12371238deserialize(ois, (Collection)bcsListeners);1239}124012411242/*1243* fields1244*/12451246/**1247* all accesses to the {@code protected transient HashMap services}1248* field should be synchronized on that object1249*/1250protected transient HashMap<Object, BCSSServiceProvider> services;12511252/**1253* The number of instances of a serializable {@code BeanContextServceProvider}.1254*/1255protected transient int serializable = 0;125612571258/**1259* Delegate for the {@code BeanContextServiceProvider}.1260*/1261protected transient BCSSProxyServiceProvider proxy;126212631264/**1265* List of {@code BeanContextServicesListener} objects.1266*/1267protected transient ArrayList<BeanContextServicesListener> bcsListeners;1268}126912701271