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