001: /*
002: * <copyright>
003: *
004: * Copyright 1997-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:
027: package org.cougaar.core.agent;
028:
029: import java.util.Arrays;
030: import java.util.ArrayList;
031: import java.util.Collections;
032: import java.util.List;
033: import org.cougaar.core.component.Component;
034: import org.cougaar.core.component.ComponentDescription;
035: import org.cougaar.core.component.ComponentDescriptions;
036: import org.cougaar.core.component.ServiceBroker;
037: import org.cougaar.core.mts.MessageAddress;
038: import org.cougaar.core.node.ComponentInitializerService;
039: import org.cougaar.core.node.NodeIdentificationService;
040: import org.cougaar.util.GenericStateModelAdapter;
041: import org.cougaar.util.log.Logger;
042: import org.cougaar.util.log.Logging;
043:
044: /**
045: * This component is the first component added to an agent, and
046: * is used to bootstrap the agent with the minimal initial
047: * components.
048: * <p>
049: * The last component bootstrapped in is {@link FindComponentsEarly},
050: * which checks for persisted component model state.
051: *
052: * @see FindComponentsEarly
053: */
054: public final class Bootstrap extends GenericStateModelAdapter implements
055: Component {
056:
057: private static final String AGENT_IP = "Node.AgentManager.Agent";
058: private static final String AGENT_IP_PREFIX = AGENT_IP + ".";
059:
060: private String agentName;
061:
062: private ServiceBroker sb;
063:
064: public void setParameter(Object x) {
065: Object o = x;
066: if (o instanceof List) {
067: List l = (List) o;
068: if (!l.isEmpty()) {
069: o = l.get(0);
070: }
071: }
072: if (o instanceof String) {
073: agentName = (String) o;
074: } else if (o instanceof MessageAddress) {
075: agentName = ((MessageAddress) o).getAddress();
076: } else {
077: throw new IllegalArgumentException(
078: "Invalid agent parameter: " + o);
079: }
080: }
081:
082: public void setServiceBroker(ServiceBroker sb) {
083: this .sb = sb;
084: }
085:
086: public void load() {
087: super .load();
088: List l = getInitialComponents();
089: overrideComponentList(l);
090: }
091:
092: private List getInitialComponents() {
093: List l = new ArrayList();
094:
095: // query comp-init service
096: boolean includesDefaultComponents = true;
097: ComponentInitializerService cis = (ComponentInitializerService) sb
098: .getService(this , ComponentInitializerService.class,
099: null);
100: try {
101: includesDefaultComponents = cis.includesDefaultComponents();
102: ComponentDescription[] descs = cis
103: .getComponentDescriptions(agentName,
104: Agent.INSERTION_POINT);
105: if (descs != null) {
106: l.addAll(Arrays.asList(descs));
107: }
108: } catch (ComponentInitializerService.InitializerException cise) {
109: Logger log = Logging.getLogger(this .getClass());
110: if (log.isInfoEnabled()) {
111: log.info("\nUnable to add " + agentName
112: + "'s components", cise);
113: }
114: } finally {
115: sb.releaseService(this , ComponentInitializerService.class,
116: cis);
117: }
118:
119: if (!includesDefaultComponents) {
120: // In the past we had a "DefaultComponents" class that hard-coded the XSL
121: // template components for non-XML configurations, e.g. INIs and DBs.
122: //
123: // That was a mess and has long been deprecated.
124: //
125: // The proposed solution is outlined in Node comments on how the
126: // ComponentInitializerService should be refactored. The agent
127: // configuration will be split into two services:
128: // a) an application configuration (XML, INI, DB, ...)
129: // b) an environment configuration (XSL template, ...)
130: // All application configuration formats will be able to use the existing
131: // XSL templates.
132: Logger log = Logging.getLogger(this .getClass());
133: log.error("Unable to find default components for "
134: + agentName);
135: }
136:
137: if (!l.isEmpty()) {
138: // pass the agentName to first component
139: //
140: // This is a hack, as noted below in the "setAgentName" method.
141: ComponentDescription c0 = (ComponentDescription) l.get(0);
142: ComponentDescription new_c0 = setAgentName(c0, agentName);
143: l.set(0, new_c0);
144: }
145:
146: return l;
147: }
148:
149: private void overrideComponentList(List l) {
150: AgentBootstrapService abs = (AgentBootstrapService) sb
151: .getService(this , AgentBootstrapService.class, null);
152: if (abs == null) {
153: throw new RuntimeException(
154: "Unable to obtain AgentBootstrapService"
155: + ", can not override the agent's component list");
156: }
157: abs.overrideComponentList(l);
158: sb.releaseService(this , AgentBootstrapService.class, abs);
159: abs = null;
160: }
161:
162: // modify a component description with the specified $AGENT_NAME
163: //
164: // This could be enhanced to support arbitrary parameters, not just
165: // our first "agentName" parameter. However, this should be the
166: // ComponentInitializerService's job, not the Bootstrap's job.
167: //
168: // In fact, this agent name should be a expressed as a per-agent "envOption",
169: // as described in the "future design ideas" in the Node class. That
170: // approach would correctly pass this agentName as an XSL template parameter,
171: // which would make it accessable anywhere in the template.
172: //
173: // More generally, the "addAgent(...)" method should support arbitrary
174: // "envOptions" and support an in-memory configuration.
175: private static ComponentDescription setAgentName(
176: ComponentDescription desc, String agentName) {
177: // see if the first param matches "$AGENT_NAME"
178: boolean matches = false;
179: Object o = desc.getParameter();
180: if (o instanceof List) {
181: List l = (List) o;
182: if (l.size() > 0) {
183: Object v = l.get(0);
184: if (v.equals("$AGENT_NAME")) {
185: matches = true;
186: }
187: }
188: }
189: if (!matches)
190: return desc;
191:
192: // replace the first param with our agent name
193: List l2 = new ArrayList((List) o);
194: l2.set(0, agentName);
195: l2 = Collections.unmodifiableList(l2);
196:
197: // return the modified desc
198: return new ComponentDescription(desc.getName(), desc
199: .getInsertionPoint(), desc.getClassname(), desc
200: .getCodebase(), l2, // new params
201: desc.getCertificate(), desc.getLeaseRequested(), desc
202: .getPolicy(), desc.getPriority());
203: }
204: }
|