001: /*
002: * <copyright>
003: *
004: * Copyright 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.node;
028:
029: import java.io.IOException;
030: import java.io.PrintWriter;
031: import java.net.URLDecoder;
032: import java.util.Date;
033:
034: import javax.servlet.http.HttpServletRequest;
035: import javax.servlet.http.HttpServletResponse;
036:
037: import org.cougaar.core.mts.MessageAddress;
038: import org.cougaar.core.service.AgentQuiescenceStateService;
039: import org.cougaar.core.service.LoggingService;
040: import org.cougaar.core.servlet.ComponentServlet;
041:
042: /**
043: * This component is a {@link javax.servlet.Servlet} that displays
044: * the agents registered with the node's {@link
045: * AgentQuiescenceStateService}, and allow an agent to be marked as
046: * "dead" (for use when the agent has been restarted elsewhere and
047: * the original instance should be ignored).
048: * <p>
049: * Address it at /agentQuiescenceState
050: * <p>
051: * Load it into every Node at BINDER or lower priority, using the
052: * insertion point
053: * <code>Node.AgentManager.Agent.PluginManager.Servlet</code>
054: */
055: public class QuiescenceStateServlet extends ComponentServlet {
056: private LoggingService log = null;
057: private AgentQuiescenceStateService aqs = null;
058: private String node = null;
059:
060: protected String getPath() {
061: return "/agentQuiescenceState";
062: }
063:
064: public void load() {
065: log = (LoggingService) serviceBroker.getService(this ,
066: LoggingService.class, null);
067: aqs = (AgentQuiescenceStateService) serviceBroker.getService(
068: this , AgentQuiescenceStateService.class, null);
069: super .load();
070: }
071:
072: public void setLoggingService(LoggingService log) {
073: this .log = log;
074: }
075:
076: public void setAgentQuiescenceStateService(
077: AgentQuiescenceStateService aqs) {
078: this .aqs = aqs;
079: }
080:
081: public void setNodeIdentificationService(
082: NodeIdentificationService nis) {
083: if (nis != null)
084: node = nis.getMessageAddress().toString();
085: }
086:
087: public void unload() {
088: super .unload();
089: // release logger, aqs
090: if (aqs != null) {
091: serviceBroker.releaseService(this ,
092: AgentQuiescenceStateService.class, aqs);
093: aqs = null;
094: }
095:
096: if (log != null) {
097: serviceBroker.releaseService(this , LoggingService.class,
098: log);
099: log = null;
100: }
101: }
102:
103: public void doGet(HttpServletRequest sreq, HttpServletResponse sres)
104: throws IOException {
105: // create a new handler per request, so we don't mangle our
106: // per-request variables
107: MyHandler h = new MyHandler(log, aqs, node);
108: h.execute(sreq, sres);
109: }
110:
111: public void doPut(HttpServletRequest sreq, HttpServletResponse sres)
112: throws IOException {
113: // create a new handler per request, so we don't mangle our
114: // per-request variables
115: MyHandler h = new MyHandler(log, aqs, node);
116: h.execute(sreq, sres);
117: }
118:
119: // The servlet should throw up a table of Agents, Dead, Enabled, Quiescent, MarkDead (a button)
120: // It needs both an HTML and an XML format for easy ACME use
121:
122: private static class MyHandler {
123:
124: private final LoggingService log;
125: private final AgentQuiescenceStateService aqs;
126: private HttpServletRequest sreq;
127: private PrintWriter out;
128:
129: private static final String HTML_FORMAT = "HTML";
130: private static final String XML_FORMAT = "XML";
131: private String format = HTML_FORMAT;
132: private MessageAddress[] agents; // List of Nodes agents
133: private String nodeName; // local node
134: private MessageAddress agentToKill = null; // agent to mark as dead
135:
136: public MyHandler(LoggingService log,
137: AgentQuiescenceStateService aqs, String node) {
138: this .log = log;
139: this .aqs = aqs;
140: this .nodeName = node;
141: agents = aqs.listAgentsRegistered();
142: if (log != null && log.isDebugEnabled()) {
143: log
144: .debug(nodeName
145: + ".QStateServlet invoked. Got list of agents of length "
146: + agents.length);
147: }
148: }
149:
150: public void execute(HttpServletRequest sreq,
151: HttpServletResponse sres) throws IOException
152: //, ServletException
153: {
154: this .sreq = sreq;
155: parseParams();
156: if (format == XML_FORMAT) {
157: // Print XML header
158: sres.setContentType("text/xml");
159: this .out = sres.getWriter();
160: out.println("<?xml version='1.0'?>");
161:
162: performXMLRequest();
163: } else {
164: // Doing HTML page
165: this .out = sres.getWriter();
166: printHeader();
167: performRequest();
168: printForm();
169: printFooter();
170: }
171: this .out.flush();
172: }
173:
174: // Get parameters from the URI
175: private void parseParams() {
176: String form = paramSingle("format");
177:
178: // Only use the specified format if it is XML.
179: // Else use default (HTML)
180: if (XML_FORMAT.equalsIgnoreCase(form))
181: format = XML_FORMAT;
182:
183: String deadAgent = paramSingle("dead");
184: if (deadAgent != null)
185: agentToKill = MessageAddress
186: .getMessageAddress(deadAgent);
187: else
188: agentToKill = null;
189: if (log != null && log.isDebugEnabled()) {
190: log.debug(nodeName
191: + ".QStateServlet parsed params: format="
192: + format + ", deadAgent= " + deadAgent);
193: }
194: }
195:
196: // Header of the HTML page
197: private void printHeader() {
198: long now = System.currentTimeMillis();
199: out.println("<html>\n"
200: + "<head>\n"
201: + "<title>Quiescence State</title>\n"
202: + "</head>\n"
203: + "<body>"
204: + "<h2>Agents registered with "
205: + nodeName
206: + "'s Quiescence Service</h2>"
207: + "<p>\n"
208: + "Node "
209: + nodeName
210: + " is now <b>"
211: + (aqs.isNodeQuiescent() ? "Quiescent"
212: : "NOT Quiescent") + "</b><p>\n"
213: + "Time: " + now + " (" + (new Date(now))
214: + ")<p>\n");
215: }
216:
217: // HTML form for query generation, status display
218: private void printForm() {
219: // FIXME: Support multiple agent names via checkboxes or some such
220: out
221: .println("<table border=1>\n"
222: + "<form name=\"f\" method=\"GET\" action=\""
223: + sreq.getRequestURI()
224: + "\">\n"
225: + "<tr><th>Agent</th><th>Quiescent?</th><th>Blockers</th><th>Enabled?</th><th>Dead?</th><th>Mark as Dead</th></tr>\n");
226: // loop over Message addresses
227: for (int i = 0; i < agents.length; i++) {
228: printRowHTML(agents[i]);
229: }
230: out.println("</form>\n</table>\n");
231: }
232:
233: // Show status / button for one agent
234: private void printRowHTML(MessageAddress agent) {
235: out.println("<tr><td>"
236: + agent
237: + "</td>"
238: + getColumn(aqs.isAgentQuiescent(agent), true)
239: + "<td>"
240: + aqs.getAgentQuiescenceBlockers(agent)
241: + "</td>"
242: + getColumn(aqs.isAgentEnabled(agent), true)
243: + getColumn(!aqs.isAgentAlive(agent), false)
244: + "<td>"
245: + (aqs.isAgentAlive(agent) ? getButton(agent)
246: : "Already Dead") + "</td></tr>\n");
247: }
248:
249: // Show status / button for one agent
250: private void printRowXML(MessageAddress agent) {
251: out.println(" <agent name=\'"
252: + agent
253: + "\' quiescent=\'"
254: + aqs.isAgentQuiescent(agent)
255: + "\' "
256: + "enabled=\'"
257: + aqs.isAgentEnabled(agent)
258: + "\' "
259: + "dead=\'"
260: + !aqs.isAgentAlive(agent)
261: + "\'"
262: + (aqs.isAgentQuiescent(agent) ? "" : "blockers=\'"
263: + aqs.getAgentQuiescenceBlockers(agent)
264: + "\'") + "/>");
265: }
266:
267: // Color-coded boolean column
268: private String getColumn(boolean value, boolean greenValue) {
269: return "<td bgcolor=\""
270: + (value == greenValue ? "80FF80" : "FF8080")
271: + "\">" + value + "</td>";
272: }
273:
274: // Print a button to mark an agent as dead
275: private String getButton(MessageAddress agent) {
276: return "<input type=\"submit\" name=\"dead\" value=\""
277: + agent.toString() + "\">";
278: }
279:
280: // Print bottom of the HTML page
281: private void printFooter() {
282: out.println("</body></html>");
283: }
284:
285: // Do the actual action
286: private void performRequest() {
287: if (agentToKill == null)
288: return;
289: if (aqs == null)
290: return;
291: if (log != null && log.isDebugEnabled()) {
292: log.debug(nodeName + ".QStateServlet killing agent "
293: + agentToKill);
294: }
295: aqs.setAgentDead(agentToKill);
296: }
297:
298: private void performXMLRequest() {
299: performRequest();
300: out.println("<node name=\"" + nodeName + "\" quiescent=\'"
301: + aqs.isNodeQuiescent() + "\'>");
302: // loop over Message addresses
303: for (int i = 0; i < agents.length; i++) {
304: printRowXML(agents[i]);
305: }
306: out.println("</node>\n");
307: }
308:
309: // Parse a single-valued parameter (decoding it if necc.)
310: private String paramSingle(String n) {
311: String s = sreq.getParameter(n);
312: if (s == null || s.trim().length() == 0) {
313: s = null;
314: } else {
315: try {
316: s = URLDecoder.decode(s, "UTF-8");
317: } catch (Exception e) {
318: // should never happen, utf-8 is standard.
319: s = null;
320: }
321: }
322:
323: return s;
324: }
325: } // end of MyHandler
326: }
|