001: /*
002: * <copyright>
003: *
004: * Copyright 2001-2007 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:
027: package org.cougaar.core.node;
028:
029: import java.util.List;
030: import org.cougaar.core.component.Component;
031: import org.cougaar.core.component.ServiceBroker;
032: import org.cougaar.core.component.ServiceProvider;
033: import org.cougaar.core.util.Reflection;
034: import org.cougaar.util.GenericStateModelAdapter;
035:
036: /**
037: * This component can be used to import an external service into the node agent.
038: * <p>
039: * For example, the {@link NodeApplet} uses this component to advertise the
040: * {@link org.cougaar.core.service.AppletService}.
041: * <p>
042: * Two parameters are required:<br>
043: * 1) The Service class or classname.<br>
044: * 2) The Service class, classname, or instance, or the
045: * ServiceProvider class, classname, or instance.<br>
046: * A third parameter is optional:<br>
047: * 3) "true" to use the root ServiceBroker, defaults to false.<br>
048: * <p>
049: * Reflection is used wrap the 2nd parameter as the correct API, even if it
050: * doesn't implement the correct interface. For example, an external client
051: * can specify an implementation for:<pre>
052: * public interface FooService extends Service {
053: * void foo();
054: * }
055: * </pre>
056: * as:
057: * <pre>
058: * public class MyFoo {
059: * public void foo() { .. }
060: * }
061: * </pre>
062: * even though "MyFoo instanceof FooService" is false. This is supported to
063: * avoid awkward compile and classloader dependencies.
064: */
065: public class AddServiceComponent extends GenericStateModelAdapter
066: implements Component {
067:
068: private ServiceBroker sb;
069: private List params;
070:
071: private ServiceBroker the_sb;
072:
073: private Class cl;
074: private ServiceProvider sp;
075:
076: public void setServiceBroker(ServiceBroker sb) {
077: this .sb = sb;
078: }
079:
080: public void setParameter(Object o) {
081: if (!(o instanceof List)) {
082: throw new IllegalArgumentException("Expecting a List, not "
083: + (o == null ? "null" : o.getClass().getName()));
084: }
085: params = (List) o;
086: }
087:
088: public void load() {
089: super .load();
090:
091: try {
092: _load();
093: } catch (Exception e) {
094: throw new RuntimeException("Unable to load " + this , e);
095: }
096: }
097:
098: private void _load() throws Exception {
099: // extract parameters
100: int n = (params == null ? 0 : params.size());
101: if (n < 2 || n > 3) {
102: throw new RuntimeException(
103: "Expecting 2..3 parameters, not " + n);
104: }
105: Object cl_obj = params.get(0);
106: Object sv_obj = params.get(1);
107: Object is_root_obj = (n > 2 ? params.get(2) : null);
108:
109: // select broker
110: the_sb = sb;
111: boolean is_root = "true".equals(is_root_obj);
112: if (is_root) {
113: NodeControlService ncs = (NodeControlService) sb
114: .getService(this , NodeControlService.class, null);
115: if (ncs == null) {
116: throw new RuntimeException(
117: "Unable to obtain NodeControlService");
118: }
119: the_sb = ncs.getRootServiceBroker();
120: sb.releaseService(this , NodeControlService.class, ncs);
121: if (the_sb == null) {
122: throw new RuntimeException("Null root_sb");
123: }
124: }
125:
126: // get class
127: if (cl_obj instanceof String) {
128: cl_obj = Class.forName((String) cl_obj);
129: }
130: if (!(cl_obj instanceof Class)) {
131: throw new RuntimeException(
132: "Expecting a Class or String, not " + cl_obj);
133: }
134: cl = (Class) cl_obj;
135:
136: // get svc
137: if (sv_obj == null) {
138: throw new RuntimeException("Null service_object");
139: }
140: if (sv_obj instanceof String) {
141: sv_obj = Class.forName((String) sv_obj);
142: }
143: if (sv_obj instanceof Class) {
144: sv_obj = ((Class) sv_obj).newInstance();
145: }
146: boolean inst_sp = (sv_obj instanceof ServiceProvider);
147: boolean inst_cl = cl.isAssignableFrom(sv_obj.getClass());
148: if (!inst_sp && !inst_cl) {
149: // must use reflection
150: Object o;
151: try {
152: // try to wrap as "cl"
153: o = Reflection.makeProxy(sv_obj, cl);
154: inst_cl = true;
155: } catch (Exception e) {
156: try {
157: // try to wrap as "sp"
158: o = Reflection.makeProxy(sv_obj,
159: ServiceProvider.class);
160: inst_sp = true;
161: } catch (Exception e2) {
162: // missing both cl and sp methods
163: throw new RuntimeException("Unable to create " + cl
164: + " proxy for " + sv_obj.getClass(), e);
165: }
166: }
167: sv_obj = o;
168: }
169: if (inst_cl && !inst_sp) {
170: // wrap as provider
171: inst_cl = false;
172: inst_sp = true;
173: final Object svc = sv_obj;
174: sv_obj = new ServiceProvider() {
175: public Object getService(ServiceBroker sb,
176: Object requestor, Class serviceClass) {
177: return (cl.isAssignableFrom(serviceClass) ? svc
178: : null);
179: }
180:
181: public void releaseService(ServiceBroker sb,
182: Object requestor, Class serviceClass,
183: Object service) {
184: }
185: };
186: }
187: sp = (ServiceProvider) sv_obj;
188:
189: // add the service
190: the_sb.addService(cl, sp);
191: }
192:
193: public void unload() {
194: if (sp != null) {
195: the_sb.revokeService(cl, sp);
196: sp = null;
197: }
198:
199: super.unload();
200: }
201: }
|