Java tutorial
/* * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.beans.beancontext; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.TooManyListenersException; import java.util.Locale; /** * <p> * This helper class provides a utility implementation of the * java.beans.beancontext.BeanContextServices interface. * </p> * <p> * Since this class directly implements the BeanContextServices interface, * the class can, and is intended to be used either by subclassing this * implementation, or via delegation of an instance of this class * from another through the BeanContextProxy interface. * </p> * * @author Laurence P. G. Cable * @since 1.2 */ public class BeanContextServicesSupport extends BeanContextSupport implements BeanContextServices { private static final long serialVersionUID = -8494482757288719206L; /** * <p> * Construct a BeanContextServicesSupport instance * </p> * * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer * @param lcle The current Locale for this BeanContext. * @param dTime The initial state, true if in design mode, false if runtime. * @param visible The initial visibility. * */ public BeanContextServicesSupport(BeanContextServices peer, Locale lcle, boolean dTime, boolean visible) { super(peer, lcle, dTime, visible); } /** * Create an instance using the specified Locale and design mode. * * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer * @param lcle The current Locale for this BeanContext. * @param dtime The initial state, true if in design mode, false if runtime. */ public BeanContextServicesSupport(BeanContextServices peer, Locale lcle, boolean dtime) { this(peer, lcle, dtime, true); } /** * Create an instance using the specified locale * * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer * @param lcle The current Locale for this BeanContext. */ public BeanContextServicesSupport(BeanContextServices peer, Locale lcle) { this(peer, lcle, false, true); } /** * Create an instance with a peer * * @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer */ public BeanContextServicesSupport(BeanContextServices peer) { this(peer, null, false, true); } /** * Create an instance that is not a delegate of another object */ public BeanContextServicesSupport() { this(null, null, false, true); } /** * called by BeanContextSupport superclass during construction and * deserialization to initialize subclass transient state. * * subclasses may envelope this method, but should not override it or * call it directly. */ public void initialize() { super.initialize(); services = new HashMap<>(serializable + 1); bcsListeners = new ArrayList<>(1); } /** * Gets the {@code BeanContextServices} associated with this * {@code BeanContextServicesSupport}. * * @return the instance of {@code BeanContext} * this object is providing the implementation for. */ public BeanContextServices getBeanContextServicesPeer() { return (BeanContextServices) getBeanContextChildPeer(); } /************************************************************************/ /* * protected nested class containing per child information, an instance * of which is associated with each child in the "children" hashtable. * subclasses can extend this class to include their own per-child state. * * Note that this 'value' is serialized with the corresponding child 'key' * when the BeanContextSupport is serialized. */ protected class BCSSChild extends BeanContextSupport.BCSChild { private static final long serialVersionUID = -3263851306889194873L; /* * private nested class to map serviceClass to Provider and requestors * listeners. */ class BCSSCServiceClassRef { // create an instance of a service ref BCSSCServiceClassRef(Class<?> sc, BeanContextServiceProvider bcsp, boolean delegated) { super(); serviceClass = sc; if (delegated) delegateProvider = bcsp; else serviceProvider = bcsp; } // add a requestor and assoc listener void addRequestor(Object requestor, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException { BeanContextServiceRevokedListener cbcsrl = requestors.get(requestor); if (cbcsrl != null && !cbcsrl.equals(bcsrl)) throw new TooManyListenersException(); requestors.put(requestor, bcsrl); } // remove a requestor void removeRequestor(Object requestor) { requestors.remove(requestor); } // check a requestors listener void verifyRequestor(Object requestor, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException { BeanContextServiceRevokedListener cbcsrl = requestors.get(requestor); if (cbcsrl != null && !cbcsrl.equals(bcsrl)) throw new TooManyListenersException(); } void verifyAndMaybeSetProvider(BeanContextServiceProvider bcsp, boolean isDelegated) { BeanContextServiceProvider current; if (isDelegated) { // the provider is delegated current = delegateProvider; if (current == null || bcsp == null) { delegateProvider = bcsp; return; } } else { // the provider is registered with this BCS current = serviceProvider; if (current == null || bcsp == null) { serviceProvider = bcsp; return; } } if (!current.equals(bcsp)) throw new UnsupportedOperationException( "existing service reference obtained from different BeanContextServiceProvider not supported"); } @SuppressWarnings("unchecked") // Cast from clone Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> cloneOfEntries() { return ((HashMap<Object, BeanContextServiceRevokedListener>) requestors.clone()).entrySet() .iterator(); } Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> entries() { return requestors.entrySet().iterator(); } boolean isEmpty() { return requestors.isEmpty(); } Class<?> getServiceClass() { return serviceClass; } BeanContextServiceProvider getServiceProvider() { return serviceProvider; } BeanContextServiceProvider getDelegateProvider() { return delegateProvider; } boolean isDelegated() { return delegateProvider != null; } void addRef(boolean delegated) { if (delegated) { delegateRefs++; } else { serviceRefs++; } } void releaseRef(boolean delegated) { if (delegated) { if (--delegateRefs == 0) { delegateProvider = null; } } else { if (--serviceRefs <= 0) { serviceProvider = null; } } } int getRefs() { return serviceRefs + delegateRefs; } int getDelegateRefs() { return delegateRefs; } int getServiceRefs() { return serviceRefs; } /* * fields */ Class<?> serviceClass; BeanContextServiceProvider serviceProvider; int serviceRefs; BeanContextServiceProvider delegateProvider; // proxy int delegateRefs; HashMap<Object, BeanContextServiceRevokedListener> requestors = new HashMap<>(1); } /* * per service reference info ... */ class BCSSCServiceRef { BCSSCServiceRef(BCSSCServiceClassRef scref, boolean isDelegated) { serviceClassRef = scref; delegated = isDelegated; } void addRef() { refCnt++; } int release() { return --refCnt; } BCSSCServiceClassRef getServiceClassRef() { return serviceClassRef; } boolean isDelegated() { return delegated; } /* * fields */ BCSSCServiceClassRef serviceClassRef; int refCnt = 1; boolean delegated = false; } BCSSChild(Object bcc, Object peer) { super(bcc, peer); } // note usage of service per requestor, per service synchronized void usingService(Object requestor, Object service, Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean isDelegated, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException, UnsupportedOperationException { // first, process mapping from serviceClass to requestor(s) BCSSCServiceClassRef serviceClassRef = null; if (serviceClasses == null) serviceClasses = new HashMap<>(1); else serviceClassRef = serviceClasses.get(serviceClass); if (serviceClassRef == null) { // new service being used ... serviceClassRef = new BCSSCServiceClassRef(serviceClass, bcsp, isDelegated); serviceClasses.put(serviceClass, serviceClassRef); } else { // existing service ... serviceClassRef.verifyAndMaybeSetProvider(bcsp, isDelegated); // throws serviceClassRef.verifyRequestor(requestor, bcsrl); // throws } serviceClassRef.addRequestor(requestor, bcsrl); serviceClassRef.addRef(isDelegated); // now handle mapping from requestor to service(s) BCSSCServiceRef serviceRef = null; Map<Object, BCSSCServiceRef> services = null; if (serviceRequestors == null) { serviceRequestors = new HashMap<>(1); } else { services = serviceRequestors.get(requestor); } if (services == null) { services = new HashMap<>(1); serviceRequestors.put(requestor, services); } else serviceRef = services.get(service); if (serviceRef == null) { serviceRef = new BCSSCServiceRef(serviceClassRef, isDelegated); services.put(service, serviceRef); } else { serviceRef.addRef(); } } // release a service reference synchronized void releaseService(Object requestor, Object service) { if (serviceRequestors == null) return; Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor); if (services == null) return; // oops its not there anymore! BCSSCServiceRef serviceRef = services.get(service); if (serviceRef == null) return; // oops its not there anymore! BCSSCServiceClassRef serviceClassRef = serviceRef.getServiceClassRef(); boolean isDelegated = serviceRef.isDelegated(); BeanContextServiceProvider bcsp = isDelegated ? serviceClassRef.getDelegateProvider() : serviceClassRef.getServiceProvider(); bcsp.releaseService(BeanContextServicesSupport.this.getBeanContextServicesPeer(), requestor, service); serviceClassRef.releaseRef(isDelegated); serviceClassRef.removeRequestor(requestor); if (serviceRef.release() == 0) { services.remove(service); if (services.isEmpty()) { serviceRequestors.remove(requestor); serviceClassRef.removeRequestor(requestor); } if (serviceRequestors.isEmpty()) { serviceRequestors = null; } if (serviceClassRef.isEmpty()) { serviceClasses.remove(serviceClassRef.getServiceClass()); } if (serviceClasses.isEmpty()) serviceClasses = null; } } // revoke a service synchronized void revokeService(Class<?> serviceClass, boolean isDelegated, boolean revokeNow) { if (serviceClasses == null) return; BCSSCServiceClassRef serviceClassRef = serviceClasses.get(serviceClass); if (serviceClassRef == null) return; Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> i = serviceClassRef.cloneOfEntries(); BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent( BeanContextServicesSupport.this.getBeanContextServicesPeer(), serviceClass, revokeNow); boolean noMoreRefs = false; while (i.hasNext() && serviceRequestors != null) { Map.Entry<Object, BeanContextServiceRevokedListener> entry = i.next(); BeanContextServiceRevokedListener listener = entry.getValue(); if (revokeNow) { Object requestor = entry.getKey(); Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor); if (services != null) { Iterator<Map.Entry<Object, BCSSCServiceRef>> i1 = services.entrySet().iterator(); while (i1.hasNext()) { Map.Entry<Object, BCSSCServiceRef> tmp = i1.next(); BCSSCServiceRef serviceRef = tmp.getValue(); if (serviceRef.getServiceClassRef().equals(serviceClassRef) && isDelegated == serviceRef.isDelegated()) { i1.remove(); } } if (noMoreRefs = services.isEmpty()) { serviceRequestors.remove(requestor); } } if (noMoreRefs) serviceClassRef.removeRequestor(requestor); } listener.serviceRevoked(bcsre); } if (revokeNow && serviceClasses != null) { if (serviceClassRef.isEmpty()) serviceClasses.remove(serviceClass); if (serviceClasses.isEmpty()) serviceClasses = null; } if (serviceRequestors != null && serviceRequestors.isEmpty()) serviceRequestors = null; } // release all references for this child since it has been unnested. void cleanupReferences() { if (serviceRequestors == null) return; Iterator<Map.Entry<Object, Map<Object, BCSSCServiceRef>>> requestors = serviceRequestors.entrySet() .iterator(); while (requestors.hasNext()) { Map.Entry<Object, Map<Object, BCSSCServiceRef>> tmp = requestors.next(); Object requestor = tmp.getKey(); Iterator<Map.Entry<Object, BCSSCServiceRef>> services = tmp.getValue().entrySet().iterator(); requestors.remove(); while (services.hasNext()) { Map.Entry<Object, BCSSCServiceRef> entry = services.next(); Object service = entry.getKey(); BCSSCServiceRef sref = entry.getValue(); BCSSCServiceClassRef scref = sref.getServiceClassRef(); BeanContextServiceProvider bcsp = sref.isDelegated() ? scref.getDelegateProvider() : scref.getServiceProvider(); scref.removeRequestor(requestor); services.remove(); while (sref.release() >= 0) { bcsp.releaseService(BeanContextServicesSupport.this.getBeanContextServicesPeer(), requestor, service); } } } serviceRequestors = null; serviceClasses = null; } void revokeAllDelegatedServicesNow() { if (serviceClasses == null) return; Iterator<BCSSCServiceClassRef> serviceClassRefs = new HashSet<>(serviceClasses.values()).iterator(); while (serviceClassRefs.hasNext()) { BCSSCServiceClassRef serviceClassRef = serviceClassRefs.next(); if (!serviceClassRef.isDelegated()) continue; Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> i = serviceClassRef.cloneOfEntries(); BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent( BeanContextServicesSupport.this.getBeanContextServicesPeer(), serviceClassRef.getServiceClass(), true); boolean noMoreRefs = false; while (i.hasNext()) { Map.Entry<Object, BeanContextServiceRevokedListener> entry = i.next(); BeanContextServiceRevokedListener listener = entry.getValue(); Object requestor = entry.getKey(); Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor); if (services != null) { Iterator<Map.Entry<Object, BCSSCServiceRef>> i1 = services.entrySet().iterator(); while (i1.hasNext()) { Map.Entry<Object, BCSSCServiceRef> tmp = i1.next(); BCSSCServiceRef serviceRef = tmp.getValue(); if (serviceRef.getServiceClassRef().equals(serviceClassRef) && serviceRef.isDelegated()) { i1.remove(); } } if (noMoreRefs = services.isEmpty()) { serviceRequestors.remove(requestor); } } if (noMoreRefs) serviceClassRef.removeRequestor(requestor); listener.serviceRevoked(bcsre); if (serviceClassRef.isEmpty()) serviceClasses.remove(serviceClassRef.getServiceClass()); } } if (serviceClasses.isEmpty()) serviceClasses = null; if (serviceRequestors != null && serviceRequestors.isEmpty()) serviceRequestors = null; } /* * fields */ private transient HashMap<Class<?>, BCSSCServiceClassRef> serviceClasses; private transient HashMap<Object, Map<Object, BeanContextServicesSupport.BCSSChild.BCSSCServiceRef>> serviceRequestors; } /** * <p> * Subclasses can override this method to insert their own subclass * of Child without having to override add() or the other Collection * methods that add children to the set. * </p> * * @param targetChild the child to create the Child on behalf of * @param peer the peer if the targetChild and peer are related by BeanContextProxy */ protected BCSChild createBCSChild(Object targetChild, Object peer) { return new BCSSChild(targetChild, peer); } /************************************************************************/ /** * subclasses may subclass this nested class to add behaviors for * each BeanContextServicesProvider. */ protected static class BCSSServiceProvider implements Serializable { private static final long serialVersionUID = 861278251667444782L; BCSSServiceProvider(Class<?> sc, BeanContextServiceProvider bcsp) { super(); serviceProvider = bcsp; } /** * Returns the service provider. * @return the service provider */ protected BeanContextServiceProvider getServiceProvider() { return serviceProvider; } /** * The service provider. */ protected BeanContextServiceProvider serviceProvider; } /** * subclasses can override this method to create new subclasses of * BCSSServiceProvider without having to override addService() in * order to instantiate. * @param sc the class * @param bcsp the service provider * @return a service provider without overriding addService() */ protected BCSSServiceProvider createBCSSServiceProvider(Class<?> sc, BeanContextServiceProvider bcsp) { return new BCSSServiceProvider(sc, bcsp); } /************************************************************************/ /** * add a BeanContextServicesListener * * @throws NullPointerException if the argument is null */ public void addBeanContextServicesListener(BeanContextServicesListener bcsl) { if (bcsl == null) throw new NullPointerException("bcsl"); synchronized (bcsListeners) { if (bcsListeners.contains(bcsl)) return; else bcsListeners.add(bcsl); } } /** * remove a BeanContextServicesListener */ public void removeBeanContextServicesListener(BeanContextServicesListener bcsl) { if (bcsl == null) throw new NullPointerException("bcsl"); synchronized (bcsListeners) { if (!bcsListeners.contains(bcsl)) return; else bcsListeners.remove(bcsl); } } /** * add a service * @param serviceClass the service class * @param bcsp the service provider */ public boolean addService(Class<?> serviceClass, BeanContextServiceProvider bcsp) { return addService(serviceClass, bcsp, true); } /** * add a service * @param serviceClass the service class * @param bcsp the service provider * @param fireEvent whether or not an event should be fired * @return true if the service was successfully added */ protected boolean addService(Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean fireEvent) { if (serviceClass == null) throw new NullPointerException("serviceClass"); if (bcsp == null) throw new NullPointerException("bcsp"); synchronized (BeanContext.globalHierarchyLock) { if (services.containsKey(serviceClass)) return false; else { services.put(serviceClass, createBCSSServiceProvider(serviceClass, bcsp)); if (bcsp instanceof Serializable) serializable++; if (!fireEvent) return true; BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent( getBeanContextServicesPeer(), serviceClass); fireServiceAdded(bcssae); synchronized (children) { Iterator<Object> i = children.keySet().iterator(); while (i.hasNext()) { Object c = i.next(); if (c instanceof BeanContextServices) { ((BeanContextServicesListener) c).serviceAvailable(bcssae); } } } return true; } } } /** * remove a service * @param serviceClass the service class * @param bcsp the service provider * @param revokeCurrentServicesNow whether or not to revoke the service */ public void revokeService(Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean revokeCurrentServicesNow) { if (serviceClass == null) throw new NullPointerException("serviceClass"); if (bcsp == null) throw new NullPointerException("bcsp"); synchronized (BeanContext.globalHierarchyLock) { if (!services.containsKey(serviceClass)) return; BCSSServiceProvider bcsssp = services.get(serviceClass); if (!bcsssp.getServiceProvider().equals(bcsp)) throw new IllegalArgumentException("service provider mismatch"); services.remove(serviceClass); if (bcsp instanceof Serializable) serializable--; Iterator<BeanContextSupport.BCSChild> i = bcsChildren(); // get the BCSChild values. while (i.hasNext()) { ((BCSSChild) i.next()).revokeService(serviceClass, false, revokeCurrentServicesNow); } fireServiceRevoked(serviceClass, revokeCurrentServicesNow); } } /** * has a service, which may be delegated */ public synchronized boolean hasService(Class<?> serviceClass) { if (serviceClass == null) throw new NullPointerException("serviceClass"); synchronized (BeanContext.globalHierarchyLock) { if (services.containsKey(serviceClass)) return true; BeanContextServices bcs = null; try { bcs = (BeanContextServices) getBeanContext(); } catch (ClassCastException cce) { return false; } return bcs == null ? false : bcs.hasService(serviceClass); } } /************************************************************************/ /* * a nested subclass used to represent a proxy for serviceClasses delegated * to an enclosing BeanContext. */ protected class BCSSProxyServiceProvider implements BeanContextServiceProvider, BeanContextServiceRevokedListener { BCSSProxyServiceProvider(BeanContextServices bcs) { super(); nestingCtxt = bcs; } public Object getService(BeanContextServices bcs, Object requestor, Class<?> serviceClass, Object serviceSelector) { Object service = null; try { service = nestingCtxt.getService(bcs, requestor, serviceClass, serviceSelector, this); } catch (TooManyListenersException tmle) { return null; } return service; } public void releaseService(BeanContextServices bcs, Object requestor, Object service) { nestingCtxt.releaseService(bcs, requestor, service); } public Iterator<?> getCurrentServiceSelectors(BeanContextServices bcs, Class<?> serviceClass) { return nestingCtxt.getCurrentServiceSelectors(serviceClass); } public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) { Iterator<BeanContextSupport.BCSChild> i = bcsChildren(); // get the BCSChild values. while (i.hasNext()) { ((BCSSChild) i.next()).revokeService(bcsre.getServiceClass(), true, bcsre.isCurrentServiceInvalidNow()); } } /* * fields */ private BeanContextServices nestingCtxt; } /************************************************************************/ /** * obtain a service which may be delegated */ public Object getService(BeanContextChild child, Object requestor, Class<?> serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException { if (child == null) throw new NullPointerException("child"); if (serviceClass == null) throw new NullPointerException("serviceClass"); if (requestor == null) throw new NullPointerException("requestor"); if (bcsrl == null) throw new NullPointerException("bcsrl"); Object service = null; BCSSChild bcsc; BeanContextServices bcssp = getBeanContextServicesPeer(); synchronized (BeanContext.globalHierarchyLock) { synchronized (children) { bcsc = (BCSSChild) children.get(child); } if (bcsc == null) throw new IllegalArgumentException("not a child of this context"); // not a child ... BCSSServiceProvider bcsssp = services.get(serviceClass); if (bcsssp != null) { BeanContextServiceProvider bcsp = bcsssp.getServiceProvider(); service = bcsp.getService(bcssp, requestor, serviceClass, serviceSelector); if (service != null) { // do bookkeeping ... try { bcsc.usingService(requestor, service, serviceClass, bcsp, false, bcsrl); } catch (TooManyListenersException tmle) { bcsp.releaseService(bcssp, requestor, service); throw tmle; } catch (UnsupportedOperationException uope) { bcsp.releaseService(bcssp, requestor, service); throw uope; // unchecked rt exception } return service; } } if (proxy != null) { // try to delegate ... service = proxy.getService(bcssp, requestor, serviceClass, serviceSelector); if (service != null) { // do bookkeeping ... try { bcsc.usingService(requestor, service, serviceClass, proxy, true, bcsrl); } catch (TooManyListenersException tmle) { proxy.releaseService(bcssp, requestor, service); throw tmle; } catch (UnsupportedOperationException uope) { proxy.releaseService(bcssp, requestor, service); throw uope; // unchecked rt exception } return service; } } } return null; } /** * release a service */ public void releaseService(BeanContextChild child, Object requestor, Object service) { if (child == null) throw new NullPointerException("child"); if (requestor == null) throw new NullPointerException("requestor"); if (service == null) throw new NullPointerException("service"); BCSSChild bcsc; synchronized (BeanContext.globalHierarchyLock) { synchronized (children) { bcsc = (BCSSChild) children.get(child); } if (bcsc != null) bcsc.releaseService(requestor, service); else throw new IllegalArgumentException("child actual is not a child of this BeanContext"); } } /** * @return an iterator for all the currently registered service classes. */ public Iterator<Object> getCurrentServiceClasses() { return new BCSIterator(services.keySet().iterator()); } /** * @return an iterator for all the currently available service selectors * (if any) available for the specified service. */ public Iterator<?> getCurrentServiceSelectors(Class<?> serviceClass) { BCSSServiceProvider bcsssp = services.get(serviceClass); return bcsssp != null ? new BCSIterator(bcsssp.getServiceProvider() .getCurrentServiceSelectors(getBeanContextServicesPeer(), serviceClass)) : null; } /** * BeanContextServicesListener callback, propagates event to all * currently registered listeners and BeanContextServices children, * if this BeanContextService does not already implement this service * itself. * * subclasses may override or envelope this method to implement their * own propagation semantics. */ public void serviceAvailable(BeanContextServiceAvailableEvent bcssae) { synchronized (BeanContext.globalHierarchyLock) { if (services.containsKey(bcssae.getServiceClass())) return; fireServiceAdded(bcssae); Iterator<Object> i; synchronized (children) { i = children.keySet().iterator(); } while (i.hasNext()) { Object c = i.next(); if (c instanceof BeanContextServices) { ((BeanContextServicesListener) c).serviceAvailable(bcssae); } } } } /** * BeanContextServicesListener callback, propagates event to all * currently registered listeners and BeanContextServices children, * if this BeanContextService does not already implement this service * itself. * * subclasses may override or envelope this method to implement their * own propagation semantics. */ public void serviceRevoked(BeanContextServiceRevokedEvent bcssre) { synchronized (BeanContext.globalHierarchyLock) { if (services.containsKey(bcssre.getServiceClass())) return; fireServiceRevoked(bcssre); Iterator<Object> i; synchronized (children) { i = children.keySet().iterator(); } while (i.hasNext()) { Object c = i.next(); if (c instanceof BeanContextServices) { ((BeanContextServicesListener) c).serviceRevoked(bcssre); } } } } /** * Gets the {@code BeanContextServicesListener} (if any) of the specified * child. * * @param child the specified child * @return the BeanContextServicesListener (if any) of the specified child */ protected static final BeanContextServicesListener getChildBeanContextServicesListener(Object child) { try { return (BeanContextServicesListener) child; } catch (ClassCastException cce) { return null; } } /** * called from superclass child removal operations after a child * has been successfully removed. called with child synchronized. * * This subclass uses this hook to immediately revoke any services * being used by this child if it is a BeanContextChild. * * subclasses may envelope this method in order to implement their * own child removal side-effects. */ protected void childJustRemovedHook(Object child, BCSChild bcsc) { BCSSChild bcssc = (BCSSChild) bcsc; bcssc.cleanupReferences(); } /** * called from setBeanContext to notify a BeanContextChild * to release resources obtained from the nesting BeanContext. * * This method revokes any services obtained from its parent. * * subclasses may envelope this method to implement their own semantics. */ protected synchronized void releaseBeanContextResources() { Object[] bcssc; super.releaseBeanContextResources(); synchronized (children) { if (children.isEmpty()) return; bcssc = children.values().toArray(); } for (int i = 0; i < bcssc.length; i++) { ((BCSSChild) bcssc[i]).revokeAllDelegatedServicesNow(); } proxy = null; } /** * called from setBeanContext to notify a BeanContextChild * to allocate resources obtained from the nesting BeanContext. * * subclasses may envelope this method to implement their own semantics. */ protected synchronized void initializeBeanContextResources() { super.initializeBeanContextResources(); BeanContext nbc = getBeanContext(); if (nbc == null) return; try { BeanContextServices bcs = (BeanContextServices) nbc; proxy = new BCSSProxyServiceProvider(bcs); } catch (ClassCastException cce) { // do nothing ... } } /** * Fires a {@code BeanContextServiceEvent} notifying of a new service. * @param serviceClass the service class */ protected final void fireServiceAdded(Class<?> serviceClass) { BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent(getBeanContextServicesPeer(), serviceClass); fireServiceAdded(bcssae); } /** * Fires a {@code BeanContextServiceAvailableEvent} indicating that a new * service has become available. * * @param bcssae the {@code BeanContextServiceAvailableEvent} */ protected final void fireServiceAdded(BeanContextServiceAvailableEvent bcssae) { Object[] copy; synchronized (bcsListeners) { copy = bcsListeners.toArray(); } for (int i = 0; i < copy.length; i++) { ((BeanContextServicesListener) copy[i]).serviceAvailable(bcssae); } } /** * Fires a {@code BeanContextServiceEvent} notifying of a service being revoked. * * @param bcsre the {@code BeanContextServiceRevokedEvent} */ protected final void fireServiceRevoked(BeanContextServiceRevokedEvent bcsre) { Object[] copy; synchronized (bcsListeners) { copy = bcsListeners.toArray(); } for (int i = 0; i < copy.length; i++) { ((BeanContextServiceRevokedListener) copy[i]).serviceRevoked(bcsre); } } /** * Fires a {@code BeanContextServiceRevokedEvent} * indicating that a particular service is * no longer available. * @param serviceClass the service class * @param revokeNow whether or not the event should be revoked now */ protected final void fireServiceRevoked(Class<?> serviceClass, boolean revokeNow) { Object[] copy; BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(getBeanContextServicesPeer(), serviceClass, revokeNow); synchronized (bcsListeners) { copy = bcsListeners.toArray(); } for (int i = 0; i < copy.length; i++) { ((BeanContextServicesListener) copy[i]).serviceRevoked(bcsre); } } /** * called from BeanContextSupport writeObject before it serializes the * children ... * * This class will serialize any Serializable BeanContextServiceProviders * herein. * * subclasses may envelope this method to insert their own serialization * processing that has to occur prior to serialization of the children */ protected synchronized void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException { oos.writeInt(serializable); if (serializable <= 0) return; int count = 0; Iterator<Map.Entry<Object, BCSSServiceProvider>> i = services.entrySet().iterator(); while (i.hasNext() && count < serializable) { Map.Entry<Object, BCSSServiceProvider> entry = i.next(); BCSSServiceProvider bcsp = null; try { bcsp = entry.getValue(); } catch (ClassCastException cce) { continue; } if (bcsp.getServiceProvider() instanceof Serializable) { oos.writeObject(entry.getKey()); oos.writeObject(bcsp); count++; } } if (count != serializable) throw new IOException("wrote different number of service providers than expected"); } /** * called from BeanContextSupport readObject before it deserializes the * children ... * * This class will deserialize any Serializable BeanContextServiceProviders * serialized earlier thus making them available to the children when they * deserialized. * * subclasses may envelope this method to insert their own serialization * processing that has to occur prior to serialization of the children */ protected synchronized void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException { serializable = ois.readInt(); int count = serializable; while (count > 0) { services.put(ois.readObject(), (BCSSServiceProvider) ois.readObject()); count--; } } /** * serialize the instance */ private synchronized void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); serialize(oos, (Collection) bcsListeners); } /** * deserialize the instance */ private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject(); deserialize(ois, (Collection) bcsListeners); } /* * fields */ /** * all accesses to the {@code protected transient HashMap services} * field should be synchronized on that object */ protected transient HashMap<Object, BCSSServiceProvider> services; /** * The number of instances of a serializable {@code BeanContextServceProvider}. */ protected transient int serializable = 0; /** * Delegate for the {@code BeanContextServiceProvider}. */ protected transient BCSSProxyServiceProvider proxy; /** * List of {@code BeanContextServicesListener} objects. */ protected transient ArrayList<BeanContextServicesListener> bcsListeners; }