001: /*
002: * <copyright>
003: *
004: * Copyright 2001-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 org.cougaar.util.log.Logger;
029: import org.cougaar.util.log.Logging;
030:
031: import java.util.ArrayList;
032:
033: /** A Wrapper Binder contructed by ServiceFilter which
034: * watches service requests and has convenient overridable points
035: * where extensions may monitor, edit, veto or wrap services
036: * requested by the client.
037: * <p>
038: * Specific implementations still will need to implement getBinderProxy
039: * so the right methods are presented
040: * <p>
041: * For an example of using this, see the class org.cougaar.core.examples.PluginServiceFilter
042: * in core/examples (part of the core cougaar documentation/development package).
043: **/
044: public abstract class ServiceFilterBinder extends BinderWrapper // only uses part of it...
045: {
046: private final static Logger logger = Logging
047: .getLogger(ServiceFilterBinder.class);
048:
049: protected ServiceFilterBinder(BinderFactory bf, Object child) {
050: super (bf, child);
051: myContainerProxy = createContainerProxy();
052: }
053:
054: public void setBindingSite(BindingSite bs) {
055: super .setBindingSite(bs);
056: myFilteringServiceBroker = createFilteringServiceBroker(getServiceBroker());
057: }
058:
059: private ContainerAPI myContainerProxy = null;
060:
061: /** define to choose the class of the BinderProxy.
062: * Should usually be an extension of ServiceFilterBinderProxy.
063: * The default creates and returns an instance of ServiceFilterContainerProxy.
064: **/
065: protected ContainerAPI createContainerProxy() {
066: return new ServiceFilterContainerProxy();
067: }
068:
069: /** Defines a pass-through insulation layer to ensure that the plugin cannot
070: * downcast the BindingSite to the Binder and gain control via introspection
071: * and/or knowledge of the Binder class. This is neccessary when Binders do
072: * not have private channels of communication to the Container.
073: **/
074: protected ContainerAPI getContainerProxy() {
075: return myContainerProxy;
076: }
077:
078: private ServiceBroker myFilteringServiceBroker = null;
079:
080: /** Define to choose the implementatino of the service broker filter, which
081: * should be an extension of FilteringServiceBroker. This method is called
082: * when setBindingSite is invoked.
083: **/
084: protected abstract ServiceBroker createFilteringServiceBroker(
085: ServiceBroker sb);
086:
087: protected ServiceBroker getFilteringServiceBroker() {
088: return myFilteringServiceBroker;
089: }
090:
091: /** Base class for implementing filtering BinderProxies.
092: * Binders will need to extend this with any additional methods required by
093: * their BindingSite.
094: **/
095: public class ServiceFilterContainerProxy implements ContainerAPI {
096: public ServiceFilterContainerProxy() {
097: }
098:
099: public ServiceBroker getServiceBroker() {
100: return getFilteringServiceBroker();
101: }
102:
103: public void requestStop() {
104: } // ignore
105:
106: public boolean remove(Object childComponent) {
107: return ServiceFilterBinder.this .remove(childComponent);
108: }
109: }
110:
111: /** Base class for filtering/auditing/etc services, extending
112: * DelegatingServiceBroker for security.
113: *
114: * This implementation acts as a passthrough for publish/subscribe
115: * mechanisms
116: **/
117: public class FilteringServiceBroker extends DelegatingServiceBroker {
118: public FilteringServiceBroker(ServiceBroker delegate) {
119: super (delegate);
120: }
121:
122: /** A map of wrapped Service to tuples of requested client and actual service
123: * to support releaseService.
124: **/
125: private ArrayList serviceTuples = new ArrayList(1);
126:
127: /**
128: * This implementation of getService calls allowService(serviceClass). If allowService
129: * returns true, will then call getClientProxy to proxy the client, delegates to the real broker
130: * to request the service, then calls getServiceProxy to wrap the service. <p>
131: **/
132: public Object getService(Object requestor, Class serviceClass,
133: ServiceRevokedListener srl) {
134: if (allowService(serviceClass)) {
135: // get the client proxy
136: Object clientProxy = getClientProxy(requestor,
137: serviceClass);
138: if (clientProxy == requestor) {
139: logger
140: .warn(
141: "getClientProxy should return null instead of result == requestor",
142: new Throwable());
143: clientProxy = null;
144: }
145: Object rc = (clientProxy != null) ? clientProxy
146: : requestor;
147:
148: // get the service
149: Object service = super
150: .getService(rc, serviceClass, srl);
151: if (service == null)
152: return null;
153:
154: // get the service proxy
155: Object serviceProxy = getServiceProxy(service,
156: serviceClass, rc);
157: if (serviceProxy == service) {
158: logger
159: .warn(
160: "getServiceProxy should return null instead of result == service",
161: new Throwable());
162: serviceProxy = null;
163: }
164: Object rs = (serviceProxy != null) ? serviceProxy
165: : service;
166:
167: if (clientProxy == null && serviceProxy == null) {
168: // no client or server proxies - no need to track it with a tuple
169: return service;
170: }
171: if (logger.isDebugEnabled()) {
172: if (clientProxy != null && serviceProxy == null) {
173: logger
174: .debug("ClientProxy without ServiceProxy. service="
175: + serviceClass
176: + ", binder="
177: + this );
178: }
179: }
180:
181: synchronized (serviceTuples) {
182: serviceTuples.add(new ServiceTuple(requestor,
183: clientProxy, serviceClass, service,
184: serviceProxy));
185: }
186: return rs;
187: } else {
188: // service request vetoed
189: return null;
190: }
191: }
192:
193: /** Override to control if a given service class is allowed or now **/
194: protected boolean allowService(Class serviceClass) {
195: return true;
196: }
197:
198: /** Override to specify an alternative instance to use as the client
199: * (requestor) object when actually requesting the service.
200: * A return value of null is interpreted as "no proxy".
201: * This implementation always returns null.
202: **/
203: protected Object getClientProxy(Object client,
204: Class serviceClass) {
205: return null;
206: }
207:
208: /** Override to specify an alternative instance to use as the service
209: * implementation passed back to the client component.
210: * A return value of null is interpreted as "no proxy".
211: * This implementation always returns null.
212: * @param client is the client object passed up to the real service broker.
213: * This is usually the requestor, but may be a proxy for the requestor if
214: * getClientProxy was exercised.
215: **/
216: protected Object getServiceProxy(Object service,
217: Class serviceClass, Object client) {
218: return null;
219: }
220:
221: /** As usual, releases a service previously requested from the ServiceBroker.
222: * here, we do additional work to make sure that the service implementation
223: * is actually released, regardless of the combination of proxies the
224: * binder may have provided.
225: * Calls releaseServiceProxy and releaseClientProxy as appropriate.
226: **/
227: public void releaseService(Object requestor,
228: Class serviceClass, Object service) {
229: ServiceTuple t;
230: synchronized (serviceTuples) {
231: int i = serviceTuples.indexOf(new ServiceTuple(
232: requestor, serviceClass));
233: if (i == -1) {
234: // no proxy information - just pass it up
235: super .releaseService(requestor, serviceClass,
236: service);
237: return;
238: }
239: t = (ServiceTuple) serviceTuples.remove(i);
240: }
241:
242: // release our service proxy
243: Object sp = t.getServiceProxy();
244: if (sp != null)
245: releaseServiceProxy(sp, t.getService(), t
246: .getServiceClass());
247:
248: try {
249: // really release the service
250: super .releaseService(t.getRequestedClient(), t
251: .getServiceClass(), t.getService());
252: } finally {
253: // release our client proxy
254: Object cp = t.getClientProxy();
255: if (cp != null)
256: releaseClientProxy(cp, t.getClient(), t
257: .getServiceClass());
258: }
259: }
260:
261: /** Called to release a serviceProxy previously constructed by the binder.
262: * Override to change the default behavior of "do nothing". Note that this
263: * method is called <em>before</em> the real service is released.
264: **/
265: protected void releaseServiceProxy(Object serviceProxy,
266: Object service, Class serviceClass) {
267: }
268:
269: /** Called to release a clientProxy previously constructed by the binder.
270: * Override to change the default behavior of "do nothing". Note that this
271: * method is called <em>after</em> the service is released.
272: **/
273: protected void releaseClientProxy(Object clientProxy,
274: Object client, Class serviceClass) {
275: }
276: }
277:
278: public static class ServiceTuple {
279: public Object client;
280: public Object clientProxy;
281: public Class serviceClass;
282: public Object service;
283: public Object serviceProxy;
284:
285: public ServiceTuple(Object r, Object cp, Class sc, Object s,
286: Object sp) {
287: client = r;
288: clientProxy = cp;
289: serviceClass = sc;
290: service = s;
291: serviceProxy = sp;
292: }
293:
294: // used for only to create match for .equals
295: public ServiceTuple(Object r, Class sc) {
296: client = r;
297: serviceClass = sc;
298: }
299:
300: public Object getClient() {
301: return client;
302: }
303:
304: public Object getClientProxy() {
305: return clientProxy;
306: }
307:
308: public Class getServiceClass() {
309: return serviceClass;
310: }
311:
312: public Object getService() {
313: return service;
314: }
315:
316: public Object getServiceProxy() {
317: return serviceProxy;
318: }
319:
320: public Object getRequestedClient() {
321: return (clientProxy != null) ? clientProxy : client;
322: }
323:
324: public Object getReturnedService() {
325: return (serviceProxy != null) ? serviceProxy : service;
326: }
327:
328: public boolean equals(Object o) {
329: return ((o instanceof ServiceTuple)
330: && client.equals(((ServiceTuple) o).client) && serviceClass
331: .equals(((ServiceTuple) o).serviceClass));
332: }
333: }
334: }
|