1 /* BeanContextServicesSupport.java --
2 Copyright (C) 2003, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 package java.beans.beancontext;
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;
52 import java.util.TooManyListenersException;
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
60 * @author Michael Koch
61 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
64 public class BeanContextServicesSupport
65 extends BeanContextSupport
66 implements BeanContextServices
68 private static final long serialVersionUID = -8494482757288719206L;
70 protected class BCSSChild
71 extends BeanContextSupport.BCSChild
73 private static final long serialVersionUID = -3263851306889194873L;
75 BCSSChild(Object targetChild, Object peer)
77 super(targetChild, peer);
81 protected class BCSSProxyServiceProvider
82 implements BeanContextServiceProvider,
83 BeanContextServiceRevokedListener
85 private static final long serialVersionUID = 7078212910685744490L;
87 private BeanContextServiceProvider provider;
89 public Iterator getCurrentServiceSelectors (BeanContextServices bcs,
92 return provider.getCurrentServiceSelectors(bcs, serviceClass);
95 public Object getService (BeanContextServices bcs,
98 Object serviceSelector)
100 return provider.getService(bcs, requestor, serviceClass,
104 public void releaseService (BeanContextServices bcs,
108 provider.releaseService(bcs, requestor, service);
111 public void serviceRevoked (BeanContextServiceRevokedEvent bcsre)
113 if (provider instanceof BeanContextServiceRevokedListener)
114 ((BeanContextServiceRevokedListener) provider).serviceRevoked(bcsre);
118 protected static class BCSSServiceProvider
119 implements Serializable
121 private static final long serialVersionUID = 861278251667444782L;
123 protected BeanContextServiceProvider serviceProvider;
125 private Class serviceClass;
127 private BCSSServiceProvider(Class serviceClass,
128 BeanContextServiceProvider provider)
130 this.serviceClass = serviceClass;
131 serviceProvider = provider;
134 protected BeanContextServiceProvider getServiceProvider()
136 return serviceProvider;
139 private Class getServiceClass()
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.
151 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
153 private static abstract class Request
155 private Object requestor;
157 public Request(Object requestor)
159 this.requestor = requestor;
162 public boolean equals(Object obj)
164 if (obj instanceof Request)
166 Request req = (Request) obj;
167 return req.getRequestor().equals(requestor);
172 public Object getRequestor()
180 * Represents a relationship between a service requestor
181 * and a revocation listener.
183 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
185 private static class ServiceRequest
189 private BeanContextServiceRevokedListener listener;
191 public ServiceRequest(Object requestor,
192 BeanContextServiceRevokedListener listener)
195 this.listener = listener;
198 public boolean equals(Object obj)
200 if (obj instanceof ServiceRequest)
202 ServiceRequest sr = (ServiceRequest) obj;
203 return (super.equals(obj) &&
204 sr.getListener().equals(listener));
209 public BeanContextServiceRevokedListener getListener()
216 * Represents a relationship between a service requestor
217 * and a service instance.
219 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
221 private static class ServiceLease
225 private Object service;
227 public ServiceLease(Object requestor, Object service)
230 this.service = service;
233 public boolean equals(Object obj)
235 if (obj instanceof ServiceLease)
237 ServiceLease sl = (ServiceLease) obj;
238 return (super.equals(obj) &&
239 sl.getService().equals(service));
244 public Object getService()
251 * A collection of listeners who receive availability
252 * and revocation notifications.
254 protected transient ArrayList bcsListeners;
256 protected transient BCSSProxyServiceProvider proxy;
259 * The number of serializable service providers.
261 protected transient int serializable;
264 * A map of registered services, linking the service
265 * class to its associated {@link BCSSServiceProvider}.
267 protected transient HashMap services;
270 * A map of children to a list of services they
273 private transient HashMap serviceUsers;
276 * A map of services to {@link ServiceRequest}s.
278 private transient HashMap serviceRequests;
281 * A map of {@link ServiceLease}s to providers.
283 private transient HashMap serviceLeases;
286 * Construct a {@link BeanContextServicesSupport} instance.
288 public BeanContextServicesSupport ()
294 * Construct a {@link BeanContextServicesSupport} instance.
296 * @param peer the bean context services peer (<code>null</code> permitted).
298 public BeanContextServicesSupport (BeanContextServices peer)
304 * Construct a {@link BeanContextServicesSupport} instance.
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).
310 public BeanContextServicesSupport(BeanContextServices peer, Locale locale)
316 * Construct a {@link BeanContextServicesSupport} instance.
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
324 public BeanContextServicesSupport(BeanContextServices peer, Locale locale,
327 super(peer, locale, dtime);
331 * Construct a {@link BeanContextServicesSupport} instance.
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
338 * @param visible initial value of the <code>okToUseGui</code> flag.
340 public BeanContextServicesSupport(BeanContextServices peer, Locale locale,
341 boolean dtime, boolean visible)
343 super(peer, locale, dtime, visible);
347 * Adds a new listener for service availability and
350 * @param listener the listener to add.
352 public void addBeanContextServicesListener
353 (BeanContextServicesListener listener)
355 synchronized (bcsListeners)
357 if (! bcsListeners.contains(listener))
358 bcsListeners.add(listener);
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>.
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)
375 public boolean addService (Class serviceClass,
376 BeanContextServiceProvider bcsp)
378 return addService(serviceClass, bcsp, true);
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>.
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
393 * @return true if the service was registered successfully.
395 protected boolean addService (Class serviceClass,
396 BeanContextServiceProvider bcsp,
399 synchronized (globalHierarchyLock)
401 synchronized (services)
403 if (services.containsKey(serviceClass))
405 services.put(serviceClass,
406 createBCSSServiceProvider(serviceClass, bcsp));
407 if (bcsp instanceof Serializable)
410 fireServiceAdded(serviceClass);
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.
423 * @param ois the stream from which data is being deserialized.
424 * @throws IOException if an I/O error occurs.
425 * @throws ClassNotFoundException if the class of a deserialized object
428 protected void bcsPreDeserializationHook (ObjectInputStream ois)
429 throws ClassNotFoundException, IOException
431 serializable = ois.readInt();
432 for (int a = 0; a < serializable; ++a)
434 BCSSServiceProvider bcsssp = (BCSSServiceProvider) ois.readObject();
435 addService(bcsssp.getServiceClass(), bcsssp.getServiceProvider());
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.
446 * @param oos the stream to which data is being serialized.
447 * @throws IOException if an I/O error occurs.
449 protected void bcsPreSerializationHook (ObjectOutputStream oos)
452 oos.writeInt(serializable);
453 synchronized (services)
455 Iterator i = services.values().iterator();
458 BCSSServiceProvider bcsssp = (BCSSServiceProvider) i.next();
459 if (bcsssp.getServiceProvider() instanceof Serializable)
460 oos.writeObject(bcsssp);
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
472 * @param child the child being removed.
473 * @param bcsc the support object for the child.
475 protected void childJustRemovedHook (Object child,
476 BeanContextSupport.BCSChild bcsc)
478 if (child instanceof BeanContextChild)
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);
489 * Overrides the {@link BeanContextSupport#createBCSChild} method
490 * so as to use a {@link BCSSChild} instead.
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}.
496 protected BeanContextSupport.BCSChild createBCSChild (Object targetChild,
499 return new BCSSChild(targetChild, peer);
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.
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.
512 protected BeanContextServicesSupport.BCSSServiceProvider
513 createBCSSServiceProvider (Class sc, BeanContextServiceProvider bcsp)
515 return new BCSSServiceProvider(sc, bcsp);
519 * Sends a <code>BeanContextServiceAvailableEvent</code> to all
520 * registered listeners.
522 * @param bcssae the event to send.
524 protected final void fireServiceAdded (BeanContextServiceAvailableEvent bcssae)
526 synchronized (bcsListeners)
528 int size = bcsListeners.size();
529 for (int i = 0; i < size; ++i)
531 BeanContextServicesListener bcsl
532 = (BeanContextServicesListener) bcsListeners.get(i);
533 bcsl.serviceAvailable(bcssae);
539 * Sends a <code>BeanContextServiceAvailableEvent</code> to all
540 * registered listeners.
542 * @param serviceClass the service that is now available.
543 * @see #fireServiceAdded(BeanContextServiceAvailableEvent)
545 protected final void fireServiceAdded (Class serviceClass)
547 fireServiceAdded(new BeanContextServiceAvailableEvent(this,
552 * Sends a <code>BeanContextServiceRevokedEvent</code> to all
553 * registered listeners.
555 * @param event the event to send.
557 protected final void fireServiceRevoked(BeanContextServiceRevokedEvent event)
559 synchronized (bcsListeners)
561 int size = bcsListeners.size();
562 for (int i = 0; i < size; ++i)
564 BeanContextServicesListener bcsl
565 = (BeanContextServicesListener) bcsListeners.get(i);
566 bcsl.serviceRevoked(event);
568 List requests = (List) serviceRequests.get(event.getServiceClass());
569 if (requests != null)
571 Iterator i = requests.iterator();
574 ServiceRequest r = (ServiceRequest) i.next();
575 r.getListener().serviceRevoked(event);
582 * Sends a <code>BeanContextServiceRevokedEvent</code> to all
583 * registered listeners.
585 * @param serviceClass the service that has been revoked.
586 * @see #fireServiceRevoked(BeanContextServiceRevokedEvent)
588 protected final void fireServiceRevoked (Class serviceClass,
591 fireServiceRevoked(new BeanContextServiceRevokedEvent(this, serviceClass,
596 * Returns the services peer given at construction time,
597 * or <code>null</code> if no peer was given.
599 * @return the {@link BeanContextServices} peer.
601 public BeanContextServices getBeanContextServicesPeer ()
603 return (BeanContextServices) beanContextChildPeer;
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.
611 * @param child the child (<code>null</code> permitted).
613 * @return The child cast to {@link BeanContextServicesListener}.
615 protected static final BeanContextServicesListener
616 getChildBeanContextServicesListener(Object child)
618 if (child instanceof BeanContextServicesListener)
619 return (BeanContextServicesListener) child;
625 * Returns an iterator over the currently available
628 * @return an iterator over the currently available services.
630 public Iterator getCurrentServiceClasses ()
632 synchronized (globalHierarchyLock)
634 synchronized (services)
636 return services.keySet().iterator();
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.
649 * @param serviceClass the service whose provider's selectors should
651 * @return an {@link Iterator} over the service selectors of the
652 * provider of the given service.
654 public Iterator getCurrentServiceSelectors (Class serviceClass)
656 synchronized (globalHierarchyLock)
658 synchronized (services)
660 BeanContextServiceProvider bcsp
661 = ((BCSSServiceProvider)
662 services.get(serviceClass)).getServiceProvider();
666 return bcsp.getCurrentServiceSelectors(this, serviceClass);
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>
679 * @param child the child obtaining the reference.
680 * @param requestor the requestor of the service, which may be the
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.
690 public Object getService (BeanContextChild child, Object requestor,
691 Class serviceClass, Object serviceSelector,
692 BeanContextServiceRevokedListener bcsrl)
693 throws TooManyListenersException
695 synchronized (globalHierarchyLock)
697 synchronized (services)
700 BeanContextServiceProvider provider = ((BCSSServiceProvider)
701 services.get(serviceClass)).getServiceProvider();
702 if (provider != null)
704 service = provider.getService(this, requestor, serviceClass,
706 List childServices = (List) serviceUsers.get(child);
707 if (childServices == null)
709 childServices = new ArrayList();
710 serviceUsers.put(child, childServices);
712 childServices.add(serviceClass);
716 BeanContextServices peer = getBeanContextServicesPeer();
718 service = peer.getService(child, requestor, serviceClass,
719 serviceSelector, bcsrl);
725 ServiceRequest request = new ServiceRequest(requestor, bcsrl);
726 Set requests = (Set) serviceRequests.get(serviceClass);
727 if (requests == null)
729 requests = new HashSet();
730 serviceRequests.put(serviceClass, requests);
732 requests.add(request);
733 ServiceLease lease = new ServiceLease(requestor, service);
734 serviceLeases.put(lease, provider);
742 * Returns true if the specified service is available.
744 * @param serviceClass the service to check for.
745 * @return true if the service is available.
747 public boolean hasService (Class serviceClass)
749 synchronized (globalHierarchyLock)
751 synchronized (services)
753 return services.containsKey(serviceClass);
758 public void initialize ()
762 bcsListeners = new ArrayList();
763 services = new HashMap();
764 serviceUsers = new HashMap();
765 serviceRequests = new HashMap();
766 serviceLeases = new HashMap();
770 * Subclasses may override this method to allocate resources
771 * from the nesting bean context.
773 protected void initializeBeanContextResources()
775 /* Purposefully left empty */
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.
784 protected void releaseBeanContextResources()
786 /* Purposefully left empty */
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.
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.
799 public void releaseService (BeanContextChild child, Object requestor,
802 synchronized (globalHierarchyLock)
804 synchronized (services)
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);
813 BeanContextServices peer = getBeanContextServicesPeer();
815 peer.releaseService(child, requestor, service);
817 serviceLeases.remove(lease);
822 public void removeBeanContextServicesListener
823 (BeanContextServicesListener listener)
825 synchronized (bcsListeners)
827 bcsListeners.remove(listener);
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.
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.
843 public void revokeService (Class serviceClass, BeanContextServiceProvider bcsp,
844 boolean revokeCurrentServicesNow)
846 synchronized (globalHierarchyLock)
848 synchronized (services)
850 fireServiceRevoked(serviceClass, revokeCurrentServicesNow);
851 services.remove(serviceClass);
852 if (bcsp instanceof Serializable)
858 public void serviceAvailable (BeanContextServiceAvailableEvent bcssae)
860 synchronized (services)
862 Class klass = bcssae.getServiceClass();
863 if (services.containsKey(klass))
865 Iterator it = bcsChildren();
868 Object obj = it.next();
869 if (obj instanceof BeanContextServices)
870 ((BeanContextServices) obj).serviceAvailable(bcssae);
875 public void serviceRevoked (BeanContextServiceRevokedEvent bcssre)
877 synchronized (services)
879 Class klass = bcssre.getServiceClass();
880 if (services.containsKey(klass))
882 Iterator it = bcsChildren();
885 Object obj = it.next();
886 if (obj instanceof BeanContextServices)
887 ((BeanContextServices) obj).serviceRevoked(bcssre);