|
Embedded or Stand-alone
Listing 4. The ApplicationMonitorClient object should be consumed by applications written in Java. Applications written in other languages should use its stand-alone functionality. package Client;
import Server.*;
import java.net.*;
import java.io.*;
import java.util.*;
import Util.*;
import javax.xml.parsers.
ParserConfigurationException;
import org.xml.sax.SAXException;
/**
* The ApplicationMonitorClient is used to
* communicate with the ApplicationMonitorServer.
* It performs the task of registration as well
* as sending messages and receiving commands.
*/
public class ApplicationMonitorClient extends
Thread implements ApplicationMonitorInterface
{
private DataOutputStream dataOutput;
// The output stream of the socket connected to
// the ApplicationMonitorServer
private DataInputStream dataInput;
// The input stream of the socket connected to
// the ApplicationMonitorServer
private Socket socket;
// The TCP socket connected to the
// ApplicationMonitorServer
private String appName;
// The name of the application being registered
private String args[];
// The command-line arguments used to launch
// the client application
private Vector msgBuffer = new Vector();
// Buffer used to store messages to be sent to
// the ApplicationMonitorServer
private SendMsgThread sendMsgThread;
// The thread to send messages to the
// ApplicationMonitorServer
private int restartCount;
// Number of automatic restarts assigned to the
// client
private Process currentProcess = null;
// The process spawned
private boolean external = false;
// TRUE ApplicationMonitorClient runs an
// external process, FALSE it embedded within a
// process
// Message serverity constants
public final static String WARNING = "WARNING";
public final static String ERROR = "ERROR";
public final static String INFO = "INFO";
// Default version constant
public final static String VERSION = "NONE";
// Default: multiple instances are allowed on
// any Host on the network.
private int numberOfInstances = ANYNUMBER;
// Default: the version is set to NONE
private String version = VERSION;
/**
* Constructor. Used to launch a given process
* and register it with the
* ApplicationMonitorServer. The output stream
* of the spawned process is captured and sent
* as INFO messages to the
* ApplicationMonitorServer
*/
public ApplicationMonitorClient(
String _appName, int _numberOfInstances,
String _version, int _autoRestartCount,
String _args[], String _pingArgs[],
boolean _external) throws IOException,
InterruptedException
{
this(_appName, _pingArgs, _numberOfInstances,
_version, _autoRestartCount, _external);
// Spawn the requested process
Runtime appSpawn = Runtime.getRuntime();
currentProcess = appSpawn.exec(_args);
// Capture the spawned process's standard
// output and error streams
InputStream in =
currentProcess.getInputStream();
InputStream err =
currentProcess.getErrorStream();
ProcessExternalStream outputStream =
new ProcessExternalStream(in, this);
ProcessExternalStream errorStream =
new ProcessExternalStream(err, this);
outputStream.start();
errorStream.start();
// Wait for the spawn process to complete.
// This prevents the ApplicationMonitorClient
// for exiting.
currentProcess.waitFor();
}
/**
* Constructs an ApplicationMonitorClient
* instance. Application specific sets are
* stored, a thread to send messages to the
* ApplicationMonitorServer is created and
* started, and a thread to register and receive
* ApplicationMonitorServer commands is started.
*/
public ApplicationMonitorClient(
String _appName, String _args[],
int _numberOfInstances, String _version,
int _restartCount, boolean _external)
{
appName = _appName;
args = _args;
numberOfInstances = _numberOfInstances;
version = _version;
restartCount = _restartCount;
external = _external;
// Create and start the thread that sends
// messages to the ApplicationMonitorServer
sendMsgThread = new SendMsgThread(msgBuffer);
sendMsgThread.start();
// Start the thread that registers and
// receives ApplicationMonitorServer commands
start();
}
/**
* Thread that registers and receives
* ApplicationMonitorServer commands
*/
public void run()
{
createConnection();
}
/**
* Connect to the ApplicationMonitorServer given
* the System property defined host and port
* 3500. Once a successful connection is
* established the client is registered, and
* starts listening for ApplicationMonitorServer
* commands.
*/
public void createConnection()
{
String host = null;
while(true)
{
try
{
File applicationMonitorPropertiesFile =
new File(System.getProperty(
"ApplicationMonitor.PropertyFile",
"c:\\temp\\ApplicationMonitorProperties.ini"));
Properties applicationMonitorProperties =
new Properties();
applicationMonitorProperties.setProperty(
"ApplicationMonitor.
ApplicationMonitorServerHost",
"localhost");
if (
applicationMonitorPropertiesFile.
exists())
{
FileInputStream fileInput = null;
try
{
fileInput = new FileInputStream(
applicationMonitorPropertiesFile);
applicationMonitorProperties.load(
fileInput);
}
catch(IOException ex)
{
}
finally
{
if (fileInput != null)
try { fileInput.close(); }
catch(Exception ex) { }
}
}
host =
applicationMonitorProperties.getProperty(
"ApplicationMonitor.
ApplicationMonitorServerHost");
socket = new Socket(host, 3500);
dataOutput = new DataOutputStream(
socket.getOutputStream());
dataInput = new DataInputStream(
socket.getInputStream());
break;
}
catch(IOException ex)
{
System.out.println(
"Error Connecting to Adminstrator: " +
ex);
dataOutput = null;
dataInput = null;
}
try { Thread.sleep(1000); } catch(
Exception ex) { }
}
// Register with the ApplicationMonitorServer
register();
sendMsgThread.setDataOutput(dataOutput);
// Wait for ApplicationMonitorServer commands
readCommands();
}
/**
* Register the remote application with the
* AppliationMonitorServer
*/
public void register()
{
try
{
// Create a <Register> XML
XMLMessageUtil registerMessage =
new XMLMessageUtil("Register");
registerMessage.add("AppName", appName);
registerMessage.add("Host",
InetAddress.getLocalHost().
getHostAddress());
registerMessage.add("Version", version);
registerMessage.add("InstancesAllowed",
String.valueOf(numberOfInstances));
registerMessage.add("RestartCount",
String.valueOf(restartCount));
// If external is TRUE then the
// ApplicationMonitorClient is serving as a
// wrapper otherwise the java executable
// and CLASSPATH are included within the
// parameter XML specification.
if (external)
registerMessage.add("ParameterNumber",
String.valueOf(args.length+3));
else
registerMessage.add("ParameterNumber",
String.valueOf(args.length+4));
String javaHome = System.getProperty(
"java.home");
if (javaHome !=
null && javaHome.length() > 0)
{
String fileSeparator =
System.getProperty("file.separator");
registerMessage.add("ARG0", javaHome +
fileSeparator + "bin" + fileSeparator +
"java");
}
else
registerMessage.add("ARG0", "java");
int argCount = 1;
if (System.getProperty("java.class.path") !=
null && System.getProperty(
"java.class.path").length() > 0)
{
registerMessage.add("ARG1", "-classpath");
registerMessage.add("ARG2",
System.getProperty("java.class.path"));
argCount = 3;
}
int argStart = 0;
if (external)
{
registerMessage.add("ARG" + argCount,
args[0]);
argStart = 1;
}
else
registerMessage.add("ARG" + argCount,
appName);
for (int i=argStart; i<args.length; i++)
{
argCount++;
registerMessage.add("ARG" + argCount,
args[i]);
}
registerMessage.send(dataOutput);
registerMessage = null;
}
catch(IOException ex)
{
System.out.println("Error Registering: " +
ex);
try { socket.close(); } catch(
Exception ex2) { }
createConnection();
}
catch(ParserConfigurationException ex)
{
System.out.println(
"Error Creating Registration Message: " +
ex);
}
}
/**
* Adds a message and serverity to the message
* buffer for later processing by the
* SendMsgThread object
*/
public void sendMessage(String _severity,
String _msg)
{
synchronized(msgBuffer)
{
msgBuffer.add(new MsgOb(_severity, _msg));
}
}
/**
* Read XML commands from the
* ApplicationMonitorServer. Currently the only
* command processed is the KILL command.
*/
public void readCommands()
{
try
{
while(true)
{
try
{
// Wait forever util a
// ApplicationMonitorServer command is
// received
XMLMessageUtil commandMessage =
new XMLMessageUtil(dataInput);
if (
commandMessage.getRootNodeName().
equals("Command"))
{
String action = null;
try
{
action =
commandMessage.getValue("Action");
if (action == null)
continue;
}
catch(Exception ex)
{
continue;
}
if (action.equals("KILL"))
{
// If the command is "KILL", kill
// the spawned process (if one
// exists) and exit.
if (currentProcess != null)
currentProcess.destroy();
System.exit(0);
}
}
}
catch(ParserConfigurationException ex)
{
System.out.println(
"Error Parsing Incoming XML Command: " +
ex);
}
catch(SAXException ex)
{
System.out.println(
"Error Parsing Incoming XML Command: " +
ex);
}
}
}
catch(IOException ex)
{
System.out.println(
"Adminstrator has disconnected: " + ex);
}
// If we are here then the socket connected
// to the ApplicationMonitorServer
// disconnected. The connection attempted to
// be re-established.
try { socket.close(); } catch(
Exception ex) { }
createConnection();
}
/**
* Before we exit, terminate spawned processes
* if it exits
*/
protected void finalize() throws Throwable {
super.finalize();
if (currentProcess != null)
currentProcess.destroy();
}
/**
* Main method is used to launch an external
* application for the purpose of registering
* and controlling via the
* ApplicationMonitorServer@param args[0]
* The name of the application to be stored in
* the ApplicationMonitorServer's registry
* @param args[1] The version of the application
* @param args[2] The number of application
* instances allowed (ANYNUMBER | ONEPERHOST |
* ONEPERNETWORK)
* @param args[3] The number of auto restarts
* allowed (Use 0 for none, > 0 for auto
* restarts)
* @param args[4] ... args[n] The command-line
* arguments required to launch the external
* application
*/
public static void main(String args[])
{
try
{
if (args.length < 5)
{
System.out.println(
"Incorrect Arguments: Usage");
System.out.println(
"args[0] - The name of the application
to be stored in the
ApplicationMonitorServer's registry");
System.out.println(
"args[1] - The version of the
application");
System.out.println(
"args[2] - The number of application
instances allowed (ANYNUMBER |
ONEPERHOST | ONEPERNETWORK)");
System.out.println(
"args[3] - The number of auto restarts
allowed");
System.out.println(
"args[4] ... args[n] The command-line
arguments required to launch the
external application");
System.exit(0);
}
int numberOfInstances = ANYNUMBER;
if (args[2].equalsIgnoreCase("ANYNUMBER"))
numberOfInstances = ANYNUMBER;
else if (args[2].equalsIgnoreCase(
"ONEPERHOST"))
numberOfInstances = ONEPERHOST;
else if (args[2].equalsIgnoreCase(
"ONEPERNETWORK"))
numberOfInstances = ONEPERNETWORK;
else
{
System.out.println(
"Number Of Instances Unknown: " +
numberOfInstances);
System.exit(0);
}
String clientArgs[] =
new String[args.length+1];
clientArgs[0] =
"Client.ApplicationMonitorClient";
// Store arguments needed to restart this
// application from the
// ApplicationMonitorServer
System.arraycopy(args, 0, clientArgs, 1,
args.length);
// Store arguments needed to exec the
// external application
String launchArgs[] =
new String[args.length - 4];
System.arraycopy(args, 4, launchArgs, 0,
args.length-4);
ApplicationMonitorClient client =
new ApplicationMonitorClient(args[0],
numberOfInstances, args[1],
Integer.parseInt(args[3]), launchArgs,
clientArgs, true);
}
catch(Exception ex)
{
System.out.println(
"Error Starting ApplicationMonitorClient
Wrapped Executable: " + ex);
}
}
}
|