001: /*
002: * <copyright>
003: *
004: * Copyright 2000-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.tools.csmart.ui.console;
028:
029: import org.cougaar.tools.csmart.ui.viewer.CSMART;
030: import org.cougaar.tools.server.ProcessDescription;
031: import org.cougaar.tools.server.RemoteHost;
032: import org.cougaar.tools.server.RemoteHostRegistry;
033: import org.cougaar.tools.server.RemoteListenable;
034: import org.cougaar.tools.server.RemoteProcess;
035: import org.cougaar.util.log.Logger;
036:
037: import javax.swing.*;
038: import java.util.ArrayList;
039: import java.util.Iterator;
040: import java.util.List;
041: import java.util.Observable;
042: import java.util.Observer;
043:
044: /**
045: * Support for communications with the AppServer (Application Server)
046: * that handles starting and stopping nodes and directing node output
047: * to listeners.
048: */
049: public class AppServerSupport implements Observer {
050: private RemoteHostRegistry remoteHostRegistry;
051: private CSMARTConsoleModel model;
052: private transient Logger log;
053:
054: public AppServerSupport(CSMARTConsoleModel model) {
055: createLogger();
056: remoteHostRegistry = RemoteHostRegistry.getInstance();
057: this .model = model;
058: model.addObserver(this );
059: }
060:
061: private void createLogger() {
062: log = CSMART.createLogger(this .getClass().getName());
063: }
064:
065: /**
066: * Kill all running processes on all known AppServers.
067: */
068: public void killAllProcesses() {
069: refreshAppServers();
070: ArrayList appServers = model.getAppServers();
071: for (int i = 0; i < appServers.size(); i++) {
072: AppServerDesc desc = (AppServerDesc) appServers.get(i);
073: RemoteHost appServer = desc.appServer;
074: List nodes = getNodesOfAppServer(appServer);
075: if (nodes == null)
076: continue;
077: for (Iterator j = nodes.iterator(); j.hasNext();) {
078: ProcessDescription pd = (ProcessDescription) j.next();
079: String name = pd.getName();
080: try {
081: RemoteProcess node = appServer
082: .getRemoteProcess(name);
083: if (node != null) {
084: try {
085: node.getRemoteListenable().flushOutput();
086: } catch (Exception e) {
087: if (log.isWarnEnabled()) {
088: log.warn(
089: "killAllProceses: Exception flushing output for "
090: + name, e);
091: }
092: }
093: if (log.isDebugEnabled()) {
094: log.debug("About to kill process " + name);
095: }
096: node.destroy();
097: } else {
098: if (log.isWarnEnabled())
099: log
100: .warn("killAllProcesses: couldn't get remote process "
101: + name);
102: }
103: } catch (Exception e) {
104: if (log.isErrorEnabled()) {
105: log.error("Exception killing process for "
106: + name + ": ", e);
107: }
108: }
109: }
110: }
111: }
112:
113: /**
114: * Get the list of attached nodes and kill their listeners.
115: * Used when detaching from a running society.
116: */
117: public void killListeners() {
118: refreshAppServers();
119: ArrayList nodes = model.getAttachedNodes();
120: String myListener = CSMART.getNodeListenerId();
121: for (int i = 0; i < nodes.size(); i++) {
122: String name = (String) nodes.get(i);
123: AppServerDesc desc = model.getAppServer(name);
124: RemoteHost appServer = desc.appServer;
125: RemoteListenable rl = findListener(appServer, name);
126: if (rl == null)
127: continue;
128: if (log.isDebugEnabled()) {
129: log.debug("Killing node listener for node: " + name);
130: }
131: try {
132: rl.flushOutput();
133: } catch (Exception e) {
134: if (log.isErrorEnabled()) {
135: log.error(
136: "killListener: Exception flushing output for "
137: + name + ": ", e);
138: }
139: }
140: try {
141: rl.removeListener(myListener);
142: } catch (Exception e) {
143: if (log.isErrorEnabled()) {
144: log.error(
145: "killListener: Exception killing listener for "
146: + name + ": ", e);
147: }
148: }
149: }
150: }
151:
152: /**
153: * Add or refresh app servers.
154: */
155: public void update(Observable o, Object arg) {
156: if (arg instanceof AppServerRequest) {
157: AppServerRequest request = (AppServerRequest) arg;
158: if (request.action == AppServerRequest.ADD)
159: add(request.hostName, request.port);
160: } else if (arg instanceof String) {
161: if (((String) arg).equals(model.APP_SERVERS_REFRESH))
162: refreshAppServers();
163: }
164: }
165:
166: /**
167: * Attempt to contact an app server on the host and port.
168: * If successful, get a list of the nodes on that app server
169: * and update the model's node-to-app server mapping.
170: */
171: public void add(String hostName, int port) {
172: // first, make sure that we can contact this app server
173: RemoteHost appServer = contactAppServer(hostName, port);
174: if (appServer == null)
175: return;
176: AppServerDesc desc = new AppServerDesc(appServer, hostName,
177: port);
178: model.addAppServer(desc);
179: // next, add new nodes if any
180: addNewNodes(desc);
181: }
182:
183: /**
184: * Contact the app server on the host and port.
185: * If successful, return a reference to the app server;
186: * else return null.
187: */
188: private RemoteHost contactAppServer(String hostName, int port) {
189: RemoteHost appServer = null;
190: try {
191: // Third argument is whether AppServer should be verbose
192: // -- it will print to STDOUT in the CSMART window
193: appServer = remoteHostRegistry.lookupRemoteHost(hostName,
194: port, false);
195: } catch (Exception e) {
196: if (log.isErrorEnabled()) {
197: log.error("Unable to contact app-server on " + hostName
198: + ":" + port, e);
199: }
200: final String myHost = hostName;
201: final int myPort = port;
202: SwingUtilities.invokeLater(new Runnable() {
203: public void run() {
204: JOptionPane.showMessageDialog(null,
205: "Unable to contact app-server on " + myHost
206: + ":" + myPort
207: + "; check that server is running");
208: }
209: });
210: return null;
211: }
212: return appServer;
213: }
214:
215: /**
216: * Get list of nodes that this app server knows about.
217: * Returns list of ProcessDescriptions.
218: */
219: private List getNodesOfAppServer(RemoteHost appServer) {
220: List nodes = null;
221: try {
222: nodes = appServer.listProcessDescriptions();
223: } catch (Exception e) {
224: if (log.isErrorEnabled()) {
225: log
226: .error(
227: "Exception getting info from app server: ",
228: e);
229: }
230: return null;
231: }
232: return nodes;
233: }
234:
235: /**
236: * After contacting a new app server,
237: * update the node to app server mapping.
238: */
239: private void addNewNodes(AppServerDesc appServerDesc) {
240: RemoteHost appServer = appServerDesc.appServer;
241: List nodes = getNodesOfAppServer(appServer);
242: if (nodes != null) {
243: for (Iterator j = nodes.iterator(); j.hasNext();) {
244: ProcessDescription pd = (ProcessDescription) j.next();
245: String name = pd.getName();
246: if (log.isDebugEnabled()) {
247: log.debug("Adding app server for: " + name + " "
248: + appServerDesc);
249: }
250: model.addNodeToAppServerMapping(name, appServerDesc);
251: }
252: }
253: }
254:
255: /**
256: * Updates both the App Servers and the nodes they control.
257: */
258: public void refreshAppServers() {
259: ArrayList appServerDescs = model.getAppServers();
260: for (int i = 0; i < appServerDescs.size(); i++) {
261: AppServerDesc appServerDesc = (AppServerDesc) appServerDescs
262: .get(i);
263: try {
264: RemoteHost appServer = remoteHostRegistry
265: .lookupRemoteHost(appServerDesc.hostName,
266: appServerDesc.port, false);
267: } catch (Exception e) {
268: if (log.isErrorEnabled()) {
269: log.error("Exception contacting app server: ", e);
270: }
271: // remove app server that isn't responding
272: model.appServerDelete(appServerDesc);
273: continue;
274: }
275: List nodes = null;
276: try {
277: nodes = appServerDesc.appServer
278: .listProcessDescriptions();
279: } catch (Exception e) {
280: if (log.isErrorEnabled()) {
281: log.error(
282: "Exception getting info from app server: ",
283: e);
284: }
285: // remove app server that isn't responding
286: model.appServerDelete(appServerDesc);
287: continue;
288: }
289: if (nodes != null) {
290: for (Iterator j = nodes.iterator(); j.hasNext();) {
291: ProcessDescription pd = (ProcessDescription) j
292: .next();
293: String name = pd.getName();
294: AppServerDesc asd = model.getAppServer(name);
295: if (asd == null) {
296: // add app server mapping for newly discovered nodes
297: if (log.isDebugEnabled()) {
298: log.debug("Adding app server for: " + name
299: + " " + appServerDesc);
300: }
301: model.addNodeToAppServerMapping(name,
302: appServerDesc);
303: }
304: }
305: }
306: }
307: }
308:
309: /**
310: * Get the nodes for each app server. If CSMART isn't listening
311: * on the node, then return it as an unattached node.
312: * Returns an array of Strings (node names).
313: */
314: public ArrayList getUnattachedNodes() {
315: ArrayList unattachedNodes = new ArrayList();
316: ArrayList appServers = model.getAppServers();
317: for (int i = 0; i < appServers.size(); i++) {
318: AppServerDesc appServerDesc = (AppServerDesc) appServers
319: .get(i);
320: List nodes = getNodesOfAppServer(appServerDesc.appServer);
321: if (nodes != null) {
322: for (Iterator j = nodes.iterator(); j.hasNext();) {
323: ProcessDescription pd = (ProcessDescription) j
324: .next();
325: String name = pd.getName();
326: if (findListener(appServerDesc.appServer, name) == null)
327: unattachedNodes.add(name);
328: }
329: }
330: }
331: return unattachedNodes;
332: }
333:
334: /**
335: * Returns listener if it finds a listener on the node
336: * that this instance of CSMART created.
337: */
338: private RemoteListenable findListener(RemoteHost appServer,
339: String name) {
340: try {
341: RemoteProcess node = appServer.getRemoteProcess(name);
342: if (node != null) {
343: RemoteListenable rl = node.getRemoteListenable();
344: List listenerNames = rl.list();
345: for (int j = 0; j < listenerNames.size(); j++) {
346: String s = (String) listenerNames.get(j);
347: if (s.equals(CSMART.getNodeListenerId()))
348: return rl;
349: }
350: } else {
351: if (log.isWarnEnabled())
352: log
353: .warn("findListener got null RemoteProcess from appServer for node "
354: + name);
355: }
356: } catch (Exception e) {
357: if (log.isErrorEnabled()) {
358: log.error(
359: "Exception searching for CSMART listeners on process "
360: + name, e);
361: }
362: }
363: return null;
364: }
365: }
|