Use the JMX VirtualMachine Management API in tools.jar to find the JMS connector URL instead of the private sun APIs.

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1147154 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Timothy A. Bish 2011-07-15 13:56:24 +00:00
parent 8e61f519df
commit 2cce056eb4

View File

@ -19,7 +19,6 @@ package org.apache.activemq.console.command;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
@ -27,29 +26,29 @@ import java.net.URLClassLoader;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Properties;
import javax.management.MBeanServerConnection; import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL; import javax.management.remote.JMXServiceURL;
import sun.management.ConnectorAddressLink;
public abstract class AbstractJmxCommand extends AbstractCommand { public abstract class AbstractJmxCommand extends AbstractCommand {
public static String DEFAULT_JMX_URL; public static String DEFAULT_JMX_URL;
private static String jmxUser; private static String jmxUser;
private static String jmxPassword; private static String jmxPassword;
private static final String CONNECTOR_ADDRESS =
"com.sun.management.jmxremote.localConnectorAddress";
private JMXServiceURL jmxServiceUrl; private JMXServiceURL jmxServiceUrl;
private boolean jmxUseLocal; private boolean jmxUseLocal;
private JMXConnector jmxConnector; private JMXConnector jmxConnector;
private MBeanServerConnection jmxConnection; private MBeanServerConnection jmxConnection;
static { static {
DEFAULT_JMX_URL = System.getProperty("activemq.jmx.url", "service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"); DEFAULT_JMX_URL = System.getProperty("activemq.jmx.url", "service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
jmxUser = System.getProperty("activemq.jmx.user"); jmxUser = System.getProperty("activemq.jmx.user");
jmxPassword = System.getProperty("activemq.jmx.password"); jmxPassword = System.getProperty("activemq.jmx.password");
} }
/** /**
@ -59,13 +58,70 @@ public abstract class AbstractJmxCommand extends AbstractCommand {
protected JMXServiceURL getJmxServiceUrl() { protected JMXServiceURL getJmxServiceUrl() {
return jmxServiceUrl; return jmxServiceUrl;
} }
public static String getJVM() {
return System.getProperty("java.vm.specification.vendor");
}
public static boolean isSunJVM() { public static String getJVM() {
return getJVM().equals("Sun Microsystems Inc."); return System.getProperty("java.vm.specification.vendor");
}
public static boolean isSunJVM() {
return getJVM().equals("Sun Microsystems Inc.");
}
/**
* Finds the JMX Url for a VM by its process id
*
* @param pid
* The process id value of the VM to search for.
*
* @return the JMX Url of the VM with the given pid or null if not found.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected String findJMXUrlByProcessId(int pid) {
if (isSunJVM()) {
try {
// Classes are all dynamically loaded, since they are specific to Sun VM
// if it fails for any reason default jmx url will be used
// tools.jar are not always included used by default class loader, so we
// will try to use custom loader that will try to load tools.jar
String javaHome = System.getProperty("java.home");
String tools = javaHome + File.separator +
".." + File.separator + "lib" + File.separator + "tools.jar";
URLClassLoader loader = new URLClassLoader(new URL[]{new File(tools).toURI().toURL()});
Class virtualMachine = Class.forName("com.sun.tools.attach.VirtualMachine", true, loader);
Class virtualMachineDescriptor = Class.forName("com.sun.tools.attach.VirtualMachineDescriptor", true, loader);
Method getVMList = virtualMachine.getMethod("list", (Class[])null);
Method attachToVM = virtualMachine.getMethod("attach", String.class);
Method getAgentProperties = virtualMachine.getMethod("getAgentProperties", (Class[])null);
Method getVMId = virtualMachineDescriptor.getMethod("id", (Class[])null);
List allVMs = (List)getVMList.invoke(null, (Object[])null);
for(Object vmInstance : allVMs) {
String id = (String)getVMId.invoke(vmInstance, (Object[])null);
if (id.equals(Integer.toString(pid))) {
Object vm = attachToVM.invoke(null, id);
Properties agentProperties = (Properties)getAgentProperties.invoke(vm, (Object[])null);
String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS);
if (connectorAddress != null) {
return connectorAddress;
} else {
break;
}
}
}
} catch (Exception ignore) {
}
}
return null;
} }
/** /**
@ -73,59 +129,61 @@ public abstract class AbstractJmxCommand extends AbstractCommand {
* @return JMX service url * @return JMX service url
* @throws MalformedURLException * @throws MalformedURLException
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" })
protected JMXServiceURL useJmxServiceUrl() throws MalformedURLException { protected JMXServiceURL useJmxServiceUrl() throws MalformedURLException {
if (getJmxServiceUrl() == null) { if (getJmxServiceUrl() == null) {
String jmxUrl = DEFAULT_JMX_URL; String jmxUrl = DEFAULT_JMX_URL;
int connectingPid = -1; int connectingPid = -1;
if (isSunJVM()) { if (isSunJVM()) {
try { try {
// Try to attach to the local process
// Classes are all dynamically loaded, since they are specific to Sun VM // Classes are all dynamically loaded, since they are specific to Sun VM
// if it fails for any reason default jmx url will be used // if it fails for any reason default jmx url will be used
// tools.jar are not always included used by default class loader, so we
// tools.jar are not always included used by default // will try to use custom loader that will try to load tools.jar
// class loader, so we will try to use custom loader that will
// try to load tools.jar
String javaHome = System.getProperty("java.home"); String javaHome = System.getProperty("java.home");
String tools = javaHome + File.separator + String tools = javaHome + File.separator +
".." + File.separator + "lib" + File.separator + "tools.jar"; ".." + File.separator + "lib" + File.separator + "tools.jar";
URLClassLoader loader = new URLClassLoader(new URL[]{new File(tools).toURI().toURL()}); URLClassLoader loader = new URLClassLoader(new URL[]{new File(tools).toURI().toURL()});
// load all classes dynamically so we can compile on non-Sun VMs Class virtualMachine = Class.forName("com.sun.tools.attach.VirtualMachine", true, loader);
Class virtualMachineDescriptor = Class.forName("com.sun.tools.attach.VirtualMachineDescriptor", true, loader);
//MonitoredHost host = MonitoredHost.getMonitoredHost(new HostIdentifier((String)null));
Class monitoredHostClass = Class.forName("sun.jvmstat.monitor.MonitoredHost", true, loader); Method getVMList = virtualMachine.getMethod("list", (Class[])null);
Method getMonitoredHostMethod = monitoredHostClass.getMethod("getMonitoredHost", String.class); Method attachToVM = virtualMachine.getMethod("attach", String.class);
Object host = getMonitoredHostMethod.invoke(null, (String)null); Method getAgentProperties = virtualMachine.getMethod("getAgentProperties", (Class[])null);
//Set vms = host.activeVms(); Method getVMDescriptor = virtualMachineDescriptor.getMethod("displayName", (Class[])null);
Method activeVmsMethod = host.getClass().getMethod("activeVms", null); Method getVMId = virtualMachineDescriptor.getMethod("id", (Class[])null);
Set vms = (Set)activeVmsMethod.invoke(host, null);
for (Object vmid: vms) { List allVMs = (List)getVMList.invoke(null, (Object[])null);
int pid = ((Integer) vmid).intValue();
//MonitoredVm mvm = host.getMonitoredVm(new VmIdentifier(vmid.toString())); for(Object vmInstance : allVMs) {
Class vmIdentifierClass = Class.forName("sun.jvmstat.monitor.VmIdentifier", true, loader); String displayName = (String)getVMDescriptor.invoke(vmInstance, (Object[])null);
Constructor vmIdentifierConstructor = vmIdentifierClass.getConstructor(String.class); if (displayName.contains("run.jar start")) {
Object vmIdentifier = vmIdentifierConstructor.newInstance(vmid.toString()); String id = (String)getVMId.invoke(vmInstance, (Object[])null);
Method getMonitoredVmMethod = host.getClass().getMethod("getMonitoredVm", vmIdentifierClass);
Object mvm = getMonitoredVmMethod.invoke(host, vmIdentifier); Object vm = attachToVM.invoke(null, id);
//String name = MonitoredVmUtil.commandLine(mvm);
Class monitoredVmUtilClass = Class.forName("sun.jvmstat.monitor.MonitoredVmUtil", true, loader); Properties agentProperties = (Properties)getAgentProperties.invoke(vm, (Object[])null);
Method commandLineMethod = monitoredVmUtilClass.getMethod("commandLine", Class.forName("sun.jvmstat.monitor.MonitoredVm", true, loader)); String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS);
String name = (String)commandLineMethod.invoke(null, mvm);
if (name.contains("run.jar start")) { if (connectorAddress != null) {
connectingPid = pid; jmxUrl = connectorAddress;
jmxUrl = ConnectorAddressLink.importFrom(pid); connectingPid = Integer.parseInt(id);
break; context.print("useJmxServiceUrl Found JMS Url: " + jmxUrl);
break;
}
} }
} }
} catch (Exception ignore) {} } catch (Exception ignore) {
}
} }
if (connectingPid != -1) { if (connectingPid != -1) {
context.print("Connecting to pid: " + connectingPid); context.print("Connecting to pid: " + connectingPid);
} else { } else {
context.print("Connecting to JMX URL: " + jmxUrl); context.print("Connecting to JMX URL: " + jmxUrl);
} }
setJmxServiceUrl(jmxUrl); setJmxServiceUrl(jmxUrl);
} }
@ -160,10 +218,10 @@ public abstract class AbstractJmxCommand extends AbstractCommand {
/** /**
* Sets the JMS user name to use * Sets the JMS user name to use
* @param jmxUser - the jmx * @param jmxUser - the jmx
*/ */
public void setJmxUser(String jmxUser) { public void setJmxUser(String jmxUser) {
this.jmxUser = jmxUser; AbstractJmxCommand.jmxUser = jmxUser;
} }
/** /**
@ -179,7 +237,7 @@ public abstract class AbstractJmxCommand extends AbstractCommand {
* @param jmxPassword - the password used for JMX authentication * @param jmxPassword - the password used for JMX authentication
*/ */
public void setJmxPassword(String jmxPassword) { public void setJmxPassword(String jmxPassword) {
this.jmxPassword = jmxPassword; AbstractJmxCommand.jmxPassword = jmxPassword;
} }
/** /**
@ -282,7 +340,7 @@ public abstract class AbstractJmxCommand extends AbstractCommand {
int pid = Integer.parseInt(tokens.remove(0)); int pid = Integer.parseInt(tokens.remove(0));
context.print("Connecting to pid: " + pid); context.print("Connecting to pid: " + pid);
String jmxUrl = ConnectorAddressLink.importFrom(pid); String jmxUrl = findJMXUrlByProcessId(pid);
// If jmx url already specified // If jmx url already specified
if (getJmxServiceUrl() != null) { if (getJmxServiceUrl() != null) {
context.printException(new IllegalArgumentException("JMX URL already specified.")); context.printException(new IllegalArgumentException("JMX URL already specified."));