X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fclasspath%2Fjava%2Fbeans%2Fbeancontext%2FBeanContextServicesSupport.java;h=f354ff474481eb71de908f3e0f83a364bf205859;hb=65bf3316cf384588453604be6b4f0ed3751a8b0f;hp=4da523eeb06e187c3c2fa7b4bd66e952a0269661;hpb=8fc56618a84446beccd45b80381cdfe0e94050df;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java b/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java index 4da523eeb06..f354ff47448 100644 --- a/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java +++ b/libjava/classpath/java/beans/beancontext/BeanContextServicesSupport.java @@ -46,12 +46,21 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Locale; +import java.util.Set; import java.util.TooManyListenersException; /** + * This is a helper class for implementing a bean context which + * supplies services. It is intended to be used either by + * subclassing or by calling methods of this implementation + * from another. + * * @author Michael Koch + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @since 1.2 */ public class BeanContextServicesSupport @@ -77,38 +86,39 @@ public class BeanContextServicesSupport { private static final long serialVersionUID = 7078212910685744490L; - private BCSSProxyServiceProvider() + private BeanContextServiceProvider provider; + + private BCSSProxyServiceProvider(BeanContextServiceProvider p) { + provider = p; } public Iterator getCurrentServiceSelectors (BeanContextServices bcs, Class serviceClass) - throws NotImplementedException { - throw new Error ("Not implemented"); + return provider.getCurrentServiceSelectors(bcs, serviceClass); } public Object getService (BeanContextServices bcs, Object requestor, Class serviceClass, Object serviceSelector) - throws NotImplementedException { - throw new Error ("Not implemented"); + return provider.getService(bcs, requestor, serviceClass, + serviceSelector); } public void releaseService (BeanContextServices bcs, Object requestor, Object service) - throws NotImplementedException { - throw new Error ("Not implemented"); + provider.releaseService(bcs, requestor, service); } public void serviceRevoked (BeanContextServiceRevokedEvent bcsre) - throws NotImplementedException { - throw new Error ("Not implemented"); + if (provider instanceof BeanContextServiceRevokedListener) + ((BeanContextServiceRevokedListener) provider).serviceRevoked(bcsre); } } @@ -119,51 +129,233 @@ public class BeanContextServicesSupport protected BeanContextServiceProvider serviceProvider; - private BCSSServiceProvider() + private Class serviceClass; + + private BCSSServiceProvider(Class serviceClass, + BeanContextServiceProvider provider) { + this.serviceClass = serviceClass; + serviceProvider = provider; } protected BeanContextServiceProvider getServiceProvider() { return serviceProvider; } + + private Class getServiceClass() + { + return serviceClass; + } + } - protected transient ArrayList bcsListeners; + /** + * Represents a request for a service. This is + * a common superclass used by the classes which maintain + * the listener-requestor and service-requestor relationships. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private static abstract class Request + { + private Object requestor; + + public Request(Object requestor) + { + this.requestor = requestor; + } + + public boolean equals(Object obj) + { + if (obj instanceof Request) + { + Request req = (Request) obj; + return req.getRequestor().equals(requestor); + } + return false; + } + + public Object getRequestor() + { + return requestor; + } + + } + + /** + * Represents a relationship between a service requestor + * and a revocation listener. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private static class ServiceRequest + extends Request + { + + private BeanContextServiceRevokedListener listener; + + public ServiceRequest(Object requestor, + BeanContextServiceRevokedListener listener) + { + super(requestor); + this.listener = listener; + } + + public boolean equals(Object obj) + { + if (obj instanceof ServiceRequest) + { + ServiceRequest sr = (ServiceRequest) obj; + return (super.equals(obj) && + sr.getListener().equals(listener)); + } + return false; + } + + public BeanContextServiceRevokedListener getListener() + { + return listener; + } + } + + /** + * Represents a relationship between a service requestor + * and a service instance. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private static class ServiceLease + extends Request + { + private Object service; + + public ServiceLease(Object requestor, Object service) + { + super(requestor); + this.service = service; + } + + public boolean equals(Object obj) + { + if (obj instanceof ServiceLease) + { + ServiceLease sl = (ServiceLease) obj; + return (super.equals(obj) && + sl.getService().equals(service)); + } + return false; + } + + public Object getService() + { + return service; + } + } + + /** + * A collection of listeners who receive availability + * and revocation notifications. + */ + protected transient ArrayList bcsListeners; + protected transient BCSSProxyServiceProvider proxy; + /** + * The number of serializable service providers. + */ protected transient int serializable; + /** + * A map of registered services, linking the service + * class to its associated {@link BCSSServiceProvider}. + */ protected transient HashMap services; + /** + * A map of children to a list of services they + * have obtained. + */ + private transient HashMap serviceUsers; + + /** + * A map of services to {@link ServiceRequest}s. + */ + private transient HashMap serviceRequests; + + /** + * A map of {@link ServiceLease}s to providers. + */ + private transient HashMap serviceLeases; + + /** + * Construct a {@link BeanContextServicesSupport} instance. + */ public BeanContextServicesSupport () { super(); } + /** + * Construct a {@link BeanContextServicesSupport} instance. + * + * @param peer the bean context services peer (null permitted). + */ public BeanContextServicesSupport (BeanContextServices peer) { super(peer); } + /** + * Construct a {@link BeanContextServicesSupport} instance. + * + * @param peer the bean context peer (null permitted). + * @param locale the locale (null permitted, equivalent to + * the default locale). + */ public BeanContextServicesSupport(BeanContextServices peer, Locale locale) { super(peer, locale); } + /** + * Construct a {@link BeanContextServicesSupport} instance. + * + * @param peer the bean context peer (null permitted). + * @param locale the locale (null permitted, equivalent to + * the default locale). + * @param dtime a flag indicating whether or not the bean context is in + * design time mode. + */ public BeanContextServicesSupport(BeanContextServices peer, Locale locale, boolean dtime) { super(peer, locale, dtime); } + /** + * Construct a {@link BeanContextServicesSupport} instance. + * + * @param peer the bean context peer (null permitted). + * @param locale the locale (null permitted, equivalent to + * the default locale). + * @param dtime a flag indicating whether or not the bean context is in + * design time mode. + * @param visible initial value of the okToUseGui flag. + */ public BeanContextServicesSupport(BeanContextServices peer, Locale locale, boolean dtime, boolean visible) { super(peer, locale, dtime, visible); } - + + /** + * Adds a new listener for service availability and + * revocation events. + * + * @param listener the listener to add. + */ public void addBeanContextServicesListener (BeanContextServicesListener listener) { @@ -174,60 +366,168 @@ public class BeanContextServicesSupport } } + /** + * Registers a new service from the specified service provider. + * The service is internally associated with the service provider + * and a BeanContextServiceAvailableEvent is fired. If + * the service is already registered, then this method instead + * returns false. This is equivalent to calling + * addService(serviceClass, bcsp, true). + * + * @param serviceClass the class of the service to be registered. + * @param bcsp the provider of the given service. + * @return true if the service was registered successfully. + * @see #addService(Class, BeanContextServiceProvider, boolean) + */ public boolean addService (Class serviceClass, BeanContextServiceProvider bcsp) { return addService(serviceClass, bcsp, true); } + /** + * Registers a new service from the specified service provider. + * The service is internally associated with the service provider + * and (if fireEvent is true) a + * BeanContextServiceAvailableEvent is fired. If + * the service is already registered, then this method instead + * returns false. + * + * @param serviceClass the class of the service to be registered. + * @param bcsp the provider of the given service. + * @param fireEvent true if a service availability event should + * be fired. + * @return true if the service was registered successfully. + */ protected boolean addService (Class serviceClass, BeanContextServiceProvider bcsp, boolean fireEvent) { - synchronized (services) + synchronized (globalHierarchyLock) { - if (services.containsKey(serviceClass)) - return false; - services.put(serviceClass, bcsp); - if (bcsp instanceof Serializable) - ++serializable; - fireServiceAdded(serviceClass); - return true; + synchronized (services) + { + if (services.containsKey(serviceClass)) + return false; + services.put(serviceClass, + createBCSSServiceProvider(serviceClass, bcsp)); + if (bcsp instanceof Serializable) + ++serializable; + if (fireEvent) + fireServiceAdded(serviceClass); + return true; + } } } + /** + * Deserializes any service providers which are serializable. This + * method is called by the readObject method of + * {@link BeanContextSupport} prior to deserialization of the children. + * Subclasses may envelope its behaviour in order to read further + * serialized data to the stream. + * + * @param oos the stream from which data is being deserialized. + * @throws IOException if an I/O error occurs. + * @throws ClassNotFoundException if the class of a deserialized object + * can not be found. + */ protected void bcsPreDeserializationHook (ObjectInputStream ois) - throws ClassNotFoundException, IOException, NotImplementedException + throws ClassNotFoundException, IOException { - throw new Error ("Not implemented"); + serializable = ois.readInt(); + for (int a = 0; a < serializable; ++a) + { + BCSSServiceProvider bcsssp = (BCSSServiceProvider) ois.readObject(); + addService(bcsssp.getServiceClass(), bcsssp.getServiceProvider()); + } } + /** + * Serializes any service providers which are serializable. This + * method is called by the writeObject method of + * {@link BeanContextSupport} prior to serialization of the children. + * Subclasses may envelope its behaviour in order to add further + * serialized data to the stream. + * + * @param oos the stream to which data is being serialized. + * @throws IOException if an I/O error occurs. + */ protected void bcsPreSerializationHook (ObjectOutputStream oos) - throws IOException, NotImplementedException + throws IOException { - throw new Error ("Not implemented"); + oos.writeInt(serializable); + synchronized (services) + { + Iterator i = services.values().iterator(); + while (i.hasNext()) + { + BCSSServiceProvider bcsssp = (BCSSServiceProvider) i.next(); + if (bcsssp.getServiceProvider() instanceof Serializable) + oos.writeObject(bcsssp); + } + } } - + + /** + * Revokes any services used by a child that has just been removed. + * The superclass ({@link BeanContextSupport}) calls this method + * when a child has just been successfully removed. Subclasses can + * extend this method in order to perform additional operations + * on child removal. + * + * @param child the child being removed. + * @param bcsc the support object for the child. + */ protected void childJustRemovedHook (Object child, BeanContextSupport.BCSChild bcsc) - throws NotImplementedException { - throw new Error ("Not implemented"); + if (child instanceof BeanContextChild) + { + BeanContextChild bcchild = (BeanContextChild) child; + Iterator childServices = ((List) serviceUsers.get(bcchild)).iterator(); + while (childServices.hasNext()) + releaseService(bcchild, this, childServices.next()); + serviceUsers.remove(bcchild); + } } + /** + * Overrides the {@link BeanContextSupport#createBCSChild} method + * so as to use a {@link BCSSChild} instead. + * + * @param targetChild the child to create the child for. + * @param peer the peer which relates to the child if a proxy is used. + * @return a new instance of {@link BCSSChild}. + */ protected BeanContextSupport.BCSChild createBCSChild (Object targetChild, Object peer) { return new BCSSChild(targetChild, peer); } + /** + * Provides a hook so that subclasses can replace the + * {@link BCSSServiceProvider} class, used to store registered + * service providers, with a subclass without replacing the + * {@link #addService(Class, BeanContextServiceProvider)} method. + * + * @param sc the class of service being registered. + * @param bcsp the provider of the service. + * @return a instance of {@link BCSSServiceProvider} wrapping the provider. + */ protected BeanContextServicesSupport.BCSSServiceProvider createBCSSServiceProvider (Class sc, BeanContextServiceProvider bcsp) - throws NotImplementedException { - throw new Error ("Not implemented"); + return new BCSSServiceProvider(sc, bcsp); } + /** + * Sends a BeanContextServiceAvailableEvent to all + * registered listeners. + * + * @param bcssae the event to send. + */ protected final void fireServiceAdded (BeanContextServiceAvailableEvent bcssae) { synchronized (bcsListeners) @@ -242,12 +542,25 @@ public class BeanContextServicesSupport } } + /** + * Sends a BeanContextServiceAvailableEvent to all + * registered listeners. + * + * @param serviceClass the service that is now available. + * @see #fireServiceAdded(BeanContextServiceAvailableEvent) + */ protected final void fireServiceAdded (Class serviceClass) { fireServiceAdded(new BeanContextServiceAvailableEvent(this, serviceClass)); } + /** + * Sends a BeanContextServiceRevokedEvent to all + * registered listeners. + * + * @param event the event to send. + */ protected final void fireServiceRevoked(BeanContextServiceRevokedEvent event) { synchronized (bcsListeners) @@ -259,9 +572,26 @@ public class BeanContextServicesSupport = (BeanContextServicesListener) bcsListeners.get(i); bcsl.serviceRevoked(event); } + List requests = (List) serviceRequests.get(event.getServiceClass()); + if (requests != null) + { + Iterator i = requests.iterator(); + while (i.hasNext()) + { + ServiceRequest r = (ServiceRequest) i.next(); + r.getListener().serviceRevoked(event); + } + } } } + /** + * Sends a BeanContextServiceRevokedEvent to all + * registered listeners. + * + * @param serviceClass the service that has been revoked. + * @see #fireServiceRevoked(BeanContextServiceRevokedEvent) + */ protected final void fireServiceRevoked (Class serviceClass, boolean revokeNow) { @@ -269,51 +599,166 @@ public class BeanContextServicesSupport revokeNow)); } + /** + * Returns the services peer given at construction time, + * or null if no peer was given. + * + * @return the {@link BeanContextServices} peer. + */ public BeanContextServices getBeanContextServicesPeer () - throws NotImplementedException { - throw new Error ("Not implemented"); + return (BeanContextServices) beanContextChildPeer; } + /** + * Returns child as an instance of + * {@link BeanContextServicesListener}, or null if + * child does not implement that interface. + * + * @param child the child (null permitted). + * + * @return The child cast to {@link BeanContextServicesListener}. + */ protected static final BeanContextServicesListener - getChildBeanContextServicesListener (Object child) - throws NotImplementedException + getChildBeanContextServicesListener(Object child) { - throw new Error ("Not implemented"); + if (child instanceof BeanContextServicesListener) + return (BeanContextServicesListener) child; + else + return null; } + /** + * Returns an iterator over the currently available + * services. + * + * @return an iterator over the currently available services. + */ public Iterator getCurrentServiceClasses () { - synchronized (services) + synchronized (globalHierarchyLock) { - return services.keySet().iterator(); + synchronized (services) + { + return services.keySet().iterator(); + } } } + /** + * Returns an iterator over the service selectors of the service + * provider for the given service. The iterator is actually + * obtained by calling the + * {@link BeanContextServiceProvider#getCurrentServiceSelectors} + * of the provider itself. If the specified service is not available, + * null is returned. + * + * @param serviceClass the service whose provider's selectors should + * be iterated over. + * @return an {@link Iterator} over the service selectors of the + * provider of the given service. + */ public Iterator getCurrentServiceSelectors (Class serviceClass) { - synchronized (services) + synchronized (globalHierarchyLock) { - // FIXME: what if service does not exist? Must write a test. - BeanContextServiceProvider bcsp - = (BeanContextServiceProvider) services.get(serviceClass); - return bcsp.getCurrentServiceSelectors(this, serviceClass); + synchronized (services) + { + BeanContextServiceProvider bcsp + = ((BCSSServiceProvider) + services.get(serviceClass)).getServiceProvider(); + if (bcsp == null) + return null; + else + return bcsp.getCurrentServiceSelectors(this, serviceClass); + } } } + /** + * Retrieves the specified service. If a provider for the service + * is registered in this context, then the request is passed on to + * the provider and the service returned. Otherwise, the request + * is delegated to a parent {@link BeanContextServices}, if possible. + * If the service can not be found at all, then null + * is returned. + * + * @param child the child obtaining the reference. + * @param requestor the requestor of the service, which may be the + * child itself. + * @param serviceClass the service being requested. + * @param serviceSelector an additional service-dependent parameter + * (may be null if not appropriate). + * @param bcsrl a listener used to notify the requestor that the service + * has since been revoked. + * @return a reference to the service requested, or null. + * @throws TooManyListenersException according to Sun's documentation. + */ public Object getService (BeanContextChild child, Object requestor, Class serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) - throws TooManyListenersException, NotImplementedException + throws TooManyListenersException { - throw new Error ("Not implemented"); + synchronized (globalHierarchyLock) + { + synchronized (services) + { + Object service; + BeanContextServiceProvider provider = ((BCSSServiceProvider) + services.get(serviceClass)).getServiceProvider(); + if (provider != null) + { + service = provider.getService(this, requestor, serviceClass, + serviceSelector); + List childServices = (List) serviceUsers.get(child); + if (childServices == null) + { + childServices = new ArrayList(); + serviceUsers.put(child, childServices); + } + childServices.add(serviceClass); + } + else + { + BeanContextServices peer = getBeanContextServicesPeer(); + if (peer != null) + service = peer.getService(child, requestor, serviceClass, + serviceSelector, bcsrl); + else + service = null; + } + if (service != null) + { + ServiceRequest request = new ServiceRequest(requestor, bcsrl); + Set requests = (Set) serviceRequests.get(serviceClass); + if (requests == null) + { + requests = new HashSet(); + serviceRequests.put(serviceClass, requests); + } + requests.add(request); + ServiceLease lease = new ServiceLease(requestor, service); + serviceLeases.put(lease, provider); + } + return service; + } + } } + /** + * Returns true if the specified service is available. + * + * @param serviceClass the service to check for. + * @return true if the service is available. + */ public boolean hasService (Class serviceClass) { - synchronized (services) + synchronized (globalHierarchyLock) { - return services.containsKey(serviceClass); + synchronized (services) + { + return services.containsKey(serviceClass); + } } } @@ -323,25 +768,62 @@ public class BeanContextServicesSupport bcsListeners = new ArrayList(); services = new HashMap(); + serviceUsers = new HashMap(); + serviceRequests = new HashMap(); + serviceLeases = new HashMap(); } - protected void initializeBeanContextResources () - throws NotImplementedException + /** + * Subclasses may override this method to allocate resources + * from the nesting bean context. + */ + protected void initializeBeanContextResources() { - throw new Error ("Not implemented"); + /* Purposefully left empty */ } - protected void releaseBeanContextResources () - throws NotImplementedException + /** + * Relinquishes any resources obtained from the parent context. + * Specifically, those services obtained from the parent are revoked. + * Subclasses may override this method to deallocate resources + * from the nesting bean context. + */ + protected void releaseBeanContextResources() { - throw new Error ("Not implemented"); + /* Purposefully left empty */ } + /** + * Releases the reference to a service held by a + * {@link BeanContextChild} (or an arbitrary object associated + * with it). It simply calls the appropriate method on the + * underlying provider. + * + * @param child the child who holds the reference. + * @param requestor the object that requested the reference. + * @param service the service being released. + */ public void releaseService (BeanContextChild child, Object requestor, Object service) - throws NotImplementedException { - throw new Error ("Not implemented"); + synchronized (globalHierarchyLock) + { + synchronized (services) + { + ServiceLease lease = new ServiceLease(requestor, service); + BeanContextServiceProvider provider = (BeanContextServiceProvider) + serviceLeases.get(lease); + if (provider != null) + provider.releaseService(this, requestor, service); + else + { + BeanContextServices peer = getBeanContextServicesPeer(); + if (peer != null) + peer.releaseService(child, requestor, service); + } + serviceLeases.remove(lease); + } + } } public void removeBeanContextServicesListener @@ -349,17 +831,35 @@ public class BeanContextServicesSupport { synchronized (bcsListeners) { - int index = bcsListeners.indexOf(listener); - if (index > -1) - bcsListeners.remove(index); + bcsListeners.remove(listener); } } + /** + * Revokes the given service. A {@link BeanContextServiceRevokedEvent} is + * emitted to all registered {@link BeanContextServiceRevokedListener}s + * and {@link BeanContextServiceListener}s. If revokeCurrentServicesNow + * is true, termination of the service is immediate. Otherwise, prior + * acquisitions of the service by requestors remain valid. + * + * @param serviceClass the service to revoke. + * @param bcsp the provider of the revoked service. + * @param revokeCurrentServicesNow true if this is an exceptional circumstance + * where service should be immediately revoked. + */ public void revokeService (Class serviceClass, BeanContextServiceProvider bcsp, boolean revokeCurrentServicesNow) - throws NotImplementedException { - throw new Error ("Not implemented"); + synchronized (globalHierarchyLock) + { + synchronized (services) + { + fireServiceRevoked(serviceClass, revokeCurrentServicesNow); + services.remove(serviceClass); + if (bcsp instanceof Serializable) + --serializable; + } + } } public void serviceAvailable (BeanContextServiceAvailableEvent bcssae)