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.wp;
028:
029: import java.io.IOException;
030: import java.io.PrintWriter;
031: import java.net.URI;
032: import java.util.ArrayList;
033: import java.util.Collection;
034: import java.util.Collections;
035: import java.util.Date;
036: import java.util.Iterator;
037: import java.util.List;
038: import java.util.Map;
039: import java.util.Set;
040: import javax.servlet.http.HttpServletRequest;
041: import javax.servlet.http.HttpServletResponse;
042: import org.cougaar.core.service.LoggingService;
043: import org.cougaar.core.service.wp.AddressEntry;
044: import org.cougaar.core.service.wp.Callback;
045: import org.cougaar.core.service.wp.Cert;
046: import org.cougaar.core.service.wp.Request;
047: import org.cougaar.core.service.wp.Response;
048: import org.cougaar.core.service.wp.WhitePagesService;
049: import org.cougaar.core.servlet.ComponentServlet;
050:
051: /**
052: * This component loads the optional "/wp" servlet for viewing and
053: * altering the white pages.
054: * <p>
055: * Load into any agent:<pre>
056: * <component class="org.cougaar.core.wp.WhitePagesServlet">
057: * <argument>/wp</argument>
058: * </component>
059: * </pre>
060: * <p>
061: * For starters, just click on "submit" to do a recursive
062: * white pages dump.
063: */
064: public class WhitePagesServlet extends ComponentServlet {
065:
066: // default "recursive_dump" depth-first recursion limit
067: private static final int DEFAULT_LIMIT = 3;
068:
069: private LoggingService log;
070: private WhitePagesService wps;
071:
072: public void setLoggingService(LoggingService log) {
073: this .log = log;
074: }
075:
076: public void setWhitePagesService(WhitePagesService wps) {
077: this .wps = wps;
078: }
079:
080: public void doGet(HttpServletRequest sreq, HttpServletResponse sres)
081: throws IOException {
082: // create a new handler per request, so we don't mangle our
083: // per-request variables
084: MyHandler h = new MyHandler(getEncodedAgentName(), log, wps);
085: h.execute(sreq, sres);
086: }
087:
088: private static class MyHandler {
089:
090: private final String localAgent;
091: private final LoggingService log;
092: private final WhitePagesService wps;
093:
094: private HttpServletRequest sreq;
095: private PrintWriter out;
096:
097: private String action;
098: private String s_minAge;
099: private long minAge;
100: private String s_timeout;
101: private long timeout;
102: private boolean async;
103: private String s_limit;
104: private String name;
105: private String type;
106: private String s_uri;
107: private String s_cert;
108: private boolean cacheOnly;
109:
110: public MyHandler(String localAgent, LoggingService log,
111: WhitePagesService wps) {
112: this .localAgent = localAgent;
113: this .log = log;
114: this .wps = wps;
115: }
116:
117: public void execute(HttpServletRequest sreq,
118: HttpServletResponse sres) throws IOException
119: //, ServletException
120: {
121: this .sreq = sreq;
122: this .out = sres.getWriter();
123: parseParams();
124: printHeader();
125: printForm();
126: performRequest();
127: printFooter();
128: }
129:
130: private void parseParams() {
131: action = param("action");
132: s_minAge = param("minAge");
133: if (s_minAge != null) {
134: minAge = Long.parseLong(s_minAge);
135: }
136: s_timeout = param("timeout");
137: if (s_timeout != null) {
138: timeout = Long.parseLong(s_timeout);
139: }
140: async = "true".equals(param("async"));
141: s_limit = param("limit");
142: name = param("name");
143: type = param("type");
144: s_uri = param("uri");
145: s_cert = param("cert");
146: cacheOnly = "true".equals(param("cacheOnly"));
147: }
148:
149: private void printHeader() {
150: long now = System.currentTimeMillis();
151: out
152: .println("<html>\n"
153: + "<head>\n"
154: + "<title>Cougaar White Pages</title>\n"
155: + "<script language=\"JavaScript\">\n"
156: + "<!--\n"
157: + "function selectOp() {\n"
158: + " var i = document.f.action.selectedIndex;\n"
159: + " var s = document.f.action.options[i].text;\n"
160: + " var showLimit = (s == \"recursive_dump\");\n"
161: + " var showMinAge =\n"
162: + " (s == \"uncache\" ||\n"
163: + " s == \"prefetch\");\n"
164: + " var showType = \n"
165: + " (s == \"get\" ||\n"
166: + " s == \"uncache\" ||\n"
167: + " s == \"prefetch\" ||\n"
168: + " s == \"bind\" ||\n"
169: + " s == \"rebind\" ||\n"
170: + " s == \"unbind\");\n"
171: + " var showURI =\n"
172: + " (s == \"uncache\" ||\n"
173: + " s == \"prefetch\" ||\n"
174: + " s == \"bind\" ||\n"
175: + " s == \"rebind\" ||\n"
176: + " s == \"unbind\");\n"
177: + " var showCert = showURI;\n"
178: + " enable(showLimit, document.f.limit)\n"
179: + " enable(showMinAge, document.f.minAge)\n"
180: + " enable(showType, document.f.type)\n"
181: + " enable(showURI, document.f.uri)\n"
182: + " enable(showCert, document.f.cert)\n"
183: + "}\n"
184: + "function enable(b, txt) {\n"
185: + " txt.disabled=!b;\n"
186: + " txt.style.background=(b?\"white\":\"grey\");\n"
187: + "}\n" + "// -->\n" + "</script>\n"
188: + "</head>\n" + "<body onLoad=selectOp()>"
189: + "<h2>Cougaar White Pages Servlet</h2>"
190: + "<p>\n" + "Agent: " + localAgent
191: + "<p>\n" + "Time: " + now + " ("
192: + (new Date(now)) + ")" + "<p>");
193: }
194:
195: private void printForm() {
196: out
197: .println("<table border=1>\n"
198: + "<form name=\"f\" method=\"GET\" action=\""
199: + sreq.getRequestURI()
200: + "\">\n"
201: + "<tr><th colspan=2>Request</th></tr>\n"
202: + "<tr><td>Action</td><td>"
203: + "<select name=\"action\" onChange=\"selectOp()\">\n"
204: + option("recursive_dump", action)
205: + option("get", action)
206: + option("getAll", action)
207: + option("list", action)
208: + option("uncache", action)
209: + option("prefetch", action)
210: + option("bind", action)
211: + option("rebind", action)
212: + option("unbind", action)
213: + "</select>\n"
214: + "</td><tr>\n"
215: + "<tr><td>Cache-only</td><td>"
216: + "<select name=\"cacheOnly\">"
217: + "<option value=\"false\""
218: + (cacheOnly ? "" : " selected")
219: + ">false</option>\n"
220: + "<option value=\"true\""
221: + (cacheOnly ? " selected" : "")
222: + ">true</option>\n"
223: + "</select>\n"
224: + "</td></tr>\n"
225: + "<tr><td>Min. Age</td><td>"
226: + input("minAge", s_minAge)
227: + "</td></tr>\n"
228: + "<tr><td>Timeout</td><td>"
229: + input("timeout", s_timeout)
230: + "</td></tr>\n"
231: + "<tr><td>Blocking</td><td>"
232: + "<select name=\"async\">"
233: + "<option value=\"false\""
234: + (async ? "" : " selected")
235: + ">Wait for response</option>\n"
236: + "<option value=\"true\""
237: + (async ? " selected" : "")
238: + ">Don't wait (async)</option>\n"
239: + "</select>\n"
240: + "</td></tr>\n"
241: + "<tr><td>Recursion limit</td><td>\n"
242: + input("limit", s_limit, 4)
243: + " <i>(< 0 is none, default is "
244: + DEFAULT_LIMIT
245: + ")</i>"
246: + "</td><tr>\n"
247: + "<tr><td>Entry</td><td>\n"
248: + "<table border=1>\n"
249: + "<tr><td>Name</td><td>"
250: + input("name", name)
251: + "</td></tr>\n<tr><td>Type</td><td>"
252: + input("type", type)
253: + "</td></tr>\n<tr><td>URI</td><td>"
254: + input("uri", s_uri, 40)
255: + "</td></tr>\n<tr><td>Cert</td><td>"
256: + input("cert", s_cert, 40)
257: + "</td></tr>\n</table>\n"
258: + "</td></tr>\n"
259: + "<tr><td>"
260: + "<input type=\"submit\" value=\"Submit\">\n"
261: + "</td><td>"
262: + "<input type=\"reset\" value=\"Reset\">\n"
263: + "</td></tr>\n" + "</form>\n" + "</table>");
264: }
265:
266: private void performRequest() {
267: try {
268: Request req = null;
269: int options = (cacheOnly ? Request.CACHE_ONLY
270: : Request.NONE);
271: if ("recursive_dump".equals(action)) {
272: String suffix = (name == null ? "." : name);
273: if (suffix.startsWith(".")) {
274: int limit = DEFAULT_LIMIT;
275: if (s_limit != null) {
276: limit = Integer.parseInt(s_limit);
277: }
278: submitDump(suffix, limit);
279: } else {
280: out
281: .println("<font color=\"red\">Recursive dump suffix must"
282: + " start with \".\", not \""
283: + suffix + "\"</font>");
284: }
285: } else if ("get".equals(action)) {
286: if (name == null) {
287: out
288: .println("<font color=\"red\">Please specify a name</font>");
289: } else if (type == null) {
290: out
291: .println("<font color=\"red\">Please specify a type</font>");
292: } else {
293: req = new Request.Get(options, name, type);
294: }
295: } else if ("getAll".equals(action)) {
296: if (name == null) {
297: out
298: .println("<font color=\"red\">Please specify a name</font>");
299: } else {
300: req = new Request.GetAll(options, name);
301: }
302: } else if ("list".equals(action)) {
303: String tmp = (name == null ? "." : name);
304: if (tmp.startsWith(".")) {
305: req = new Request.List(options, tmp);
306: } else {
307: out
308: .println("<font color=\"red\">List suffix must start"
309: + " with \".\", not \""
310: + tmp
311: + "\"</font>");
312: }
313: } else if ("uncache".equals(action)
314: || "prefetch".equals(action)) {
315: boolean uncache = "uncache".equals(action);
316: boolean prefetch = "prefetch".equals(action);
317: AddressEntry ae = ((type == null || s_uri == null) ? (null)
318: : parseEntry());
319: if (name == null) {
320: out
321: .println("<font color=\"red\">Please specify name</font>");
322: } else {
323: req = new Request.Flush(Request.CACHE_ONLY,
324: name, minAge, ae, uncache, prefetch);
325: }
326: } else if ("bind".equals(action)
327: || "rebind".equals(action)) {
328: boolean overWrite = "rebind".equals(action);
329: AddressEntry ae = parseEntry();
330: if (ae != null) {
331: req = new Request.Bind(Request.NONE, ae,
332: overWrite, false);
333: }
334: } else if ("unbind".equals(action)) {
335: AddressEntry ae = parseEntry();
336: if (ae != null) {
337: req = new Request.Unbind(Request.NONE, ae);
338: }
339: } else if (action != null) {
340: out.println("<font color=\"red\">Unknown action: "
341: + action + "</font>");
342: }
343: if (req != null) {
344: submit(req);
345: }
346: } catch (Exception e) {
347: e.printStackTrace(out);
348: }
349: }
350:
351: private void printFooter() {
352: out.println("</body></html>");
353: }
354:
355: private String param(String n) {
356: String s = sreq.getParameter(n);
357: if (s == null || s.length() == 0) {
358: s = null;
359: }
360: return s;
361: }
362:
363: private static String option(String n, String v) {
364: return "<option value=\"" + n + "\""
365: + ((v != null && v.equals(n)) ? " selected" : "")
366: + ">" + n + "</option>";
367: }
368:
369: private static String input(String n, String v) {
370: return input(n, v, 40);
371: }
372:
373: private static String input(String n, String v, int size) {
374: return "<input type=\"text\" size=" + size + " name=\"" + n
375: + "\"" + (v == null ? "" : " value=\"" + v + "\"")
376: + ">";
377: }
378:
379: private AddressEntry parseEntry() throws Exception {
380: String x_uri = s_uri;
381: if ("unbind".equals(action) && s_uri == null) {
382: x_uri = "ignored://wp-servlet";
383: }
384: if (name == null || type == null || x_uri == null) {
385: out
386: .println("<font color=\"red\">Missing required field</font>");
387: return null;
388: }
389: if (name.startsWith(".")) {
390: out
391: .println("<font color=\"red\">Name can't start with \".\"</font>");
392: return null;
393: }
394: URI uri = URI.create(s_uri);
395: Cert cert;
396: if (s_cert == null || "null".equals(s_cert)
397: || "null_cert".equals(s_cert)) {
398: cert = Cert.NULL;
399: } else {
400: cert = new Cert.Indirect(s_cert);
401: }
402: AddressEntry ae = AddressEntry.getAddressEntry(name, type,
403: uri, cert);
404: return ae;
405: }
406:
407: private void submitDump(String suffix, int limit)
408: throws Exception {
409: out.println("<p><hr><p>");
410: if (wps == null) {
411: out
412: .println("<font color=\"red\">No WhitePagesService?</font>");
413: return;
414: }
415: printTableStart();
416: recurseDump(suffix, 0, limit);
417: printTableEnd();
418: }
419:
420: // recursive!
421: private int recurseDump(String suffix, int idx, int limit)
422: throws Exception {
423: int newIdx = idx;
424: if (limit == 0) {
425: ++newIdx;
426: out
427: .println("<tr>"
428: + "<td align=right>"
429: + newIdx
430: + " </td>"
431: + "<td colspan=4><a href=\""
432: + sreq.getRequestURI()
433: + "?action=recursive_dump"
434: + "&cacheOnly="
435: + cacheOnly
436: + "&name="
437: + suffix
438: + (type == null ? ""
439: : ("&type=" + type))
440: + (s_uri == null ? ""
441: : ("&uri=" + s_uri))
442: + (s_timeout == null ? ""
443: : ("&timeout=" + s_timeout))
444: + (s_limit == null ? ""
445: : ("&limit=" + s_limit))
446: + "\">" + suffix + "</a></td>"
447: + "</tr>");
448: return newIdx;
449: }
450: Set names = wps.list(suffix, timeout);
451: int n = (names == null ? 0 : names.size());
452: if (n <= 0) {
453: ++newIdx;
454: out.println("<tr>" + "<td align=right>" + newIdx
455: + " </td>"
456: + "<td colspan=4>None listed for \"" + suffix
457: + "\"</td>" + "</tr>");
458: return newIdx;
459: }
460: List l = new ArrayList(names);
461: Collections.sort(l);
462: for (int i = 0; i < n; i++) {
463: String s = (String) l.get(i);
464: if (s == null) {
465: } else if (s.length() > 0 && s.charAt(0) == '.') {
466: newIdx = recurseDump(s, newIdx, (limit - 1));
467: } else {
468: Map m = wps.getAll(s, timeout);
469: newIdx = print(m, newIdx);
470: }
471: }
472: return newIdx;
473: }
474:
475: private void submit(Request req) {
476: out.println("<p><hr><p>");
477: if (wps == null) {
478: out
479: .println("<font color=\"red\">No WhitePagesService?</font>");
480: return;
481: }
482: Response res = wps.submit(req);
483: if (async) {
484: Callback c = new Callback() {
485: public void execute(Response res) {
486: if (log != null && log.isInfoEnabled()) {
487: log.info(localAgent + ": " + res);
488: }
489: }
490: };
491: res.addCallback(c);
492: out.println("Submitted asynchronous request");
493: } else {
494: try {
495: res.waitForIsAvailable(timeout);
496: } catch (InterruptedException ie) {
497: out.println("<p><font color=\"red\">Interruped: "
498: + ie + "</font><p>");
499: }
500: print(res);
501: }
502: }
503:
504: private void print(Response res) {
505: out.print("<b>" + action + ":</b><br>");
506: if (!res.isAvailable()) {
507: out.println("Not available yet");
508: } else if (res.isTimeout()) {
509: out.print("Timeout");
510: } else if (!res.isSuccess()) {
511: print(res.getException());
512: } else {
513: // success:
514: if (res instanceof Response.Get) {
515: AddressEntry ae = ((Response.Get) res)
516: .getAddressEntry();
517: print(ae);
518: } else if (res instanceof Response.GetAll) {
519: Map m = ((Response.GetAll) res).getAddressEntries();
520: print(m);
521: } else if (res instanceof Response.List) {
522: Set names = ((Response.List) res).getNames();
523: print(names);
524: } else if (res instanceof Response.Bind) {
525: Response.Bind bres = (Response.Bind) res;
526: if (bres.didBind()) {
527: long leaseExpireTime = bres.getExpirationTime();
528: out
529: .print("Bind succeded, lease renewal due at "
530: + leaseExpireTime
531: + " ("
532: + (new Date(leaseExpireTime))
533: + ")");
534: } else {
535: AddressEntry usurperEntry = bres
536: .getUsurperEntry();
537: if (usurperEntry == null) {
538: out
539: .println("Bind failed, reason is unknown");
540: } else {
541: out
542: .println("Bind failed, usurper entry is:<br>");
543: print(usurperEntry);
544: }
545: }
546: } else if (res instanceof Response.Unbind) {
547: if (((Response.Unbind) res).didUnbind()) {
548: out.println("Unbind succeeded");
549: } else {
550: out.println("Unbind failed?");
551: }
552: } else {
553: out.println(res);
554: }
555: }
556: }
557:
558: private void printTableStart() {
559: out.print("<table border=1>\n" + "<tr>" + "<th> </th>"
560: + "<th>Name</th>" + "<th>Type</th>"
561: + "<th>URI</th>" + "<th>Cert</th>" + "</tr>\n");
562: }
563:
564: private void printTableEnd() {
565: out.println("</table>");
566: }
567:
568: private void print(Map m) {
569: printTableStart();
570: print(m, 0);
571: printTableEnd();
572: }
573:
574: private void print(AddressEntry ae) {
575: printTableStart();
576: print(ae, 0);
577: printTableEnd();
578: }
579:
580: private int print(Map m, int idx) {
581: int ret = idx;
582: if (m != null && !m.isEmpty()) {
583: for (Iterator iter = m.values().iterator(); iter
584: .hasNext();) {
585: AddressEntry ae = (AddressEntry) iter.next();
586: if (print(ae, ret)) {
587: ++ret;
588: }
589: }
590: }
591: return ret;
592: }
593:
594: private boolean print(AddressEntry ae, int idx) {
595: if (ae != null) {
596: out.print("<tr>" + "<td align=right>" + (idx + 1)
597: + " </td>" + "<td align=right>"
598: + ae.getName() + "</td>" + "<td align=right>"
599: + ae.getType() + "</td>" + "<td>" + ae.getURI()
600: + "</td>" + "<td align=right>" + ae.getCert()
601: + "</td>" + "</td></tr>\n");
602: return true;
603: }
604: return false;
605: }
606:
607: private void print(Set names) {
608: int n = (names == null ? 0 : names.size());
609: out.println("Names[" + n + "]:<br>");
610: if (n <= 0) {
611: return;
612: }
613: out.println("<table border=0>\n<li>");
614: List l = new ArrayList(names);
615: Collections.sort(l);
616: for (int i = 0; i < n; i++) {
617: String ni = (String) l.get(i);
618: out.print("<tr><td align=right>" + (i + 1)
619: + ". </td>" + "<td align=right>");
620: if (ni == null) {
621: out.print("<i>null?</i>");
622: } else if (ni.length() == 0) {
623: out.print("<i>empty?</i>");
624: } else if (ni.charAt(0) != '.') {
625: out.print("<a href=\"" + sreq.getRequestURI()
626: + "?action=get&name=" + ni + "\">" + ni
627: + "</a>");
628: } else {
629: out.print("<a href=\"" + sreq.getRequestURI()
630: + "?action=list&name=" + ni + "\">" + ni
631: + "</a>");
632: }
633: out.println("</td></tr>\n");
634: }
635: out.println("</table>");
636: }
637:
638: private void print(Exception e) {
639: out.println("Failure</td><td>");
640: if (e == null) {
641: out.print("null");
642: return;
643: }
644: out.println("<pre>");
645: e.printStackTrace(out);
646: out.println("</pre>");
647: }
648: }
649: }
|