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:     BCSSProxyServiceProvider(BeanContextServiceProvider p)
  90:     {
  91:       provider = p;
  92:     }
  93: 
  94:     public Iterator getCurrentServiceSelectors (BeanContextServices bcs,
  95:                                                 Class serviceClass)
  96:     {
  97:       return provider.getCurrentServiceSelectors(bcs, serviceClass);
  98:     }
  99: 
 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: }