001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2006 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.awt.BorderLayout;
030: import java.awt.Component;
031: import java.awt.Dimension;
032: import java.awt.Event;
033: import java.awt.Graphics;
034: import java.awt.LayoutManager;
035: import java.applet.Applet;
036: import java.applet.AppletContext;
037: import java.lang.reflect.Method;
038: import java.net.URL;
039: import java.util.ArrayList;
040: import java.util.List;
041: import java.util.Map;
042: import java.util.Properties;
043:
044: import org.cougaar.core.service.AppletService;
045:
046: /**
047: * This component loads a Cougaar {@link Node} as a browser {@link Applet}.
048: * <p>
049: * The server requires an HTML file to load this applet, e.g.:<pre>
050: * <html><body><applet
051: * code=org.cougaar.core.node.NodeApplet.class
052: * archive="lib/bootstrap.jar,lib/util.jar,lib/core.jar,lib/<i>your_code</i>.jar,sys/log4j.jar"
053: * width=400 height=400>
054: * <param name="properties" value="
055: * -Dorg.cougaar.node.name=<i>MyNode</i>
056: * -Dorg.cougaar.society.file=<i>MyNode.xml</i>
057: * "/>
058: * Unable to load Applet.
059: * </applet></body></html>
060: * </pre>
061: * In addition to the above jars, the server directory will also require your
062: * agent XML file (e.g. "MyNode.xml") and the agent template configuration
063: * files:<pre>
064: * configs/common/*.xsl
065: * </pre>
066: */
067: public class NodeApplet extends Applet {
068:
069: private static final String[] REQUIRED_PROPS = new String[] {
070: "properties", "-Dorg.cougaar.society.file",
071: "-Dorg.cougaar.node.name", "-Dorg.xml.sax.driver", };
072:
073: private static final String[] DEFAULT_PROPS = new String[] {
074: // read the node from XML
075: "-Dorg.cougaar.core.node.InitializationComponent=XML",
076: // avoid javaiopatch check in persistence
077: "-Dorg.cougaar.core.persistence.verifyJavaIOPatch=false",
078: // don't set thread name (access denied)
079: "-Dorg.cougaar.core.blackboard.client.setThreadName=false",
080: // local-only wp
081: "-Dorg.cougaar.society.xsl.param.wpserver=singlenode",
082: // local-only mts
083: "-Dorg.cougaar.society.xsl.param.mts=singlenode",
084: // avoid mtsstd jar
085: "-Dorg.cougaar.society.xsl.param.socketFactory=false",
086: // trim the config:
087: "-Dorg.cougaar.society.xsl.param.servlets=false",
088: "-Dorg.cougaar.society.xsl.param.planning=false",
089: "-Dorg.cougaar.society.xsl.param.communities=false",
090: "-Dorg.cougaar.core.load.planning=false",
091: // no "LDMDomains.ini"
092: "-Dorg.cougaar.core.domain.config.enable=false",
093: // TODO sysProps: org.cougaar.core.qos.rss.RSSMetricsUpdateServiceImpl
094: "-Dorg.cougaar.society.xsl.param.metrics=trivial", };
095:
096: // defaults for -Dorg.xml.sax.driver
097: private static final String[] XML_DRIVERS = new String[] {
098: "org.apache.crimson.parser.XMLReaderImpl", // jdk1.4
099: "com.sun.org.apache.xerces.internal.parsers.SAXParser", // jdk1.5
100: };
101:
102: // applet run state
103: private static final int LOADING = 0;
104: private static final int RUNNING = 1;
105: private static final int FAILED = 2;
106: private static final int STOPPED = 3;
107:
108: private final Object state_lock = new Object();
109: private int state = LOADING;
110:
111: // shutdown support
112: private final NodeControlSupport ncs = new NodeControlSupport();
113:
114: public void init() {
115: setLayout(new BorderLayout());
116:
117: // override properties table
118: Properties props;
119: try {
120: props = createProperties();
121: } catch (Exception e) {
122: // probably missing a required property
123: updateState(FAILED, e);
124: return;
125: }
126:
127: // define external services
128: List l = new ArrayList();
129: l.add(new Object[] { "Node.AgentManager.Agent.Component",
130: "HIGH", "org.cougaar.core.node.SetPropertiesComponent",
131: props });
132: l.add(new Object[] { "Node.AgentManager.Agent.Component",
133: "HIGH", "org.cougaar.core.node.GetServiceComponent",
134: "org.cougaar.core.node.NodeControlService", ncs });
135: l.add(new Object[] { "Node.AgentManager.Agent.Component",
136: "HIGH", "org.cougaar.core.node.AddServiceComponent",
137: "org.cougaar.core.service.AppletService",
138: createAppletService(), "true" });
139: final Object[] args = l.toArray();
140:
141: // launch node
142: Runnable r = new Runnable() {
143: public void run() {
144: Throwable t = null;
145: try {
146: Class cl = Class
147: .forName("org.cougaar.core.node.Node");
148: Method m = cl.getMethod("launch",
149: new Class[] { Object[].class });
150: m.invoke(null, new Object[] { args });
151: } catch (Throwable e) {
152: t = new RuntimeException("Unable to start node", e);
153: }
154:
155: updateState((t == null ? RUNNING : FAILED), t);
156: }
157: };
158: (new Thread(r, "Cougaar main")).start();
159: }
160:
161: private Properties createProperties() {
162: Properties ret = new Properties();
163:
164: // tell our node to call "SystemProperties.overrideProperties(..)"
165: // and set the minimal allowed applet -Ds:
166: // java.version, os.name, ..
167: ret.put("override_props", "true");
168: ret.put("finalize_props", "true");
169: ret.put("put_applet_props", "true");
170:
171: // figure out our cip, which is our path minus the basename
172: // e.g. http://x:y/z/file --> http://x:y/z
173: URL url = getCodeBase();
174: String cip = "";
175: if (url.getProtocol() != null)
176: cip += url.getProtocol() + "://";
177: if (url.getHost() != null)
178: cip += url.getHost();
179: if (url.getPort() >= 0)
180: cip += ":" + url.getPort();
181: if (url.getPath() != null) {
182: String s = url.getPath();
183: int i = s.lastIndexOf("/");
184: if (i > 0)
185: s = s.substring(0, i);
186: cip += s;
187: }
188:
189: // required cougaar install path as a URL:
190: ret.put("org.cougaar.install.path", cip);
191: ret.put("user.home", cip);
192: ret.put("user.dir", cip);
193:
194: // config path without $CWD
195: ret.put("org.cougaar.config.path", cip + ";" + cip
196: + "/configs/common");
197:
198: // set default properties
199: putAll(ret, DEFAULT_PROPS);
200:
201: // copy in optional applet params
202: String more_props = getParameter("properties");
203: if (more_props != null) {
204: ret.put("properties", "true");
205: String[] sa = more_props.split(" ");
206: putAll(ret, sa);
207: }
208:
209: // we must explicitly set the xml factory driver, otherwise the XMLFactory
210: // will attempt to call "System.getProperty(..)" and throw an exception
211: if (!ret.containsKey("org.xml.sax.driver")) {
212: for (int i = 0; i < XML_DRIVERS.length; i++) {
213: String s = XML_DRIVERS[i];
214: try {
215: Class c = Class.forName(s);
216: } catch (Exception e) {
217: continue;
218: }
219: ret.put("org.xml.sax.driver", s);
220: break;
221: }
222: }
223:
224: // check for required properties
225: for (int i = 0; i < REQUIRED_PROPS.length; i++) {
226: String s = REQUIRED_PROPS[i];
227: if (s.startsWith("-D"))
228: s = s.substring(2);
229: if (!ret.containsKey(s)) {
230: throw new RuntimeException("Missing parameter: " + s);
231: }
232: }
233:
234: // remove artificial "properties" property
235: ret.remove("properties");
236:
237: return ret;
238: }
239:
240: private static void putAll(Map m, String[] sa) {
241: int n = (sa == null ? 0 : sa.length);
242: for (int i = 0; i < n; i++) {
243: String s = sa[i].trim();
244: int j = s.indexOf('=');
245: if (j <= 0 || j >= s.length() - 1)
246: continue;
247: String name = s.substring(0, j);
248: if (name.startsWith("-D"))
249: name = name.substring(2);
250: String value = s.substring(j + 1);
251: m.put(name, value);
252: }
253: }
254:
255: public void destroy() {
256: updateState(STOPPED, null);
257: ncs.shutdown();
258: }
259:
260: public String getAppletInfo() {
261: return "Cougaar";
262: }
263:
264: private AppletService createAppletService() {
265: // this is a dumb proxy
266: return new AppletService() {
267: public boolean isActive() {
268: return NodeApplet.this .isActive();
269: }
270:
271: public URL getDocumentBase() {
272: return NodeApplet.this .getDocumentBase();
273: }
274:
275: public URL getCodeBase() {
276: return NodeApplet.this .getCodeBase();
277: }
278:
279: public String getParameter(String name) {
280: return NodeApplet.this .getParameter(name);
281: }
282:
283: public void showStatus(String msg) {
284: NodeApplet.this .showStatus(msg);
285: }
286:
287: public void showDocument(URL url, String target) {
288: AppletContext ac = NodeApplet.this .getAppletContext();
289: if (target == null) {
290: ac.showDocument(url);
291: } else {
292: ac.showDocument(url, target);
293: }
294: }
295:
296: public Dimension getSize() {
297: return NodeApplet.this .getSize();
298: }
299:
300: public void setLayout(LayoutManager mgr) {
301: NodeApplet.this .setLayout(mgr);
302: }
303:
304: public Component add(Component comp) {
305: return NodeApplet.this .add(comp);
306: }
307:
308: public Component add(String name, Component comp) {
309: return NodeApplet.this .add(name, comp);
310: }
311:
312: public void override_action(ActionHandler action) {
313: NodeApplet.this .override_action(action);
314: }
315:
316: public void override_paint(PaintHandler paint) {
317: NodeApplet.this .override_paint(paint);
318: }
319: };
320: }
321:
322: private final AppletService.ActionHandler super ActionHandler = new AppletService.ActionHandler() {
323: public boolean action(AppletService.ActionHandler x, Event evt,
324: Object what) {
325: return NodeApplet.super .action(evt, what);
326: }
327: };
328: private AppletService.ActionHandler actionHandler = super ActionHandler;
329:
330: private void updateState(int i, Throwable t) {
331: if (t != null) {
332: t.printStackTrace();
333: }
334: synchronized (state_lock) {
335: state = i;
336: state_lock.notifyAll();
337: repaint();
338: }
339: }
340:
341: private final AppletService.PaintHandler super PaintHandler = new AppletService.PaintHandler() {
342: public void paint(AppletService.PaintHandler x, Graphics g) {
343: NodeApplet.super .paint(g);
344:
345: String msg;
346: synchronized (state_lock) {
347: msg = (state == LOADING ? "Loading Cougaar.."
348: : state == RUNNING ? "Cougaar is Running"
349: : state == STOPPED ? "Stopping Cougaar"
350: : "Failed to start Cougaar (see Java Console)");
351: }
352:
353: g.setFont(new java.awt.Font("System", java.awt.Font.BOLD,
354: 14));
355: Dimension d = getSize();
356: int row = (d == null ? 18 : (int) (d.getHeight() / 2));
357: g.drawString(msg, 10, row);
358: }
359: };
360: private AppletService.PaintHandler paintHandler = super PaintHandler;
361:
362: private void override_action(AppletService.ActionHandler handler) {
363: this .actionHandler = (handler == null ? super ActionHandler
364: : handler);
365: repaint();
366: }
367:
368: private void override_paint(AppletService.PaintHandler handler) {
369: this .paintHandler = (handler == null ? super PaintHandler
370: : handler);
371: }
372:
373: public boolean action(Event evt, Object what) {
374: return actionHandler.action(super ActionHandler, evt, what);
375: }
376:
377: public void paint(Graphics g) {
378: paintHandler.paint(super PaintHandler, g);
379: }
380:
381: public static class NodeControlSupport {
382: private Object svc;
383:
384: public void setService(Class cl, Object svc) {
385: this .svc = svc;
386: }
387:
388: public void shutdown() {
389: if (svc != null) {
390: try {
391: Class cl = svc.getClass();
392: Method m = cl.getMethod("shutdown", (Class[]) null);
393: m.invoke(svc, (Object[]) null);
394: } catch (Exception e) {
395: e.printStackTrace();
396: }
397: }
398: svc = null;
399: }
400: }
401: }
|