001: /*
002: * <copyright>
003: *
004: * Copyright 2000-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.qos.frame;
028:
029: import java.io.IOException;
030: import java.io.PrintWriter;
031: import java.net.URLDecoder;
032: import java.net.URLEncoder;
033: import java.util.Collection;
034: import java.util.HashSet;
035: import java.util.Iterator;
036: import java.util.Map;
037: import java.util.Properties;
038: import java.util.Set;
039:
040: import javax.servlet.http.HttpServletRequest;
041: import javax.servlet.http.HttpServletResponse;
042:
043: import org.cougaar.core.service.LoggingService;
044: import org.cougaar.core.servlet.ComponentServlet;
045: import org.cougaar.core.util.UID;
046: import org.cougaar.util.Sortings;
047: import org.xml.sax.Attributes;
048:
049: /**
050: * This servlet displays {@link FrameSet}s and allows the user
051: * to modify slot values.
052: * <p>
053: * To load this servlet, add the following to any agent's XML
054: * configuration:<pre>
055: * <component
056: * class="org.cougaar.core.qos.frame.FrameViewerServlet"/>
057: * </pre>
058: */
059: public class FrameViewerServlet extends ComponentServlet {
060:
061: private LoggingService log;
062: private FrameSetService fss;
063:
064: protected String getPath() {
065: String s = super .getPath();
066: return (s == null ? "/frames" : s);
067: }
068:
069: public void setLoggingService(LoggingService log) {
070: this .log = log;
071: }
072:
073: public void load() {
074: super .load();
075: fss = (FrameSetService) getServiceBroker().getService(this ,
076: FrameSetService.class, null);
077: if (fss == null && log.isWarnEnabled()) {
078: log.warn("Unable to obtain FrameSetService");
079: }
080: }
081:
082: static class PrototypeComparator implements java.util.Comparator {
083: public int compare(Object x, Object y) {
084: String x_name = ((PrototypeFrame) x).getName();
085: String y_name = ((PrototypeFrame) y).getName();
086: return x_name.compareTo(y_name);
087: }
088:
089: public boolean equals(Object thing) {
090: return thing == this ;
091: }
092: }
093:
094: private static final java.util.Comparator cmp = new PrototypeComparator();
095:
096: public void doGet(HttpServletRequest request,
097: HttpServletResponse response) throws IOException {
098: (new Worker(request, response)).execute();
099: }
100:
101: private class Worker {
102: // from the "doGet(..)":
103: private final HttpServletRequest request;
104: private final HttpServletResponse response;
105:
106: private PrintWriter out;
107:
108: private static final int NUM_SEARCH_SLOTS = 3;
109:
110: // from URL-params:
111: private static final String PAGE_PARAM = "page";
112: private static final String SEARCH_PAGE = "search";
113: private static final String RESULT_PAGE = "result";
114: private String page;
115:
116: private static final String NAME_PARAM = "name";
117: private String name;
118:
119: private static final String KIND_PARAM = "kind";
120: private String kind;
121:
122: private static final String SLOT_PARAM = "slot";
123: private final String[] slots = new String[NUM_SEARCH_SLOTS];
124: private static final String VALUE_PARAM = "value";
125: private final String[] values = new String[NUM_SEARCH_SLOTS];
126:
127: private static final String UID_PARAM = "uid";
128: private UID modifyUID;
129:
130: private static final String NEW_SLOT_PARAM = "newSlot";
131: private String newSlot;
132: private static final String NEW_VALUE_PARAM = "newValue";
133: private String newValue;
134:
135: public Worker(HttpServletRequest request,
136: HttpServletResponse response) {
137: this .request = request;
138: this .response = response;
139: }
140:
141: public void execute() throws IOException {
142: parseParams();
143: writeResponse();
144: }
145:
146: private void parseParams() throws IOException {
147: page = getParameter(PAGE_PARAM);
148: if (page == null) {
149: return;
150: }
151: name = getParameter(NAME_PARAM);
152: kind = getParameter(KIND_PARAM);
153: for (int i = 0; i < NUM_SEARCH_SLOTS; i++) {
154: String s = getParameter(SLOT_PARAM + i);
155: if (s == null)
156: continue;
157: slots[i] = s;
158: s = request.getParameter(VALUE_PARAM + i);
159: if (s != null)
160: s = s.trim();
161: values[i] = s;
162: }
163: newSlot = getParameter(NEW_SLOT_PARAM);
164: newValue = getParameter(NEW_VALUE_PARAM);
165:
166: String suid = getParameter(UID_PARAM);
167: if (suid != null) {
168: modifyUID = decodeUID(suid);
169: }
170: }
171:
172: private void writeResponse() throws IOException {
173: response.setContentType("text/html");
174: out = response.getWriter();
175:
176: if (SEARCH_PAGE.equals(page)) {
177: writeSearchPage();
178: } else if (RESULT_PAGE.equals(page)) {
179: writeResultPage();
180: } else {
181: writeMainPage();
182: }
183: out.flush();
184: }
185:
186: private void writeMainPage() {
187: out.print("<html>\n" + "<head>\n" + "<title>"
188: + "FrameSet Viewer" + "</title>\n" + "</head>\n"
189: + "<frameset rows=\"35%,65%\">\n" + "<frame"
190: + " src=\"" + request.getRequestURI() + "?"
191: + PAGE_PARAM + "=" + SEARCH_PAGE + "\" name=\""
192: + SEARCH_PAGE + "\">\n" + "<frame src=\""
193: + request.getRequestURI() + "?" + PAGE_PARAM + "="
194: + RESULT_PAGE + "\" name=\"" + RESULT_PAGE
195: + "\">\n" + "</frameset>\n");
196: }
197:
198: private void writeSearchPage() {
199: Set names = fss.getNames();
200: out.print("<html><head>\n"
201: + "<script language=\"javascript\">\n" + "<!--\n"
202: + "var names = new Array();\n"
203: + "var kinds = new Array();\n");
204: if (names != null && names.size() > 0) {
205: Set allKinds = new HashSet();
206: int i = 0;
207: for (Iterator itr = Sortings.sort(names).iterator(); itr
208: .hasNext(); i++) {
209: String ni = (String) itr.next();
210: FrameSet fs = fss.findFrameSet(ni, null);
211: if (fs == null)
212: continue;
213: out.print("names[" + i + "] = '" + ni + "';\n"
214: + "kinds[" + i + "] = [ '*'"
215: + ", '--Prototypes--'");
216:
217: Collection kinds = fs.getPrototypes();
218: if (kinds != null) {
219: allKinds.addAll(kinds);
220: for (Iterator i2 = Sortings.sort(kinds, cmp)
221: .iterator(); i2.hasNext();) {
222: out.print(", '"
223: + ((PrototypeFrame) i2.next())
224: .getName() + "'");
225: }
226: }
227: out.print(" ];\n");
228: }
229: out.print("names[" + i + "] = '*';\n" + "kinds[" + i
230: + "] = [ '*'");
231: for (Iterator i2 = Sortings.sort(allKinds, cmp)
232: .iterator(); i2.hasNext();) {
233: out.print(", '"
234: + ((PrototypeFrame) i2.next()).getName()
235: + "'");
236: }
237: out.print(" ];\n");
238: }
239: out
240: .print("\n" + "function init() {\n"
241: + " var box = document.myform."
242: + NAME_PARAM
243: + ";\n"
244: + " for (var i = 0; i < names.length; i++) {\n"
245: + " box.options[i] = new Option(names[i], names[i]);\n"
246: + " }\n"
247: + " box.options[0].selected = true;\n"
248: + " setKinds();\n"
249: + "}\n"
250: + "\n"
251: + "function setKinds() {\n"
252: + " var nameIdx = document.myform."
253: + NAME_PARAM
254: + ".selectedIndex;\n"
255: + " var vals = kinds[nameIdx]\n"
256: + " var box = document.myform."
257: + KIND_PARAM
258: + ";\n"
259: + " box.options.length = 0;\n"
260: + " for (var i = 0; i < vals.length; i++) {\n"
261: + " box.options[i] = new Option(vals[i], vals[i]);\n"
262: + " }\n"
263: + " box.options[0].selected = true;\n"
264: + "}\n"
265: + "-->\n"
266: + "</script>\n"
267: + "</head>\n");
268: out.print("<body onload=\"init()\">\n"
269: + "<form name=\"myform\" method=\"GET\" action=\""
270: + request.getRequestURI() + "\" target=\""
271: + RESULT_PAGE + "\">\n"
272: + "<b>Find FrameSet:</b><br>\n"
273: + "<input type=hidden name=\"" + PAGE_PARAM
274: + "\" value=\"" + RESULT_PAGE + "\"/>\n"
275: + "<table border=\"0\">\n");
276: // drop-down names
277: out.print("<tr><td>FrameSet Name: </td><td>"
278: + "<select name=\"" + NAME_PARAM
279: + "\" onchange=\"setKinds();\"/>\n"
280: + "</td></tr>\n");
281: // drop-down kinds
282: out.print("<tr><td>Prototype Kind: </td><td>"
283: + "<select name=\"" + KIND_PARAM + "\"/>\n");
284: out.print("<tr><td colspan=3>Properties:</td></tr>\n");
285: for (int i = 0; i < NUM_SEARCH_SLOTS; i++) {
286: out.print("<tr><td> " + i + ": </td>"
287: + "<td><input name=\"" + SLOT_PARAM + i
288: + "\" type=\"text\" size=\"20\" value=\""
289: + (slots[i] == null ? "" : slots[i])
290: + "\"></td>" + "<td><input name=\""
291: + VALUE_PARAM + i
292: + "\" type=\"text\" size=\"20\" value=\""
293: + (values[i] == null ? "" : values[i])
294: + "\"></td>" + "</tr>\n");
295: }
296: out.print("<tr><td>"
297: + "<input type=\"submit\" value=\"Search\"/>"
298: + "</td></tr>\n" + "</table>\n" + "</form>\n"
299: + "</body></html>");
300: }
301:
302: private void writeResultPage() {
303: out.print("<html><body>\n");
304: if (name == null || kind == null) {
305: out.print("Specify a FrameSet Name and Frame Kind\n"
306: + "</body></html>\n");
307: return;
308: }
309:
310: if (name.equals("*")) {
311: Set names = fss.getNames();
312: if (names != null && names.size() > 0) {
313: int i = 0;
314: for (Iterator itr = Sortings.sort(names).iterator(); itr
315: .hasNext(); i++) {
316: String ni = (String) itr.next();
317: out.print("<table border=1>\n"
318: + "<tr bgcolor=\"DDDDDD\"><th>"
319: + "FrameSet " + i + ": " + ni
320: + "</th></tr>" + "<tr><td>\n");
321: writeFrameSet(ni);
322: out.print("</td></tr>\n" + "</table>\n");
323: }
324: }
325: } else {
326: writeFrameSet(name);
327: }
328:
329: out.print("</body></html>");
330: }
331:
332: private void writeFrameSet(String fsname) {
333: FrameSet fs = fss.findFrameSet(fsname, null);
334: if (fs == null) {
335: out.print("Unknown FrameSet Name: " + fsname + "<p>\n");
336: return;
337: }
338: writeFrameSet(fs);
339: }
340:
341: private void writeFrameSet(FrameSet fs) {
342:
343: Properties slot_value_pairs = new Properties();
344: for (int i = 0; i < NUM_SEARCH_SLOTS; i++) {
345: if (slots[i] == null)
346: continue;
347: slot_value_pairs.setProperty(slots[i], values[i]);
348: }
349:
350: Set frames;
351: if (kind.equals("*")) {
352: frames = new HashSet();
353: Collection kinds = fs.getPrototypes();
354: if (kinds != null && !kinds.isEmpty()) {
355: for (Iterator i2 = Sortings.sort(kinds, cmp)
356: .iterator(); i2.hasNext();) {
357: String k = ((PrototypeFrame) i2.next())
358: .getName();
359: Set set = fs.findFrames(k, slot_value_pairs);
360: if (set == null)
361: continue;
362: frames.addAll(set);
363: }
364: }
365: } else if (kind.equals("--Prototypes--")) {
366: frames = new HashSet();
367: frames.addAll(fs.getPrototypes());
368: } else {
369: frames = fs.findFrames(kind, slot_value_pairs);
370: }
371:
372: int nframes = (frames == null ? 0 : frames.size());
373: out.print("Found " + nframes + " matching Frame"
374: + (nframes == 1 ? "" : "s")
375: + (nframes > 0 ? ":<p>" : ".") + "\n");
376: if (nframes == 0) {
377: return;
378: }
379:
380: int i = 0;
381: for (Iterator itr = frames.iterator(); itr.hasNext();) {
382: Frame f = (Frame) itr.next();
383: i++;
384: writeFrame(f, fs, i);
385: out.print("<p>\n");
386: }
387: }
388:
389: private void writeFrame(Frame f, FrameSet fs, int i) {
390: UID uid = f.getUID();
391:
392: boolean selected = false;
393: boolean modified = false;
394: Object oldValue = null;
395: if (modifyUID != null && modifyUID.equals(uid)
396: && newSlot != null) {
397: selected = true;
398: out.print("<a name=\"modified\">");
399: Object o = f.getValue(newSlot);
400: if (!(o == null ? newValue == null : o.equals(newValue))) {
401: if (newValue == null) {
402: System.out.println("FIXME: removeValue("
403: + newSlot + ")");
404: }
405: f.setValue(newSlot, newValue);
406: modified = true;
407: oldValue = o;
408: }
409: }
410:
411: out
412: .print("<table border=1>\n"
413: + "<tr bgcolor=\"DDDDDD\"><th colspan=4>"
414: + (f instanceof PrototypeFrame ? "Prototype"
415: : "Frame")
416: + " "
417: + i
418: + "</th></tr>\n"
419: + "<tr><td><table border=0>\n"
420: + "<tr><td>FrameSet Name: </td><td colspan=3>"
421: + fs.getName()
422: + "</td></tr>\n"
423: + "<tr><td>Kind: </td><td colspan=3>"
424: + (f instanceof PrototypeFrame ? ((PrototypeFrame) f)
425: .getName()
426: : f.getKind()) + "</td></tr>\n"
427: + "<tr><td>UID: </td><td colspan=3>"
428: + linkToUID(f.getUID()) + "</td></tr>\n");
429: PrototypeFrame proto = f.getPrototype();
430: out.print("<tr><td>Prototype: </td><td colspan=3>"
431: + (proto == null ? "<i>null</i>" : proto.getName()
432: + " (" + linkToUID(proto.getUID()) + ")")
433: + "</td></tr>\n");
434: if (f instanceof DataFrame) {
435: DataFrame container = ((DataFrame) f).containerFrame();
436: out
437: .print("<tr><td>Container: </td><td colspan=3>"
438: + (container == null ? "<i>null</i>"
439: : container.getKind()
440: + " ("
441: + linkToUID(container
442: .getUID())
443: + ")") + "</td></tr>\n");
444: }
445: Map vp = null;
446: String description = null;
447: if (f instanceof DataFrame) {
448: vp = ((DataFrame) f).slotDescriptions();
449: description = "All Slots";
450: } else if (f instanceof PrototypeFrame) {
451: vp = ((PrototypeFrame) f).getSlotDefinitions();
452: description = "Declared Slots";
453: }
454: int nvp = (vp == null ? 0 : vp.size());
455: out.print("<tr><td colspan=4>" + description + "[" + nvp
456: + "]:</td></tr>\n");
457: if (nvp > 0) {
458: int j = 0;
459: Iterator itr = vp.entrySet().iterator();
460: while (itr.hasNext()) {
461: Map.Entry entry = (Map.Entry) itr.next();
462: String key = (String) entry.getKey();
463: Object val = entry.getValue();
464: if (val instanceof SlotDescription)
465: val = ((SlotDescription) val).value;
466: else if (val instanceof Attributes)
467: val = ((Attributes) val)
468: .getValue("default-value");
469: j++;
470: out
471: .print("<tr><td> "
472: + j
473: + ": </td>"
474: + "<td>"
475: + key
476: + "</td><td>"
477: + (val == DataFrame.NIL
478: || val == null ? "<no-value>"
479: : val)
480: + "</td>"
481: + "<td>"
482: + (modified && key.equals(newSlot) ? "<b>(was "
483: + (oldValue == DataFrame.NIL ? "<no-value>"
484: : oldValue)
485: + ")</b>"
486: : "") + "</td>" + "</tr>\n");
487: }
488: }
489: out.print("<tr>" + "<form method=\"GET\" action=\""
490: + request.getRequestURI() + "#modified"
491: + "\" target=\"" + RESULT_PAGE + "\">\n"
492: + "<input type=hidden name=\"" + PAGE_PARAM
493: + "\" value=\"" + RESULT_PAGE + "\"/>\n"
494: + "<input type=hidden name=\"" + NAME_PARAM
495: + "\" value=\"" + name + "\"/>\n"
496: + "<input type=hidden name=\"" + KIND_PARAM
497: + "\" value=\"" + kind + "\"/>\n");
498: for (int j = 0; j < NUM_SEARCH_SLOTS; j++) {
499: if (slots[j] == null)
500: continue;
501: out.print("<input type=hidden name=\"" + SLOT_PARAM + j
502: + "\" value=\"" + slots[j] + "\"/>\n");
503: if (values[j] != null) {
504: out.print("<input type=hidden name=\""
505: + VALUE_PARAM + j + "\" value=\""
506: + values[j] + "\"/>\n");
507: }
508: }
509: out.print("<input type=hidden name=\"" + UID_PARAM
510: + "\" value=\"" + encodeUID(f.getUID()) + "\"/>\n");
511: out.print("<td>"
512: + (modified ? "<b>Modified</b>" : "Modify")
513: + " slot: </td>" + "<td><input name=\""
514: + NEW_SLOT_PARAM
515: + "\" type=\"text\" size=\"20\" value=\""
516: + (selected && newSlot != null ? newSlot : "")
517: + "\"></td>" + "<td><input name=\""
518: + NEW_VALUE_PARAM
519: + "\" type=\"text\" size=\"20\" value=\""
520: + (selected && newValue != null ? newValue : "")
521: + "\"></td>"
522: + "<td><input type=\"submit\" value=\"Modify\"/>\n"
523: + "</td>" + "</form>\n" + "</tr>\n" + "</table>"
524: + "</td></tr></table>\n");
525: }
526:
527: private String linkToUID(UID uid) {
528: if (uid == null) {
529: return "<i>null</i>";
530: }
531: return "<a href=\"/$" + getEncodedAgentName()
532: + "/tasks?mode=10&uid=" + encodeUID(uid) + "\">"
533: + uid + "</a>";
534: }
535:
536: private String encodeUID(UID uid) {
537: try {
538: return URLEncoder.encode(uid.toString(), "UTF-8");
539: } catch (Exception e) {
540: throw new IllegalArgumentException(
541: "Unable to encode UID: " + uid);
542: }
543: }
544:
545: private UID decodeUID(String s) {
546: try {
547: String s2 = URLDecoder.decode(s, "UTF-8");
548: return UID.toUID(s2);
549: } catch (Exception e) {
550: throw new IllegalArgumentException(
551: "Unable to decode UID: " + s);
552: }
553: }
554:
555: private String getParameter(String name) {
556: return getParameter(name, null);
557: }
558:
559: private String getParameter(String name, String defaultValue) {
560: String value = request.getParameter(name);
561: if (value != null) {
562: value = value.trim();
563: if (value.length() == 0) {
564: value = null;
565: }
566: }
567: if (value == null) {
568: value = defaultValue;
569: }
570: return value;
571: }
572: }
573: }
|