001    /* BeanContextServicesSupport.java --
002       Copyright (C) 2003, 2005  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.beans.beancontext;
040    
041    import gnu.classpath.NotImplementedException;
042    
043    import java.io.IOException;
044    import java.io.ObjectInputStream;
045    import java.io.ObjectOutputStream;
046    import java.io.Serializable;
047    import java.util.ArrayList;
048    import java.util.HashMap;
049    import java.util.HashSet;
050    import java.util.Iterator;
051    import java.util.List;
052    import java.util.Locale;
053    import java.util.Set;
054    import java.util.TooManyListenersException;
055    
056    /**
057     * This is a helper class for implementing a bean context which
058     * supplies services.  It is intended to be used either by
059     * subclassing or by calling methods of this implementation
060     * from another.
061     *
062     * @author Michael Koch
063     * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
064     * @since 1.2
065     */
066    public class BeanContextServicesSupport
067      extends BeanContextSupport
068      implements BeanContextServices
069    {
070      private static final long serialVersionUID = -8494482757288719206L;
071      
072      protected class BCSSChild
073        extends BeanContextSupport.BCSChild
074      {
075        private static final long serialVersionUID = -3263851306889194873L;
076    
077        BCSSChild(Object targetChild, Object peer)
078        {
079          super(targetChild, peer);
080        }
081      }
082    
083      protected class BCSSProxyServiceProvider
084        implements BeanContextServiceProvider,
085        BeanContextServiceRevokedListener
086      {
087        private static final long serialVersionUID = 7078212910685744490L;
088    
089        private BeanContextServiceProvider provider;
090    
091        private BCSSProxyServiceProvider(BeanContextServiceProvider p)
092        {
093          provider = p;
094        }
095    
096        public Iterator getCurrentServiceSelectors (BeanContextServices bcs,
097                                                    Class serviceClass)
098        {
099          return provider.getCurrentServiceSelectors(bcs, serviceClass);
100        }
101    
102        public Object getService (BeanContextServices bcs,
103                                  Object requestor,
104                                  Class serviceClass,
105                                  Object serviceSelector)
106        {
107          return provider.getService(bcs, requestor, serviceClass,
108                                     serviceSelector);
109        }
110    
111        public void releaseService (BeanContextServices bcs,
112                                    Object requestor,
113                                    Object service)
114        {
115          provider.releaseService(bcs, requestor, service);
116        }
117    
118        public void serviceRevoked (BeanContextServiceRevokedEvent bcsre)
119        {
120          if (provider instanceof BeanContextServiceRevokedListener)
121            ((BeanContextServiceRevokedListener) provider).serviceRevoked(bcsre);
122        }
123      }
124    
125      protected static class BCSSServiceProvider
126        implements Serializable
127      {
128        private static final long serialVersionUID = 861278251667444782L;
129    
130        protected BeanContextServiceProvider serviceProvider;
131    
132        private Class serviceClass;
133    
134        private BCSSServiceProvider(Class serviceClass,
135                                    BeanContextServiceProvider provider)
136        {
137          this.serviceClass = serviceClass;
138          serviceProvider = provider;
139        }
140    
141        protected BeanContextServiceProvider getServiceProvider()
142        {
143          return serviceProvider;
144        }
145    
146        private Class getServiceClass()
147        {
148          return serviceClass;
149        }
150    
151      }
152    
153      /**
154       * Represents a request for a service.  This is
155       * a common superclass used by the classes which maintain
156       * the listener-requestor and service-requestor relationships.
157       *
158       * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
159       */
160      private static abstract class Request
161      {
162        private Object requestor;
163    
164        public Request(Object requestor)
165        {
166          this.requestor = requestor;
167        }
168    
169        public boolean equals(Object obj)
170        {
171          if (obj instanceof Request)
172            {
173              Request req = (Request) obj;
174              return req.getRequestor().equals(requestor);
175            }
176          return false;
177        }
178    
179        public Object getRequestor()
180        {
181          return requestor;
182        }
183    
184      }
185    
186      /**
187       * Represents a relationship between a service requestor
188       * and a revocation listener.
189       *
190       * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
191       */
192      private static class ServiceRequest
193        extends Request
194      {
195    
196        private BeanContextServiceRevokedListener listener;
197    
198        public ServiceRequest(Object requestor,
199                              BeanContextServiceRevokedListener listener)
200        {
201          super(requestor);
202          this.listener = listener;
203        }
204    
205        public boolean equals(Object obj)
206        {
207          if (obj instanceof ServiceRequest)
208            {
209              ServiceRequest sr = (ServiceRequest) obj;
210              return (super.equals(obj) &&
211                      sr.getListener().equals(listener));
212            }
213          return false;
214        }
215    
216        public BeanContextServiceRevokedListener getListener()
217        {
218          return listener;
219        }
220      }
221    
222      /**
223       * Represents a relationship between a service requestor
224       * and a service instance.
225       *
226       * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
227       */
228      private static class ServiceLease
229        extends Request
230      {
231    
232        private Object service;
233    
234        public ServiceLease(Object requestor, Object service)
235        {
236          super(requestor);
237          this.service = service;
238        }
239    
240        public boolean equals(Object obj)
241        {
242          if (obj instanceof ServiceLease)
243            {
244              ServiceLease sl = (ServiceLease) obj;
245              return (super.equals(obj) &&
246                      sl.getService().equals(service));
247            }
248          return false;
249        }
250    
251        public Object getService()
252        {
253          return service;
254        }
255      }
256    
257      /**
258       * A collection of listeners who receive availability
259       * and revocation notifications.
260       */
261      protected transient ArrayList bcsListeners;
262        
263      protected transient BCSSProxyServiceProvider proxy;
264    
265      /**
266       * The number of serializable service providers.
267       */
268      protected transient int serializable;
269    
270      /**
271       * A map of registered services, linking the service
272       * class to its associated {@link BCSSServiceProvider}.
273       */
274      protected transient HashMap services;
275    
276      /**
277       * A map of children to a list of services they
278       * have obtained.
279       */
280      private transient HashMap serviceUsers;
281    
282      /**
283       * A map of services to {@link ServiceRequest}s.
284       */
285      private transient HashMap serviceRequests;
286    
287      /**
288       * A map of {@link ServiceLease}s to providers.
289       */
290      private transient HashMap serviceLeases;
291    
292      /**
293       * Construct a {@link BeanContextServicesSupport} instance.
294       */
295      public BeanContextServicesSupport ()
296      {
297        super();
298      }
299    
300      /**
301       * Construct a {@link BeanContextServicesSupport} instance.
302       * 
303       * @param peer the bean context services peer (<code>null</code> permitted).
304       */
305      public BeanContextServicesSupport (BeanContextServices peer)
306      {
307        super(peer);
308      }
309    
310      /**
311       * Construct a {@link BeanContextServicesSupport} instance.
312       * 
313       * @param peer the bean context peer (<code>null</code> permitted).
314       * @param locale the locale (<code>null</code> permitted, equivalent to 
315       *     the default locale).
316       */
317      public BeanContextServicesSupport(BeanContextServices peer, Locale locale)
318      {
319        super(peer, locale);
320      }
321    
322      /**
323       * Construct a {@link BeanContextServicesSupport} instance.
324       * 
325       * @param peer  the bean context peer (<code>null</code> permitted).
326       * @param locale  the locale (<code>null</code> permitted, equivalent to 
327       *     the default locale).
328       * @param dtime  a flag indicating whether or not the bean context is in
329       *     design time mode.
330       */
331      public BeanContextServicesSupport(BeanContextServices peer, Locale locale,
332                                        boolean dtime)
333      {
334        super(peer, locale, dtime);
335      }
336    
337      /**
338       * Construct a {@link BeanContextServicesSupport} instance.
339       * 
340       * @param peer  the bean context peer (<code>null</code> permitted).
341       * @param locale  the locale (<code>null</code> permitted, equivalent to 
342       *     the default locale).
343       * @param dtime  a flag indicating whether or not the bean context is in
344       *     design time mode.
345       * @param visible  initial value of the <code>okToUseGui</code> flag.
346       */
347      public BeanContextServicesSupport(BeanContextServices peer, Locale locale,
348                                        boolean dtime, boolean visible)
349      {
350        super(peer, locale, dtime, visible);
351      }
352      
353      /**
354       * Adds a new listener for service availability and
355       * revocation events.
356       *
357       * @param listener the listener to add.
358       */
359      public void addBeanContextServicesListener
360        (BeanContextServicesListener listener)
361      {
362        synchronized (bcsListeners)
363          {
364            if (! bcsListeners.contains(listener))
365              bcsListeners.add(listener);
366          }
367      }
368    
369      /**
370       * Registers a new service from the specified service provider.
371       * The service is internally associated with the service provider
372       * and a <code>BeanContextServiceAvailableEvent</code> is fired.  If
373       * the service is already registered, then this method instead
374       * returns <code>false</code>.  This is equivalent to calling
375       * <code>addService(serviceClass, bcsp, true)</code>.
376       *
377       * @param serviceClass the class of the service to be registered.
378       * @param bcsp the provider of the given service.
379       * @return true if the service was registered successfully.
380       * @see #addService(Class, BeanContextServiceProvider, boolean)
381       */
382      public boolean addService (Class serviceClass,
383                                 BeanContextServiceProvider bcsp)
384      {
385        return addService(serviceClass, bcsp, true);
386      }
387    
388      /**
389       * Registers a new service from the specified service provider.
390       * The service is internally associated with the service provider
391       * and (if <code>fireEvent</code> is true) a
392       * <code>BeanContextServiceAvailableEvent</code> is fired.  If
393       * the service is already registered, then this method instead
394       * returns <code>false</code>.
395       *
396       * @param serviceClass the class of the service to be registered.
397       * @param bcsp the provider of the given service.
398       * @param fireEvent true if a service availability event should
399       *                  be fired.
400       * @return true if the service was registered successfully.
401       */
402      protected boolean addService (Class serviceClass,
403                                    BeanContextServiceProvider bcsp,
404                                    boolean fireEvent)
405      {
406        synchronized (globalHierarchyLock)
407          {
408            synchronized (services)
409              {
410                if (services.containsKey(serviceClass))
411                  return false;
412                services.put(serviceClass,
413                             createBCSSServiceProvider(serviceClass, bcsp));
414                if (bcsp instanceof Serializable)
415                  ++serializable;
416                if (fireEvent)
417                  fireServiceAdded(serviceClass);
418                return true;
419              }
420          }
421      }
422      
423      /**
424       * Deserializes any service providers which are serializable.  This
425       * method is called by the <code>readObject</code> method of
426       * {@link BeanContextSupport} prior to deserialization of the children.
427       * Subclasses may envelope its behaviour in order to read further
428       * serialized data to the stream.
429       *
430       * @param oos the stream from which data is being deserialized.
431       * @throws IOException if an I/O error occurs.
432       * @throws ClassNotFoundException if the class of a deserialized object
433       *                                can not be found.
434       */
435      protected void bcsPreDeserializationHook (ObjectInputStream ois)
436        throws ClassNotFoundException, IOException
437      {
438        serializable = ois.readInt();
439        for (int a = 0; a < serializable; ++a)
440          {
441            BCSSServiceProvider bcsssp = (BCSSServiceProvider) ois.readObject();
442            addService(bcsssp.getServiceClass(), bcsssp.getServiceProvider());
443          }
444      }
445    
446      /**
447       * Serializes any service providers which are serializable.  This
448       * method is called by the <code>writeObject</code> method of
449       * {@link BeanContextSupport} prior to serialization of the children.
450       * Subclasses may envelope its behaviour in order to add further
451       * serialized data to the stream.
452       *
453       * @param oos the stream to which data is being serialized.
454       * @throws IOException if an I/O error occurs.
455       */
456      protected void bcsPreSerializationHook (ObjectOutputStream oos) 
457        throws IOException
458      {
459        oos.writeInt(serializable);
460        synchronized (services)
461          {
462            Iterator i = services.values().iterator();
463            while (i.hasNext())
464              {
465                BCSSServiceProvider bcsssp = (BCSSServiceProvider) i.next();
466                if (bcsssp.getServiceProvider() instanceof Serializable)
467                  oos.writeObject(bcsssp);
468              }
469          }
470      }
471    
472      /**
473       * Revokes any services used by a child that has just been removed.
474       * The superclass ({@link BeanContextSupport}) calls this method
475       * when a child has just been successfully removed.  Subclasses can
476       * extend this method in order to perform additional operations
477       * on child removal.
478       *
479       * @param child the child being removed.
480       * @param bcsc the support object for the child.
481       */ 
482      protected void childJustRemovedHook (Object child,
483                                           BeanContextSupport.BCSChild bcsc)
484      {
485        if (child instanceof BeanContextChild)
486          {
487            BeanContextChild bcchild = (BeanContextChild) child;
488            Iterator childServices = ((List) serviceUsers.get(bcchild)).iterator();
489            while (childServices.hasNext())
490              releaseService(bcchild, this, childServices.next());
491            serviceUsers.remove(bcchild);
492          }
493      }
494    
495      /**
496       * Overrides the {@link BeanContextSupport#createBCSChild} method
497       * so as to use a {@link BCSSChild} instead.
498       *
499       * @param targetChild the child to create the child for.
500       * @param peer the peer which relates to the child if a proxy is used.
501       * @return a new instance of {@link BCSSChild}.
502       */
503      protected BeanContextSupport.BCSChild createBCSChild (Object targetChild,
504                                                            Object peer)
505      {
506        return new BCSSChild(targetChild, peer);
507      }
508    
509      /**
510       * Provides a hook so that subclasses can replace the
511       * {@link BCSSServiceProvider} class, used to store registered
512       * service providers, with a subclass without replacing the
513       * {@link #addService(Class, BeanContextServiceProvider)} method.
514       *
515       * @param sc the class of service being registered.
516       * @param bcsp the provider of the service.
517       * @return a instance of {@link BCSSServiceProvider} wrapping the provider.
518       */
519      protected BeanContextServicesSupport.BCSSServiceProvider
520      createBCSSServiceProvider (Class sc, BeanContextServiceProvider bcsp)
521      {
522        return new BCSSServiceProvider(sc, bcsp);
523      }
524    
525      /**
526       * Sends a <code>BeanContextServiceAvailableEvent</code> to all
527       * registered listeners.
528       *
529       * @param bcssae the event to send.
530       */
531      protected final void fireServiceAdded (BeanContextServiceAvailableEvent bcssae)
532      {
533        synchronized (bcsListeners)
534          {
535            int size = bcsListeners.size();
536            for (int i = 0; i < size; ++i)
537              {
538                BeanContextServicesListener bcsl
539                  = (BeanContextServicesListener) bcsListeners.get(i);
540                bcsl.serviceAvailable(bcssae);
541              }
542          }
543      }
544    
545      /**
546       * Sends a <code>BeanContextServiceAvailableEvent</code> to all
547       * registered listeners.
548       *
549       * @param serviceClass the service that is now available.
550       * @see #fireServiceAdded(BeanContextServiceAvailableEvent)
551       */
552      protected final void fireServiceAdded (Class serviceClass)
553      {
554        fireServiceAdded(new BeanContextServiceAvailableEvent(this,
555                                                              serviceClass));
556      }
557    
558      /**
559       * Sends a <code>BeanContextServiceRevokedEvent</code> to all
560       * registered listeners.
561       *
562       * @param event the event to send.
563       */
564      protected final void fireServiceRevoked(BeanContextServiceRevokedEvent event)
565      {
566        synchronized (bcsListeners)
567          {
568            int size = bcsListeners.size();
569            for (int i = 0; i < size; ++i)
570              {
571                BeanContextServicesListener bcsl
572                  = (BeanContextServicesListener) bcsListeners.get(i);
573                bcsl.serviceRevoked(event);
574              }
575            List requests = (List) serviceRequests.get(event.getServiceClass());
576            if (requests != null)
577              {
578                Iterator i = requests.iterator();
579                while (i.hasNext())
580                  {
581                    ServiceRequest r = (ServiceRequest) i.next();
582                    r.getListener().serviceRevoked(event);
583                  }
584              }
585          }
586      }
587    
588      /**
589       * Sends a <code>BeanContextServiceRevokedEvent</code> to all
590       * registered listeners.
591       *
592       * @param serviceClass the service that has been revoked.
593       * @see #fireServiceRevoked(BeanContextServiceRevokedEvent)
594       */
595      protected final void fireServiceRevoked (Class serviceClass,
596                                               boolean revokeNow)
597      {
598        fireServiceRevoked(new BeanContextServiceRevokedEvent(this, serviceClass,
599                                                              revokeNow));
600      }
601    
602      /**
603       * Returns the services peer given at construction time,
604       * or <code>null</code> if no peer was given.
605       *
606       * @return the {@link BeanContextServices} peer.
607       */
608      public BeanContextServices getBeanContextServicesPeer ()
609      {
610        return (BeanContextServices) beanContextChildPeer;
611      }
612    
613      /**
614       * Returns <code>child</code> as an instance of 
615       * {@link BeanContextServicesListener}, or <code>null</code> if 
616       * <code>child</code> does not implement that interface.
617       * 
618       * @param child  the child (<code>null</code> permitted).
619       * 
620       * @return The child cast to {@link BeanContextServicesListener}.
621       */
622      protected static final BeanContextServicesListener
623          getChildBeanContextServicesListener(Object child)
624      {
625        if (child instanceof BeanContextServicesListener) 
626          return (BeanContextServicesListener) child;
627        else 
628          return null;
629      }
630    
631      /**
632       * Returns an iterator over the currently available
633       * services.
634       *
635       * @return an iterator over the currently available services.
636       */
637      public Iterator getCurrentServiceClasses ()
638      {
639        synchronized (globalHierarchyLock)
640          {
641            synchronized (services)
642              {
643                return services.keySet().iterator();
644              }
645          }
646      }
647    
648      /**
649       * Returns an iterator over the service selectors of the service
650       * provider for the given service.  The iterator is actually
651       * obtained by calling the
652       * {@link BeanContextServiceProvider#getCurrentServiceSelectors}
653       * of the provider itself.  If the specified service is not available,
654       * <code>null</code> is returned.
655       *
656       * @param serviceClass the service whose provider's selectors should
657       *                     be iterated over.
658       * @return an {@link Iterator} over the service selectors of the
659       *         provider of the given service.
660       */
661      public Iterator getCurrentServiceSelectors (Class serviceClass)
662      {
663        synchronized (globalHierarchyLock)
664          {
665            synchronized (services)
666              {
667                BeanContextServiceProvider bcsp
668                  = ((BCSSServiceProvider)
669                     services.get(serviceClass)).getServiceProvider();
670                if (bcsp == null)
671                  return null;
672                else
673                  return bcsp.getCurrentServiceSelectors(this, serviceClass);
674              }
675          }
676      }
677    
678      /**
679       * Retrieves the specified service.  If a provider for the service
680       * is registered in this context, then the request is passed on to
681       * the provider and the service returned.  Otherwise, the request
682       * is delegated to a parent {@link BeanContextServices}, if possible.
683       * If the service can not be found at all, then <code>null</code>
684       * is returned.
685       *
686       * @param child the child obtaining the reference.
687       * @param requestor the requestor of the service, which may be the
688       *                  child itself.
689       * @param serviceClass the service being requested.
690       * @param serviceSelector an additional service-dependent parameter
691       *                        (may be <code>null</code> if not appropriate).
692       * @param bcsrl a listener used to notify the requestor that the service
693       *              has since been revoked.
694       * @return a reference to the service requested, or <code>null</code>.
695       * @throws TooManyListenersException according to Sun's documentation.
696       */
697      public Object getService (BeanContextChild child, Object requestor,
698                                Class serviceClass, Object serviceSelector,
699                                BeanContextServiceRevokedListener bcsrl)
700        throws TooManyListenersException
701      {
702        synchronized (globalHierarchyLock)
703          {
704            synchronized (services)
705              {
706                Object service;
707                BeanContextServiceProvider provider = ((BCSSServiceProvider)
708                  services.get(serviceClass)).getServiceProvider();
709                if (provider != null)
710                  {
711                    service = provider.getService(this, requestor, serviceClass,
712                                                  serviceSelector);
713                    List childServices = (List) serviceUsers.get(child);
714                    if (childServices == null)
715                      {
716                        childServices = new ArrayList();
717                        serviceUsers.put(child, childServices);
718                      }
719                    childServices.add(serviceClass);
720                  }
721                else 
722                  {
723                    BeanContextServices peer = getBeanContextServicesPeer();
724                    if (peer != null)
725                      service = peer.getService(child, requestor, serviceClass,
726                                                serviceSelector, bcsrl);
727                    else
728                      service = null;
729                  }                                                                     
730                if (service != null)
731                  {
732                    ServiceRequest request = new ServiceRequest(requestor, bcsrl);
733                    Set requests = (Set) serviceRequests.get(serviceClass);
734                    if (requests == null)
735                      {
736                        requests = new HashSet();
737                        serviceRequests.put(serviceClass, requests);
738                      }
739                    requests.add(request);
740                    ServiceLease lease = new ServiceLease(requestor, service);
741                    serviceLeases.put(lease, provider);
742                  }
743                return service;
744              }
745          }
746      }
747    
748      /**
749       * Returns true if the specified service is available.
750       *
751       * @param serviceClass the service to check for.
752       * @return true if the service is available.
753       */
754      public boolean hasService (Class serviceClass)
755      {
756        synchronized (globalHierarchyLock)
757          {
758            synchronized (services)
759              {
760                return services.containsKey(serviceClass);
761              }
762          }
763      }
764    
765      public void initialize ()
766      {
767        super.initialize();
768    
769        bcsListeners = new ArrayList();
770        services = new HashMap();
771        serviceUsers = new HashMap();
772        serviceRequests = new HashMap();
773        serviceLeases = new HashMap();
774      }
775    
776      /**
777       * Subclasses may override this method to allocate resources
778       * from the nesting bean context.
779       */
780      protected  void initializeBeanContextResources()
781      {
782        /* Purposefully left empty */
783      }
784    
785      /**
786       * Relinquishes any resources obtained from the parent context.
787       * Specifically, those services obtained from the parent are revoked.
788       * Subclasses may override this method to deallocate resources
789       * from the nesting bean context.  
790       */
791      protected void releaseBeanContextResources()
792      {
793        /* Purposefully left empty */
794      }
795    
796      /**
797       * Releases the reference to a service held by a
798       * {@link BeanContextChild} (or an arbitrary object associated
799       * with it).  It simply calls the appropriate method on the
800       * underlying provider.
801       *
802       * @param child the child who holds the reference.
803       * @param requestor the object that requested the reference.
804       * @param service the service being released.
805       */
806      public void releaseService (BeanContextChild child, Object requestor,
807                                  Object service)
808      {
809        synchronized (globalHierarchyLock)
810          {
811            synchronized (services)
812              {
813                ServiceLease lease = new ServiceLease(requestor, service);
814                BeanContextServiceProvider provider = (BeanContextServiceProvider)
815                  serviceLeases.get(lease);
816                if (provider != null)
817                  provider.releaseService(this, requestor, service);
818                else
819                  {
820                    BeanContextServices peer = getBeanContextServicesPeer();
821                    if (peer != null)
822                      peer.releaseService(child, requestor, service);
823                  }
824                serviceLeases.remove(lease);
825              }
826          }
827      }
828    
829      public void removeBeanContextServicesListener
830        (BeanContextServicesListener listener)
831      {
832        synchronized (bcsListeners)
833          {
834            bcsListeners.remove(listener);
835          }
836      }
837    
838      /**
839       * Revokes the given service.  A {@link BeanContextServiceRevokedEvent} is
840       * emitted to all registered {@link BeanContextServiceRevokedListener}s
841       * and {@link BeanContextServiceListener}s.  If <code>revokeCurrentServicesNow</code>
842       * is true, termination of the service is immediate.  Otherwise, prior
843       * acquisitions of the service by requestors remain valid.
844       *
845       * @param serviceClass the service to revoke.
846       * @param bcsp the provider of the revoked service.
847       * @param revokeCurrentServicesNow true if this is an exceptional circumstance
848       *                                 where service should be immediately revoked.
849       */
850      public void revokeService (Class serviceClass, BeanContextServiceProvider bcsp,
851                                 boolean revokeCurrentServicesNow)
852      {
853        synchronized (globalHierarchyLock)
854          {
855            synchronized (services)
856              {
857                fireServiceRevoked(serviceClass, revokeCurrentServicesNow);
858                services.remove(serviceClass);
859                if (bcsp instanceof Serializable)
860                  --serializable;
861              }
862          }
863      }
864    
865      public void serviceAvailable (BeanContextServiceAvailableEvent bcssae)
866      {
867        synchronized (services)
868          {
869            Class klass = bcssae.getServiceClass();
870            if (services.containsKey(klass))
871              return;
872            Iterator it = bcsChildren();
873            while (it.hasNext())
874              {
875                Object obj = it.next();
876                if (obj instanceof BeanContextServices)
877                  ((BeanContextServices) obj).serviceAvailable(bcssae);
878              }
879          }
880      }
881    
882      public void serviceRevoked (BeanContextServiceRevokedEvent bcssre)
883      {
884        synchronized (services)
885          {
886            Class klass = bcssre.getServiceClass();
887            if (services.containsKey(klass))
888              return;
889            Iterator it = bcsChildren();
890            while (it.hasNext())
891              {
892                Object obj = it.next();
893                if (obj instanceof BeanContextServices)
894                  ((BeanContextServices) obj).serviceRevoked(bcssre);
895              }
896          }
897      }
898    }