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.script;
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 procs.
062: * <p>
063: * The path of the servlet is "/move/proc".
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 Scripts.
071: * <p>
072: * "Remove" removes the Script with the UID specified by
073: * the required "removeUID" parameter.
074: * <p>
075: * "Add" creates a new Script. Most of the parameters
076: * below are used to support "Add".
077: * </li><p>
078: * <li><tt>removeUID=String</tt><br>
079: * If the action is "Remove", this is the UID of the script
080: * to be removed. Any running procs are killed.
081: * </li><p>
082: * <li><tt>scriptUID=String</tt><br>
083: * If the action is "Add", this is the UID of the script.
084: * </li><p>
085: * </ul>
086: * <p>
087: * Note the <b>SECURITY</b> issues of moving agents!
088: */
089: public class ProcServlet extends BaseServletComponent implements
090: BlackboardClient {
091:
092: protected static final UnaryPredicate PROC_PRED = new UnaryPredicate() {
093: public boolean execute(Object o) {
094: return (o instanceof Proc);
095: }
096: };
097:
098: protected static final UnaryPredicate SCRIPT_PRED = new UnaryPredicate() {
099: public boolean execute(Object o) {
100: return (o instanceof Script);
101: }
102: };
103:
104: protected MessageAddress agentId;
105: protected MessageAddress nodeId;
106:
107: protected BlackboardService blackboard;
108: protected DomainService domain;
109: protected LoggingService log;
110: protected MobilityTestFactory mobilityTestFactory;
111:
112: protected String getPath() {
113: return "/move/proc";
114: }
115:
116: protected Servlet createServlet() {
117: // create inner class
118: return new MyServlet();
119: }
120:
121: // aquire services:
122: public void load() {
123:
124: // get the log
125: log = (LoggingService) serviceBroker.getService(this ,
126: LoggingService.class, null);
127: if (log == null) {
128: log = LoggingService.NULL;
129: }
130:
131: // get the agentId
132: AgentIdentificationService agentIdService = (AgentIdentificationService) serviceBroker
133: .getService(this , AgentIdentificationService.class,
134: null);
135: if (agentIdService == null) {
136: throw new RuntimeException(
137: "Unable to obtain agent-id service");
138: }
139: this .agentId = agentIdService.getMessageAddress();
140: serviceBroker.releaseService(this ,
141: AgentIdentificationService.class, agentIdService);
142: if (agentId == null) {
143: throw new RuntimeException("Unable to obtain agent id");
144: }
145:
146: // get the nodeId
147: NodeIdentificationService nodeIdService = (NodeIdentificationService) serviceBroker
148: .getService(this , NodeIdentificationService.class, null);
149: if (nodeIdService == null) {
150: throw new RuntimeException(
151: "Unable to obtain node-id service");
152: }
153: this .nodeId = nodeIdService.getMessageAddress();
154: serviceBroker.releaseService(this ,
155: NodeIdentificationService.class, nodeIdService);
156: if (nodeId == null) {
157: throw new RuntimeException("Unable to obtain node id");
158: }
159:
160: // get the mobility domain
161: this .domain = (DomainService) serviceBroker.getService(this ,
162: DomainService.class, null);
163: if (domain == null) {
164: throw new RuntimeException(
165: "Unable to obtain domain service");
166: }
167:
168: // get the mobility test factory (for script creation)
169: this .mobilityTestFactory = (MobilityTestFactory) domain
170: .getFactory("mobilityTest");
171: if (mobilityTestFactory == null) {
172: throw new RuntimeException(
173: "Mobility test factory (and domain \"mobilityTest\")"
174: + " not enabled");
175: }
176:
177: // get the blackboard
178: this .blackboard = (BlackboardService) serviceBroker.getService(
179: this , BlackboardService.class, null);
180: if (blackboard == null) {
181: throw new RuntimeException(
182: "Unable to obtain blackboard service");
183: }
184:
185: super .load();
186: }
187:
188: // release services:
189: public void unload() {
190: super .unload();
191: if (blackboard != null) {
192: serviceBroker.releaseService(this , BlackboardService.class,
193: blackboard);
194: blackboard = null;
195: }
196: if (domain != null) {
197: serviceBroker.releaseService(this , DomainService.class,
198: domain);
199: domain = null;
200: mobilityTestFactory = null;
201: }
202: if ((log != null) && (log != LoggingService.NULL)) {
203: serviceBroker.releaseService(this , LoggingService.class,
204: log);
205: log = LoggingService.NULL;
206: }
207: }
208:
209: protected Collection queryScripts() {
210: Collection ret = null;
211: try {
212: blackboard.openTransaction();
213: ret = blackboard.query(SCRIPT_PRED);
214: } finally {
215: blackboard.closeTransactionDontReset();
216: }
217: return ret;
218: }
219:
220: protected Collection queryProcs() {
221: Collection ret = null;
222: try {
223: blackboard.openTransaction();
224: ret = blackboard.query(PROC_PRED);
225: } finally {
226: blackboard.closeTransactionDontReset();
227: }
228: return ret;
229: }
230:
231: protected Script queryScript(final UID uid) {
232: if (uid == null) {
233: throw new IllegalArgumentException("null uid");
234: }
235: UnaryPredicate pred = new UnaryPredicate() {
236: public boolean execute(Object o) {
237: return ((o instanceof Script) && (uid
238: .equals(((Script) o).getUID())));
239: }
240: };
241: Script ret = null;
242: try {
243: blackboard.openTransaction();
244: Collection c = blackboard.query(pred);
245: if ((c != null) && (c.size() >= 1)) {
246: ret = (Script) c.iterator().next();
247: }
248: } finally {
249: blackboard.closeTransactionDontReset();
250: }
251: return ret;
252: }
253:
254: protected Proc queryProc(final UID uid) {
255: if (uid == null) {
256: throw new IllegalArgumentException("null uid");
257: }
258: UnaryPredicate pred = new UnaryPredicate() {
259: public boolean execute(Object o) {
260: return ((o instanceof Proc) && (uid.equals(((Proc) o)
261: .getUID())));
262: }
263: };
264: Proc ret = null;
265: try {
266: blackboard.openTransaction();
267: Collection c = blackboard.query(pred);
268: if ((c != null) && (c.size() >= 1)) {
269: ret = (Proc) c.iterator().next();
270: }
271: } finally {
272: blackboard.closeTransactionDontReset();
273: }
274: return ret;
275: }
276:
277: protected Step queryStep(final UID uid) {
278: if (uid == null) {
279: throw new IllegalArgumentException("null uid");
280: }
281: UnaryPredicate pred = new UnaryPredicate() {
282: public boolean execute(Object o) {
283: return ((o instanceof Step) && (uid.equals(((Step) o)
284: .getUID())));
285: }
286: };
287: Step ret = null;
288: try {
289: blackboard.openTransaction();
290: Collection c = blackboard.query(pred);
291: if ((c != null) && (c.size() >= 1)) {
292: ret = (Step) c.iterator().next();
293: }
294: } finally {
295: blackboard.closeTransactionDontReset();
296: }
297: return ret;
298: }
299:
300: protected Proc createProc(UID scriptUID) {
301: Proc proc = mobilityTestFactory.createProc(scriptUID);
302: if (log.isInfoEnabled()) {
303: log.info("Created new proc: " + proc);
304: }
305: return proc;
306: }
307:
308: protected void addProc(Proc proc) {
309: try {
310: blackboard.openTransaction();
311: blackboard.publishAdd(proc);
312: } finally {
313: blackboard.closeTransactionDontReset();
314: }
315: }
316:
317: protected void removeProc(Proc proc) {
318: try {
319: blackboard.openTransaction();
320: blackboard.publishRemove(proc);
321: } finally {
322: blackboard.closeTransactionDontReset();
323: }
324: }
325:
326: /**
327: * Servlet to handle requests.
328: */
329: private class MyServlet extends HttpServlet {
330:
331: public void doGet(HttpServletRequest req,
332: HttpServletResponse res) throws IOException {
333: MyWorker mw = new MyWorker(req, res);
334: mw.execute();
335: }
336:
337: private class MyWorker {
338:
339: // from the "doGet(..)":
340: private HttpServletRequest request;
341: private HttpServletResponse response;
342:
343: // from the URL-params:
344: // (see the class-level javadocs for details)
345:
346: // actions:
347:
348: public static final String ACTION_PARAM = "action";
349: public static final String ADD_VALUE = "Add";
350: public static final String REMOVE_VALUE = "Remove";
351: public static final String REFRESH_VALUE = "Refresh";
352: public String action;
353:
354: // remove uid:
355:
356: public static final String REMOVE_UID_PARAM = "removeUID";
357: public String removeUID;
358:
359: // content:
360:
361: public static final String SCRIPT_UID_PARAM = "scriptUID";
362: public UID scriptUID;
363:
364: // worker constructor:
365: public MyWorker(HttpServletRequest request,
366: HttpServletResponse response) {
367: this .request = request;
368: this .response = response;
369: }
370:
371: // handle a request:
372: public void execute() throws IOException {
373: parseParams();
374: writeResponse();
375: }
376:
377: private void parseParams() throws IOException {
378: // action:
379: action = request.getParameter(ACTION_PARAM);
380:
381: // remove param:
382: removeUID = request.getParameter(REMOVE_UID_PARAM);
383: if ((removeUID != null) && (removeUID.length() == 0)) {
384: removeUID = null;
385: }
386:
387: // script uid:
388: String s = request.getParameter(SCRIPT_UID_PARAM);
389: if ((s != null) && (s.length() > 0)) {
390: scriptUID = UID.toUID(s);
391: }
392: }
393:
394: private void writeResponse() throws IOException {
395: if (ADD_VALUE.equals(action)) {
396: try {
397: Script script = queryScript(scriptUID);
398: if (script == null) {
399: throw new IllegalArgumentException(
400: "Unknown script with UID "
401: + scriptUID);
402: }
403: Proc proc = createProc(scriptUID);
404: addProc(proc);
405: } catch (Exception e) {
406: writeFailure(e);
407: return;
408: }
409: writeSuccess();
410: } else if (REMOVE_VALUE.equals(action)) {
411: try {
412: UID uid = UID.toUID(removeUID);
413: Proc proc = queryProc(uid);
414: if (proc != null) {
415: removeProc(proc);
416: }
417: } catch (Exception e) {
418: writeFailure(e);
419: return;
420: }
421: writeSuccess();
422: } else {
423: writeUsage();
424: }
425: }
426:
427: private void writeUsage() throws IOException {
428: response.setContentType("text/html");
429: PrintWriter out = response.getWriter();
430: out.print("<html><head><title>Proc ");
431: out.print(agentId);
432: out.print("</title></head>" + "<body>\n" + "<h2>Proc ");
433: out.print(agentId);
434: out.print("</h2>\n");
435: writeForm(out);
436: out.print("</body></html>\n");
437: out.close();
438: }
439:
440: private void writeFailure(Exception e) throws IOException {
441: // generate an HTML error response, with a 404 error code.
442: //
443: // use "setStatus" instead of "sendError" -- see bug 1259
444:
445: response.setContentType("text/html");
446: response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
447: PrintWriter out = response.getWriter();
448:
449: out.print("<html><head><title>Failed proc for ");
450: out.print(agentId);
451: out.print("</title></head>" + "<body>\n"
452: + "<center><h1>Failed proc for ");
453: out.print(agentId);
454: out.print("</h1></center>" + "<p><pre>\n");
455: e.printStackTrace(out);
456: out
457: .print("\n</pre><p>"
458: + "<h2>Please double-check these parameters:</h2>\n");
459: writeForm(out);
460: out.print("</body></html>\n");
461: out.close();
462: }
463:
464: private void writeSuccess() throws IOException {
465: response.setContentType("text/html");
466: PrintWriter out = response.getWriter();
467: out.print("<html><head><title>Proc ");
468: out.print(agentId);
469: out.print("</title></head>" + "<body>\n"
470: + "<center><h1>Submitted proc for ");
471: out.print(agentId);
472: out.print("</h1></center><p>\n");
473: writeForm(out);
474: out.print("</body></html>\n");
475: out.close();
476: }
477:
478: private void writeForm(PrintWriter out) throws IOException {
479: // begin form
480: out.print("<form method=\"GET\" action=\"");
481: out.print(request.getRequestURI());
482: out.print("\">\n");
483: // show the current time
484: long nowTime = System.currentTimeMillis();
485: out.print("<i>Time: ");
486: out.print(new Date(nowTime));
487: out.print("</i> (");
488: out.print(nowTime);
489: out.print(")<p>");
490: out.print("<h2>" + "Local Procs:</h2><p>");
491: // show current proc objects
492: Collection procs = queryProcs();
493: int nprocs = ((procs != null) ? procs.size() : 0);
494: if (nprocs == 0) {
495: out.print("<i>none</i>");
496: } else {
497: out
498: .print("<table border=1 cellpadding=1\n"
499: + " cellspacing=1 width=95%\n"
500: + " bordercolordark=#660000 bordercolorlight=#cc9966>\n"
501: + "<tr><td>\n"
502: + "<font size=+1 color=mediumblue><b>UID</b></font>"
503: + "</td><td>\n"
504: + "<font size=+1 color=mediumblue><b>Script</b></font>"
505: + "</td><td>"
506: + "<font size=+1 color=mediumblue><b>Start Time</b></font>"
507: + "</td><td>"
508: + "<font size=+1 color=mediumblue><b># Moves</b></font>"
509: + "</td><td>"
510: + "<font size=+1 color=mediumblue><b>End Time</b></font>"
511: + "</td><td>"
512: + "<font size=+1 color=mediumblue><b>Step Status</b></font>"
513: + "</td><td>"
514: + "<font size=+1 color=mediumblue><b>Step</b></font>"
515: + "</td><td>"
516: + "<font size=+1 color=mediumblue><b>Script Index</b></font>"
517: + "</td></tr>\n");
518: Iterator iter = procs.iterator();
519: for (int i = 0; i < nprocs; i++) {
520: Proc proc = (Proc) iter.next();
521: out.print("<tr><td>" + proc.getUID()
522: + "</td><td>"
523: + proc.getScriptUID()
524: + // FIXME href link?
525: "</td><td>" + proc.getStartTime()
526: + "</td><td>" + proc.getMoveCount()
527: + "</td>");
528: long endTime = proc.getEndTime();
529: UID stepUID = proc.getStepUID();
530: if ((endTime > 0) && (stepUID == null)) {
531: out.print("<td>" + endTime
532: + "</td><td colspan=3 bgcolor=\""
533: + "#BBFFBB" + // green
534: "\">Completed</td>");
535: } else {
536: out.print("<td>" + endTime
537: + "</td><td bgcolor=\"");
538: String s;
539: if (stepUID == null) {
540: s = "#BBBBBB" + // grey
541: "\">Null";
542: } else {
543: Step step = queryStep(stepUID);
544: if (step == null) {
545: s = "#BBBBFF" + // blue
546: "\">Not in blackboard!";
547: } else {
548: StepStatus status = step
549: .getStatus();
550: String color;
551: switch (status.getState()) {
552: case StepStatus.UNSEEN:
553: color = "#FFFFFF"; // white
554: break;
555: case StepStatus.PAUSED:
556: color = "#FFFFBB"; // yellow
557: break;
558: case StepStatus.RUNNING:
559: color = "#EFFFBB"; // yellow (green)
560: break;
561: case StepStatus.SUCCESS:
562: color = "#BBFFBB"; // green
563: break;
564: case StepStatus.FAILURE:
565: case StepStatus.TIMEOUT:
566: default:
567: color = "#FFBBBB"; // red
568: break;
569: }
570: s = color + "\">"
571: + status.getStateAsString();
572: }
573: }
574: out.print(s + "</td><td>" + stepUID
575: + // FIXME href link?
576: "</td><td>" + proc.getScriptIndex()
577: + "</td>");
578: }
579: out.print("</tr>\n");
580: }
581: out.print("</table>\n");
582: }
583: out.print("<p><input type=\"submit\" name=\""
584: + ACTION_PARAM + "\" value=\"" + REFRESH_VALUE
585: + "\">\n");
586:
587: // allow user to remove an existing proc
588: out.print("<p><hr><p>"
589: + "<h2>Remove an existing Proc:</h2>\n");
590: if (nprocs > 0) {
591: out.print("Proc UID: <select name=\""
592: + REMOVE_UID_PARAM + "\">");
593: Iterator iter = procs.iterator();
594: for (int i = 0; i < nprocs; i++) {
595: Proc proc = (Proc) iter.next();
596: UID uid = proc.getUID();
597: out.print("<option value=\"");
598: out.print(uid);
599: out.print("\">");
600: out.print(uid);
601: out.print("</option>");
602: }
603: out.print("</select>"
604: + "<input type=\"submit\" name=\""
605: + ACTION_PARAM + "\" value=\""
606: + REMOVE_VALUE + "\">\n");
607: } else {
608: out.print("<i>none</i>");
609: }
610:
611: // allow user to submit a new Proc
612: out.print("<p><hr><p>"
613: + "<h2>Create a new Proc:</h2>\n");
614: Collection scripts = queryScripts();
615: int nscripts = ((scripts != null) ? scripts.size() : 0);
616: if (nscripts > 0) {
617: out.print("Script UID: <select name=\""
618: + SCRIPT_UID_PARAM + "\">");
619: Iterator iter = scripts.iterator();
620: for (int i = 0; i < nscripts; i++) {
621: Script script = (Script) iter.next();
622: UID uid = script.getUID();
623: out.print("<option value=\"");
624: out.print(uid);
625: out.print("\">");
626: out.print(uid);
627: out.print("</option>");
628: }
629: out.print("</select>"
630: + "<input type=\"submit\" name=\""
631: + ACTION_PARAM + "\" value=\"" + ADD_VALUE
632: + "\">\n");
633: } else {
634: out.print("<i>no scripts</i>");
635: }
636:
637: out.print("<p>" + "<input type=\"reset\">"
638: + "</form>\n");
639: }
640: }
641: }
642:
643: // odd BlackboardClient method:
644: public String getBlackboardClientName() {
645: return toString();
646: }
647:
648: // odd BlackboardClient method:
649: public long currentTimeMillis() {
650: throw new UnsupportedOperationException(this
651: + " asked for the current time???");
652: }
653:
654: // unused BlackboardClient method:
655: public boolean triggerEvent(Object event) {
656: // if we had Subscriptions we'd need to implement this.
657: //
658: // see "ComponentPlugin" for details.
659: throw new UnsupportedOperationException(this
660: + " only supports Blackboard queries, but received "
661: + "a \"trigger\" event: " + event);
662: }
663:
664: public String toString() {
665: return "\"" + getPath() + "\" servlet";
666: }
667: }
|