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.examples.mobility.step;
028:
029: import java.io.ByteArrayOutputStream;
030: import java.io.IOException;
031: import java.io.PrintWriter;
032: import java.net.MalformedURLException;
033: import java.net.URL;
034: import java.net.URLDecoder;
035: import java.util.ArrayList;
036: import java.util.Collection;
037: import java.util.Date;
038: import java.util.Enumeration;
039: import java.util.Iterator;
040: import java.util.List;
041: import javax.servlet.Servlet;
042: import javax.servlet.http.HttpServlet;
043: import javax.servlet.http.HttpServletRequest;
044: import javax.servlet.http.HttpServletResponse;
045: import org.cougaar.core.blackboard.BlackboardClient;
046: import org.cougaar.core.examples.mobility.ldm.*;
047: import org.cougaar.core.mobility.Ticket;
048: import org.cougaar.core.mobility.ldm.MobilityFactory;
049: import org.cougaar.core.mts.MessageAddress;
050: import org.cougaar.core.node.NodeIdentificationService;
051: import org.cougaar.core.service.AgentIdentificationService;
052: import org.cougaar.core.service.BlackboardService;
053: import org.cougaar.core.service.DomainService;
054: import org.cougaar.core.service.LoggingService;
055: import org.cougaar.core.servlet.BaseServletComponent;
056: import org.cougaar.core.util.UID;
057: import org.cougaar.util.UnaryPredicate;
058:
059: /**
060: * Servlet that allows the client to add, remove, and view
061: * mobility test "Step" objects.check for
062: * <p>
063: * The path of the servlet is "/move/step".
064: * <p>
065: * The URL parameters to this servlet are:
066: * <ul><p>
067: * <li><tt>action=STRING</tt><br>
068: * Option action selection, where the default is "Refresh".
069: * <p>
070: * "Refresh" displays the current Steps and their status.
071: * <p>
072: * "Remove" removes the Step with the UID specified by
073: * the required "removeUID" parameter.
074: * <p>
075: * "Add" creates a new Step. Most of the parameters
076: * below are used to support "Add".
077: * </li><p>
078: * <li><tt>actorAgent=STRING</tt><br>
079: * Optional name of the agent to perform the step. Defaults
080: * to this servlet's agent.
081: * <li><p>
082: * <li><tt>pauseTime=STRING</tt><br>
083: * Optional time in milliseconds to pause before starting the
084: * step. A value of "0" indicates no pause, which is the
085: * default. If the value starts with a "+" then the pause
086: * time is relative to the current time (e.g. "+5000" for
087: * 5 seconds after the submit). Other values are absolute
088: * times in milliseconds (e.g. "1023309610110").
089: * </li><p>
090: * <li><tt>timeoutTime=STRING</tt><br>
091: * Optional time in milliseconds for the time limit of
092: * the step. Supports the same "+" and time options as
093: * the "pauseTime" parameter.
094: * </li><p>
095: * <li><tt>mobileAgent=STRING</tt><br>
096: * Option agent to move. Defaults to this servlet's agent.
097: * </li><p>
098: * <li><tt>originNode=STRING</tt><br>
099: * Option origin node for the mobile agent. Defaults to
100: * wherever the agent happens to be at the time of the submit.
101: * If set, the move will assert the agent starting node
102: * location.
103: * </li><p>
104: * <li><tt>destNode=STRING</tt><br>
105: * Option destination node for the mobile agent. Defaults
106: * to wherever the agent happens to be at the time of
107: * the submit.
108: * </li><p>
109: * <li><tt>isForceRestart=BOOLEAN</tt><br>
110: * Only applies when the destNode is not specified or
111: * matches the current agent location. If true, the agent
112: * will undergo most of the move work, even though it's
113: * already at the specified destination node.
114: * </li><p>
115: * </ul>
116: * <p>
117: * Note the <b>SECURITY</b> issues of moving agents!
118: */
119: public class StepManagerServlet extends BaseServletComponent implements
120: BlackboardClient {
121:
122: protected static final UnaryPredicate STEP_PRED = new UnaryPredicate() {
123: public boolean execute(Object o) {
124: return (o instanceof Step);
125: }
126: };
127:
128: protected MessageAddress agentId;
129: protected MessageAddress nodeId;
130:
131: protected BlackboardService blackboard;
132: protected DomainService domain;
133: protected LoggingService log;
134: protected MobilityFactory mobilityFactory;
135: protected MobilityTestFactory mobilityTestFactory;
136:
137: protected String getPath() {
138: return "/move/step";
139: }
140:
141: protected Servlet createServlet() {
142: // create inner class
143: return new MyServlet();
144: }
145:
146: // aquire services:
147: public void load() {
148:
149: // get the log
150: log = (LoggingService) serviceBroker.getService(this ,
151: LoggingService.class, null);
152: if (log == null) {
153: log = LoggingService.NULL;
154: }
155:
156: // get the agentId
157: AgentIdentificationService agentIdService = (AgentIdentificationService) serviceBroker
158: .getService(this , AgentIdentificationService.class,
159: null);
160: if (agentIdService == null) {
161: throw new RuntimeException(
162: "Unable to obtain agent-id service");
163: }
164: this .agentId = agentIdService.getMessageAddress();
165: serviceBroker.releaseService(this ,
166: AgentIdentificationService.class, agentIdService);
167: if (agentId == null) {
168: throw new RuntimeException("Unable to obtain agent id");
169: }
170:
171: // get the nodeId
172: NodeIdentificationService nodeIdService = (NodeIdentificationService) serviceBroker
173: .getService(this , NodeIdentificationService.class, null);
174: if (nodeIdService == null) {
175: throw new RuntimeException(
176: "Unable to obtain node-id service");
177: }
178: this .nodeId = nodeIdService.getMessageAddress();
179: serviceBroker.releaseService(this ,
180: NodeIdentificationService.class, nodeIdService);
181: if (nodeId == null) {
182: throw new RuntimeException("Unable to obtain node id");
183: }
184:
185: // get the mobility domain
186: this .domain = (DomainService) serviceBroker.getService(this ,
187: DomainService.class, null);
188: if (domain == null) {
189: throw new RuntimeException(
190: "Unable to obtain domain service");
191: }
192:
193: // get the mobility factory (for ticket creation)
194: this .mobilityFactory = (MobilityFactory) domain
195: .getFactory("mobility");
196: if (mobilityFactory == null) {
197: throw new RuntimeException(
198: "Mobility factory (and domain \"mobility\")"
199: + " not enabled");
200: }
201:
202: // get the mobility test factory (for step creation)
203: this .mobilityTestFactory = (MobilityTestFactory) domain
204: .getFactory("mobilityTest");
205: if (mobilityTestFactory == null) {
206: throw new RuntimeException(
207: "Mobility test factory (and domain \"mobilityTest\")"
208: + " not enabled");
209: }
210:
211: // get the blackboard
212: this .blackboard = (BlackboardService) serviceBroker.getService(
213: this , BlackboardService.class, null);
214: if (blackboard == null) {
215: throw new RuntimeException(
216: "Unable to obtain blackboard service");
217: }
218:
219: super .load();
220: }
221:
222: // release services:
223: public void unload() {
224: super .unload();
225: if (blackboard != null) {
226: serviceBroker.releaseService(this , BlackboardService.class,
227: blackboard);
228: blackboard = null;
229: }
230: if (domain != null) {
231: serviceBroker.releaseService(this , DomainService.class,
232: domain);
233: domain = null;
234: mobilityFactory = null;
235: mobilityTestFactory = null;
236: }
237: if ((log != null) && (log != LoggingService.NULL)) {
238: serviceBroker.releaseService(this , LoggingService.class,
239: log);
240: log = LoggingService.NULL;
241: }
242: }
243:
244: protected Collection querySteps() {
245: Collection ret = null;
246: try {
247: blackboard.openTransaction();
248: ret = blackboard.query(STEP_PRED);
249: } finally {
250: blackboard.closeTransactionDontReset();
251: }
252: return ret;
253: }
254:
255: protected Step queryStep(final UID uid) {
256: if (uid == null) {
257: throw new IllegalArgumentException("null uid");
258: }
259: UnaryPredicate pred = new UnaryPredicate() {
260: public boolean execute(Object o) {
261: return ((o instanceof Step) && (uid.equals(((Step) o)
262: .getUID())));
263: }
264: };
265: Step ret = null;
266: try {
267: blackboard.openTransaction();
268: Collection c = blackboard.query(pred);
269: if ((c != null) && (c.size() >= 1)) {
270: ret = (Step) c.iterator().next();
271: }
272: } finally {
273: blackboard.closeTransactionDontReset();
274: }
275: return ret;
276: }
277:
278: protected Ticket createTicket(String mobileAgent,
279: String originNode, String destNode, boolean isForceRestart) {
280: if (mobilityFactory == null) {
281: throw new RuntimeException(
282: "Mobility factory (and domain) not enabled");
283: }
284: MessageAddress mobileAgentAddr = null;
285: MessageAddress originNodeAddr = null;
286: MessageAddress destNodeAddr = null;
287: if (mobileAgent != null) {
288: mobileAgentAddr = MessageAddress
289: .getMessageAddress(mobileAgent);
290: }
291: if (originNode != null) {
292: originNodeAddr = MessageAddress
293: .getMessageAddress(originNode);
294: }
295: if (destNode != null) {
296: destNodeAddr = MessageAddress.getMessageAddress(destNode);
297: }
298: Object ticketId = mobilityFactory.createTicketIdentifier();
299: Ticket ticket = new Ticket(ticketId, mobileAgentAddr,
300: originNodeAddr, destNodeAddr, isForceRestart);
301: return ticket;
302: }
303:
304: protected StepOptions createStepOptions(String actorAgent,
305: Ticket ticket, long pauseTime, long timeoutTime) {
306: MessageAddress actorAgentAddr = ((actorAgent != null) ? (MessageAddress
307: .getMessageAddress(actorAgent))
308: : (agentId));
309: StepOptions so = new StepOptions(null, agentId, // source
310: actorAgentAddr, ticket, pauseTime, timeoutTime);
311: return so;
312: }
313:
314: protected Step createStep(StepOptions options) {
315: Step step = mobilityTestFactory.createStep(options);
316: if (log.isInfoEnabled()) {
317: log.info("Created new step: " + step);
318: }
319: return step;
320: }
321:
322: protected void addStep(Step step) {
323: try {
324: blackboard.openTransaction();
325: blackboard.publishAdd(step);
326: } finally {
327: blackboard.closeTransactionDontReset();
328: }
329: }
330:
331: protected void removeStep(Step step) {
332: try {
333: blackboard.openTransaction();
334: blackboard.publishRemove(step);
335: } finally {
336: blackboard.closeTransactionDontReset();
337: }
338: }
339:
340: /**
341: * Servlet to handle requests.
342: */
343: private class MyServlet extends HttpServlet {
344:
345: public void doGet(HttpServletRequest req,
346: HttpServletResponse res) throws IOException {
347: MyWorker mw = new MyWorker(req, res);
348: mw.execute();
349: }
350:
351: private class MyWorker {
352:
353: // from the "doGet(..)":
354: private HttpServletRequest request;
355: private HttpServletResponse response;
356:
357: // from the URL-params:
358: // (see the class-level javadocs for details)
359:
360: // actions:
361:
362: public static final String ACTION_PARAM = "action";
363: public static final String ADD_VALUE = "Add";
364: public static final String REMOVE_VALUE = "Remove";
365: public static final String REFRESH_VALUE = "Refresh";
366: public String action;
367:
368: // remove uid:
369:
370: public static final String REMOVE_UID_PARAM = "removeUID";
371: public String removeUID;
372:
373: // step options:
374:
375: public static final String ACTOR_AGENT_PARAM = "actorAgent";
376: public String actorAgent;
377:
378: public static final String PAUSE_TIME_PARAM = "pauseTime";
379: public long pauseTime;
380:
381: public static final String TIMEOUT_TIME_PARAM = "timeoutTime";
382: public long timeoutTime;
383:
384: // ticket options:
385:
386: public static final String MOBILE_AGENT_PARAM = "mobileAgent";
387: public String mobileAgent;
388:
389: public static final String ORIGIN_NODE_PARAM = "originNode";
390: public String originNode;
391:
392: public static final String DEST_NODE_PARAM = "destNode";
393: public String destNode;
394:
395: public static final String IS_FORCE_RESTART_PARAM = "isForceRestart";
396: public boolean isForceRestart;
397:
398: // worker constructor:
399: public MyWorker(HttpServletRequest request,
400: HttpServletResponse response) {
401: this .request = request;
402: this .response = response;
403: }
404:
405: // handle a request:
406: public void execute() throws IOException {
407: parseParams();
408: writeResponse();
409: }
410:
411: private void parseParams() throws IOException {
412: // action:
413: action = request.getParameter(ACTION_PARAM);
414:
415: // remove param:
416: removeUID = request.getParameter(REMOVE_UID_PARAM);
417: if ((removeUID != null) && (removeUID.length() == 0)) {
418: removeUID = null;
419: }
420:
421: // step options:
422: long nowTime = -1;
423: actorAgent = request.getParameter(ACTOR_AGENT_PARAM);
424: if ((actorAgent != null) && (actorAgent.length() == 0)) {
425: actorAgent = null;
426: }
427: String sPauseTime = request
428: .getParameter(PAUSE_TIME_PARAM);
429: if ((sPauseTime != null) && (sPauseTime.length() > 0)) {
430: boolean isDelta = false;
431: if (sPauseTime.startsWith("+")) {
432: isDelta = true;
433: sPauseTime = sPauseTime.substring(1);
434: if (nowTime <= 0) {
435: nowTime = System.currentTimeMillis();
436: }
437: }
438: pauseTime = Long.parseLong(sPauseTime);
439: if (isDelta) {
440: pauseTime += nowTime;
441: }
442: }
443: String sTimeoutTime = request
444: .getParameter(TIMEOUT_TIME_PARAM);
445: if ((sTimeoutTime != null)
446: && (sTimeoutTime.length() > 0)) {
447: boolean isDelta = false;
448: if (sTimeoutTime.startsWith("+")) {
449: isDelta = true;
450: sTimeoutTime = sTimeoutTime.substring(1);
451: if (nowTime <= 0) {
452: nowTime = System.currentTimeMillis();
453: }
454: }
455: timeoutTime = Long.parseLong(sTimeoutTime);
456: if (isDelta) {
457: timeoutTime += nowTime;
458: }
459: }
460:
461: // ticket options:
462: mobileAgent = request.getParameter(MOBILE_AGENT_PARAM);
463: if ((mobileAgent != null)
464: && (mobileAgent.length() == 0)) {
465: mobileAgent = null;
466: }
467: destNode = request.getParameter(DEST_NODE_PARAM);
468: if ((destNode != null) && (destNode.length() == 0)) {
469: destNode = null;
470: }
471: originNode = request.getParameter(ORIGIN_NODE_PARAM);
472: if ((originNode != null) && (originNode.length() == 0)) {
473: originNode = null;
474: }
475: isForceRestart = "true".equals(request
476: .getParameter(IS_FORCE_RESTART_PARAM));
477: }
478:
479: private void writeResponse() throws IOException {
480: if (ADD_VALUE.equals(action)) {
481: try {
482: Ticket ticket = createTicket(mobileAgent,
483: originNode, destNode, isForceRestart);
484: StepOptions options = createStepOptions(
485: actorAgent, ticket, pauseTime,
486: timeoutTime);
487: Step step = createStep(options);
488: addStep(step);
489: } catch (Exception e) {
490: writeFailure(e);
491: return;
492: }
493: writeSuccess();
494: } else if (REMOVE_VALUE.equals(action)) {
495: try {
496: UID uid = UID.toUID(removeUID);
497: Step step = queryStep(uid);
498: if (step != null) {
499: removeStep(step);
500: }
501: } catch (Exception e) {
502: writeFailure(e);
503: return;
504: }
505: writeSuccess();
506: } else {
507: writeUsage();
508: }
509: }
510:
511: private void writeUsage() throws IOException {
512: response.setContentType("text/html");
513: PrintWriter out = response.getWriter();
514: out.print("<html><head><title>Step ");
515: out.print(agentId);
516: out.print("</title></head>" + "<body>\n" + "<h2>Step ");
517: out.print(agentId);
518: out.print("</h2>\n");
519: writeForm(out);
520: out.print("</body></html>\n");
521: out.close();
522: }
523:
524: private void writeFailure(Exception e) throws IOException {
525: // generate an HTML error response, with a 404 error code.
526: //
527: // use "setStatus" instead of "sendError" -- see bug 1259
528:
529: response.setContentType("text/html");
530: response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
531: PrintWriter out = response.getWriter();
532:
533: out.print("<html><head><title>Failed step for ");
534: out.print(agentId);
535: out.print("</title></head>" + "<body>\n"
536: + "<center><h1>Failed step for ");
537: out.print(agentId);
538: out.print("</h1></center>" + "<p><pre>\n");
539: e.printStackTrace(out);
540: out
541: .print("\n</pre><p>"
542: + "<h2>Please double-check these parameters:</h2>\n");
543: writeForm(out);
544: out.print("</body></html>\n");
545: out.close();
546: }
547:
548: private void writeSuccess() throws IOException {
549: response.setContentType("text/html");
550: PrintWriter out = response.getWriter();
551: out.print("<html><head><title>Step ");
552: out.print(agentId);
553: out.print("</title></head>" + "<body>\n"
554: + "<center><h1>Submitted step for ");
555: out.print(agentId);
556: out.print("</h1></center><p>\n");
557: writeForm(out);
558: out.print("</body></html>\n");
559: out.close();
560: }
561:
562: private void writeForm(PrintWriter out) throws IOException {
563: // begin form
564: out.print("<form method=\"GET\" action=\"");
565: out.print(request.getRequestURI());
566: out.print("\">\n");
567: // show the current time
568: long nowTime = System.currentTimeMillis();
569: out.print("<i>Time: ");
570: out.print(new Date(nowTime));
571: out.print("</i> (");
572: out.print(nowTime);
573: out.print(")<p>");
574: out.print("<h2>" + "Local Steps:</h2><p>");
575: // show current Steps objects
576: Collection c = querySteps();
577: int n = ((c != null) ? c.size() : 0);
578: if (n == 0) {
579: out.print("<i>none</i>");
580: } else {
581: out
582: .print("<table border=1 cellpadding=1\n"
583: + " cellspacing=1 width=95%\n"
584: + " bordercolordark=#660000 bordercolorlight=#cc9966>\n"
585: + "<tr>"
586: + "<td rowspan=2>\n"
587: + "<font size=+1 color=mediumblue><b>UID</b></font>"
588: + "</td>"
589: + "<td colspan=5>"
590: + "<font size=+1 color=mediumblue><b>Options</b></font>"
591: + "</td>"
592: + "<td colspan=4>"
593: + "<font size=+1 color=mediumblue><b>Status</b></font>"
594: + "</td>"
595: + "</tr>\n"
596: + "<tr>\n"
597: + "<td><font color=mediumblue><b>Source</b></font></td>\n"
598: + "<td><font color=mediumblue><b>Target</b></font></td>\n"
599: + "<td><font color=mediumblue><b>Ticket</b></font></td>\n"
600: + "<td><font color=mediumblue><b>Pause Time</b></font></td>\n"
601: + "<td><font color=mediumblue><b>Timeout Time</b></font></td>\n"
602: + "<td><font color=mediumblue><b>State</b></font></td>\n"
603: + "<td><font color=mediumblue><b>Start Time</b></font></td>\n"
604: + "<td><font color=mediumblue><b>End Time</b></font></td>\n"
605: + "<td><font color=mediumblue><b>Move Status</b></font></td>\n"
606: + "</tr>\n");
607: Iterator iter = c.iterator();
608: for (int i = 0; i < n; i++) {
609: Step step = (Step) iter.next();
610: out.print("<tr><td>");
611: out.print(step.getUID());
612: out.print("</td><td>");
613: StepOptions options = step.getOptions();
614: out.print(options.getSource());
615: out.print("</td><td>");
616: out.print(options.getTarget());
617: out.print("</td><td>");
618: out.print(options.getTicket());
619: out.print("</td><td>");
620: out.print(options.getPauseTime());
621: out.print("</td><td>");
622: out.print(options.getTimeoutTime());
623: out.print("</td><td bgcolor=\"");
624: StepStatus results = step.getStatus();
625: switch (results.getState()) {
626: case StepStatus.UNSEEN:
627: out.print("white");
628: break;
629: case StepStatus.PAUSED:
630: case StepStatus.RUNNING:
631: out.print("yellow");
632: break;
633: case StepStatus.SUCCESS:
634: out.print("green");
635: break;
636: case StepStatus.FAILURE:
637: case StepStatus.TIMEOUT:
638: default:
639: out.print("red");
640: break;
641: }
642: out.print("\">");
643: out.print(results.getStateAsString());
644: out.print("</td><td>");
645: out.print(results.getStartTime());
646: out.print("</td><td>");
647: out.print(results.getEndTime());
648: out.print("</td><td>");
649: out.print(results.getMoveStatus());
650: out.print("</td></tr>\n");
651: }
652: out.print("</table>\n");
653: }
654: out.print("<p><input type=\"submit\" name=\""
655: + ACTION_PARAM + "\" value=\"" + REFRESH_VALUE
656: + "\">\n");
657:
658: // allow user to remove an existing step
659: out.print("<p><hr><p>"
660: + "<h2>Remove an existing Step:</h2>\n");
661: n = ((c != null) ? c.size() : 0);
662: boolean anyRemovable = false;
663: if (n > 0) {
664: Iterator iter = c.iterator();
665: for (int i = 0; i < n; i++) {
666: Step step = (Step) iter.next();
667: StepOptions options = step.getOptions();
668: if (!(agentId.equals(options.getSource()))) {
669: // only allow removal of steps created by
670: // this servlet or another local plugin
671: continue;
672: }
673: UID uid = step.getUID();
674: if (!(anyRemovable)) {
675: anyRemovable = true;
676: out.print("<select name=\""
677: + REMOVE_UID_PARAM + "\">");
678: }
679: out.print("<option value=\"");
680: out.print(uid);
681: out.print("\">");
682: out.print(uid);
683: out.print("</option>");
684: }
685: if (anyRemovable) {
686: out.print("</select>"
687: + "<input type=\"submit\" name=\""
688: + ACTION_PARAM + "\" value=\""
689: + REMOVE_VALUE + "\">\n");
690: }
691: }
692: if (!(anyRemovable)) {
693: out.print("<i>none</i>");
694: }
695:
696: // allow user to submit a new Step request
697: out.print("<p><hr><p>"
698: + "<h2>Create a new Step:</h2>\n");
699: out.print("<table>\n" + "<tr><td>" + "Actor Agent"
700: + "</td><td>\n"
701: + "<input type=\"text\" name=\""
702: + ACTOR_AGENT_PARAM + "\" size=30 value=\"");
703: out.print((actorAgent != null) ? actorAgent : agentId
704: .toString());
705: out.print("\">" + "</td><td>"
706: + "<i>(which agent should run the step)</i>"
707: + "</td></tr>\n" + "<tr><td>" + "Pause Time"
708: + "</td><td>\n"
709: + "<input type=\"text\" name=\""
710: + PAUSE_TIME_PARAM + "\" size=30 value=\"");
711: out.print(pauseTime > 0 ? pauseTime : 0);
712: out
713: .print("\">"
714: + "</td><td>"
715: + "<i>(pause time <a href=\"#time\">notes</a>)</i>"
716: + "</td></tr>\n" + "<tr><td>"
717: + "Timeout Time" + "</td><td>\n"
718: + "<input type=\"text\" name=\""
719: + TIMEOUT_TIME_PARAM
720: + "\" size=30 value=\"");
721: out.print(timeoutTime > 0 ? timeoutTime : 0);
722: out
723: .print("\">"
724: + "</td><td>"
725: + "<i>(timeout time <a href=\"#time\">notes</a>)</i>"
726: + "</td></tr>\n" + "<tr><td>"
727: + "Mobile Agent" + "</td><td>\n"
728: + "<input type=\"text\" name=\""
729: + MOBILE_AGENT_PARAM
730: + "\" size=30 value=\"");
731: out.print(mobileAgent != null ? mobileAgent : agentId
732: .toString());
733: out.print("\">" + "</td><td>"
734: + "<i>(which agent to move)</i>"
735: + "</td></tr>\n" + "<tr><td>" + "Origin Node"
736: + "</td><td>" + "<input type=\"text\" name=\""
737: + ORIGIN_NODE_PARAM + "\" size=30 value=\"");
738: out.print(originNode != null ? originNode : nodeId
739: .toString());
740: out.print("\">" + "</td><td>"
741: + "<i>(where the agent should be now)</i>"
742: + "</td></tr>\n" + "<tr><td>"
743: + "Destination Node" + "</td><td>"
744: + "<input type=\"text\" name=\""
745: + DEST_NODE_PARAM + "\" size=30 value=\"");
746: out.print(destNode != null ? destNode : nodeId
747: .toString());
748: out
749: .print("\">"
750: + "</td><td>"
751: + "<i>(where the agent should be relocated)</i>"
752: + "</td></tr>\n" + "<tr><td>"
753: + "Force Restart" + "</td><td>"
754: + "<select name=\""
755: + IS_FORCE_RESTART_PARAM + "\">"
756: + "<option value=\"true\"");
757: if (isForceRestart) {
758: out.print(" selected");
759: }
760: out.print(">true</option>" + "<option value=\"false\"");
761: if (!(isForceRestart)) {
762: out.print(" selected");
763: }
764: out.print(">false</option>" + "</select>" + "</td><td>"
765: + "<i>(restart in place if already at"
766: + " destination)</i>" + "</td></tr>\n"
767: + "<tr><td colwidth=2>"
768: + "<input type=\"submit\" name=\""
769: + ACTION_PARAM + "\" value=\"" + ADD_VALUE
770: + "\">" + " " + "<input type=\"reset\">"
771: + "</td></tr>\n" + "</table>\n");
772:
773: // footnotes
774: out
775: .print("<p><hr><p>"
776: + "<a name=\"time\"><br>"
777: + "Time is either 0 or negative for none, +<i>N</i> for"
778: + " N milliseconds after the submit button is pressed, or"
779: + " <i>N</i> for absolute time.<br>"
780: + "For example, +5000 is 5 seconds after the button press."
781: + "</form>\n");
782: }
783: }
784: }
785:
786: // odd BlackboardClient method:
787: public String getBlackboardClientName() {
788: return toString();
789: }
790:
791: // odd BlackboardClient method:
792: public long currentTimeMillis() {
793: throw new UnsupportedOperationException(this
794: + " asked for the current time???");
795: }
796:
797: // unused BlackboardClient method:
798: public boolean triggerEvent(Object event) {
799: // if we had Subscriptions we'd need to implement this.
800: //
801: // see "ComponentPlugin" for details.
802: throw new UnsupportedOperationException(this
803: + " only supports Blackboard queries, but received "
804: + "a \"trigger\" event: " + event);
805: }
806:
807: public String toString() {
808: return "\"" + getPath() + "\" servlet";
809: }
810: }
|