libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / java / beans / beancontext / BeanContextServicesSupport.java
blob725c2d468885b09185e667fb6b4448b9635c2527
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)
9 any later version.
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
19 02110-1301 USA.
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.
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;
51 import java.util.Set;
52 import java.util.TooManyListenersException;
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.
60 * @author Michael Koch
61 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
62 * @since 1.2
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)
91 provider = p;
94 public Iterator getCurrentServiceSelectors (BeanContextServices bcs,
95 Class serviceClass)
97 return provider.getCurrentServiceSelectors(bcs, serviceClass);
100 public Object getService (BeanContextServices bcs,
101 Object requestor,
102 Class serviceClass,
103 Object serviceSelector)
105 return provider.getService(bcs, requestor, serviceClass,
106 serviceSelector);
109 public void releaseService (BeanContextServices bcs,
110 Object requestor,
111 Object service)
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()
146 return serviceClass;
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);
174 return false;
177 public Object getRequestor()
179 return requestor;
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
191 extends Request
194 private BeanContextServiceRevokedListener listener;
196 public ServiceRequest(Object requestor,
197 BeanContextServiceRevokedListener listener)
199 super(requestor);
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));
211 return false;
214 public BeanContextServiceRevokedListener getListener()
216 return listener;
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
227 extends Request
230 private Object service;
232 public ServiceLease(Object requestor, Object service)
234 super(requestor);
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));
246 return false;
249 public Object getService()
251 return service;
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
276 * have obtained.
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 ()
295 super();
299 * Construct a {@link BeanContextServicesSupport} instance.
301 * @param peer the bean context services peer (<code>null</code> permitted).
303 public BeanContextServicesSupport (BeanContextServices peer)
305 super(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)
317 super(peer, 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
327 * design time mode.
329 public BeanContextServicesSupport(BeanContextServices peer, Locale locale,
330 boolean dtime)
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
342 * design time mode.
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
353 * revocation events.
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
397 * be fired.
398 * @return true if the service was registered successfully.
400 protected boolean addService (Class serviceClass,
401 BeanContextServiceProvider bcsp,
402 boolean fireEvent)
404 synchronized (globalHierarchyLock)
406 synchronized (services)
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;
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
431 * can not be found.
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)
455 throws IOException
457 oos.writeInt(serializable);
458 synchronized (services)
460 Iterator i = services.values().iterator();
461 while (i.hasNext())
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
475 * on child removal.
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,
502 Object peer)
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,
553 serviceClass));
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();
577 while (i.hasNext())
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,
594 boolean revokeNow)
596 fireServiceRevoked(new BeanContextServiceRevokedEvent(this, serviceClass,
597 revokeNow));
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;
625 else
626 return null;
630 * Returns an iterator over the currently available
631 * services.
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
655 * be iterated over.
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();
668 if (bcsp == null)
669 return null;
670 else
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>
682 * is returned.
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.
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)
704 Object service;
705 BeanContextServiceProvider provider = ((BCSSServiceProvider)
706 services.get(serviceClass)).getServiceProvider();
707 if (provider != null)
709 service = provider.getService(this, requestor, serviceClass,
710 serviceSelector);
711 List childServices = (List) serviceUsers.get(child);
712 if (childServices == null)
714 childServices = new ArrayList();
715 serviceUsers.put(child, childServices);
717 childServices.add(serviceClass);
719 else
721 BeanContextServices peer = getBeanContextServicesPeer();
722 if (peer != null)
723 service = peer.getService(child, requestor, serviceClass,
724 serviceSelector, bcsrl);
725 else
726 service = null;
728 if (service != null)
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);
741 return service;
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 ()
765 super.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,
805 Object service)
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);
816 else
818 BeanContextServices peer = getBeanContextServicesPeer();
819 if (peer != null)
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)
858 --serializable;
863 public void serviceAvailable (BeanContextServiceAvailableEvent bcssae)
865 synchronized (services)
867 Class klass = bcssae.getServiceClass();
868 if (services.containsKey(klass))
869 return;
870 Iterator it = bcsChildren();
871 while (it.hasNext())
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))
886 return;
887 Iterator it = bcsChildren();
888 while (it.hasNext())
890 Object obj = it.next();
891 if (obj instanceof BeanContextServices)
892 ((BeanContextServices) obj).serviceRevoked(bcssre);