OSDN Git Service

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