0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.beans.beancontext;
0019:
0020: import java.io.IOException;
0021: import java.io.ObjectInputStream;
0022: import java.io.ObjectOutputStream;
0023: import java.io.Serializable;
0024: import java.util.ArrayList;
0025: import java.util.HashMap;
0026: import java.util.Iterator;
0027: import java.util.Locale;
0028: import java.util.TooManyListenersException;
0029: import java.util.Map.Entry;
0030:
0031: import org.apache.harmony.beans.internal.nls.Messages;
0032:
0033: /**
0034: * This support class implements <code>BeanContextServices</code> interface.
0035: * This class can be used directly, or be a super class of your class, or be a
0036: * delegate of your implementation that needs to support
0037: * <code>BeanContextServices</code> interface.
0038: *
0039: */
0040: public class BeanContextServicesSupport extends BeanContextSupport
0041: implements BeanContextServices, Serializable {
0042:
0043: private static class ServiceRecord {
0044:
0045: BeanContextServiceProvider provider;
0046:
0047: BeanContextChild child;
0048:
0049: Object requestor;
0050:
0051: Class serviceClass;
0052:
0053: BeanContextServiceRevokedListener revokedListener;
0054:
0055: Object service;
0056:
0057: boolean isDelegate;
0058:
0059: ServiceRecord(BeanContextServiceProvider provider,
0060: BeanContextChild child, Object requestor,
0061: Class serviceClass,
0062: BeanContextServiceRevokedListener revokedListener,
0063: Object service, boolean isDelegate) {
0064: this .provider = provider;
0065: this .child = child;
0066: this .requestor = requestor;
0067: this .serviceClass = serviceClass;
0068: this .revokedListener = revokedListener;
0069: this .service = service;
0070: this .isDelegate = isDelegate;
0071: }
0072: }
0073:
0074: /**
0075: * Every child of context is companied with a <code>BCSSChild</code>
0076: * instance. It can hold implementation specific information about each
0077: * child.
0078: * <p>
0079: * This class keeps records of all services requests submitted by this
0080: * child.
0081: * </p>
0082: *
0083: */
0084: protected class BCSSChild extends BeanContextSupport.BCSChild {
0085:
0086: private static final long serialVersionUID = -3263851306889194873L;
0087:
0088: transient ArrayList<ServiceRecord> serviceRecords;
0089:
0090: BCSSChild(Object child, Object proxyPeer) {
0091: super (child, proxyPeer);
0092: }
0093:
0094: }
0095:
0096: /**
0097: * This class implements the <code>BeanContextServiceProvider</code>
0098: * interface by wrapping a <code>BeanContextServices</code>. All services
0099: * registered in the <code>BeanContextServices</code> are accessible via
0100: * this wrapper service provider.
0101: * <p>
0102: * This class is used by <code>BeanContextServicesSupport</code> to access
0103: * services provided by its parent context (if there is one).
0104: * </p>
0105: *
0106: */
0107: protected class BCSSProxyServiceProvider implements
0108: BeanContextServiceProvider,
0109: BeanContextServiceRevokedListener {
0110:
0111: private BeanContextServices backBCS;
0112:
0113: BCSSProxyServiceProvider(BeanContextServices backBCS) {
0114: this .backBCS = backBCS;
0115: }
0116:
0117: /**
0118: * Throws <code>UnsupportedOperationException</code>.
0119: */
0120: public Iterator getCurrentServiceSelectors(
0121: BeanContextServices bcs, Class serviceClass) {
0122: throw new UnsupportedOperationException();
0123: }
0124:
0125: /**
0126: * Throws <code>UnsupportedOperationException</code>.
0127: */
0128: public Object getService(BeanContextServices bcs,
0129: Object requestor, Class serviceClass,
0130: Object serviceSelector) {
0131: throw new UnsupportedOperationException();
0132: }
0133:
0134: /**
0135: * Delegate to the wrapped <code>BeanContextServices</code>.
0136: */
0137: Object getService(BeanContextServices bcs, Object requestor,
0138: Class serviceClass, Object serviceSelector,
0139: BeanContextServiceRevokedListener listener)
0140: throws TooManyListenersException {
0141: return backBCS.getService(BeanContextServicesSupport.this
0142: .getBeanContextServicesPeer(), requestor,
0143: serviceClass, serviceSelector,
0144: new ServiceRevokedListenerDelegator(listener));
0145: }
0146:
0147: /**
0148: * Delegate to the wrapped <code>BeanContextServices</code>.
0149: */
0150: public void releaseService(BeanContextServices bcs,
0151: Object requestor, Object service) {
0152: backBCS.releaseService(BeanContextServicesSupport.this
0153: .getBeanContextServicesPeer(), requestor, service);
0154: }
0155:
0156: /**
0157: * Throws <code>UnsupportedOperationException</code>.
0158: */
0159: public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) {
0160: throw new UnsupportedOperationException();
0161: }
0162:
0163: }
0164:
0165: private class ServiceRevokedListenerDelegator implements
0166: BeanContextServiceRevokedListener {
0167:
0168: private BeanContextServiceRevokedListener backListener;
0169:
0170: public ServiceRevokedListenerDelegator(
0171: BeanContextServiceRevokedListener backListener) {
0172: this .backListener = backListener;
0173: }
0174:
0175: public void serviceRevoked(BeanContextServiceRevokedEvent event) {
0176: backListener
0177: .serviceRevoked(new BeanContextServiceRevokedEvent(
0178: BeanContextServicesSupport.this
0179: .getBeanContextServicesPeer(),
0180: event.getServiceClass(), event
0181: .isCurrentServiceInvalidNow()));
0182: }
0183:
0184: }
0185:
0186: /**
0187: * Every servie registered in this context is companied with a
0188: * <code>BCSSServiceProvider</code> instance. It can hold implementation
0189: * specific information about each registered service.
0190: * <p>
0191: * This class holds a reference to the service provider of the service.
0192: * </p>
0193: *
0194: */
0195: protected static class BCSSServiceProvider implements Serializable {
0196:
0197: static final long serialVersionUID = 861278251667444782L;
0198:
0199: /**
0200: * The service provider of the related service.
0201: */
0202: protected BeanContextServiceProvider serviceProvider;
0203:
0204: BCSSServiceProvider(BeanContextServiceProvider provider) {
0205: this .serviceProvider = provider;
0206: }
0207:
0208: /**
0209: * Returns the service provider of the related service.
0210: *
0211: * @return the service provider of the related service
0212: */
0213: protected BeanContextServiceProvider getServiceProvider() {
0214: return serviceProvider;
0215: }
0216:
0217: }
0218:
0219: static final long serialVersionUID = -8494482757288719206L;
0220:
0221: /**
0222: * A map of all registered services - key is service class, value is
0223: * <code>BCSSServiceProvider</code> object. All access to this object
0224: * should be synchronized on itself.
0225: */
0226: @SuppressWarnings("unchecked")
0227: protected transient HashMap services;
0228:
0229: /**
0230: * The number of serializable service providers currently registered.
0231: */
0232: protected transient int serializable;
0233:
0234: /**
0235: * A proxy service provider that delegates service requests to the parent
0236: * context.
0237: */
0238: protected transient BCSSProxyServiceProvider proxy;
0239:
0240: /**
0241: * A list of registered <code>BeanContextServicesListener</code>s. All
0242: * access to this object should be synchronized on itself.
0243: */
0244: @SuppressWarnings("unchecked")
0245: protected transient ArrayList bcsListeners;
0246:
0247: /**
0248: * Constructs a standard <code>BeanContextServicesSupport</code>.
0249: */
0250: public BeanContextServicesSupport() {
0251: super ();
0252: }
0253:
0254: /**
0255: * Constructs a <code>BeanContextServicesSupport</code> which is a
0256: * delegate of the given peer.
0257: *
0258: * @param peer
0259: * the peer of this context
0260: */
0261: public BeanContextServicesSupport(BeanContextServices peer) {
0262: super (peer);
0263: }
0264:
0265: /**
0266: * Constructs a <code>BeanContextServicesSupport</code> which is a
0267: * delegate of the given peer.
0268: *
0269: * @param peer
0270: * the peer of this context
0271: * @param locale
0272: * the locale of this context
0273: */
0274: public BeanContextServicesSupport(BeanContextServices peer,
0275: Locale locale) {
0276: super (peer, locale);
0277: }
0278:
0279: /**
0280: * Constructs a <code>BeanContextServicesSupport</code> which is a
0281: * delegate of the given peer.
0282: *
0283: * @param peer
0284: * the peer of this context
0285: * @param locale
0286: * the locale of this context
0287: * @param designTime
0288: * whether in design mode or not
0289: */
0290: public BeanContextServicesSupport(BeanContextServices peer,
0291: Locale locale, boolean designTime) {
0292: super (peer, locale, designTime);
0293: }
0294:
0295: /**
0296: * Constructs a <code>BeanContextServicesSupport</code> which is a
0297: * delegate of the given peer.
0298: *
0299: * @param peer
0300: * the peer of this context
0301: * @param locale
0302: * the locale of this context
0303: * @param designTime
0304: * whether in design mode or not
0305: * @param okToUseGui
0306: * whether GUI is usable or not
0307: */
0308: public BeanContextServicesSupport(BeanContextServices peer,
0309: Locale locale, boolean designTime, boolean okToUseGui) {
0310: super (peer, locale, designTime, okToUseGui);
0311: }
0312:
0313: /*
0314: * (non-Javadoc)
0315: *
0316: * @see java.beans.beancontext.BeanContextServices#addBeanContextServicesListener(java.beans.beancontext.BeanContextServicesListener)
0317: */
0318: public void addBeanContextServicesListener(
0319: BeanContextServicesListener listener) {
0320: if (listener == null) {
0321: throw new NullPointerException();
0322: }
0323: synchronized (bcsListeners) {
0324: bcsListeners.add(listener);
0325: }
0326: }
0327:
0328: /**
0329: * Add a service to this context.
0330: * <p>
0331: * Delegate to <code>addService(serviceClass, provider, true)</code>.
0332: * </p>
0333: *
0334: * @see java.beans.beancontext.BeanContextServices#addService(java.lang.Class,
0335: * java.beans.beancontext.BeanContextServiceProvider)
0336: */
0337: public boolean addService(Class serviceClass,
0338: BeanContextServiceProvider provider) {
0339: return addService(serviceClass, provider, true);
0340: }
0341:
0342: /**
0343: * Add a service to this context.
0344: * <p>
0345: * If the service already exists in the context, simply return false.
0346: * Otherwise, the service is added and event is fired if required.
0347: * </p>
0348: *
0349: * @param serviceClass
0350: * the service class
0351: * @param provider
0352: * the provider of the service
0353: * @param fireEvent
0354: * the flag indicating to fire event or not
0355: * @return true if the service is added; or false if the context already has
0356: * this service
0357: */
0358: protected boolean addService(Class serviceClass,
0359: BeanContextServiceProvider provider, boolean fireEvent) {
0360: if (serviceClass == null || provider == null) {
0361: throw new NullPointerException();
0362: }
0363:
0364: synchronized (globalHierarchyLock) {
0365: synchronized (services) {
0366: if (services.containsKey(serviceClass)) {
0367: return false;
0368: }
0369: // add to services
0370: services.put(serviceClass, createBCSSServiceProvider(
0371: serviceClass, provider));
0372: // count Serializable
0373: if (provider instanceof Serializable) {
0374: serializable++;
0375: }
0376: }
0377: }
0378:
0379: if (fireEvent) {
0380: // notify all listeners and BeanContextServices children
0381: notifyServiceAvailable(new BeanContextServiceAvailableEvent(
0382: this , serviceClass));
0383: }
0384: return true;
0385: }
0386:
0387: private void notifyServiceAvailable(
0388: BeanContextServiceAvailableEvent event) {
0389: fireServiceAdded(event);
0390: Object childs[] = copyChildren();
0391: for (int i = 0; i < childs.length; i++) {
0392: if (childs[i] instanceof BeanContextServices) {
0393: ((BeanContextServices) childs[i])
0394: .serviceAvailable(event);
0395: }
0396: }
0397: }
0398:
0399: /**
0400: * Deserializes all serializable services and their providers before the
0401: * children of this context is deserialized.
0402: * <p>
0403: * First a <code>int</code> is read, indicating the number of services to
0404: * read. Then pairs of service class and service provider are read one by
0405: * one.
0406: * </p>
0407: *
0408: * @see java.beans.beancontext.BeanContextSupport#bcsPreDeserializationHook(java.io.ObjectInputStream)
0409: */
0410: protected void bcsPreDeserializationHook(ObjectInputStream ois)
0411: throws IOException, ClassNotFoundException {
0412: super .bcsPreDeserializationHook(ois);
0413:
0414: // deserialize services
0415: synchronized (services) {
0416: serializable = ois.readInt();
0417: for (int i = 0; i < serializable; i++) {
0418: Object serviceClass = ois.readObject();
0419: Object bcssProvider = ois.readObject();
0420: services.put((Class) serviceClass,
0421: (BCSSServiceProvider) bcssProvider);
0422: }
0423: }
0424: }
0425:
0426: /**
0427: * Serializes all serializable services and their providers before the
0428: * children of this context is serialized.
0429: * <p>
0430: * First a <code>int</code> is writtern, indicating the number of
0431: * serializable services. Then pairs of service class and service provider
0432: * are writtern one by one.
0433: * </p>
0434: *
0435: * @see java.beans.beancontext.BeanContextSupport#bcsPreSerializationHook(java.io.ObjectOutputStream)
0436: */
0437: protected void bcsPreSerializationHook(ObjectOutputStream oos)
0438: throws IOException {
0439: super .bcsPreSerializationHook(oos);
0440:
0441: // serialize services
0442: synchronized (services) {
0443: oos.writeInt(serializable);
0444: for (Iterator iter = services.entrySet().iterator(); iter
0445: .hasNext();) {
0446: Entry entry = (Entry) iter.next();
0447: if (((BCSSServiceProvider) entry.getValue())
0448: .getServiceProvider() instanceof Serializable) {
0449: oos.writeObject(entry.getKey());
0450: oos.writeObject(entry.getValue());
0451: }
0452: }
0453: }
0454: }
0455:
0456: /**
0457: * This method is called everytime a child is removed from this context.
0458: * <p>
0459: * The implementation releases all services requested by the child.
0460: * </p>
0461: *
0462: * @see java.beans.beancontext.BeanContextSupport#childJustRemovedHook(java.lang.Object,
0463: * java.beans.beancontext.BeanContextSupport.BCSChild)
0464: */
0465: protected void childJustRemovedHook(Object child, BCSChild bcsChild) {
0466: if (bcsChild instanceof BCSSChild) {
0467: releaseServicesForChild((BCSSChild) bcsChild, false);
0468: }
0469: }
0470:
0471: /**
0472: * Release all services requested by the given child.
0473: *
0474: * @param bcssChild
0475: * a child
0476: * @param delegatedServices
0477: * only release services that are delegated to parent context
0478: */
0479: private void releaseServicesForChild(BCSSChild bcssChild,
0480: boolean delegatedServices) {
0481: if (bcssChild.serviceRecords == null
0482: || bcssChild.serviceRecords.isEmpty()) {
0483: return;
0484: }
0485: synchronized (bcssChild.child) {
0486: Object records[] = bcssChild.serviceRecords.toArray();
0487: for (int i = 0; i < records.length; i++) {
0488: ServiceRecord rec = (ServiceRecord) records[i];
0489: if (delegatedServices) {
0490: if (rec.isDelegate) {
0491: releaseServiceWithoutCheck(rec.child,
0492: bcssChild, rec.requestor, rec.service,
0493: true);
0494: }
0495: } else {
0496: releaseServiceWithoutCheck(rec.child, bcssChild,
0497: rec.requestor, rec.service, false);
0498: }
0499: }
0500: }
0501: }
0502:
0503: /**
0504: * Creates a <code>BCSSChild</code> object to company the given child.
0505: *
0506: * @see java.beans.beancontext.BeanContextSupport#createBCSChild(java.lang.Object,
0507: * java.lang.Object)
0508: */
0509: protected BCSChild createBCSChild(Object child, Object proxyPeer) {
0510: return new BCSSChild(child, proxyPeer);
0511: }
0512:
0513: /**
0514: * Creates a <code>BCSSServiceProvider</code> to company the given
0515: * service.
0516: *
0517: * @param serviceClass
0518: * the service class
0519: * @param provider
0520: * the service provider
0521: * @return a <code>BCSSServiceProvider</code> to company the given service
0522: */
0523: protected BCSSServiceProvider createBCSSServiceProvider(
0524: Class serviceClass, BeanContextServiceProvider provider) {
0525: return new BCSSServiceProvider(provider);
0526: }
0527:
0528: /**
0529: * Fires a <code>BeanContextServiceAvailableEvent</code> to registered
0530: * <code>BeanContextServicesListener</code>s.
0531: *
0532: * @param serviceClass
0533: * the service that has been added
0534: */
0535: protected final void fireServiceAdded(Class serviceClass) {
0536: fireServiceAdded(new BeanContextServiceAvailableEvent(this ,
0537: serviceClass));
0538: }
0539:
0540: /**
0541: * Fires a <code>BeanContextServiceAvailableEvent</code> to registered
0542: * <code>BeanContextServicesListener</code>s.
0543: *
0544: * @param event
0545: * the event
0546: */
0547: protected final void fireServiceAdded(
0548: BeanContextServiceAvailableEvent event) {
0549: Object listeners[];
0550: synchronized (bcsListeners) {
0551: listeners = bcsListeners.toArray();
0552: }
0553: for (int i = 0; i < listeners.length; i++) {
0554: BeanContextServicesListener l = (BeanContextServicesListener) listeners[i];
0555: l.serviceAvailable(event);
0556: }
0557: }
0558:
0559: /**
0560: * Fires a <code>BeanContextServiceRevokedEvent</code> to registered
0561: * <code>BeanContextServicesListener</code>s.
0562: *
0563: * @param serviceClass
0564: * the service that has been revoked
0565: * @param revokeNow
0566: * whether to terminate service immediately
0567: */
0568: protected final void fireServiceRevoked(Class serviceClass,
0569: boolean revokeNow) {
0570: fireServiceRevoked(new BeanContextServiceRevokedEvent(this ,
0571: serviceClass, revokeNow));
0572: }
0573:
0574: /**
0575: * Fires a <code>BeanContextServiceRevokedEvent</code> to registered
0576: * <code>BeanContextServicesListener</code>s.
0577: *
0578: * @param event
0579: * the event
0580: */
0581: protected final void fireServiceRevoked(
0582: BeanContextServiceRevokedEvent event) {
0583: Object listeners[];
0584: synchronized (bcsListeners) {
0585: listeners = bcsListeners.toArray();
0586: }
0587: for (int i = 0; i < listeners.length; i++) {
0588: BeanContextServicesListener l = (BeanContextServicesListener) listeners[i];
0589: l.serviceRevoked(event);
0590: }
0591: }
0592:
0593: /**
0594: * Returns the peer of this context casted as
0595: * <code>BeanContextServices</code>.
0596: *
0597: * @return the peer of this context casted as
0598: * <code>BeanContextServices</code>
0599: */
0600: public BeanContextServices getBeanContextServicesPeer() {
0601: return (BeanContextServices) beanContextChildPeer;
0602: }
0603:
0604: /**
0605: * Returns the given child casted to
0606: * <code>BeanContextServicesListener</code>, or null if it does not
0607: * implements the interface.
0608: *
0609: * @param child
0610: * a child
0611: * @return the given child casted to
0612: * <code>BeanContextServicesListener</code>, or null if it does
0613: * not implements the interface
0614: */
0615: protected static final BeanContextServicesListener getChildBeanContextServicesListener(
0616: Object child) {
0617: if (child instanceof BeanContextServicesListener) {
0618: return (BeanContextServicesListener) child;
0619: }
0620: return null;
0621: }
0622:
0623: /**
0624: * Returns an iterator of all registered service classes, with
0625: * <code>removed()</code> disabled.
0626: *
0627: * @return an iterator of all registered service classes
0628: * @see java.beans.beancontext.BeanContextServices#getCurrentServiceClasses()
0629: */
0630: public Iterator getCurrentServiceClasses() {
0631: synchronized (services) {
0632: return new BCSIterator(services.keySet().iterator());
0633: }
0634: }
0635:
0636: /**
0637: * Returns the service selectors of the specified service. The iterator's
0638: * <code>remove()</code> operation is disabled.
0639: *
0640: * @see java.beans.beancontext.BeanContextServices#getCurrentServiceSelectors(java.lang.Class)
0641: */
0642: public Iterator getCurrentServiceSelectors(Class serviceClass) {
0643: BeanContextServiceProvider provider = getLocalServiceProvider(serviceClass);
0644: return provider == null ? null : new BCSIterator(provider
0645: .getCurrentServiceSelectors(
0646: getBeanContextServicesPeer(), serviceClass));
0647: }
0648:
0649: private BeanContextServiceProvider getLocalServiceProvider(
0650: Class serviceClass) {
0651: synchronized (services) {
0652: BCSSServiceProvider bcssProvider = (BCSSServiceProvider) services
0653: .get(serviceClass);
0654: if (bcssProvider != null) {
0655: return bcssProvider.getServiceProvider();
0656: }
0657: return null;
0658: }
0659: }
0660:
0661: /**
0662: * Get a service instance on behalf of the specified child of this context,
0663: * by calling the registered service provider, or by delegating to the
0664: * parent context.
0665: *
0666: * @param child
0667: * the child that request service
0668: * @param requestor
0669: * the requestor object
0670: * @param serviceClass
0671: * the service class
0672: * @param serviceSelector
0673: * the service selectors
0674: * @param bcsrl
0675: * the <code>BeanContextServiceRevokedListener</code>
0676: * @return a service instance on behalf of the specified child of this
0677: * context
0678: * @throws IllegalArgumentException
0679: * if <code>child</code> is not a child of this context
0680: * @throws TooManyListenersException
0681: * @see java.beans.beancontext.BeanContextServices#getService(java.beans.beancontext.BeanContextChild,
0682: * java.lang.Object, java.lang.Class, java.lang.Object,
0683: * java.beans.beancontext.BeanContextServiceRevokedListener)
0684: */
0685: public Object getService(BeanContextChild child, Object requestor,
0686: Class serviceClass, Object serviceSelector,
0687: BeanContextServiceRevokedListener bcsrl)
0688: throws TooManyListenersException {
0689: if (child == null || requestor == null || serviceClass == null
0690: || bcsrl == null) {
0691: throw new NullPointerException();
0692: }
0693:
0694: BCSSChild bcssChild = null;
0695: BeanContextServiceProvider provider = null;
0696: Object service = null;
0697: boolean isDelegate = false;
0698:
0699: synchronized (globalHierarchyLock) {
0700: // check child
0701: synchronized (children) {
0702: bcssChild = (BCSSChild) children.get(child);
0703: }
0704: if (bcssChild == null) {
0705: throw new IllegalArgumentException(
0706: "not a child of this context");
0707: }
0708:
0709: // try local service
0710: provider = getLocalServiceProvider(serviceClass);
0711: if (provider != null) {
0712: service = provider.getService(
0713: getBeanContextServicesPeer(), requestor,
0714: serviceClass, serviceSelector);
0715: }
0716:
0717: // no local service, try delegate
0718: if (service == null && proxy != null) {
0719: provider = proxy;
0720: service = proxy.getService(
0721: getBeanContextServicesPeer(), requestor,
0722: serviceClass, serviceSelector, bcsrl);
0723: isDelegate = true;
0724: }
0725: }
0726:
0727: if (service != null) {
0728: // save record
0729: synchronized (child) {
0730: if (bcssChild.serviceRecords == null) {
0731: bcssChild.serviceRecords = new ArrayList<ServiceRecord>();
0732: }
0733: bcssChild.serviceRecords.add(new ServiceRecord(
0734: provider, child, requestor, serviceClass,
0735: bcsrl, service, isDelegate));
0736: }
0737: }
0738:
0739: return service;
0740: }
0741:
0742: /**
0743: * Checks whether a service is registed in this context or the parent
0744: * context.
0745: *
0746: * @param serviceClass
0747: * the service class
0748: * @return true if the service is registered
0749: * @see java.beans.beancontext.BeanContextServices#hasService(java.lang.Class)
0750: */
0751: public boolean hasService(Class serviceClass) {
0752: if (serviceClass == null) {
0753: throw new NullPointerException();
0754: }
0755:
0756: boolean has;
0757: synchronized (services) {
0758: has = services.containsKey(serviceClass);
0759: }
0760: if (!has && getBeanContext() instanceof BeanContextServices) {
0761: has = ((BeanContextServices) getBeanContext())
0762: .hasService(serviceClass);
0763: }
0764: return has;
0765: }
0766:
0767: /*
0768: * (non-Javadoc)
0769: *
0770: * @see java.beans.beancontext.BeanContextSupport#initialize()
0771: */
0772: public void initialize() {
0773: super .initialize();
0774: services = new HashMap<Class, BCSSServiceProvider>();
0775: serializable = 0;
0776: proxy = null;
0777: bcsListeners = new ArrayList<BeanContextServicesListener>();
0778: }
0779:
0780: /**
0781: * Called after the parent context is updated. The implementation checks if
0782: * the parent context is a <code>BeanContextServices</code>. If it is,
0783: * then a <code>BCSSProxyServiceProvider</code> is created to delegate
0784: * service requests to the parent context.
0785: *
0786: * @see java.beans.beancontext.BeanContextChildSupport#initializeBeanContextResources()
0787: */
0788: protected void initializeBeanContextResources() {
0789: super .initializeBeanContextResources();
0790:
0791: BeanContext context = getBeanContext();
0792: if (context instanceof BeanContextServices) {
0793: proxy = new BCSSProxyServiceProvider(
0794: (BeanContextServices) context);
0795: } else {
0796: proxy = null;
0797: }
0798: }
0799:
0800: /**
0801: * Called before the parent context is updated. The implementation releases
0802: * any service that is currently provided by the parent context.
0803: *
0804: * @see java.beans.beancontext.BeanContextChildSupport#releaseBeanContextResources()
0805: */
0806: protected void releaseBeanContextResources() {
0807: super .releaseBeanContextResources();
0808:
0809: releaseAllDelegatedServices();
0810: proxy = null;
0811: }
0812:
0813: private void releaseAllDelegatedServices() {
0814: synchronized (children) {
0815: for (Iterator iter = bcsChildren(); iter.hasNext();) {
0816: releaseServicesForChild((BCSSChild) iter.next(), true);
0817: }
0818: }
0819: }
0820:
0821: /**
0822: * Release a service which has been requested previously.
0823: *
0824: * @param child
0825: * the child that request the service
0826: * @param requestor
0827: * the requestor object
0828: * @param service
0829: * the service instance
0830: * @throws IllegalArgumentException
0831: * if <code>child</code> is not a child of this context
0832: */
0833: public void releaseService(BeanContextChild child,
0834: Object requestor, Object service) {
0835: if (child == null || requestor == null || service == null) {
0836: throw new NullPointerException();
0837: }
0838:
0839: synchronized (globalHierarchyLock) {
0840: BCSSChild bcssChild;
0841: synchronized (children) {
0842: bcssChild = (BCSSChild) children.get(child);
0843: }
0844: if (bcssChild == null) {
0845: throw new IllegalArgumentException(
0846: "not a child of this context");
0847: }
0848:
0849: releaseServiceWithoutCheck(child, bcssChild, requestor,
0850: service, false);
0851: }
0852: }
0853:
0854: /**
0855: * Releases a service without checking the membership of the child.
0856: */
0857: private void releaseServiceWithoutCheck(BeanContextChild child,
0858: BCSSChild bcssChild, Object requestor, Object service,
0859: boolean callRevokedListener) {
0860:
0861: if (bcssChild.serviceRecords == null
0862: || bcssChild.serviceRecords.isEmpty()) {
0863: return;
0864: }
0865:
0866: synchronized (child) {
0867: // scan record
0868: for (Iterator iter = bcssChild.serviceRecords.iterator(); iter
0869: .hasNext();) {
0870: ServiceRecord rec = (ServiceRecord) iter.next();
0871: if (rec.requestor == requestor
0872: && rec.service == service) {
0873: // release service
0874: rec.provider.releaseService(
0875: getBeanContextServicesPeer(), requestor,
0876: service);
0877: // call service revoked listener
0878: if (callRevokedListener
0879: && rec.revokedListener != null) {
0880: rec.revokedListener
0881: .serviceRevoked(new BeanContextServiceRevokedEvent(
0882: getBeanContextServicesPeer(),
0883: rec.serviceClass, true));
0884: }
0885: // remove record
0886: iter.remove();
0887: break;
0888: }
0889: }
0890: }
0891: }
0892:
0893: /*
0894: * (non-Javadoc)
0895: *
0896: * @see java.beans.beancontext.BeanContextServices#removeBeanContextServicesListener(java.beans.beancontext.BeanContextServicesListener)
0897: */
0898: public void removeBeanContextServicesListener(
0899: BeanContextServicesListener listener) {
0900: if (listener == null) {
0901: throw new NullPointerException();
0902: }
0903: synchronized (bcsListeners) {
0904: bcsListeners.remove(listener);
0905: }
0906: }
0907:
0908: /**
0909: * Revokes a service in this bean context.
0910: * <p>
0911: * The given service provider is unregistered and a
0912: * <code>BeanContextServiceRevokedEvent</code> is fired. All registered
0913: * service listeners and current service users get notified.
0914: * </p>
0915: *
0916: * @param serviceClass
0917: * the service class
0918: * @param serviceProvider
0919: * the service provider
0920: * @param revokeCurrentServicesNow
0921: * true if service should be terminated immediantly
0922: * @see java.beans.beancontext.BeanContextServices#revokeService(java.lang.Class,
0923: * java.beans.beancontext.BeanContextServiceProvider, boolean)
0924: */
0925: public void revokeService(Class serviceClass,
0926: BeanContextServiceProvider serviceProvider,
0927: boolean revokeCurrentServicesNow) {
0928: if (serviceClass == null || serviceProvider == null) {
0929: throw new NullPointerException();
0930: }
0931:
0932: synchronized (globalHierarchyLock) {
0933: synchronized (services) {
0934: BCSSServiceProvider bcssProvider = (BCSSServiceProvider) services
0935: .get(serviceClass);
0936: if (bcssProvider == null) { // non-exist service
0937: return;
0938: }
0939: if (bcssProvider.getServiceProvider() != serviceProvider) {
0940: throw new IllegalArgumentException(
0941: "not the service provider registered with this context");
0942: }
0943:
0944: services.remove(serviceClass);
0945:
0946: if (serviceProvider instanceof Serializable) {
0947: serializable--;
0948: }
0949: }
0950: }
0951:
0952: // notify listeners
0953: fireServiceRevoked(serviceClass, revokeCurrentServicesNow);
0954:
0955: // notify service users
0956: notifyServiceRevokedToServiceUsers(serviceClass,
0957: serviceProvider, revokeCurrentServicesNow);
0958: }
0959:
0960: /**
0961: * Notify all children that a service has been revoked.
0962: */
0963: private void notifyServiceRevokedToServiceUsers(Class serviceClass,
0964: BeanContextServiceProvider serviceProvider,
0965: boolean revokeCurrentServicesNow) {
0966: synchronized (children) {
0967: for (Iterator iter = bcsChildren(); iter.hasNext();) {
0968: BCSSChild bcssChild = (BCSSChild) iter.next();
0969: notifyServiceRevokedToServiceUsers(serviceClass,
0970: serviceProvider, revokeCurrentServicesNow,
0971: bcssChild);
0972: }
0973: }
0974: }
0975:
0976: /**
0977: * Notify the given child that a service has been revoked.
0978: */
0979: private void notifyServiceRevokedToServiceUsers(Class serviceClass,
0980: BeanContextServiceProvider serviceProvider,
0981: boolean revokeCurrentServicesNow, BCSSChild bcssChild) {
0982: if (bcssChild.serviceRecords == null
0983: || bcssChild.serviceRecords.isEmpty()) {
0984: return;
0985: }
0986: synchronized (bcssChild.child) {
0987: for (Iterator it = bcssChild.serviceRecords.iterator(); it
0988: .hasNext();) {
0989: ServiceRecord rec = (ServiceRecord) it.next();
0990: if (rec.serviceClass == serviceClass
0991: && rec.provider == serviceProvider
0992: && rec.revokedListener != null
0993: && !rec.isDelegate) {
0994: rec.revokedListener
0995: .serviceRevoked(new BeanContextServiceRevokedEvent(
0996: getBeanContextServicesPeer(),
0997: serviceClass,
0998: revokeCurrentServicesNow));
0999: // prevent duplicate notification
1000: rec.revokedListener = null;
1001: }
1002: }
1003: }
1004: }
1005:
1006: /**
1007: * Notify all listeners and children that implements
1008: * <code>BeanContextServices</code> of the event.
1009: *
1010: * @see java.beans.beancontext.BeanContextServicesListener#serviceAvailable(java.beans.beancontext.BeanContextServiceAvailableEvent)
1011: */
1012: public void serviceAvailable(BeanContextServiceAvailableEvent event) {
1013: if (null == event) {
1014: throw new NullPointerException(Messages
1015: .getString("beans.1C")); //$NON-NLS-1$
1016: }
1017: if (services.containsKey(event.serviceClass)) {
1018: return;
1019: }
1020: fireServiceAdded(event);
1021: Object childs[] = copyChildren();
1022: for (int i = 0; i < childs.length; i++) {
1023: if (childs[i] instanceof BeanContextServices) {
1024: ((BeanContextServices) childs[i])
1025: .serviceAvailable(event);
1026: }
1027: }
1028: }
1029:
1030: /**
1031: * Notify all listeners and children that implements
1032: * <code>BeanContextServices</code> of the event.
1033: *
1034: * @see java.beans.beancontext.BeanContextServiceRevokedListener#serviceRevoked(java.beans.beancontext.BeanContextServiceRevokedEvent)
1035: */
1036: public void serviceRevoked(BeanContextServiceRevokedEvent event) {
1037: if (null == event) {
1038: throw new NullPointerException(Messages
1039: .getString("beans.1C")); //$NON-NLS-1$
1040: }
1041: if (services.containsKey(event.serviceClass)) {
1042: return;
1043: }
1044: fireServiceRevoked(event);
1045: Object childs[] = copyChildren();
1046: for (int i = 0; i < childs.length; i++) {
1047: if (childs[i] instanceof BeanContextServices) {
1048: ((BeanContextServices) childs[i]).serviceRevoked(event);
1049: }
1050: }
1051: }
1052:
1053: /**
1054: * The implementation goes through following steps:
1055: * <p>
1056: * <ol>
1057: * <li>Calls <code>defaultWriteObject()</code>.</li>
1058: * <li>Writes out serializable service listeners.</li>
1059: * </ol>
1060: * </p>
1061: *
1062: * @param oos
1063: * the object output stream
1064: * @throws IOException
1065: * if I/O exception occurs
1066: */
1067: private void writeObject(ObjectOutputStream oos) throws IOException {
1068:
1069: oos.defaultWriteObject();
1070:
1071: synchronized (bcsListeners) {
1072: serialize(oos, bcsListeners);
1073: }
1074: }
1075:
1076: /**
1077: * The implementation goes through following steps:
1078: * <p>
1079: * <ol>
1080: * <li>Calls <code>defaultReadObject()</code>.</li>
1081: * <li>Reads serializable service listeners.</li>
1082: * </ol>
1083: * </p>
1084: *
1085: * @param ois
1086: * the object input stream
1087: * @throws IOException
1088: * if I/O error occurs
1089: * @throws ClassNotFoundException
1090: * if class of read object is not found
1091: */
1092: private void readObject(ObjectInputStream ois) throws IOException,
1093: ClassNotFoundException {
1094:
1095: ois.defaultReadObject();
1096:
1097: synchronized (bcsListeners) {
1098: deserialize(ois, bcsListeners);
1099: }
1100: }
1101:
1102: }
|