/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.sql.test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Closeable; import java.io.IOException; import java.lang.management.ManagementFactory; import java.net.MalformedURLException; import javax.management.Attribute; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; /** Provides a JMX interface to the server in the test framework */ public class JMXInterpreter implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(JMXInterpreter.class); public JMXServiceURL serviceURL; private JmxAdapter adapter; void ensureConnection(String host, int port) { if(adapter == null) { adapter = new RemoteJmxAdapter(host, port); if(!adapter.tryOpen()) { LOG.debug("Couldn't connect to remote JMX adapter: {}", adapter.describeConnection()); adapter = new LocalJmxAdapter(); if(!adapter.tryOpen()) { LOG.debug("Couldn't connect to local JMX adapter: {}", adapter.describeConnection()); } } } } @Override public void close() { try { if(adapter != null) { adapter.close(); } } catch(IOException e) { LOG.debug("Caught closing adapter", e); } } public JmxAdapter getAdapter() { return adapter; } public Object makeBeanCall(String host, int port, String objectName, String method, Object[] parameters, String callType) throws Exception { ensureConnection(host, port); if(adapter == null) { throw new Exception("Can't connect"); } MBeanServerConnection mbs = adapter.getConnection(); ObjectName mxbeanName = new ObjectName(objectName); MBeanInfo info = mbs.getMBeanInfo(mxbeanName); String[] signature = null; if(callType.equalsIgnoreCase("method")) { for(MBeanOperationInfo op : info.getOperations()) { if(method.equalsIgnoreCase(op.getDescription())) { signature = new String[op.getSignature().length]; for(int a = 0; a < op.getSignature().length; a++) { signature[a] = op.getSignature()[a].getType(); } break; } } } Object data = null; if(callType.equalsIgnoreCase("method")) { data = mbs.invoke(mxbeanName, method, parameters, signature); } else if(callType.equalsIgnoreCase("get")) { data = mbs.getAttribute(mxbeanName, method); } else { Attribute attr = null; for(int x = 0; x < info.getAttributes().length; x++) { if(method.equalsIgnoreCase(info.getAttributes()[x].getName())) { if(info.getAttributes()[x].getType().equalsIgnoreCase(double.class.getName())) { attr = new Attribute(method, new Double(String.valueOf(parameters[0]))); } else if(info.getAttributes()[x].getType().equalsIgnoreCase(long.class.getName())) { attr = new Attribute(method, new Long(String.valueOf(parameters[0]))); } else if(info.getAttributes()[x].getType().equalsIgnoreCase(int.class.getName())) { attr = new Attribute(method, new Integer(String.valueOf(parameters[0]))); } else if(info.getAttributes()[x].getType().equalsIgnoreCase(String.class.getName())) { attr = new Attribute(method, String.valueOf(parameters[0])); } else if(info.getAttributes()[x].getType().equalsIgnoreCase(Boolean.class.getName())) { attr = new Attribute(method, Boolean.valueOf(String.valueOf(parameters[0]))); } else { throw new Exception("Unknown Attribute type found as " + info.getAttributes()[x].getType()); } break; } } mbs.setAttribute(mxbeanName, attr); } return data; } public interface JmxAdapter extends Closeable { boolean tryOpen(); String describeConnection(); MBeanServerConnection getConnection(); } private static class RemoteJmxAdapter implements JmxAdapter { @Override public boolean tryOpen() { JMXServiceURL serviceUrl; //service:jmx:rmi:///jndi/rmi://localhost:8082/jmxrmi try { serviceUrl = new JMXServiceURL(urlString); } catch(MalformedURLException e) { LOG.warn("Caught opening URL: {}", urlString, e); return false; } try { connector = JMXConnectorFactory.connect(serviceUrl); connection = connector.getMBeanServerConnection(); } catch(IOException e) { LOG.warn("Error connecting to URL: {}", serviceUrl, e); return false; } assert connection != null; return true; } @Override public MBeanServerConnection getConnection() { if(connection == null) { throw new IllegalStateException("not connected: " + describeConnection()); } return connection; } @Override public String describeConnection() { return urlString; } @Override public void close() throws IOException { connector.close(); } public RemoteJmxAdapter(String host, int port) { urlString = "service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi"; } private final String urlString; private JMXConnector connector; private MBeanServerConnection connection; } private static class LocalJmxAdapter implements JmxAdapter { @Override public boolean tryOpen() { return true; } @Override public String describeConnection() { return "local VM connection"; } @Override public MBeanServerConnection getConnection() { return ManagementFactory.getPlatformMBeanServer(); } @Override public void close() { // nothing to do } } }