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.mts.std;
028:
029: import java.io.PrintWriter;
030: import java.io.UnsupportedEncodingException;
031: import java.net.URLDecoder;
032: import java.net.URLEncoder;
033: import java.util.ArrayList;
034: import java.util.Arrays;
035: import java.util.Collections;
036: import java.util.Comparator;
037: import java.util.Date;
038: import java.util.List;
039:
040: import javax.servlet.http.HttpServletRequest;
041:
042: import org.cougaar.core.component.ServiceBroker;
043: import org.cougaar.core.mts.AttributeConstants;
044: import org.cougaar.core.mts.Message;
045: import org.cougaar.core.mts.MessageAddress;
046: import org.cougaar.core.mts.MessageAttributes;
047: import org.cougaar.core.servlet.ServletFrameset;
048: import org.cougaar.mts.base.DestinationQueueMonitorService;
049:
050: /**
051: * This Servlet displays the state of the DestinationQueues. It can
052: * also be used to "return" an XML form of the same data to connected
053: * clients.
054: */
055: public final class DestinationQueueMonitorServlet extends
056: ServletFrameset {
057:
058: // values for the FRAME url parameter
059: private static final String INFO_FRAME = "infoFrame";
060: private static final String SELECT_FRAME = "selectFrame";
061:
062: private static final String DESTINATION_PARAM = "agent";
063: private static final String FORMAT_PARAM = "format";
064:
065: private final DestinationQueueMonitorService destinationQueueMonitorService;
066:
067: private static final Comparator MESSAGE_ADDRESS_COMPARATOR = new Comparator() {
068: public int compare(Object a, Object b) {
069: String sa = ((MessageAddress) a).getAddress();
070: String sb = ((MessageAddress) b).getAddress();
071: return sa.compareTo(sb);
072: }
073: };
074:
075: public DestinationQueueMonitorServlet(ServiceBroker sb) {
076: super (sb);
077:
078: destinationQueueMonitorService = (DestinationQueueMonitorService) sb
079: .getService(this , DestinationQueueMonitorService.class,
080: null);
081: }
082:
083: // Implementations of ServletFrameset's abstract methods
084:
085: public String getPath() {
086: return "/message/queues";
087: }
088:
089: public String getTitle() {
090: return "MTS Queues";
091: }
092:
093: private void printMessage(int count, AttributedMessage am,
094: PrintWriter out) {
095: if (am == null) {
096: out.print("<tr><td align=right>" + count
097: + "</td><td>null</tr>\n");
098: return;
099: }
100: out.print("<tr><td align=right>" + count
101: + "</td><td align=right>");
102: Message m = am.getRawMessage();
103: MessageAddress source = m.getOriginator();
104: out.print(source.getAddress());
105: out.print("</td><td>");
106: MessageAttributes sourceAtts = source.getMessageAttributes();
107: if (sourceAtts == null) {
108: out.print(" ");
109: } else {
110: out.print(encodeHTML(sourceAtts.getAttributesAsString()));
111: }
112: MessageAddress target = m.getTarget();
113: out.print("</td><td>");
114: out.print(target.getAddress());
115: out.print("</td><td>");
116: MessageAttributes targetAtts = target.getMessageAttributes();
117: if (targetAtts == null) {
118: out.print(" ");
119: } else {
120: out.print(encodeHTML(targetAtts.getAttributesAsString()));
121: }
122: out.print("</td><td>");
123: out.print(encodeHTML(am.getAttributesAsString()));
124: out.print("</td><td>");
125: out.print(m.getClass().getName());
126: out.print("</td><td>");
127: out.print(encodeHTML(m.toString()));
128: out.print("</td></tr>");
129: }
130:
131: private void printMessageXML(AttributedMessage am, PrintWriter out) {
132: if (am == null) {
133: return;
134: }
135: out.print(" <message>\n" + " <source>");
136: Message m = am.getRawMessage();
137: MessageAddress source = m.getOriginator();
138: out.print(source.getAddress());
139: out.print("</source>\n" + " <source_attributes>");
140: MessageAttributes sourceAtts = source.getMessageAttributes();
141: if (sourceAtts != null) {
142: out.print(encodeHTML(sourceAtts.getAttributesAsString()));
143: }
144: out.print("</source_attributes>\n" + " <target>");
145: MessageAddress target = m.getTarget();
146: out.print(target.getAddress());
147: out.print("</target>\n" + " <target_attributes>");
148: MessageAttributes targetAtts = target.getMessageAttributes();
149: if (targetAtts != null) {
150: out.print(encodeHTML(targetAtts.getAttributesAsString()));
151: }
152: out.print("</source_attributes>\n" + " <attributes>");
153: out.print(encodeHTML(am.getAttributesAsString()));
154: out.print("</attributes>\n" + " <class>");
155: out.print(m.getClass().getName());
156: out.print("</class>\n" + " <to_string>");
157: out.print(encodeHTML(m.toString()));
158: out.print("</to_string>\n" + " </message>\n");
159: }
160:
161: private void beginTable(PrintWriter out) {
162: out.print("<p><table border=1>" + "<tr>"
163: + "<th rowspan=2></th>" + "<th colspan=2>Source</th>"
164: + "<th colspan=2>Target</th>"
165: + "<th rowspan=2>Attributes</th>"
166: + "<th rowspan=2>Class</th>"
167: + "<th rowspan=2>toString</th>" + "</tr>" + "<tr>"
168: + "<td>Address</td>" + "<td>Attributes</td>"
169: + "<td>Address</td>" + "<td>Attributes</td>" + "</tr>");
170: }
171:
172: private void endTable(PrintWriter out) {
173: out.print("</table>\n");
174: }
175:
176: private long getHeadSendTime(AttributedMessage[] messages) {
177: if (messages.length > 0) {
178: AttributedMessage m = messages[0];
179: if (m != null) {
180: Object sendTime = m
181: .getAttribute(AttributeConstants.MESSAGE_SEND_TIME_ATTRIBUTE);
182: if (sendTime instanceof Long) {
183: long t = ((Long) sendTime).longValue();
184: return t;
185: }
186: }
187: }
188: return -1;
189: }
190:
191: private MessageAddress[] getDestinations(String dest) {
192: MessageAddress[] destinations;
193: if (dest == null) {
194: destinations = new MessageAddress[0];
195: } else if (dest.equals("*")) {
196: destinations = destinationQueueMonitorService
197: .getDestinations();
198: if (destinations == null) {
199: destinations = new MessageAddress[0];
200: }
201: Arrays.sort(destinations, MESSAGE_ADDRESS_COMPARATOR);
202: } else {
203: final MessageAddress destination = MessageAddress
204: .getMessageAddress(dest);
205: destinations = new MessageAddress[] { destination };
206: }
207: return destinations;
208: }
209:
210: private AttributedMessage[] getMessages(MessageAddress addr) {
211: AttributedMessage[] messages = destinationQueueMonitorService
212: .snapshotQueue(addr);
213: if (messages == null) {
214: messages = new AttributedMessage[0];
215: }
216: return messages;
217: }
218:
219: private void printQueues(String dest, PrintWriter out) {
220: if (dest == null) {
221: return;
222: }
223:
224: out.print("<p><b>" + dest + "</b><p>");
225:
226: MessageAddress[] destinations = getDestinations(dest);
227:
228: int n = destinations.length;
229: if (n <= 0) {
230: out.print("Zero targets\n");
231: return;
232: }
233:
234: AttributedMessage[][] queues = new AttributedMessage[n][];
235: for (int i = 0; i < n; i++) {
236: AttributedMessage[] messages = getMessages(destinations[i]);
237: queues[i] = messages;
238: }
239:
240: int count = 0;
241: long minTime = -1;
242: int minCount = 0;
243: MessageAddress minAddr = null;
244: for (int i = 0; i < n; i++) {
245: AttributedMessage[] messages = queues[i];
246: long t = getHeadSendTime(messages);
247: if (t > 0 && (minTime < 0 || t < minTime)) {
248: minCount = count;
249: minTime = t;
250: minAddr = destinations[i];
251: }
252: count += messages.length;
253: }
254:
255: if (minTime > 0) {
256: out.print("Message[" + minCount + " / " + count + "] to "
257: + minAddr.getAddress()
258: + " has been pending for <b>"
259: + (System.currentTimeMillis() - minTime)
260: + "</b> millis (" + (new Date(minTime)) + ")<p>\n");
261: } else {
262: out.print("Messages[" + count + "]:\n");
263: }
264:
265: beginTable(out);
266: count = 0;
267: for (int i = 0; i < n; i++) {
268: AttributedMessage[] messages = queues[i];
269: for (int j = 0, jn = messages.length; j < jn; j++) {
270: printMessage(count++, messages[j], out);
271: }
272: }
273: endTable(out);
274: }
275:
276: public void printPage(HttpServletRequest request, PrintWriter out) {
277: String dest = request.getParameter(DESTINATION_PARAM);
278: if (dest == null) {
279: return;
280: }
281: printQueues(dest, out);
282: }
283:
284: protected List getDataSelectionList(HttpServletRequest request) {
285: MessageAddress[] destinations = getDestinations("*");
286: int n = destinations.length;
287: if (n == 0) {
288: return Collections.singletonList("*");
289: }
290: List ret = new ArrayList(n + 1);
291: ret.add("*");
292: for (int i = 0; i < n; i++) {
293: String s = destinations[i].getAddress();
294: ret.add(s);
295: }
296: return ret;
297: }
298:
299: private void printXML(HttpServletRequest request, PrintWriter out) {
300: String dest = request.getParameter(DESTINATION_PARAM);
301: MessageAddress[] destinations = getDestinations(dest);
302: int n = destinations.length;
303: out.print("<queues length=\"" + n + "\">\n");
304: for (int i = 0; i < n; i++) {
305: MessageAddress destination = destinations[i];
306: String s = destination.getAddress();
307: AttributedMessage[] messages = getMessages(destination);
308: int jn = messages.length;
309: out.print("<queue target=\"" + s + "\" length=\"" + jn
310: + "\"");
311: if (jn <= 0) {
312: out.print("/>\n");
313: } else {
314: out.print(">\n");
315: for (int j = 0; j < jn; j++) {
316: AttributedMessage am = messages[j];
317: printMessageXML(am, out);
318: }
319: out.print("</queue>\n");
320: }
321: }
322: out.print("</queues>\n");
323: }
324:
325: private void printSelectFrame(HttpServletRequest request,
326: PrintWriter out) {
327: out.print("<html><body>\n");
328: if (destinationQueueMonitorService == null) {
329: out.print("Null DestinationQueueMonitorService\n");
330: } else {
331: out.print("<ol>\n");
332: List l = getDataSelectionList(request);
333: for (int i = 0, n = l.size(); i < n; i++) {
334: String s = (String) l.get(i);
335: out.print("<li><a href=\"" + request.getRequestURL()
336: + "?" + FRAME + "=" + DATA_FRAME + "&"
337: + DESTINATION_PARAM + "=" + s + "\" target=\""
338: + DATA_FRAME + "\">" + s + "</a></li>\n");
339: }
340: out.print("</ol>\n");
341: }
342: out.print("</body></html>\n");
343: }
344:
345: private void printInfoFrame(HttpServletRequest request,
346: PrintWriter out) {
347: // Header
348: out.print("<html><head><title>");
349: out.print(getTitle());
350: out.print("</title></head>");
351:
352: // Frameset
353: int percentage = 20;
354: out.print("<frameset cols=\"");
355: out.print(percentage);
356: out.print("%,");
357: out.print(100 - percentage);
358: out.print("%\">\n");
359:
360: // show select frame
361: out.print("<frame src=\"");
362: out.print(request.getRequestURI());
363: out.print("?");
364: out.print(FRAME);
365: out.print("=");
366: out.print(SELECT_FRAME);
367: out.print("\" name=\"");
368: out.print(SELECT_FRAME);
369: out.print("\">\n");
370:
371: // show data frame
372: out.print("<frame src=\"");
373: out.print(request.getRequestURI());
374: out.print("?");
375: out.print(FRAME);
376: out.print("=");
377: out.print(DATA_FRAME);
378: out.print("\" name=\"");
379: out.print(DATA_FRAME);
380: out.print("\">\n");
381:
382: // End frameset
383: out.print("</frameset>\n");
384:
385: // Frameless browser hack
386: out.print("<noframes>Please enable frame support</noframes>");
387:
388: // End
389: out.print("</html>\n");
390: }
391:
392: protected String getMiddleFrame() {
393: return INFO_FRAME;
394: }
395:
396: protected final void printFrame(String frame,
397: HttpServletRequest request, PrintWriter out) {
398: String format = request.getParameter(FORMAT_PARAM);
399: if (format != null && format.equalsIgnoreCase("xml")) {
400: printXML(request, out);
401: return;
402: }
403: if (SELECT_FRAME.equals(frame)) {
404: printSelectFrame(request, out);
405: } else if (INFO_FRAME.equals(frame)) {
406: printInfoFrame(request, out);
407: } else {
408: super .printFrame(frame, request, out);
409: }
410: }
411:
412: private static final String encodeUTF8(String s) {
413: try {
414: return URLEncoder.encode(s, "UTF-8");
415: } catch (UnsupportedEncodingException e) {
416: throw new RuntimeException("UTF-8 not supported?", e);
417: }
418: }
419:
420: private static final String decodeUTF8(String s) {
421: try {
422: return URLDecoder.decode(s, "UTF-8");
423: } catch (UnsupportedEncodingException e) {
424: throw new RuntimeException("UTF-8 not supported?", e);
425: }
426: }
427:
428: // move me to "org.cougaar.util.StringUtility"!
429: private static final String encodeHTML(String s) {
430: return encodeHTML(s, false);
431: }
432:
433: private static final String encodeHTML(String s,
434: boolean noBreakSpaces) {
435: StringBuffer buf = null; // In case we need to edit the string
436: int ix = 0; // Beginning of uncopied part of s
437: for (int i = 0, n = s.length(); i < n; i++) {
438: String replacement = null;
439: switch (s.charAt(i)) {
440: case '"':
441: replacement = """;
442: break;
443: case '<':
444: replacement = "<";
445: break;
446: case '>':
447: replacement = ">";
448: break;
449: case '&':
450: replacement = "&";
451: break;
452: case ' ':
453: if (noBreakSpaces)
454: replacement = " ";
455: break;
456: }
457: if (replacement != null) {
458: if (buf == null)
459: buf = new StringBuffer();
460: buf.append(s.substring(ix, i));
461: buf.append(replacement);
462: ix = i + 1;
463: }
464: }
465: if (buf == null) {
466: return s;
467: } else {
468: buf.append(s.substring(ix));
469: return buf.toString();
470: }
471: }
472: }
|