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