Source for java.beans.beancontext.BeanContextServicesSupport

   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 oos 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: }