/*
*
* Copyright 2011 Performize-IT LTD.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.performizeit.jmxsupport;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.CompositeData;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class JMXConnection {
String host;
String port;
String userName = "";
String userPassword = "";
JMXServiceURL serviceURL;
private static final String CONNECTOR_ADDRESS =
"com.sun.management.jmxremote.localConnectorAddress";
private String connectURL;
private boolean originalThreadContentionEnabledValue;
public boolean isOriginalThreadContentionEnabledValue() {
return originalThreadContentionEnabledValue;
}
public void setOriginalThreadContentionEnabledValue(boolean originalThreadContentionEnabledValue) {
this.originalThreadContentionEnabledValue = originalThreadContentionEnabledValue;
}
public JMXConnection(String pid) throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException {
addToolsJar();
connectURL = pid;
// attach to the target application
com.sun.tools.attach.VirtualMachine vm =
com.sun.tools.attach.VirtualMachine.attach(pid);
JMXServiceURL u;
try {
// get the connector address
String connectorAddress =
vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
// no connector address, so we start the JMX agent
if (connectorAddress == null) {
String agent = vm.getSystemProperties().getProperty("java.home")
+ File.separator + "lib" + File.separator
+ "management-agent.jar";
vm.loadAgent(agent);
// agent is started, get the connector address
connectorAddress =
vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
}
// establish connection to connector server
// System.out.println(connectorAddress);
serviceURL = new JMXServiceURL(connectorAddress);
} finally {
vm.detach();
}
}
public JMXConnection(String serverUrl, String uName, String passwd) throws MalformedURLException {
userName = uName;
userPassword = passwd;
host = serverUrl;
port = "";
int colonIndex = serverUrl.lastIndexOf(":");
if (colonIndex > 0) {
port = serverUrl.substring(colonIndex + 1);
host = serverUrl.substring(0, colonIndex);
}
connectURL = host + ":" + port;
// System.out.println("[" + host + "] [" + port + "] [" + userName + "] [" + userPassword + "]");
serviceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + serverUrl + "/jmxrmi");
}
MBeanServerConnection server = null;
public String getConnectURL() {
return connectURL;
}
public MBeanServerConnection getServerConnection() throws IOException {
if (server == null) {
Map env = new HashMap();
if (userName != null && userPassword != null && userName.trim().length() > 0) {
String[] creds = {userName, userPassword};
env.put(JMXConnector.CREDENTIALS, creds);
}
JMXConnector conn = JMXConnectorFactory.connect(serviceURL, env);
server = conn.getMBeanServerConnection();
}
return server;
}
public static ObjectName RUNTIME = null;
public static ObjectName GC = null;
public static ObjectName THREADING = null;
static {
try {
RUNTIME = new ObjectName("java.lang:type=Runtime");
GC = new ObjectName("java.lang:type=GarbageCollector,name=*");
THREADING = new ObjectName("java.lang:type=Threading");
} catch (MalformedObjectNameException | NullPointerException ex) {
Logger.getLogger(JMXConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
public long getUptime() {
long l = -1;
try {
l = (Long) getServerConnection().getAttribute(JMXConnection.RUNTIME, "Uptime");
} catch (MBeanException ex) {
Logger.getLogger(JMXConnection.class.getName()).log(Level.SEVERE, null, ex);
} catch (AttributeNotFoundException ex) {
Logger.getLogger(JMXConnection.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstanceNotFoundException ex) {
Logger.getLogger(JMXConnection.class.getName()).log(Level.SEVERE, null, ex);
} catch (ReflectionException ex) {
Logger.getLogger(JMXConnection.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(JMXConnection.class.getName()).log(Level.SEVERE, null, ex);
}
return l;
}
public static float inSecsTimestamp(long ts) {
return ((float) ts) / 1000;
}
boolean isUseAuthentication() {
return !userName.isEmpty();
}
public CompositeData[] getThreads(long[] thIds, int stackTraceEntriesNo) throws Exception {
String[] signature = {"[J", "int"};
Object[] params = {thIds, stackTraceEntriesNo};
CompositeData[] threads = (CompositeData[]) server.invoke(THREADING, "getThreadInfo", params, signature);
return threads;
}
public long[] getThreadsCPU(long[] thIds) throws Exception {
String[] signature = {"[J"};
Object[] params = {thIds};
long[] threadsCPU = (long[]) server.invoke(THREADING, "getThreadCpuTime", params, signature);
return threadsCPU;
}
public long getThreadCPU(long thId) throws Exception {
String[] signature = {"long"};
Object[] params = {thId};
long threadCPU = (Long) server.invoke(THREADING, "getThreadCpuTime", params, signature);
return threadCPU;
}
public long[] getThreadsAllocBytes(long[] thIds) throws Exception {
String[] signature = {"[J"};
Object[] params = {thIds};
long[] threadsAllocBytes = (long[]) server.invoke(THREADING, "getThreadAllocatedBytes", params, signature);
return threadsAllocBytes;
}
private boolean supportAdvFeatures = true;
public boolean isJava16_25andAbove() {
return supportAdvFeatures;
}
public void unsetJava16_25andAbove() {
supportAdvFeatures = false;
}
public static Class addToolsJar() {
try {
return com.sun.tools.attach.VirtualMachine.class;
} catch (Throwable t) {
System.err.println("tools.jar not in class path from" + System.getProperty("java.home"));
File toolsJar = new File(System.getProperty("java.home") + "/lib/tools.jar"); //when jdk
System.err.println("try:" + toolsJar);
if (toolsJar.exists()) {
addURL(toolsJar);
System.err.println(toolsJar);
} else {
toolsJar = new File(System.getProperty("java.home") + "/../lib/tools.jar"); // when jre part of jdk
System.out.println("try:" + toolsJar);
if (toolsJar.exists()) {
addURL(toolsJar);
System.err.println("Found:" + toolsJar);
} else {
System.err.println("Unable to locate tools.jar pls add it to classpath");
}
}
}
return com.sun.tools.attach.VirtualMachine.class;
}
public long[] getThreadIds() throws Exception {
long[] thIds = (long[]) getServerConnection().getAttribute(THREADING, "AllThreadIds");
return thIds;
}
public static void addURL(File file) throws RuntimeException {
try {
URL url = file.toURL();
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class clazz = URLClassLoader.class;
// Use reflection
Method method = clazz.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(classLoader, new Object[]{url});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public long[] getThreadIds(JMXConnection server) throws Exception {
long[] thIds = (long[]) server.getServerConnection().getAttribute(THREADING, "AllThreadIds");
return thIds;
}
}