package ibis.ipl.support.management;
import ibis.io.Conversion;
import ibis.ipl.NoSuchPropertyException;
import ibis.ipl.impl.Ibis;
import ibis.ipl.support.Client;
import ibis.ipl.support.Connection;
import ibis.smartsockets.virtual.VirtualServerSocket;
import ibis.smartsockets.virtual.VirtualSocketFactory;
import ibis.util.ThreadPool;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ManagementClient implements Runnable {
private static final Logger logger = LoggerFactory
.getLogger(ManagementClient.class);
private static final int CONNECTION_BACKLOG = 10;
private final VirtualSocketFactory virtualSocketFactory;
private final VirtualServerSocket serverSocket;
private final Ibis ibis;
private boolean ended;
public ManagementClient(Properties properties, Ibis ibis)
throws IOException {
this.ibis = ibis;
String clientID = properties.getProperty(Ibis.ID_PROPERTY);
Client client = Client.getOrCreateClient(clientID, properties, 0);
this.virtualSocketFactory = client.getFactory();
serverSocket = virtualSocketFactory.createServerSocket(
Protocol.VIRTUAL_PORT, CONNECTION_BACKLOG, null);
ThreadPool.createNew(this, "Management Client");
}
private Object getIbisAttribute(String name) throws NoSuchPropertyException {
if (name.equalsIgnoreCase("vivaldi")) {
return ibis.getVivaldiCoordinates();
}
if (name.equalsIgnoreCase("connections")) {
return ibis.connectedTo();
}
if (name.equalsIgnoreCase("outgoingMessageCount")) {
return ibis.getOutgoingMessageCount();
}
if (name.equalsIgnoreCase("bytesWritten")) {
return ibis.getBytesWritten();
}
if (name.equalsIgnoreCase("bytesSent")) {
return ibis.getBytesSent();
}
if (name.equalsIgnoreCase("incomingMessageCount")) {
return ibis.getIncomingMessageCount();
}
if (name.equalsIgnoreCase("bytesRead")) {
return ibis.getBytesRead();
}
if (name.equals("sentBytesPerIbis")) {
return ibis.getSentBytesPerIbis();
}
if (name.equals("receivedBytesPerIbis")) {
return ibis.getReceivedBytesPerIbis();
}
if (name.equals("wonElections")) {
return ibis.wonElections();
}
if (name.equals("senderConnectionTypes")) {
return ibis.getSenderConnectionTypes();
}
if (name.equals("receiverConnectionTypes")) {
return ibis.getReceiverConnectionTypes();
}
return ibis.getManagementProperty(name);
}
private void handleGetMonitorInfo(Connection connection) throws IOException {
int length = connection.in().readInt();
if (length < 0) {
connection.closeWithError("End of stream on reading request");
return;
}
AttributeDescription[] descriptions = new AttributeDescription[length];
for (int i = 0; i < descriptions.length; i++) {
descriptions[i] = new AttributeDescription(connection.in()
.readUTF(), connection.in().readUTF());
}
Object[] result = new Object[descriptions.length];
try {
Class<?> factoryClass = Class
.forName("java.lang.management.ManagementFactory");
Class<?> beanServerClass = Class
.forName("javax.management.MBeanServer");
Class<?> objectNameClass = Class
.forName("javax.management.ObjectName");
Constructor<?> objectNameClassConstructor = objectNameClass
.getConstructor(String.class);
Method getAttributeMethod = beanServerClass.getMethod(
"getAttribute", objectNameClass, String.class);
Object beanServer = factoryClass
.getMethod("getPlatformMBeanServer").invoke(null);
for (int i = 0; i < descriptions.length; i++) {
if (descriptions[i].getBeanName().equals("ibis")) {
result[i] = getIbisAttribute(descriptions[i].getAttribute());
} else {
try {
Object objectName = objectNameClassConstructor
.newInstance(descriptions[i].getBeanName());
result[i] = getAttributeMethod.invoke(beanServer,
objectName, descriptions[i].getAttribute());
} catch (Throwable t) {
logger.error("cannot get value for attribute \""
+ descriptions[i].getAttribute()
+ "\" of bean \""
+ descriptions[i].getBeanName() + "\"");
result[i] = null;
}
}
}
} catch (Throwable t) {
connection.closeWithError("Cannot load JMX: " + t);
return;
}
connection.sendOKReply();
byte[] bytes = Conversion.object2byte(result);
connection.out().writeInt(bytes.length);
connection.out().write(bytes);
connection.out().flush();
connection.close();
}
private synchronized boolean ended() {
return ended;
}
public void run() {
Connection connection = null;
while (!ended()) {
try {
logger.debug("accepting connection");
connection = new Connection(serverSocket);
logger.debug("connection accepted");
} catch (IOException e) {
if (ended) {
return;
} else {
logger.error("Accept failed, waiting a second, will retry",
e);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// IGNORE
}
}
}
try {
byte magic = connection.in().readByte();
if (magic != Protocol.MAGIC_BYTE) {
throw new IOException(
"Invalid header byte in accepting connection");
}
byte opcode = connection.in().readByte();
if (opcode < Protocol.NR_OF_OPCODES) {
logger.debug("received request: "
+ Protocol.OPCODE_NAMES[opcode]);
}
switch (opcode) {
case Protocol.OPCODE_GET_MONITOR_INFO:
handleGetMonitorInfo(connection);
break;
default:
logger.error("unknown opcode in request: " + opcode);
}
logger.debug("done handling request");
} catch (Throwable e) {
logger.error("error on handling request", e);
} finally {
connection.close();
}
}
}
public void end() {
synchronized (this) {
ended = true;
notifyAll();
}
try {
serverSocket.close();
} catch (Exception e) {
// IGNORE
}
try {
virtualSocketFactory.end();
} catch (Exception e) {
// IGNORE
}
}
}