/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.component;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.opengamma.util.ReflectionUtils;
import com.opengamma.util.StartupUtils;
/**
* A monitor that allows the Component-based server to be shutdown remotely.
*/
public final class OpenGammaComponentServerMonitor extends Thread {
private static final Logger s_logger = LoggerFactory.getLogger(ComponentManager.class);
private static final String SECRET_PROPERTY = "commandmonitor.secret";
private static final String PORT_PROPERTY = "commandmonitor.port";
private static final int DEFAULT_PORT = 8079;
private static final int COMMAND_LENGTH = 256;
static {
StartupUtils.init();
}
private ComponentRepository _repo;
private String _secret;
private DatagramSocket _socket;
/**
* Creates an instance.
*
* @param repo the repository, not null
* @param secret the secret phrase, not null
* @param port the port number
*/
private OpenGammaComponentServerMonitor(ComponentRepository repo, String secret, int port) {
_repo = repo;
_secret = secret;
setDaemon(true);
setName("OpenGammaComponentServerMonitor");
try {
_socket = new DatagramSocket(port, InetAddress.getByName("127.0.0.1"));
} catch (Exception e) {
s_logger.warn("Failed to create listening socket, monitor will not be available");
return;
}
}
/**
* Listens to the socket and stops the server when commanded.
*/
@Override
public void run() {
while (true) {
byte[] buffer = new byte[COMMAND_LENGTH];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
_socket.receive(packet);
} catch (IOException ex) {
s_logger.warn("Error while receiving command packet");
continue;
}
String received = new String(packet.getData(), 0, packet.getLength());
if (received.matches("secret:" + _secret + "\\s+command:\\w+\\s*") == false) {
s_logger.debug("Malformed command or wrong secret");
continue;
}
String command = received.replaceAll("secret:" + _secret + "\\s+command:(\\w+)\\s*", "$1");
s_logger.debug("Received command \"{}\"", command);
if (command.equals("stop")) {
handleStop();
} else if (command.equals("exit")) {
handleExit();
} else {
s_logger.debug("Unknown command \"{}\"", command);
}
}
}
private boolean isReady() {
return _socket != null;
}
private void handleStop() {
if (_repo.isRunning()) {
_repo.stop();
}
}
private void handleExit() {
handleStop();
System.exit(0);
}
//-------------------------------------------------------------------------
/**
* Creates the monitor based on a {@link ComponentRepository}.
*
* @param repo the repository, not null
*/
public static void create(ComponentRepository repo) {
String secret = System.getProperty(SECRET_PROPERTY);
if (secret != null) {
String port = System.getProperty(PORT_PROPERTY, Integer.toString(DEFAULT_PORT));
create(repo, secret, Integer.parseInt(port));
}
}
/**
* Creates the monitor based on a {@link ComponentRepository}.
*
* @param repo the repository, not null
* @param secret the secret phrase, not null
* @param port the port number
*/
public static void create(ComponentRepository repo, String secret, int port) {
OpenGammaComponentServerMonitor monitor = new OpenGammaComponentServerMonitor(repo, secret, port);
if (monitor.isReady()) {
monitor.start();
}
}
//-------------------------------------------------------------------------
/**
* Main method acting as a client of the monitor.
* <p>
* A single argument may be passed, either "stop" or "exit".
* The default is "exit" (which is a hard stop).
*
* @param args the arguments
* @throws Exception if an error occurs
*/
public static void main(String[] args) throws Exception { // CSIGNORE
InetAddress address = InetAddress.getByName("127.0.0.1");
String secret = System.getProperty(SECRET_PROPERTY);
if (secret == null) {
System.out.println("Secret must be specified on the command line using " + SECRET_PROPERTY);
System.exit(1);
}
String port = System.getProperty(PORT_PROPERTY, Integer.toString(DEFAULT_PORT));
String command = (args.length == 1) ? args[0] : "exit";
String toSend = "secret:" + secret + " command:" + command + "\n";
byte[] sBuffer = toSend.getBytes();
System.out.println("Sending \"" + command + "\" to server.");
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
DatagramPacket packet = new DatagramPacket(sBuffer, sBuffer.length, address, Integer.parseInt(port));
socket.send(packet);
} catch (Exception e) {
if (socket != null) {
ReflectionUtils.invokeNoArgsNoException(socket, "close");
}
System.out.println("Send failed...");
System.exit(1);
}
System.exit(0);
}
}