001: /*
002: * <copyright>
003: *
004: * Copyright 2000-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026: package org.cougaar.core.component;
027:
028: import java.util.ArrayList;
029: import java.util.HashMap;
030: import java.util.Iterator;
031:
032: /** Simple implementation of Cougaar component services layer.
033: * No propagation, nothing fancy.
034: * @see org.cougaar.core.component.ServiceBroker
035: **/
036:
037: public class ServiceBrokerSupport implements ExtendedServiceBroker {
038: /** the current set of Listeners. Elements are of type ServiceListener **/
039: private ArrayList listeners = new ArrayList();
040:
041: /** add a ServiceListener to this ServiceBroker Context **/
042: public void addServiceListener(ServiceListener sl) {
043: if (sl == null)
044: throw new IllegalArgumentException(
045: "Add of null ServiceListener");
046: synchronized (listeners) {
047: listeners.add(sl);
048: }
049: }
050:
051: /** remove a services listener **/
052: public void removeServiceListener(ServiceListener sl) {
053: if (sl == null)
054: throw new IllegalArgumentException(
055: "Remove of null ServiceListener");
056: synchronized (listeners) {
057: listeners.remove(sl);
058: }
059: }
060:
061: /** Apply each listener appropriately to the event **/
062: protected void applyListeners(ServiceEvent se) {
063: // Copy out the listeners while synchronized. but don't call the
064: // listeners while synchronized. Avoids a deadlock when the
065: // service broker is used within the listener.
066: ServiceListener[] listenerArray;
067: synchronized (listeners) {
068: listenerArray = new ServiceListener[listeners.size()];
069: listenerArray = (ServiceListener[]) listeners
070: .toArray(listenerArray);
071: }
072: for (int i = 0; i < listenerArray.length; i++) {
073: applyListener(listenerArray[i], se);
074: }
075: }
076:
077: protected void applyListener(ServiceListener sl, ServiceEvent se) {
078: if (sl instanceof ServiceAvailableListener) {
079: if (se instanceof ServiceAvailableEvent) {
080: ((ServiceAvailableListener) sl)
081: .serviceAvailable((ServiceAvailableEvent) se);
082: }
083: } else if (sl instanceof ServiceRevokedListener) {
084: if (se instanceof ServiceRevokedEvent) {
085: ((ServiceRevokedListener) sl)
086: .serviceRevoked((ServiceRevokedEvent) se);
087: }
088: } else {
089: // what is this?
090: }
091: }
092:
093: /** the current set of services. A map of Class serviceClass to ServiceProvider
094: * Access to services is guarded by servicesLock.
095: **/
096: private final HashMap services = new HashMap(89);
097: /** Lock for services. Protected so that extending classes can
098: * synchronize over multiple calls.
099: **/
100: protected final Object servicesLock = new Object();
101:
102: /** add a Service to this ServiceBroker Context **/
103: public boolean addService(Class serviceClass,
104: ServiceProvider serviceProvider) {
105: return addService(serviceClass, serviceProvider, 0, null);
106: }
107:
108: public boolean addService(Class serviceClass,
109: ServiceProvider serviceProvider, int providerId,
110: ComponentDescription providerDesc) {
111: if (serviceClass == null)
112: throw new IllegalArgumentException("serviceClass null");
113: if (serviceProvider == null)
114: throw new IllegalArgumentException("serviceProvider null");
115:
116: synchronized (servicesLock) {
117: Object old = services.get(serviceClass);
118: if (old != null) {
119: return false;
120: } else {
121: Entry e = new Entry(providerId, providerDesc,
122: serviceProvider);
123: services.put(serviceClass, e);
124: // fall through
125: }
126: }
127:
128: // notify any listeners
129: applyListeners(new ServiceAvailableEvent(this , serviceClass));
130:
131: return true;
132: }
133:
134: /** remoke or remove an existing service **/
135: public void revokeService(Class serviceClass,
136: ServiceProvider serviceProvider) {
137: revokeService(serviceClass, serviceProvider, 0, null);
138: }
139:
140: public void revokeService(Class serviceClass,
141: ServiceProvider serviceProvider, int providerId,
142: ComponentDescription providerDesc) {
143: if (serviceClass == null)
144: throw new IllegalArgumentException("serviceClass null");
145: if (serviceProvider == null)
146: throw new IllegalArgumentException("serviceProvider null");
147:
148: synchronized (servicesLock) {
149: Object old = services.remove(serviceClass);
150: if (old == null) {
151: return; // bail out - already revoked
152: }
153: // else fall through
154: }
155:
156: // notify any listeners
157: applyListeners(new ServiceRevokedEvent(this , serviceClass));
158: }
159:
160: /** is the service currently available? **/
161: public boolean hasService(Class serviceClass) {
162: if (serviceClass == null)
163: throw new IllegalArgumentException("serviceClass null");
164: synchronized (servicesLock) {
165: return (null != services.get(serviceClass));
166: }
167: }
168:
169: /** gets the currently available services for this context.
170: * This version copies the keyset to keep the iterator safe.
171: **/
172: public Iterator getCurrentServiceClasses() {
173: //We could cache the answer if this turns out to be a hot spot.
174: synchronized (servicesLock) {
175: ArrayList l = new ArrayList(services.keySet());
176: return l.iterator();
177: }
178: }
179:
180: /** get an instance of the requested service from a service provider associated
181: * with this context.
182: **/
183: public <T> T getService(Object requestor, Class<T> serviceClass,
184: ServiceRevokedListener srl) {
185: ServiceResult sr = getService(0, null, requestor, serviceClass,
186: srl, true);
187: return (sr == null ? null : (T) sr.getService());
188: }
189:
190: public ServiceResult getService(int requestorId,
191: ComponentDescription requestorDesc, Object requestor,
192: Class serviceClass, ServiceRevokedListener srl,
193: boolean recordInView) {
194: ServiceResult sr = getServiceAllowNull(requestorId,
195: requestorDesc, requestor, serviceClass, srl,
196: recordInView);
197: Object service = (sr == null ? null : sr.getService());
198: if (service instanceof NullService) {
199: // blocked
200: sr = new ServiceResult(sr.getProviderId(), sr
201: .getProviderComponentDescription(), null);
202: }
203: return sr;
204: }
205:
206: /**
207: * get the service and allow a NullService result, which the
208: * usual "getService(..)" replaces with null.
209: */
210: protected ServiceResult getServiceAllowNull(int requestorId,
211: ComponentDescription requestorDesc, Object requestor,
212: final Class serviceClass, final ServiceRevokedListener srl,
213: boolean recordInView) {
214: if (requestor == null)
215: throw new IllegalArgumentException("null requestor");
216: if (serviceClass == null)
217: throw new IllegalArgumentException("null serviceClass");
218:
219: Object service;
220: Entry e;
221: ServiceProvider sp;
222: synchronized (servicesLock) {
223: e = (Entry) services.get(serviceClass);
224: if (e == null)
225: return null; // bail
226: sp = e.getServiceProvider();
227: }
228: // ugh, not sure about this "sp" lock!
229: synchronized (sp) {
230: service = sp.getService(this , requestor, serviceClass);
231: if (service != null && !(service instanceof NullService)) {
232: if (!serviceClass.isAssignableFrom(service.getClass())) {
233: throw new ClassCastException("ServiceProvider "
234: + sp + " returned a Service (" + service
235: + ") which is not an instance of "
236: + serviceClass);
237: }
238: }
239: // if we're going to succeed and they passed a revoked listener...
240: if (srl != null) {
241: addServiceListener(new ServiceRevokedListener() {
242: public void serviceRevoked(ServiceRevokedEvent re) {
243: if (serviceClass.equals(re.getService()))
244: srl.serviceRevoked(re);
245: }
246: });
247: }
248: }
249: return new ServiceResult(e.getId(),
250: e.getComponentDescription(), service);
251: }
252:
253: public void releaseService(Object requestor, Class serviceClass,
254: Object service) {
255: releaseService(0, null, requestor, serviceClass, service, true);
256: }
257:
258: public void releaseService(int requestorId,
259: ComponentDescription requestorDesc, Object requestor,
260: Class serviceClass, Object service, boolean recordInView) {
261: if (requestor == null)
262: throw new IllegalArgumentException("null requestor");
263: if (serviceClass == null)
264: throw new IllegalArgumentException("null serviceClass");
265:
266: ServiceProvider sp;
267: synchronized (servicesLock) {
268: Entry e = (Entry) services.get(serviceClass);
269: sp = (e == null ? null : e.getServiceProvider());
270: }
271: if (sp != null) {
272: synchronized (sp) {
273: sp.releaseService(this , requestor, serviceClass,
274: service);
275: }
276: }
277: }
278:
279: private static final class Entry {
280: private final int id;
281: private final ComponentDescription desc;
282: private final ServiceProvider sp;
283:
284: public Entry(int id, ComponentDescription desc,
285: ServiceProvider sp) {
286: this .id = id;
287: this .desc = desc;
288: this .sp = sp;
289: }
290:
291: public int getId() {
292: return id;
293: }
294:
295: public ComponentDescription getComponentDescription() {
296: return desc;
297: }
298:
299: public ServiceProvider getServiceProvider() {
300: return sp;
301: }
302: }
303: }
|