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 java.lang.reflect.Field;
029: import java.lang.reflect.InvocationTargetException;
030: import java.lang.reflect.Method;
031: import java.util.ArrayList;
032: import java.util.Iterator;
033:
034: import org.cougaar.util.annotations.Cougaar;
035: import org.cougaar.util.log.Logger;
036: import org.cougaar.util.log.Logging;
037:
038: /** A collection of utilities to be used for binding components
039: **/
040:
041: public abstract class BindingUtility {
042:
043: public static boolean activate(Object child,
044: BindingSite bindingSite, ServiceBroker serviceBroker) {
045: setBindingSite(child, bindingSite);
046: setServices(child, serviceBroker);
047: initialize(child);
048: load(child);
049: start(child);
050: return true;
051: }
052:
053: /** Sets a the binding site of the child to the specified object
054: * if possible.
055: * @return true on success
056: **/
057: public static boolean setBindingSite(Object child,
058: BindingSite bindingSite) {
059: Class childClass = child.getClass();
060: try {
061: Method m;
062: try {
063: m = childClass.getMethod("setBindingSite",
064: new Class[] { BindingSite.class });
065: } catch (NoSuchMethodException e) {
066: return false;
067: }
068:
069: m.invoke(child, new Object[] { bindingSite });
070: return true;
071: } catch (Exception e) {
072: throw new ComponentLoadFailure("Couldn't set BindingSite",
073: child, e);
074: }
075: }
076:
077: public static boolean setServiceBroker(Object child,
078: ServiceBroker serviceBroker) {
079: Class childClass = child.getClass();
080: try {
081: Method m;
082: try {
083: m = childClass.getMethod("setServiceBroker",
084: new Class[] { ServiceBroker.class });
085: } catch (NoSuchMethodException e) {
086: return false;
087: }
088:
089: m.invoke(child, new Object[] { serviceBroker });
090: return true;
091: } catch (Exception e) {
092: throw new ComponentLoadFailure(
093: "Couldn't set ServiceBroker", child, e);
094: }
095: }
096:
097: private static class SetServiceInvocation {
098: final Field f;
099: final Method m;
100: final Object o;
101: final Object service;
102: final Class p;
103:
104: SetServiceInvocation(Method m, Object o, Object s, Class p) {
105: this .m = m;
106: this .o = o;
107: this .service = s;
108: this .p = p;
109: this .f = null;
110: }
111:
112: SetServiceInvocation(Field f, Object o, Object s, Class p) {
113: this .f = f;
114: this .o = o;
115: this .service = s;
116: this .p = p;
117: this .m = null;
118: }
119:
120: void invoke() throws InvocationTargetException,
121: IllegalAccessException {
122: // we shouldn't have been here if service is null.
123: assert service != null;
124: if (m != null) {
125: Object[] args = new Object[] { service };
126: m.invoke(o, args);
127: } else if (f != null) {
128: f.set(o, service);
129: }
130: }
131:
132: void release(ServiceBroker b, Object child) {
133: b.releaseService(child, p, service);
134: }
135: }
136:
137: public static boolean setServices(Object child,
138: ServiceBroker servicebroker) {
139: // first set the service broker, acting as if ServiceBroker
140: // implements Service (which it may become someday).
141: setServiceBroker(child, servicebroker);
142:
143: Class childClass = child.getClass();
144: // failures are Object[] tuples of Service and Throwable
145: ArrayList failures = new ArrayList(1); // remember the errors if we have to bail out
146:
147: ArrayList ssi = new ArrayList();
148:
149: try {
150: Field[] fields = childClass.getFields();
151: for (final Field field : fields) {
152: if (field
153: .isAnnotationPresent(Cougaar.ObtainService.class)) {
154: Class<?> fieldClass = field.getType();
155: if (Service.class.isAssignableFrom(fieldClass)) {
156: final Object fc = child;
157: ServiceRevokedListener srl = new ServiceRevokedListener() {
158: public void serviceRevoked(
159: ServiceRevokedEvent re) {
160: try {
161: field.set(fc, null);
162: } catch (Throwable t) {
163: Logger logger = Logging
164: .getLogger(BindingUtility.class);
165: logger.error("Component " + fc
166: + " annotated field "
167: + field
168: + " fails with null", t);
169: }
170: }
171: };
172: try {
173: Object service = servicebroker.getService(
174: child, fieldClass, srl);
175: if (service == null)
176: throw new Throwable("No service for "
177: + fieldClass);
178: // remember the services to set for the second pass
179: ssi.add(new SetServiceInvocation(field,
180: child, service, fieldClass));
181: } catch (Throwable t) {
182: Object[] fail = new Object[] { fieldClass,
183: t };
184: failures.add(fail);
185: break; // break out of the loop
186: }
187: } else if (ServiceBroker.class.equals(fieldClass)) {
188: try {
189: field.set(child, servicebroker);
190: } catch (Throwable t) {
191: Logger logger = Logging
192: .getLogger(BindingUtility.class);
193: logger.error("Component " + child
194: + " annotated field " + field
195: + " fails with ServiceBroker", t);
196: }
197: }
198: }
199: }
200: Method[] methods = childClass.getMethods();
201:
202: int l = methods.length;
203: for (int i = 0; i < l; i++) { // look at all the methods
204: Method m = methods[i];
205: String s = m.getName();
206: if ("setBindingSite".equals(s))
207: continue;
208: if ("setServiceBroker".equals(s))
209: continue;
210: Class[] params = m.getParameterTypes();
211: if (s.startsWith("set") && params.length == 1) {
212: Class p = params[0];
213: if (Service.class.isAssignableFrom(p)) {
214: String pname = p.getName();
215: { // trim the package off the classname
216: int dot = pname.lastIndexOf(".");
217: if (dot > -1)
218: pname = pname.substring(dot + 1);
219: }
220:
221: if (s.endsWith(pname)) {
222: // ok: m is a "public setX(X)" method where X is a Service.
223: // create the revocation listener
224: final Method fm = m;
225: final Object fc = child;
226: ServiceRevokedListener srl = new ServiceRevokedListener() {
227: public void serviceRevoked(
228: ServiceRevokedEvent sre) {
229: Object[] args = new Object[] { null };
230: try {
231: fm.invoke(fc, args);
232: } catch (Throwable e) {
233: Logger logger = Logging
234: .getLogger(BindingUtility.class);
235: logger
236: .error(
237: "Component "
238: + fc
239: + " service setter "
240: + fm
241: + " fails on null argument",
242: e);
243: }
244: }
245: };
246: // Let's try getting the service...
247: try {
248: Object service = servicebroker
249: .getService(child, p, srl);
250: if (service == null)
251: throw new Throwable(
252: "No service for " + p);
253:
254: // remember the services to set for the second pass
255: ssi.add(new SetServiceInvocation(m,
256: child, service, p));
257: } catch (Throwable t) {
258: Object[] fail = new Object[] { p, t };
259: failures.add(fail);
260: break; // break out of the loop
261: }
262: }
263: }
264: }
265: }
266:
267: // call the setters if we haven't failed yet
268: if (failures.size() == 0) {
269: for (Iterator it = ssi.iterator(); it.hasNext();) {
270: SetServiceInvocation setter = (SetServiceInvocation) it
271: .next();
272: try {
273: setter.invoke();
274: } catch (Throwable t) {
275: Object[] fail = new Object[] { setter.p, t };
276: failures.add(fail);
277: }
278: }
279: }
280:
281: // if we've got any failures, report on them
282: if (failures.size() > 0) {
283: Logger logger = Logging.getLogger(BindingUtility.class);
284: logger
285: .error("Component "
286: + child
287: + " could not be provided with all required services");
288: for (Iterator it = failures.iterator(); it.hasNext();) {
289: Object[] fail = (Object[]) it.next();
290: logger.error("Component " + child
291: + " Failed service " + fail[0],
292: (Throwable) fail[1]);
293: }
294: // now release any services we had grabbed
295: for (Iterator it = ssi.iterator(); it.hasNext();) {
296: SetServiceInvocation setter = (SetServiceInvocation) it
297: .next();
298: try {
299: setter.release(servicebroker, child);
300: } catch (Throwable t) {
301: logger
302: .error(
303: "Failed to release service "
304: + setter.p
305: + " while backing out initialization of "
306: + child, t);
307: }
308: }
309: }
310: } catch (Throwable e) {
311: // probably this cannot happen any more
312: throw new ComponentLoadFailure("Couldn't get services",
313: child, e);
314: }
315:
316: if (failures.size() > 0) {
317: return false;
318: } else {
319: return true;
320: }
321: }
322:
323: /** Run initialize on the child component if possible **/
324: public static boolean initialize(Object child) {
325: return call0(child, "initialize");
326: }
327:
328: /** Run load on the child component if possible **/
329: public static boolean load(Object child) {
330: return call0(child, "load");
331: }
332:
333: /** Run start on the child component if possible **/
334: public static boolean start(Object child) {
335: return call0(child, "start");
336: }
337:
338: public static boolean call0(Object child, String method) {
339: Class childClass = child.getClass();
340: Method init = null;
341: try {
342: try {
343: init = childClass.getMethod(method, (Class[]) null);
344: } catch (NoSuchMethodException e1) {
345: }
346: if (init != null) {
347: init.invoke(child, new Object[] {});
348: return true;
349: }
350: } catch (java.lang.reflect.InvocationTargetException ite) {
351: throw new ComponentRuntimeException("failed while calling "
352: + method + "()", child, ite.getCause());
353: } catch (Exception e) {
354: throw new ComponentRuntimeException("failed to call "
355: + method + "()", child, e);
356: }
357: return false;
358: }
359: }
|