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: package org.cougaar.tools.csmart.ui.console;
027:
028: import org.cougaar.tools.csmart.experiment.XMLExperiment;
029: import org.cougaar.tools.csmart.ui.viewer.CSMART;
030: import org.cougaar.tools.server.ProcessDescription;
031: import org.cougaar.tools.server.RemoteFileSystem;
032: import org.cougaar.tools.server.RemoteHost;
033: import org.cougaar.tools.server.RemoteListenable;
034: import org.cougaar.tools.server.RemoteListenableConfig;
035: import org.cougaar.tools.server.RemoteProcess;
036: import org.cougaar.util.log.Logger;
037:
038: import javax.swing.*;
039: import java.io.BufferedOutputStream;
040: import java.io.FileReader;
041: import java.io.OutputStream;
042:
043: /**
044: * org.cougaar.tools.csmart.ui.console
045: *
046: */
047: public class CreateNodeThread extends Thread {
048:
049: /** In milliseconds **/
050: private static final int KILL_PAUSE_TIME = 2000;
051:
052: /** Number of times to attempt to connect before giving up. **/
053: private static final int CONNECTION_RETRIES = 5;
054:
055: private Logger log = CSMART.createLogger(this .getClass().getName());
056: private CSMARTConsoleModel cmodel;
057: private NodeModel model;
058: RemoteProcess remoteNode = null;
059: private boolean attach = false; // true to attach to a running node
060:
061: public CreateNodeThread(CSMARTConsoleModel cmodel, NodeModel model) {
062: this .cmodel = cmodel;
063: this .model = model;
064: }
065:
066: /**
067: * Set to make run method attach to a node, rather than run a node.
068: */
069: public void setAttach(boolean attach) {
070: this .attach = attach;
071: }
072:
073: /**
074: * Start a node or attach to a node.
075: * If fail, add the node to the list of failed nodes in the model.
076: * If successful, add the node to the list of running nodes in the model.
077: */
078: public void run() {
079: String errorMsg = null;
080: if (attach)
081: errorMsg = attachToNode();
082: else
083: errorMsg = createNode();
084: String node = model.getInfo().getNodeName();
085: if (errorMsg != null) {
086: String host = model.getInfo().getHostName();
087: JOptionPane.showMessageDialog(null, "Cannot create node "
088: + node + " on: " + host + "; " + errorMsg);
089: if (attach)
090: cmodel.removeNodeModel(node);
091: else
092: model.setState(NodeModel.STATE_INITTED);
093: } else {
094: model.setState(NodeModel.STATE_RUNNING);
095: cmodel.createGUI(node);
096: }
097: }
098:
099: /**
100: * Create a node by calling the appserver.
101: * Does RMI, so may block on the network.
102: * Returns an error message if there's an exception; else returns null.
103: */
104: private String createNode() {
105: // Create the process description, then the proccess
106: String name = model.getInfo().getNodeName();
107: ProcessDescription desc = new ProcessDescription(name,
108: "csmart", model.getInfo().getProperties(), model
109: .getInfo().getArgs());
110: RemoteListenableConfig conf = new RemoteListenableConfig(model
111: .getListener(), CSMART.getNodeListenerId(), null, model
112: .getOutputPolicy());
113:
114: if (cmodel.getExperiment() instanceof XMLExperiment) {
115: try {
116: RemoteHost rh = model.getInfo().getAppServer();
117: RemoteFileSystem rfs = rh.getRemoteFileSystem();
118: String filename = ((XMLExperiment) cmodel
119: .getExperiment()).getSocietyFileName();
120:
121: OutputStream os = rfs.write("./" + filename);
122: BufferedOutputStream bos = new BufferedOutputStream(os);
123: FileReader in = new FileReader(cmodel.getXMLFile());
124: int c;
125: while ((c = in.read()) != -1) {
126: bos.write(c);
127: }
128: in.close();
129: bos.flush();
130: bos.close();
131: } catch (Exception e) {
132: e.printStackTrace();
133: }
134:
135: }
136:
137: try {
138: // Next line does the actual creation -- including RMI stuff that could take a while
139: remoteNode = model.getInfo().getAppServer()
140: .createRemoteProcess(desc, conf);
141:
142: if (log.isDebugEnabled()) {
143: log.debug("Adding listener: "
144: + CSMART.getNodeListenerId() + " for: " + name);
145: }
146: return null; // no errors
147: } catch (IllegalArgumentException iae) {
148: if (log.isErrorEnabled()) {
149: log.error("Cannot create node: "
150: + model.getInfo().getNodeName(), iae);
151: }
152: return iae.toString();
153: } catch (RuntimeException re) {
154: if (log.isWarnEnabled()) {
155: log.warn("Cannot create node: "
156: + model.getInfo().getNodeName()
157: + " Retrying with different name.");
158: }
159: try {
160: name = model.getInfo().getNodeName() + "-2";
161: desc = new ProcessDescription(name, "csmart", model
162: .getInfo().getProperties(), model.getInfo()
163: .getArgs());
164:
165: remoteNode = model.getInfo().getAppServer()
166: .createRemoteProcess(desc, conf);
167: if (log.isDebugEnabled()) {
168: log.debug("Adding listener: "
169: + CSMART.getNodeListenerId() + " for: "
170: + name);
171: }
172: return null; // no errors.
173: } catch (Exception e) {
174: if (log.isErrorEnabled()) {
175: log.error("Cannot create node with new name: "
176: + model.getInfo().getNodeName(), e);
177: return e.toString();
178: }
179: }
180: } catch (Exception e) {
181: if (log.isErrorEnabled()) {
182: log.error("Cannot create node: "
183: + model.getInfo().getNodeName(), e);
184: }
185: return e.toString();
186: }
187: return null; // no errors
188: }
189:
190: /**
191: * Destroy the node.
192: * Tries to kill the node 5 times, in case the remote machine or network is busy.
193: * Note that this is a different thread from above!
194: */
195: public void killNode() {
196: Thread nodeDestroyer = new Thread("DestroyNode"
197: + model.getInfo().getNodeName()) {
198:
199: public void run() {
200: // Try to kill the node. Try up to 5 times for now.
201: RemoteListenable rl = null;
202: for (int retries = CONNECTION_RETRIES; retries > 0; retries--) {
203: try {
204: rl = remoteNode.getRemoteListenable();
205: if (rl != null) {
206: rl.flushOutput();
207: remoteNode.destroy();
208: return;
209: }
210: } catch (Exception ex) {
211: if (rl != null) {
212: // Got the RemoteListenable, but couldn't destroy it
213: if (log.isWarnEnabled()) {
214: log.warn("Unable to destroy node "
215: + model.getNodeName()
216: + ", assuming it's dead: ", ex);
217: }
218: continue;
219: }
220: } // end of catch block
221: if (log.isWarnEnabled()) {
222: log.warn("Never got RemoteListenable for node "
223: + model.getNodeName());
224: }
225: try {
226: sleep(KILL_PAUSE_TIME);
227: } catch (InterruptedException ie) {
228: // Ignore this exception, it is not critical.
229: }
230: } // end loop trying to kill node
231: // call the method that would have been called if the node stopped
232: model.stopped();
233: }
234: };
235: nodeDestroyer.start();
236: } // end killNode
237:
238: /**
239: * Just attach listener to node.
240: * Returns an error message if there's an exception; else returns null.
241: */
242: private String attachToNode() {
243: remoteNode = null;
244: String nodeName = model.getNodeName();
245: String id = CSMART.getNodeListenerId();
246: try {
247: remoteNode = model.getInfo().getAppServer()
248: .getRemoteProcess(nodeName);
249: if (remoteNode != null) {
250: RemoteListenable rl = remoteNode.getRemoteListenable();
251: if (log.isDebugEnabled())
252: log.debug("Adding listener: " + id + " for: "
253: + nodeName);
254: rl.addListener(model.getListener(), id);
255: return null; // no errors
256: } else {
257: if (log.isWarnEnabled())
258: log
259: .warn("Got null process from AppServer for node to attach to: "
260: + nodeName);
261: throw new Exception("Null RemoteProcess for "
262: + nodeName);
263: }
264: } catch (Exception e) {
265: if (log.isErrorEnabled()) {
266: log.error("Exception attaching to: " + nodeName, e);
267: }
268: return e.toString();
269: }
270: }
271:
272: }
|