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.mlm.plugin.sample;
028:
029: import java.awt.Color;
030: import java.awt.Graphics;
031: import java.awt.image.BufferedImage;
032: import java.io.IOException;
033: import java.io.PrintWriter;
034: import java.text.DateFormat;
035: import java.text.DecimalFormat;
036: import java.text.SimpleDateFormat;
037: import java.util.Collection;
038: import java.util.Date;
039: import java.util.Iterator;
040:
041: import javax.imageio.ImageIO;
042: import javax.imageio.ImageWriter;
043: import javax.imageio.stream.MemoryCacheImageOutputStream;
044: import javax.servlet.http.HttpServlet;
045: import javax.servlet.http.HttpServletRequest;
046: import javax.servlet.http.HttpServletResponse;
047:
048: import org.cougaar.core.blackboard.IncrementalSubscription;
049: import org.cougaar.core.mts.MessageAddress;
050: import org.cougaar.core.plugin.ComponentPlugin;
051: import org.cougaar.core.service.LoggingService;
052: import org.cougaar.core.service.ServletService;
053: import org.cougaar.glm.ldm.Constants;
054: import org.cougaar.glm.ldm.asset.Organization;
055: import org.cougaar.planning.ldm.plan.AllocationResult;
056: import org.cougaar.planning.ldm.plan.PlanElement;
057: import org.cougaar.planning.ldm.plan.PrepositionalPhrase;
058: import org.cougaar.planning.ldm.plan.Task;
059: import org.cougaar.util.UnaryPredicate;
060:
061: /**
062: * The GLSInitServlet crams all of the functionality of the GLSGUIInitPlugin,
063: * GLSGUIRescindPlugin, and SQLOplanPlugin sans GUIs into one plugin
064: * The buttons are now in a client application which talks to the
065: * servlets in this plugin to publish the oplan and gls tasks
066: *
067: **/
068: public class RootWatcherServletComponent extends ComponentPlugin {
069:
070: private IncrementalSubscription selfOrgSubscription;
071: private IncrementalSubscription glsSub;
072: private Record[] records = new Record[20];
073: private int record0 = 0;
074: private int nrecords = 0;
075: private long minTimestamp = System.currentTimeMillis();
076:
077: private static final String forRoot = "ForRoot".intern();
078:
079: protected static DateFormat logTimeFormat = new SimpleDateFormat(
080: "yyyy/MM/dd HH:mm:ss.SSS");
081:
082: protected static String formatDate(long when) {
083: return logTimeFormat.format(new Date(when));
084: }
085:
086: private static DecimalFormat confidenceFormat = new DecimalFormat(
087: "##0%");
088:
089: private static UnaryPredicate selfOrgPredicate = new UnaryPredicate() {
090: public boolean execute(Object o) {
091: if (o instanceof Organization) {
092: Organization org = (Organization) o;
093: return org.isSelf();
094: }
095: return false;
096: }
097: };
098:
099: private static class Record {
100: private long timestamp;
101: private double confidence;
102:
103: public Record(long ts, double c) {
104: timestamp = ts;
105: confidence = c;
106: }
107:
108: public String getTimestampString() {
109: return formatDate(timestamp);
110: }
111:
112: public String getConfidenceString() {
113: return confidenceFormat.format(confidence);
114: }
115:
116: public double getConfidence() {
117: return confidence;
118: }
119:
120: public long getTimestamp() {
121: return timestamp;
122: }
123:
124: public String toString() {
125: return getTimestampString() + ": " + getConfidenceString();
126: }
127: }
128:
129: /**
130: * This predicate selects for root tasks injected by the GLSGUIInitPlugin
131: **/
132: private static class GLSPredicate implements UnaryPredicate {
133: MessageAddress agentId;
134: Organization self;
135:
136: public GLSPredicate(Organization self, MessageAddress agentId) {
137: this .self = self;
138: this .agentId = agentId;
139: }
140:
141: public boolean execute(Object o) {
142: if (!(o instanceof PlanElement))
143: return false;
144: PlanElement pe = (PlanElement) o;
145: Task task = pe.getTask();
146: if (!task.getVerb().equals(Constants.Verb.GETLOGSUPPORT))
147: return false;
148: if (!task.getSource().equals(agentId))
149: return false;
150: if (!task.getDestination().equals(agentId))
151: return false;
152: PrepositionalPhrase pp = task
153: .getPrepositionalPhrase(Constants.Preposition.FOR);
154: if (pp == null || !self.equals(pp.getIndirectObject()))
155: return false;
156: if (task.getPrepositionalPhrase(forRoot) == null)
157: return false;
158: return true;
159: }
160: };
161:
162: private ServletService servletService;
163:
164: /** Sets the servlet service. Called by introspection on start
165: **/
166: public void setServletService(ServletService ss) {
167: servletService = ss;
168: }
169:
170: private LoggingService logger;
171:
172: public void setLoggingService(LoggingService ls) {
173: logger = ls;
174: }
175:
176: /*
177: * Creates a subscription.
178: */
179: protected void setupSubscriptions() {
180: blackboard.getSubscriber().setShouldBePersisted(false);
181: selfOrgSubscription = (IncrementalSubscription) blackboard
182: .subscribe(selfOrgPredicate);
183: checkSelfOrg(selfOrgSubscription);
184:
185: // register with servlet service
186: try {
187: servletService.register("/rootWatcher",
188: new RootWatcherServlet());
189: } catch (Exception e) {
190: e.printStackTrace();
191: }
192: }
193:
194: /**
195: * Executes Plugin functionality.
196: */
197: public void execute() {
198: if (selfOrgSubscription != null
199: && selfOrgSubscription.hasChanged()) {
200: checkSelfOrg(selfOrgSubscription.getAddedCollection());
201: // Don't worry about changes or deletes
202: }
203: if (glsSub != null && glsSub.hasChanged()) {
204: recordGLS(glsSub.getAddedCollection());
205: recordGLS(glsSub.getChangedCollection());
206: }
207: }
208:
209: private void checkSelfOrg(Collection selfOrgs) {
210: for (Iterator i = selfOrgs.iterator(); i.hasNext();) {
211: Organization self = (Organization) i.next();
212: logger.info("self org found");
213: UnaryPredicate pred = new GLSPredicate(self,
214: getAgentIdentifier());
215: glsSub = (IncrementalSubscription) blackboard
216: .subscribe(pred);
217: blackboard.unsubscribe(selfOrgSubscription);
218: selfOrgSubscription = null;
219: recordGLS(glsSub);
220: break;
221: }
222: }
223:
224: private void recordGLS(Collection glsRoots) {
225: for (Iterator i = glsRoots.iterator(); i.hasNext();) {
226: PlanElement pe = (PlanElement) i.next();
227: Collection changes = glsSub.getChangeReports(pe);
228: boolean doit = changes == null || changes.isEmpty();
229: if (!doit) {
230: for (Iterator i2 = changes.iterator(); i2.hasNext();) {
231: if (i2.next() instanceof PlanElement.EstimatedResultChangeReport) {
232: doit = true;
233: break;
234: }
235: }
236: }
237: if (doit) {
238: AllocationResult ar = pe.getEstimatedResult();
239: double confidence = ar.getConfidenceRating();
240: Record record = new Record(System.currentTimeMillis(),
241: confidence);
242: logger.info("Adding record " + record);
243: addRecord(record);
244: }
245: }
246: }
247:
248: private synchronized void addRecord(Record newRecord) {
249: records[(record0 + nrecords) % records.length] = newRecord;
250: if (nrecords == records.length) {
251: record0++;
252: } else {
253: nrecords++;
254: }
255: }
256:
257: private synchronized void setRecordsSize(int newSize) {
258: if (newSize > 0 && newSize < 10000) {
259: records = getRecords(newSize);
260: record0 = 0;
261: nrecords = Math.min(nrecords, newSize);
262: }
263: }
264:
265: private Record[] getRecords(int newSize) {
266: int newOffset = 0;
267: int oldOffset = record0;
268: int oldSize = nrecords;
269: if (newSize < oldSize) {
270: int diff = oldSize - newSize;
271: oldOffset += diff;
272: oldSize -= diff;
273: }
274: Record[] newRecords = new Record[newSize];
275: while (oldSize > 0) {
276: int fragSize = records.length - oldOffset;
277: int size = Math.min(fragSize, oldSize);
278: System.arraycopy(records, oldOffset, newRecords, newOffset,
279: size);
280: newOffset += size;
281: newSize -= size;
282: oldOffset = (oldOffset + size) % records.length;
283: oldSize -= size;
284: }
285: return newRecords;
286: }
287:
288: private synchronized Record[] getRecords() {
289: return getRecords(nrecords);
290: }
291:
292: static String[] mimeTypes = { "image/gif", "image/png",
293: "image/jpeg", };
294:
295: private void getGraph(HttpServletResponse response)
296: throws IOException {
297: ImageWriter iw = null;
298: outer: for (int j = 0; j < mimeTypes.length; j++) {
299: String mimeType = mimeTypes[j];
300: for (Iterator i = ImageIO
301: .getImageWritersByMIMEType(mimeType); i.hasNext();) {
302: iw = (ImageWriter) i.next();
303: iw.setOutput(new MemoryCacheImageOutputStream(response
304: .getOutputStream()));
305: response.setContentType(mimeType);
306: break outer;
307: }
308: }
309: if (iw == null)
310: throw new IOException("No ImageWriter found");
311: int width = 600;
312: int height = 100;
313: int M = 10;
314: BufferedImage img = new BufferedImage(width + 2 * M, height + 2
315: * M, BufferedImage.TYPE_INT_RGB);
316: Graphics g = img.createGraphics();
317: long maxTimestamp = System.currentTimeMillis();
318: Record[] records = getRecords();
319: int xp = 0;
320: int yp = 0;
321: g.setColor(Color.lightGray);
322: g.fillRect(0, 0, 10000, 10000);
323: g.setColor(Color.black);
324: g.drawRect(0, 0, width + 2 * M - 1, height + 2 * M - 1);
325: g.setColor(Color.white);
326: g.drawLine(M, M + height - 0, M + width, M + height - 0);
327: for (long t = 0; t + minTimestamp <= maxTimestamp; t += 60000) {
328: long ts = t + minTimestamp;
329: int x = M
330: + (int) ((ts - minTimestamp) * width / (maxTimestamp - minTimestamp));
331: g.drawLine(x, M + height - 0, x, M);
332: }
333: for (int i = 0; i <= records.length; i++) {
334: Record record;
335: long ts;
336: double c;
337: int x;
338: int y;
339: if (i == records.length) {
340: ts = maxTimestamp;
341: c = records[i - 1].getConfidence();
342: } else {
343: record = records[i];
344: ts = record.getTimestamp();
345: c = record.getConfidence();
346: }
347: x = M
348: + (int) ((ts - minTimestamp) * width / (maxTimestamp - minTimestamp));
349: y = M + height - (int) (c * height);
350: if (i > 0) {
351: g.setColor(Color.black);
352: g.drawLine(xp, yp, x, y);
353: }
354: if (i < records.length) {
355: if (c < 0.9) {
356: g.setColor(Color.red);
357: } else if (c < 0.99) {
358: g.setColor(Color.yellow);
359: } else {
360: g.setColor(Color.green);
361: }
362: g.fillOval(x - 3, y - 3, 6, 6);
363: xp = x;
364: yp = y;
365: }
366: }
367: iw.write(img);
368: }
369:
370: private class RootWatcherServlet extends HttpServlet {
371: protected void doGet(HttpServletRequest request,
372: HttpServletResponse response) {
373: try {
374: setRecordsSize(Integer.parseInt(request
375: .getParameter("nrecords")));
376: } catch (Exception e) {
377: }
378: String command = request.getParameter("command");
379: if ("graph".equals(command)) {
380: try {
381: getGraph(response);
382: } catch (IOException ioe) {
383: throw new RuntimeException(ioe.toString());
384: }
385: return;
386: }
387: response.setContentType("text/html");
388: PrintWriter out;
389: try {
390: out = response.getWriter();
391: } catch (IOException ioe) {
392: return; // Quietly ignore the exception (probably closed by client)
393: }
394: String title = "History of GLS Root Task Confidence";
395: out.println("<html>");
396: out.println(" <head>");
397: out.println(" </head>");
398: out.println(" <title>");
399: out.println(title);
400: out.println(" </title>");
401: out.println(" <body>");
402: out.println("<H1>");
403: out.println(title);
404: out.println("</H1>");
405: out.println("<H2>");
406: out.println(nrecords + " records available");
407: out.println("</H2>");
408: out.println(" <img src=\"?command=graph\">");
409: out.println(" <table border=1>");
410: Record[] records = getRecords();
411: for (int i = 0; i < records.length; i++) {
412: Record record = records[i];
413: out.println(" <tr><td>" + record.getTimestampString()
414: + "</td><td align=\"right\">"
415: + record.getConfidenceString() + "</td></tr>");
416: }
417: out.println(" </table>");
418: out.println(" </body>");
419: out.println("</html>");
420: }
421: }
422: }
|