001: /*
002: * <copyright>
003: *
004: * Copyright 2002-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.Collection;
030: import java.util.Enumeration;
031: import java.util.Iterator;
032:
033: import org.cougaar.core.blackboard.CollectionSubscription;
034: import org.cougaar.core.blackboard.IncrementalSubscription;
035: import org.cougaar.core.mobility.AbstractTicket;
036: import org.cougaar.core.mobility.AddTicket;
037: import org.cougaar.core.mobility.MoveTicket;
038: import org.cougaar.core.mobility.RemoveTicket;
039: import org.cougaar.core.mobility.ldm.AgentControl;
040: import org.cougaar.core.mobility.ldm.MobilityFactory;
041: import org.cougaar.core.mts.MessageAddress;
042: import org.cougaar.core.node.NodeIdentificationService;
043: import org.cougaar.core.plugin.ComponentPlugin;
044: import org.cougaar.core.service.AgentIdentificationService;
045: import org.cougaar.core.service.DomainService;
046: import org.cougaar.core.service.LoggingService;
047: import org.cougaar.core.util.UID;
048: import org.cougaar.core.util.UniqueObject;
049: import org.cougaar.util.UnaryPredicate;
050:
051: /**
052: * This component is an optional agent plugin to redirect mobility
053: * requests ({@link AgentControl}s) from a regular agent to its
054: * node agent.
055: * <p>
056: * Note: this plugin assumes<ul>
057: * <li>All AgentControls targetted to this agent will be redirected
058: * by this plugin</li>
059: * <li>All AgentControls created by this agent are assumed to
060: * be created by this plugin, unless the control's "ownerUID"
061: * is null.</li>
062: * </ul>
063: */
064: public class RedirectMovePlugin extends ComponentPlugin {
065:
066: private MessageAddress agentId;
067: private MessageAddress nodeId;
068: private boolean isNode;
069:
070: private IncrementalSubscription incomingControlSub;
071: private IncrementalSubscription outgoingControlSub;
072:
073: private MobilityFactory mobilityFactory;
074:
075: private LoggingService log;
076:
077: public void load() {
078: super .load();
079:
080: log = (LoggingService) getServiceBroker().getService(this ,
081: LoggingService.class, null);
082: if (log == null) {
083: log = LoggingService.NULL;
084: }
085:
086: getAgentId();
087: getNodeId();
088:
089: isNode = agentId.equals(nodeId);
090: if (isNode) {
091: // accidentially loaded into node?
092: return;
093: }
094:
095: // get the mobility factory
096: DomainService domain = (DomainService) getServiceBroker()
097: .getService(this , DomainService.class, null);
098: if (domain == null) {
099: throw new RuntimeException(
100: "Unable to obtain the domain service");
101: }
102: mobilityFactory = (MobilityFactory) domain
103: .getFactory("mobility");
104: if (mobilityFactory == null) {
105: if (log.isWarnEnabled()) {
106: log
107: .warn("The agent mobility domain (\"mobility\") for agent "
108: + agentId
109: + " on node "
110: + nodeId
111: + " has been disabled.");
112: }
113: }
114: getServiceBroker().releaseService(this , DomainService.class,
115: domain);
116: }
117:
118: public void unload() {
119: if ((log != null) && (log != LoggingService.NULL)) {
120: getServiceBroker().releaseService(this ,
121: LoggingService.class, log);
122: log = LoggingService.NULL;
123: }
124: super .unload();
125: }
126:
127: protected void setupSubscriptions() {
128: if (isNode) {
129: // disabled if loaded into node
130: return;
131: }
132:
133: // agent control requests with this agent as the target
134: incomingControlSub = (IncrementalSubscription) blackboard
135: .subscribe(createIncomingControlPredicate(agentId));
136:
137: // agent control requests with this agent as the source
138: outgoingControlSub = (IncrementalSubscription) blackboard
139: .subscribe(createOutgoingControlPredicate(agentId));
140: }
141:
142: protected void execute() {
143: if (isNode) {
144: return;
145: }
146:
147: if (incomingControlSub.hasChanged()) {
148: // additions
149: Enumeration en = incomingControlSub.getAddedList();
150: while (en.hasMoreElements()) {
151: AgentControl inControl = (AgentControl) en
152: .nextElement();
153: addedIncomingControl(inControl);
154: }
155: // ignore changes: this plugin does them
156: // removals
157: en = incomingControlSub.getRemovedList();
158: while (en.hasMoreElements()) {
159: AgentControl inControl = (AgentControl) en
160: .nextElement();
161: removedIncomingControl(inControl);
162: }
163: }
164:
165: if (outgoingControlSub.hasChanged()) {
166: // ignore additions: this plugin does them
167: // changes
168: Enumeration en = outgoingControlSub.getChangedList();
169: while (en.hasMoreElements()) {
170: AgentControl inControl = (AgentControl) en
171: .nextElement();
172: changedOutgoingControl(inControl);
173: }
174: // ignore removals: this plugin does them
175: }
176: }
177:
178: private void addedIncomingControl(AgentControl inControl) {
179:
180: // assert (agentId.equals(inControl.getTarget()))
181:
182: // redirect to our parent node
183:
184: AbstractTicket abstractTicket = inControl.getAbstractTicket();
185:
186: if (mobilityFactory == null) {
187: String msg = "The agent mobility domain (\"mobility\")"
188: + " is not available for agent " + agentId
189: + ", so control request " + inControl.getUID()
190: + " has been failed";
191: if (log.isErrorEnabled()) {
192: log.error(msg);
193: }
194: inControl.setStatus(AgentControl.FAILURE,
195: new RuntimeException(msg));
196: blackboard.publishChange(inControl);
197: return;
198: }
199:
200: // expand the ticket
201: AbstractTicket fullTicket = abstractTicket;
202: if (abstractTicket instanceof MoveTicket) {
203: MoveTicket ticket = (MoveTicket) abstractTicket;
204: boolean anyMissing = false;
205: MessageAddress controlA = ticket.getMobileAgent();
206: if (controlA == null) {
207: anyMissing = true;
208: controlA = agentId;
209: }
210: MessageAddress origN = ticket.getOriginNode();
211: if (origN == null) {
212: anyMissing = true;
213: origN = nodeId;
214: }
215: MessageAddress destN = ticket.getDestinationNode();
216: if (destN == null) {
217: anyMissing = true;
218: destN = nodeId;
219: }
220: if (anyMissing) {
221: fullTicket = new MoveTicket(ticket.getIdentifier(),
222: controlA, origN, destN, ticket.isForceRestart());
223: }
224: } else if (abstractTicket instanceof AddTicket) {
225: // SARAH!
226: } else if (abstractTicket instanceof RemoveTicket) {
227: } else {
228: }
229:
230: AgentControl outControl = mobilityFactory.createAgentControl(
231: inControl.getUID(), nodeId, fullTicket);
232: blackboard.publishAdd(outControl);
233:
234: if (log.isInfoEnabled()) {
235: log.info("Redirected control request for agent " + agentId
236: + " to its parent node " + nodeId
237: + " (original request: " + inControl.getUID()
238: + ", redirected request: " + outControl.getUID()
239: + ")");
240: }
241: }
242:
243: private void removedIncomingControl(AgentControl inControl) {
244: UID inControlUID = inControl.getUID();
245: AgentControl outControl = findOutgoingControl(inControlUID);
246: if (outControl != null) {
247: // attempt to cancel the control
248: if (log.isInfoEnabled()) {
249: log
250: .info("Removing in-progress control request for agent "
251: + agentId
252: + " that was redirected to its parent node "
253: + nodeId
254: + " (original request: "
255: + outControl.getUID()
256: + ", redirected request: "
257: + inControlUID + ")");
258: }
259: blackboard.publishRemove(outControl);
260: }
261: }
262:
263: private void changedOutgoingControl(AgentControl outControl) {
264:
265: int outControlStatus = outControl.getStatusCode();
266: if (outControlStatus == AgentControl.NONE) {
267: // not done yet.
268: if (log.isDebugEnabled()) {
269: log
270: .debug("Ignoring \"no status\" change of control request"
271: + " for agent "
272: + agentId
273: + " (uid: "
274: + outControl.getUID() + ")");
275: }
276: return;
277: }
278:
279: UID inControlUID = outControl.getOwnerUID();
280: if (inControlUID == null) {
281: // the owner tag is null, so this isn't a redirect
282: if (log.isDebugEnabled()) {
283: log
284: .debug("Ignoring change to control request for agent "
285: + agentId
286: + ", it is not a redirect (uid: "
287: + outControl.getUID() + ")");
288: }
289: return;
290: }
291:
292: AgentControl inControl = findIncomingControl(inControlUID);
293: if (inControl == null) {
294: // already removed?
295: if (log.isInfoEnabled()) {
296: log.info("Agent " + agentId
297: + " control completed with status "
298: + outControl.getStatusCodeAsString()
299: + ", but the original control request "
300: + inControlUID
301: + " is no longer in the blackboard");
302: }
303: return;
304: }
305:
306: if (inControl.getStatusCode() != AgentControl.NONE) {
307: // already removed?
308: if (log.isInfoEnabled()) {
309: log.info("Agent " + agentId
310: + " control completed with status "
311: + outControl.getStatusCodeAsString()
312: + ", but the original control request "
313: + inControlUID
314: + " already has its status set to "
315: + inControl.getStatusCodeAsString());
316: }
317: return;
318: }
319:
320: if (log.isDebugEnabled()) {
321: log.debug("Copy the new control status "
322: + outControl.getStatusCodeAsString()
323: + " for agent " + agentId + " (from: "
324: + outControl.getUID() + ", to:"
325: + inControl.getUID() + ")");
326: }
327:
328: inControl.setStatus(outControlStatus, outControl
329: .getFailureStackTrace());
330: blackboard.publishChange(inControl);
331:
332: // we're done with the control now
333: blackboard.publishRemove(outControl);
334:
335: if (log.isInfoEnabled()) {
336: log.info("Updated status of control request for agent "
337: + agentId + " to "
338: + inControl.getStatusCodeAsString() + " (uid: "
339: + inControl.getUID() + ")");
340: }
341: }
342:
343: // could cache this:
344:
345: private AgentControl findIncomingControl(UID incomingControlUID) {
346: return (AgentControl) query(incomingControlSub,
347: incomingControlUID);
348: }
349:
350: private AgentControl findOutgoingControl(UID incomingControlUID) {
351: if (incomingControlUID != null) {
352: Collection real = outgoingControlSub.getCollection();
353: int n = real.size();
354: if (n > 0) {
355: for (Iterator iter = real.iterator(); iter.hasNext();) {
356: AgentControl control = (AgentControl) iter.next();
357: if (incomingControlUID
358: .equals(control.getOwnerUID())) {
359: return control;
360: }
361: }
362: }
363: }
364: return null;
365: }
366:
367: private static UniqueObject query(CollectionSubscription sub,
368: UID uid) {
369: if (uid != null) {
370: Collection real = sub.getCollection();
371: int n = real.size();
372: if (n > 0) {
373: for (Iterator iter = real.iterator(); iter.hasNext();) {
374: Object o = iter.next();
375: if (o instanceof UniqueObject) {
376: UniqueObject uo = (UniqueObject) o;
377: UID x = uo.getUID();
378: if (uid.equals(x)) {
379: return uo;
380: }
381: }
382: }
383: }
384: }
385: return null;
386: }
387:
388: private static UnaryPredicate createIncomingControlPredicate(
389: final MessageAddress agentId) {
390: return new UnaryPredicate() {
391: public boolean execute(Object o) {
392: if (o instanceof AgentControl) {
393: AgentControl control = (AgentControl) o;
394: MessageAddress target = control.getTarget();
395: return ((target == null) || agentId.equals(target));
396: }
397: return false;
398: }
399: };
400: }
401:
402: private static UnaryPredicate createOutgoingControlPredicate(
403: final MessageAddress agentId) {
404: return new UnaryPredicate() {
405: public boolean execute(Object o) {
406: if (o instanceof AgentControl) {
407: AgentControl control = (AgentControl) o;
408: MessageAddress source = control.getSource();
409: return ((source == null) || (agentId.equals(source)));
410: }
411: return false;
412: }
413: };
414: }
415:
416: private void getAgentId() {
417: // get the agentId
418: AgentIdentificationService agentIdService = (AgentIdentificationService) getServiceBroker()
419: .getService(this , AgentIdentificationService.class,
420: null);
421: if (agentIdService == null) {
422: throw new RuntimeException(
423: "Unable to obtain agent-id service");
424: }
425: this .agentId = agentIdService.getMessageAddress();
426: getServiceBroker().releaseService(this ,
427: AgentIdentificationService.class, agentIdService);
428: if (agentId == null) {
429: throw new RuntimeException("Unable to obtain agent id");
430: }
431: }
432:
433: private void getNodeId() {
434: // get the nodeId
435: NodeIdentificationService nodeIdService = (NodeIdentificationService) getServiceBroker()
436: .getService(this , NodeIdentificationService.class, null);
437: if (nodeIdService == null) {
438: throw new RuntimeException(
439: "Unable to obtain node-id service");
440: }
441: this .nodeId = nodeIdService.getMessageAddress();
442: getServiceBroker().releaseService(this ,
443: NodeIdentificationService.class, nodeIdService);
444: if (nodeId == null) {
445: throw new RuntimeException("Unable to obtain node id");
446: }
447: }
448:
449: }
|