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 BCSSProxyServiceProvider(BeanContextServiceProvider p
)
94 public Iterator
getCurrentServiceSelectors (BeanContextServices bcs
,
97 return provider
.getCurrentServiceSelectors(bcs
, serviceClass
);
100 public Object
getService (BeanContextServices bcs
,
103 Object serviceSelector
)
105 return provider
.getService(bcs
, requestor
, serviceClass
,
109 public void releaseService (BeanContextServices bcs
,
113 provider
.releaseService(bcs
, requestor
, service
);
116 public void serviceRevoked (BeanContextServiceRevokedEvent bcsre
)
118 if (provider
instanceof BeanContextServiceRevokedListener
)
119 ((BeanContextServiceRevokedListener
) provider
).serviceRevoked(bcsre
);
123 protected static class BCSSServiceProvider
124 implements Serializable
126 private static final long serialVersionUID
= 861278251667444782L;
128 protected BeanContextServiceProvider serviceProvider
;
130 private Class serviceClass
;
132 private BCSSServiceProvider(Class serviceClass
,
133 BeanContextServiceProvider provider
)
135 this.serviceClass
= serviceClass
;
136 serviceProvider
= provider
;
139 protected BeanContextServiceProvider
getServiceProvider()
141 return serviceProvider
;
144 private Class
getServiceClass()
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.
156 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
158 private static abstract class Request
160 private Object requestor
;
162 public Request(Object requestor
)
164 this.requestor
= requestor
;
167 public boolean equals(Object obj
)
169 if (obj
instanceof Request
)
171 Request req
= (Request
) obj
;
172 return req
.getRequestor().equals(requestor
);
177 public Object
getRequestor()
185 * Represents a relationship between a service requestor
186 * and a revocation listener.
188 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
190 private static class ServiceRequest
194 private BeanContextServiceRevokedListener listener
;
196 public ServiceRequest(Object requestor
,
197 BeanContextServiceRevokedListener listener
)
200 this.listener
= listener
;
203 public boolean equals(Object obj
)
205 if (obj
instanceof ServiceRequest
)
207 ServiceRequest sr
= (ServiceRequest
) obj
;
208 return (super.equals(obj
) &&
209 sr
.getListener().equals(listener
));
214 public BeanContextServiceRevokedListener
getListener()
221 * Represents a relationship between a service requestor
222 * and a service instance.
224 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
226 private static class ServiceLease
230 private Object service
;
232 public ServiceLease(Object requestor
, Object service
)
235 this.service
= service
;
238 public boolean equals(Object obj
)
240 if (obj
instanceof ServiceLease
)
242 ServiceLease sl
= (ServiceLease
) obj
;
243 return (super.equals(obj
) &&
244 sl
.getService().equals(service
));
249 public Object
getService()
256 * A collection of listeners who receive availability
257 * and revocation notifications.
259 protected transient ArrayList bcsListeners
;
261 protected transient BCSSProxyServiceProvider proxy
;
264 * The number of serializable service providers.
266 protected transient int serializable
;
269 * A map of registered services, linking the service
270 * class to its associated {@link BCSSServiceProvider}.
272 protected transient HashMap services
;
275 * A map of children to a list of services they
278 private transient HashMap serviceUsers
;
281 * A map of services to {@link ServiceRequest}s.
283 private transient HashMap serviceRequests
;
286 * A map of {@link ServiceLease}s to providers.
288 private transient HashMap serviceLeases
;
291 * Construct a {@link BeanContextServicesSupport} instance.
293 public BeanContextServicesSupport ()
299 * Construct a {@link BeanContextServicesSupport} instance.
301 * @param peer the bean context services peer (<code>null</code> permitted).
303 public BeanContextServicesSupport (BeanContextServices peer
)
309 * Construct a {@link BeanContextServicesSupport} instance.
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).
315 public BeanContextServicesSupport(BeanContextServices peer
, Locale locale
)
321 * Construct a {@link BeanContextServicesSupport} instance.
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
329 public BeanContextServicesSupport(BeanContextServices peer
, Locale locale
,
332 super(peer
, locale
, dtime
);
336 * Construct a {@link BeanContextServicesSupport} instance.
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
343 * @param visible initial value of the <code>okToUseGui</code> flag.
345 public BeanContextServicesSupport(BeanContextServices peer
, Locale locale
,
346 boolean dtime
, boolean visible
)
348 super(peer
, locale
, dtime
, visible
);
352 * Adds a new listener for service availability and
355 * @param listener the listener to add.
357 public void addBeanContextServicesListener
358 (BeanContextServicesListener listener
)
360 synchronized (bcsListeners
)
362 if (! bcsListeners
.contains(listener
))
363 bcsListeners
.add(listener
);
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>.
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)
380 public boolean addService (Class serviceClass
,
381 BeanContextServiceProvider bcsp
)
383 return addService(serviceClass
, bcsp
, true);
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>.
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
398 * @return true if the service was registered successfully.
400 protected boolean addService (Class serviceClass
,
401 BeanContextServiceProvider bcsp
,
404 synchronized (globalHierarchyLock
)
406 synchronized (services
)
408 if (services
.containsKey(serviceClass
))
410 services
.put(serviceClass
,
411 createBCSSServiceProvider(serviceClass
, bcsp
));
412 if (bcsp
instanceof Serializable
)
415 fireServiceAdded(serviceClass
);
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.
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
433 protected void bcsPreDeserializationHook (ObjectInputStream ois
)
434 throws ClassNotFoundException
, IOException
436 serializable
= ois
.readInt();
437 for (int a
= 0; a
< serializable
; ++a
)
439 BCSSServiceProvider bcsssp
= (BCSSServiceProvider
) ois
.readObject();
440 addService(bcsssp
.getServiceClass(), bcsssp
.getServiceProvider());
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.
451 * @param oos the stream to which data is being serialized.
452 * @throws IOException if an I/O error occurs.
454 protected void bcsPreSerializationHook (ObjectOutputStream oos
)
457 oos
.writeInt(serializable
);
458 synchronized (services
)
460 Iterator i
= services
.values().iterator();
463 BCSSServiceProvider bcsssp
= (BCSSServiceProvider
) i
.next();
464 if (bcsssp
.getServiceProvider() instanceof Serializable
)
465 oos
.writeObject(bcsssp
);
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
477 * @param child the child being removed.
478 * @param bcsc the support object for the child.
480 protected void childJustRemovedHook (Object child
,
481 BeanContextSupport
.BCSChild bcsc
)
483 if (child
instanceof BeanContextChild
)
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
);
494 * Overrides the {@link BeanContextSupport#createBCSChild} method
495 * so as to use a {@link BCSSChild} instead.
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}.
501 protected BeanContextSupport
.BCSChild
createBCSChild (Object targetChild
,
504 return new BCSSChild(targetChild
, peer
);
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.
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.
517 protected BeanContextServicesSupport
.BCSSServiceProvider
518 createBCSSServiceProvider (Class sc
, BeanContextServiceProvider bcsp
)
520 return new BCSSServiceProvider(sc
, bcsp
);
524 * Sends a <code>BeanContextServiceAvailableEvent</code> to all
525 * registered listeners.
527 * @param bcssae the event to send.
529 protected final void fireServiceAdded (BeanContextServiceAvailableEvent bcssae
)
531 synchronized (bcsListeners
)
533 int size
= bcsListeners
.size();
534 for (int i
= 0; i
< size
; ++i
)
536 BeanContextServicesListener bcsl
537 = (BeanContextServicesListener
) bcsListeners
.get(i
);
538 bcsl
.serviceAvailable(bcssae
);
544 * Sends a <code>BeanContextServiceAvailableEvent</code> to all
545 * registered listeners.
547 * @param serviceClass the service that is now available.
548 * @see #fireServiceAdded(BeanContextServiceAvailableEvent)
550 protected final void fireServiceAdded (Class serviceClass
)
552 fireServiceAdded(new BeanContextServiceAvailableEvent(this,
557 * Sends a <code>BeanContextServiceRevokedEvent</code> to all
558 * registered listeners.
560 * @param event the event to send.
562 protected final void fireServiceRevoked(BeanContextServiceRevokedEvent event
)
564 synchronized (bcsListeners
)
566 int size
= bcsListeners
.size();
567 for (int i
= 0; i
< size
; ++i
)
569 BeanContextServicesListener bcsl
570 = (BeanContextServicesListener
) bcsListeners
.get(i
);
571 bcsl
.serviceRevoked(event
);
573 List requests
= (List
) serviceRequests
.get(event
.getServiceClass());
574 if (requests
!= null)
576 Iterator i
= requests
.iterator();
579 ServiceRequest r
= (ServiceRequest
) i
.next();
580 r
.getListener().serviceRevoked(event
);
587 * Sends a <code>BeanContextServiceRevokedEvent</code> to all
588 * registered listeners.
590 * @param serviceClass the service that has been revoked.
591 * @see #fireServiceRevoked(BeanContextServiceRevokedEvent)
593 protected final void fireServiceRevoked (Class serviceClass
,
596 fireServiceRevoked(new BeanContextServiceRevokedEvent(this, serviceClass
,
601 * Returns the services peer given at construction time,
602 * or <code>null</code> if no peer was given.
604 * @return the {@link BeanContextServices} peer.
606 public BeanContextServices
getBeanContextServicesPeer ()
608 return (BeanContextServices
) beanContextChildPeer
;
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.
616 * @param child the child (<code>null</code> permitted).
618 * @return The child cast to {@link BeanContextServicesListener}.
620 protected static final BeanContextServicesListener
621 getChildBeanContextServicesListener(Object child
)
623 if (child
instanceof BeanContextServicesListener
)
624 return (BeanContextServicesListener
) child
;
630 * Returns an iterator over the currently available
633 * @return an iterator over the currently available services.
635 public Iterator
getCurrentServiceClasses ()
637 synchronized (globalHierarchyLock
)
639 synchronized (services
)
641 return services
.keySet().iterator();
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.
654 * @param serviceClass the service whose provider's selectors should
656 * @return an {@link Iterator} over the service selectors of the
657 * provider of the given service.
659 public Iterator
getCurrentServiceSelectors (Class serviceClass
)
661 synchronized (globalHierarchyLock
)
663 synchronized (services
)
665 BeanContextServiceProvider bcsp
666 = ((BCSSServiceProvider
)
667 services
.get(serviceClass
)).getServiceProvider();
671 return bcsp
.getCurrentServiceSelectors(this, serviceClass
);
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>
684 * @param child the child obtaining the reference.
685 * @param requestor the requestor of the service, which may be the
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.
695 public Object
getService (BeanContextChild child
, Object requestor
,
696 Class serviceClass
, Object serviceSelector
,
697 BeanContextServiceRevokedListener bcsrl
)
698 throws TooManyListenersException
700 synchronized (globalHierarchyLock
)
702 synchronized (services
)
705 BeanContextServiceProvider provider
= ((BCSSServiceProvider
)
706 services
.get(serviceClass
)).getServiceProvider();
707 if (provider
!= null)
709 service
= provider
.getService(this, requestor
, serviceClass
,
711 List childServices
= (List
) serviceUsers
.get(child
);
712 if (childServices
== null)
714 childServices
= new ArrayList();
715 serviceUsers
.put(child
, childServices
);
717 childServices
.add(serviceClass
);
721 BeanContextServices peer
= getBeanContextServicesPeer();
723 service
= peer
.getService(child
, requestor
, serviceClass
,
724 serviceSelector
, bcsrl
);
730 ServiceRequest request
= new ServiceRequest(requestor
, bcsrl
);
731 Set requests
= (Set
) serviceRequests
.get(serviceClass
);
732 if (requests
== null)
734 requests
= new HashSet();
735 serviceRequests
.put(serviceClass
, requests
);
737 requests
.add(request
);
738 ServiceLease lease
= new ServiceLease(requestor
, service
);
739 serviceLeases
.put(lease
, provider
);
747 * Returns true if the specified service is available.
749 * @param serviceClass the service to check for.
750 * @return true if the service is available.
752 public boolean hasService (Class serviceClass
)
754 synchronized (globalHierarchyLock
)
756 synchronized (services
)
758 return services
.containsKey(serviceClass
);
763 public void initialize ()
767 bcsListeners
= new ArrayList();
768 services
= new HashMap();
769 serviceUsers
= new HashMap();
770 serviceRequests
= new HashMap();
771 serviceLeases
= new HashMap();
775 * Subclasses may override this method to allocate resources
776 * from the nesting bean context.
778 protected void initializeBeanContextResources()
780 /* Purposefully left empty */
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.
789 protected void releaseBeanContextResources()
791 /* Purposefully left empty */
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.
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.
804 public void releaseService (BeanContextChild child
, Object requestor
,
807 synchronized (globalHierarchyLock
)
809 synchronized (services
)
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
);
818 BeanContextServices peer
= getBeanContextServicesPeer();
820 peer
.releaseService(child
, requestor
, service
);
822 serviceLeases
.remove(lease
);
827 public void removeBeanContextServicesListener
828 (BeanContextServicesListener listener
)
830 synchronized (bcsListeners
)
832 bcsListeners
.remove(listener
);
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.
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.
848 public void revokeService (Class serviceClass
, BeanContextServiceProvider bcsp
,
849 boolean revokeCurrentServicesNow
)
851 synchronized (globalHierarchyLock
)
853 synchronized (services
)
855 fireServiceRevoked(serviceClass
, revokeCurrentServicesNow
);
856 services
.remove(serviceClass
);
857 if (bcsp
instanceof Serializable
)
863 public void serviceAvailable (BeanContextServiceAvailableEvent bcssae
)
865 synchronized (services
)
867 Class klass
= bcssae
.getServiceClass();
868 if (services
.containsKey(klass
))
870 Iterator it
= bcsChildren();
873 Object obj
= it
.next();
874 if (obj
instanceof BeanContextServices
)
875 ((BeanContextServices
) obj
).serviceAvailable(bcssae
);
880 public void serviceRevoked (BeanContextServiceRevokedEvent bcssre
)
882 synchronized (services
)
884 Class klass
= bcssre
.getServiceClass();
885 if (services
.containsKey(klass
))
887 Iterator it
= bcsChildren();
890 Object obj
= it
.next();
891 if (obj
instanceof BeanContextServices
)
892 ((BeanContextServices
) obj
).serviceRevoked(bcssre
);