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.arch;
028:
029: import org.cougaar.core.component.ComponentDescription;
030: import org.cougaar.core.mobility.MobilityClient;
031: import org.cougaar.core.mobility.MobilityException;
032: import org.cougaar.core.mobility.MoveTicket;
033: import org.cougaar.core.mts.MessageAddress;
034: import org.cougaar.core.service.LoggingService;
035: import org.cougaar.util.GenericStateModel;
036:
037: /**
038: * Handle a request to send an agent to a remote node.
039: * <p>
040: * This does half the work, since the ack/nack will be pending.
041: */
042: public class DispatchRemoteHandler extends AbstractHandler {
043:
044: private GenericStateModel model;
045: private ComponentDescription desc;
046: private MobilityClient stateProvider;
047:
048: public DispatchRemoteHandler(MobilitySupport support,
049: GenericStateModel model, ComponentDescription desc,
050: MobilityClient stateProvider) {
051: super (support);
052: this .model = model;
053: this .desc = desc;
054: this .stateProvider = stateProvider;
055: }
056:
057: public void run() {
058: dispatchRemote();
059: }
060:
061: private void dispatchRemote() {
062:
063: Object state;
064: boolean didSuspend = false;
065: try {
066:
067: checkTicket();
068:
069: if (log.isInfoEnabled()) {
070: log.info("Begin move of agent " + id + " from "
071: + nodeId + " to "
072: + moveTicket.getDestinationNode()
073: + ", move id is " + moveTicket.getIdentifier());
074: }
075:
076: onDispatch();
077:
078: suspendAgent();
079: didSuspend = true;
080:
081: state = getAgentState();
082:
083: } catch (Exception e) {
084:
085: // obtaining the state shouldn't mangle the agent, so we'll
086: // attempt to resume the agent from its suspension.
087:
088: if (log.isErrorEnabled()) {
089: log.error("Unable to move agent " + id, e);
090: }
091: if (didSuspend) {
092: model.resume();
093: }
094:
095: onFailure(e);
096:
097: return;
098: }
099:
100: try {
101:
102: sendTransfer(desc, state);
103: state = null;
104:
105: } catch (Exception e) {
106: state = null;
107:
108: // not sure if the message was sent...
109: //
110: // attempt to resume the agent from its suspension.
111:
112: if (log.isErrorEnabled()) {
113: log.error("Failed message delivery for agent transfer",
114: e);
115: }
116:
117: model.resume();
118:
119: onFailure(e);
120:
121: return;
122: }
123:
124: if (log.isInfoEnabled()) {
125: log.info("Transfering agent " + id + " to node "
126: + moveTicket.getDestinationNode()
127: + ", waiting for an acknowledgement from node "
128: + moveTicket.getDestinationNode());
129: }
130:
131: }
132:
133: private void checkTicket() {
134:
135: // check for non-local destination
136: MessageAddress destNode = moveTicket.getDestinationNode();
137: if ((destNode == null) || (destNode.equals(nodeId))) {
138: throw new InternalError(
139: "Remote dispatch on a local destination "
140: + destNode);
141: }
142:
143: // check agent assertion
144: MessageAddress mobileAgent = moveTicket.getMobileAgent();
145: if ((mobileAgent != null) && (!(mobileAgent.equals(id)))) {
146: throw new MobilityException("Move agent " + id
147: + " doesn't match ticket agent " + mobileAgent);
148: }
149:
150: // check origin assertion
151: MessageAddress originNode = moveTicket.getOriginNode();
152: if ((originNode != null) && (!(originNode.equals(nodeId)))) {
153: throw new MobilityException("Move origin " + nodeId
154: + " for " + id + " doesn't match ticket origin "
155: + originNode);
156: }
157: }
158:
159: private void suspendAgent() {
160: if (log.isInfoEnabled()) {
161: log.info("Suspend agent " + id);
162: }
163:
164: model.suspend();
165:
166: if (log.isInfoEnabled()) {
167: log.info("Suspended agent " + id);
168: }
169: }
170:
171: private Object getAgentState() {
172: // capture the agent state
173:
174: if (stateProvider == null) {
175: if (log.isWarnEnabled()) {
176: log.warn("Agent " + id + " has no state?");
177: }
178: return null;
179: }
180:
181: if (log.isInfoEnabled()) {
182: log.info("Capture state for agent " + id);
183: }
184:
185: Object state;
186: try {
187: state = stateProvider.getState();
188: } catch (Exception e) {
189: throw new MobilityException(
190: "Unable to capture state for agent " + id
191: + ", will attempt resume", e);
192: }
193:
194: if (log.isInfoEnabled()) {
195: // FIXME maybe not log this -- state may be very verbose!
196: log.info("Captured state for agent " + id + ": " + state);
197: }
198:
199: return state;
200: }
201:
202: public String toString() {
203: return "Move (dispatch-remote) of agent " + id;
204: }
205: }
|