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:
027: package org.cougaar.core.mobility.service;
028:
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.Enumeration;
032: import java.util.Iterator;
033: import java.util.List;
034: import org.cougaar.core.agent.AgentContainer;
035: import org.cougaar.core.blackboard.CollectionSubscription;
036: import org.cougaar.core.blackboard.IncrementalSubscription;
037: import org.cougaar.core.blackboard.Subscription;
038: import org.cougaar.core.component.ComponentDescription;
039: import org.cougaar.core.component.ServiceBroker;
040: import org.cougaar.core.component.ServiceProvider;
041: import org.cougaar.core.component.ServiceRevokedListener;
042: import org.cougaar.core.domain.Factory;
043: import org.cougaar.core.mobility.AbstractTicket;
044: import org.cougaar.core.mobility.MobilityClient;
045: import org.cougaar.core.mobility.MobilityService;
046: import org.cougaar.core.mobility.ldm.AgentControl;
047: import org.cougaar.core.mobility.ldm.MobilityFactory;
048: import org.cougaar.core.mts.MessageAddress;
049: import org.cougaar.core.node.NodeControlService;
050: import org.cougaar.core.node.NodeIdentificationService;
051: import org.cougaar.core.plugin.ComponentPlugin;
052: import org.cougaar.core.service.AgentIdentificationService;
053: import org.cougaar.core.service.BlackboardService;
054: import org.cougaar.core.service.DomainService;
055: import org.cougaar.core.service.LoggingService;
056: import org.cougaar.core.service.ThreadService;
057: import org.cougaar.core.service.wp.WhitePagesService;
058: import org.cougaar.core.thread.Schedulable;
059: import org.cougaar.core.util.UID;
060: import org.cougaar.core.util.UniqueObject;
061: import org.cougaar.util.UnaryPredicate;
062:
063: /**
064: * This component is a base class for the node agent's {@link
065: * RootMobilityPlugin}.
066: * <p>
067: * This component does nothing if it is loaded into regular non-node
068: * agents.
069: */
070: public abstract class AbstractMobilityPlugin extends ComponentPlugin {
071:
072: private static final UnaryPredicate AGENT_CONTROL_PRED = new AgentControlPredicate();
073:
074: private static final class AgentControlPredicate implements
075: UnaryPredicate {
076: public boolean execute(Object o) {
077: return (o instanceof AgentControl);
078: }
079: }
080:
081: protected MessageAddress agentId;
082: protected MessageAddress nodeId;
083: protected boolean isNode;
084:
085: //private IncrementalSubscription moveSub;
086: private IncrementalSubscription controlSub;
087:
088: protected LoggingService log;
089:
090: private MobilityFactory mobilityFactory;
091:
092: // the rest is only used if (isNode == true):
093:
094: protected NodeControlService nodeControlService;
095: protected ThreadService threadService;
096: protected WhitePagesService whitePagesService;
097:
098: private ServiceBroker nodeSB;
099: protected AgentContainer agentContainer;
100:
101: private MobilityServiceProviderImpl mobileAgentSP;
102:
103: private final List todo = new ArrayList(5);
104:
105: public void load() {
106: super .load();
107:
108: // get the logger
109: log = (LoggingService) getServiceBroker().getService(this ,
110: LoggingService.class, null);
111: if (log == null) {
112: log = LoggingService.NULL;
113: }
114:
115: // get the agentId
116: AgentIdentificationService agentIdService = (AgentIdentificationService) getServiceBroker()
117: .getService(this , AgentIdentificationService.class,
118: null);
119: if (agentIdService == null) {
120: throw new RuntimeException(
121: "Unable to obtain agent-id service");
122: }
123: this .agentId = agentIdService.getMessageAddress();
124: getServiceBroker().releaseService(this ,
125: AgentIdentificationService.class, agentIdService);
126: if (agentId == null) {
127: throw new RuntimeException("Unable to obtain agent id");
128: }
129:
130: // get the nodeId
131: NodeIdentificationService nodeIdService = (NodeIdentificationService) getServiceBroker()
132: .getService(this , NodeIdentificationService.class, null);
133: if (nodeIdService == null) {
134: throw new RuntimeException(
135: "Unable to obtain node-id service");
136: }
137: this .nodeId = nodeIdService.getMessageAddress();
138: getServiceBroker().releaseService(this ,
139: NodeIdentificationService.class, nodeIdService);
140: if (nodeId == null) {
141: throw new RuntimeException("Unable to obtain node id");
142: }
143:
144: // either running within a node-agent or leaf-agent
145: isNode = (agentId.equals(nodeId));
146:
147: // get the mobility factory
148: DomainService domain = (DomainService) getServiceBroker()
149: .getService(this , DomainService.class, null);
150: if (domain == null) {
151: throw new RuntimeException(
152: "Unable to obtain the domain service");
153: }
154: mobilityFactory = (MobilityFactory) domain
155: .getFactory("mobility");
156: if (mobilityFactory == null) {
157: if (log.isWarnEnabled()) {
158: log.warn("Unable to obtain the agent mobility domain"
159: + " (\"mobility\"), please check your "
160: + "domain configuration.");
161: }
162: // okay, will fail most mobility requests
163: }
164: getServiceBroker().releaseService(this , DomainService.class,
165: domain);
166:
167: if (isNode) {
168: // get control of the node
169: nodeControlService = (NodeControlService) getServiceBroker()
170: .getService(this , NodeControlService.class, null);
171: if (nodeControlService == null) {
172: throw new RuntimeException(
173: "Unable to obtain node-control service");
174: }
175: this .nodeSB = nodeControlService.getRootServiceBroker();
176: this .agentContainer = nodeControlService.getRootContainer();
177:
178: // get the thread service
179: threadService = (ThreadService) getServiceBroker()
180: .getService(this , ThreadService.class, null);
181: if (threadService == null) {
182: throw new RuntimeException(
183: "Unable to obtain node-level thread service");
184: }
185:
186: // get the white pages service
187: whitePagesService = (WhitePagesService) getServiceBroker()
188: .getService(this , WhitePagesService.class, null);
189: if (whitePagesService == null) {
190: throw new RuntimeException(
191: "Unable to obtain the white pages service");
192: }
193:
194: // advertise our mobility service
195: if (mobileAgentSP == null) {
196: this .mobileAgentSP = new MobilityServiceProviderImpl();
197: nodeSB.addService(MobilityService.class, mobileAgentSP);
198:
199: if (log.isDebugEnabled()) {
200: log
201: .debug("Created mobile agent registry service for "
202: + nodeId);
203: }
204: } else {
205: if (log.isErrorEnabled()) {
206: log
207: .error("Mobile Agent registry service already created? "
208: + mobileAgentSP);
209: }
210: }
211: }
212: }
213:
214: public void unload() {
215: if (isNode) {
216: if (mobileAgentSP != null) {
217: nodeSB.revokeService(MobilityService.class,
218: mobileAgentSP);
219: mobileAgentSP = null;
220: }
221: if (whitePagesService != null) {
222: getServiceBroker().releaseService(this ,
223: WhitePagesService.class, whitePagesService);
224: whitePagesService = null;
225: }
226: if (nodeControlService != null) {
227: getServiceBroker().releaseService(this ,
228: NodeControlService.class, nodeControlService);
229: nodeControlService = null;
230: }
231: }
232: if ((log != null) && (log != LoggingService.NULL)) {
233: getServiceBroker().releaseService(this ,
234: LoggingService.class, log);
235: log = LoggingService.NULL;
236: }
237: super .unload();
238: }
239:
240: protected void setupSubscriptions() {
241: // subscribe to control requests that we'll execute
242: controlSub = (IncrementalSubscription) blackboard
243: .subscribe(AGENT_CONTROL_PRED);
244:
245: if (isNode) {
246: if (blackboard.didRehydrate()) {
247: if (log.isInfoEnabled()) {
248: log
249: .info("Node rehydration for agent mobility is not supported");
250: }
251: }
252: }
253: }
254:
255: protected void execute() {
256: if (!isNode)
257: return;
258:
259: // fire pending blackboard changes
260: fireAll();
261:
262: // watch control requests
263: if (controlSub.hasChanged()) {
264: // adds
265: Enumeration en = controlSub.getAddedList();
266: while (en.hasMoreElements()) {
267: AgentControl control = (AgentControl) en.nextElement();
268: addedAgentControl(control);
269: }
270: // changes
271: en = controlSub.getChangedList();
272: while (en.hasMoreElements()) {
273: AgentControl control = (AgentControl) en.nextElement();
274: changedAgentControl(control);
275: }
276: // removes
277: en = controlSub.getRemovedList();
278: while (en.hasMoreElements()) {
279: AgentControl control = (AgentControl) en.nextElement();
280: removedAgentControl(control);
281: }
282: }
283: }
284:
285: protected AgentControl findAgentControl(UID controlUID) {
286: return (AgentControl) query(controlSub, controlUID);
287: }
288:
289: /** control request for a local agent. */
290: protected abstract void addedAgentControl(AgentControl control);
291:
292: /** a control was changed. */
293: protected abstract void changedAgentControl(AgentControl control);
294:
295: /** a control was removed. */
296: protected abstract void removedAgentControl(AgentControl control);
297:
298: /** an agent registers as a mobile agent in the local node. */
299: protected abstract void registerAgent(MessageAddress id,
300: ComponentDescription desc, MobilityClient agent);
301:
302: /** an agent unregisters itself from the local mobility registry. */
303: protected abstract void unregisterAgent(MessageAddress id);
304:
305: // more node-only code:
306:
307: protected void queue(Runnable r) {
308: Schedulable sched = threadService.getThread(this , r, r
309: .toString());
310: sched.start();
311: }
312:
313: protected AgentControl createAgentControl(UID moveControlUID,
314: MessageAddress destNode, TransferTicket transferTicket) {
315: if (mobilityFactory == null) {
316: throw new RuntimeException(
317: "The agent mobility domain is not available on node "
318: + nodeId);
319: }
320: return mobilityFactory.createAgentControl(moveControlUID,
321: destNode, transferTicket);
322: }
323:
324: protected void fireLater(Runnable r) {
325: synchronized (todo) {
326: todo.add(r);
327: }
328: blackboard.signalClientActivity();
329: }
330:
331: private static UniqueObject query(CollectionSubscription sub,
332: UID uid) {
333: Collection real = sub.getCollection();
334: int n = real.size();
335: if (n > 0) {
336: for (Iterator iter = real.iterator(); iter.hasNext();) {
337: Object o = iter.next();
338: if (o instanceof UniqueObject) {
339: UniqueObject uo = (UniqueObject) o;
340: UID x = uo.getUID();
341: if (uid.equals(x)) {
342: return uo;
343: }
344: }
345: }
346: }
347: return null;
348: }
349:
350: private void fireAll() {
351: int n;
352: List l;
353: synchronized (todo) {
354: n = todo.size();
355: if (n <= 0) {
356: return;
357: }
358: l = new ArrayList(todo);
359: todo.clear();
360: }
361: for (int i = 0; i < n; i++) {
362: Runnable r = (Runnable) l.get(i);
363: r.run();
364: }
365: }
366:
367: private class MobilityServiceProviderImpl implements
368: ServiceProvider {
369:
370: // single dummy service instance
371: private final MobilityService SINGLE_SERVICE_INSTANCE = new MobilityService() {
372: };
373:
374: public Object getService(ServiceBroker sb, Object requestor,
375: Class serviceClass) {
376: // check service class
377: if (serviceClass != MobilityService.class) {
378: throw new IllegalArgumentException(
379: "Unsupported service " + serviceClass);
380: }
381: // assert that the requestor is an agent
382: if (!(requestor instanceof MobilityClient)) {
383: throw new RuntimeException(
384: "Expecting a MobilityClient requestor, not "
385: + requestor);
386: }
387: MobilityClient agent = (MobilityClient) requestor;
388: MessageAddress id = agent.getAgentIdentifier();
389:
390: // get the agent's description from its container
391: ComponentDescription desc = agentContainer
392: .getAgentDescription(id);
393: if (desc == null) {
394: throw new RuntimeException("Unable to get agent \""
395: + id + "\"'s ComponentDescription"
396: + " from the agent container ("
397: + agentContainer + ")");
398: }
399:
400: registerAgent(id, desc, agent);
401:
402: if (log.isDebugEnabled()) {
403: log.debug("Registered agent " + id
404: + " for agent mobility");
405: }
406:
407: // create a dummy service instance
408: return SINGLE_SERVICE_INSTANCE;
409: }
410:
411: public void releaseService(ServiceBroker sb, Object requestor,
412: Class serviceClass, Object service) {
413: // check service instance
414: if (service != SINGLE_SERVICE_INSTANCE) {
415: throw new IllegalArgumentException(
416: "Wrong service instance " + service);
417: }
418: MobilityClient agent = (MobilityClient) requestor;
419: MessageAddress id = agent.getAgentIdentifier();
420: unregisterAgent(id);
421: }
422: }
423: }
|