package blade.cli.jmx;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class JMXLocalConnector {
protected MBeanServerConnection mBeanServerConnection;
public JMXLocalConnector() {
}
public JMXLocalConnector(String objectName, String type) {
this(getLocalConnectorAddress(objectName, type));
}
public JMXLocalConnector(String serviceURL) {
try {
final JMXServiceURL jmxServiceUrl = new JMXServiceURL(serviceURL);
final JMXConnector jmxConnector = JMXConnectorFactory.connect(
jmxServiceUrl, null);
mBeanServerConnection = jmxConnector.getMBeanServerConnection();
} catch (Exception e) {
throw new IllegalArgumentException(
"Unable to get JMX connection", e);
}
}
static ObjectName getMBean(String objectNameVal, String type, MBeanServerConnection mBeanServerConnection)
throws IOException, MalformedObjectNameException {
final ObjectName objectName = new ObjectName(
objectNameVal + ":type=" + type + ",*");
final Set<ObjectName> objectNames = mBeanServerConnection.queryNames(
objectName, null);
if (objectNames != null && objectNames.size() > 0) {
return objectNames.iterator().next();
}
return null;
}
/**
* Uses Oracle JDK's Attach API to try to search VMs on this machine looking
* for the osgi.core MBeans. This will stop searching for VMs once the
* MBeans are found. Beware if you have multiple JVMs with osgi.core MBeans
* published.
* @param type2
* @param objectName2
*
* @return
*/
@SuppressWarnings("unchecked")
static String getLocalConnectorAddress(String objectName, String type) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
ClassLoader toolsClassloader = null;
try {
toolsClassloader = getToolsClassLoader(cl);
if (toolsClassloader != null) {
Thread.currentThread().setContextClassLoader(toolsClassloader);
Class< ? > vmClass = toolsClassloader.loadClass(
"com.sun.tools.attach.VirtualMachine");
Method listMethod = vmClass.getMethod("list");
List<Object> vmds = (List<Object>)listMethod.invoke(null);
for (Object vmd : vmds) {
try {
Class< ? > vmdClass = toolsClassloader
.loadClass(
"com.sun.tools.attach.VirtualMachineDescriptor");
Method idMethod = vmdClass.getMethod("id");
String id = (String)idMethod.invoke(vmd);
Method attachMethod = vmClass.getMethod(
"attach", String.class);
Object vm = attachMethod.invoke(null, id);
try {
Method getAgentPropertiesMethod = vmClass.getMethod(
"getAgentProperties");
Properties agentProperties =
(Properties)getAgentPropertiesMethod.invoke(vm);
String localConnectorAddress = agentProperties
.getProperty(
"com.sun.management.jmxremote.localConnectorAddress");
if (localConnectorAddress == null) {
File agentJar = findJdkJar(
"management-agent.jar");
if (agentJar != null) {
Method loadAgent = vmClass.getMethod(
"loadAgent", String.class);
loadAgent.invoke(
vm, agentJar.getCanonicalPath());
agentProperties =
(Properties)getAgentPropertiesMethod.invoke(vm);
localConnectorAddress = agentProperties
.getProperty(
"com.sun.management.jmxremote.localConnectorAddress");
}
}
if (localConnectorAddress != null) {
final JMXServiceURL jmxServiceUrl =
new JMXServiceURL(localConnectorAddress);
final JMXConnector jmxConnector =
JMXConnectorFactory.connect(
jmxServiceUrl, null);
final MBeanServerConnection mBeanServerConnection = jmxConnector
.getMBeanServerConnection();
if (mBeanServerConnection != null) {
final ObjectName framework = getMBean(
objectName, type,
mBeanServerConnection);
if (framework != null) {
return localConnectorAddress;
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
Method detachMethod = vmClass.getMethod("detach");
detachMethod.invoke(vm);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
Thread.currentThread().setContextClassLoader(cl);
// try to get custom classloader to unload native libs
try {
if (toolsClassloader != null) {
Field nl = ClassLoader.class.getDeclaredField(
"nativeLibraries");
nl.setAccessible(true);
Vector< ? > nativeLibs = (Vector< ? >)nl.get(
toolsClassloader);
for (Object nativeLib : nativeLibs) {
Field nameField =
nativeLib.getClass().getDeclaredField("name");
nameField.setAccessible(true);
String name = (String)nameField.get(nativeLib);
if (new File(name).getName().contains("attach")) {
Method f =
nativeLib.getClass().getDeclaredMethod("finalize");
f.setAccessible(true);
f.invoke(nativeLib);
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
private static ClassLoader getToolsClassLoader(ClassLoader parent)
throws IOException {
File toolsJar = findJdkJar("tools.jar");
if (toolsJar != null && toolsJar.exists()) {
URL toolsUrl = null;
try {
toolsUrl = toolsJar.toURI().toURL();
}
catch (MalformedURLException e) {
//
}
URL[] urls = new URL[] {toolsUrl};
return new URLClassLoader(urls, parent);
}
return null;
}
static File findJdkJar(String jar) throws IOException {
File retval = null;
final String jarPath = File.separator + "lib" + File.separator + jar;
final String javaHome = System.getProperty("java.home");
File jarFile = new File(javaHome + jarPath);
if (jarFile.exists()) {
retval = jarFile;
} else {
jarFile = new File(javaHome + "/.." + jarPath);
if (jarFile.exists()) {
retval = jarFile.getCanonicalFile();
}
}
return retval;
}
}