/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.visualvm.jvm;
import com.sun.tools.visualvm.application.Application;
import com.sun.tools.visualvm.application.jvm.MonitoredData;
import com.sun.tools.visualvm.core.datasupport.DataRemovedListener;
import com.sun.tools.visualvm.core.options.GlobalPreferences;
import com.sun.tools.visualvm.tools.jmx.JmxModel;
import com.sun.tools.visualvm.tools.jmx.JmxModel.ConnectionState;
import com.sun.tools.visualvm.tools.jmx.JmxModelFactory;
import com.sun.tools.visualvm.tools.jmx.JvmMXBeans;
import com.sun.tools.visualvm.tools.jmx.JvmMXBeansFactory;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Collection;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.openide.util.NbBundle;
/**
*
* @author Tomas Hurka
*/
public class JmxSupport implements DataRemovedListener {
private final static Logger LOGGER = Logger.getLogger(JmxSupport.class.getName());
private static final String PROCESS_CPU_TIME_ATTR = "ProcessCpuTime"; // NOI18N
private static final String PROCESSING_CAPACITY_ATTR = "ProcessingCapacity"; // NOI18N
private static final String PERM_GEN = "Perm Gen"; // NOI18N
private static final String PS_PERM_GEN = "PS Perm Gen"; // NOI18N
private static final String CMS_PERM_GEN = "CMS Perm Gen"; // NOI18N
private static final String G1_PERM_GEN = "G1 Perm Gen"; // NOI18N
private static final String METASPACE = "Metaspace"; // NOI18N
private static final String IBM_PERM_GEN = "class storage"; // NOI18N
private static final ObjectName osName = getOSName();
private static long INITIAL_DELAY = 100;
private Application application;
private JvmMXBeans mxbeans;
private JVMImpl jvm;
private Object processCPUTimeAttributeLock = new Object();
private Boolean processCPUTimeAttribute;
private long processCPUTimeMultiplier;
private Timer timer;
private MemoryPoolMXBean permGenPool;
private Collection<GarbageCollectorMXBean> gcList;
private String[] genName;
JmxSupport(Application app, JVMImpl vm) {
jvm = vm;
application = app;
app.notifyWhenRemoved(this);
}
RuntimeMXBean getRuntime() {
JvmMXBeans jmx = getJvmMXBeans();
if (jmx != null) {
return jmx.getRuntimeMXBean();
}
return null;
}
boolean hasProcessCPUTimeAttribute() {
synchronized (processCPUTimeAttributeLock) {
if (processCPUTimeAttribute != null) {
return processCPUTimeAttribute.booleanValue();
}
processCPUTimeAttribute = Boolean.FALSE;
JmxModel jmx = JmxModelFactory.getJmxModelFor(application);
if (jmx != null && jmx.getConnectionState().equals(ConnectionState.CONNECTED)) {
MBeanServerConnection conn = jmx.getMBeanServerConnection();
if (conn != null) {
try {
MBeanInfo info = conn.getMBeanInfo(osName);
MBeanAttributeInfo[] attrs = info.getAttributes();
processCPUTimeMultiplier = 1;
for (MBeanAttributeInfo attr : attrs) {
String name = attr.getName();
if (PROCESS_CPU_TIME_ATTR.equals(name)) {
processCPUTimeAttribute = Boolean.TRUE;
}
if (PROCESSING_CAPACITY_ATTR.equals(name)) {
Number mul = (Number) conn.getAttribute(osName,PROCESSING_CAPACITY_ATTR);
processCPUTimeMultiplier = mul.longValue();
}
}
} catch (Exception ex) {
LOGGER.throwing(JmxSupport.class.getName(), "hasProcessCPUTimeAttribute", ex); // NOI18N
}
}
}
return processCPUTimeAttribute.booleanValue();
}
}
long getProcessCPUTime() {
if (!hasProcessCPUTimeAttribute()) {
throw new UnsupportedOperationException();
}
JmxModel jmx = JmxModelFactory.getJmxModelFor(application);
if (jmx != null && jmx.getConnectionState().equals(ConnectionState.CONNECTED)) {
MBeanServerConnection conn = jmx.getMBeanServerConnection();
if (conn != null) {
try {
Long cputime = (Long)conn.getAttribute(osName,PROCESS_CPU_TIME_ATTR);
return cputime.longValue()*processCPUTimeMultiplier;
} catch (Exception ex) {
LOGGER.throwing(JmxSupport.class.getName(), "hasProcessCPUTimeAttribute", ex); // NOI18N
}
}
}
return -1;
}
synchronized JvmMXBeans getJvmMXBeans() {
if (mxbeans == null) {
JmxModel jmxModel = JmxModelFactory.getJmxModelFor(application);
if (jmxModel != null && jmxModel.getConnectionState() == ConnectionState.CONNECTED) {
mxbeans = JvmMXBeansFactory.getJvmMXBeans(jmxModel);
}
}
return mxbeans;
}
synchronized Collection<GarbageCollectorMXBean> getGarbageCollectorMXBeans() {
if (gcList == null) {
JvmMXBeans jmx = getJvmMXBeans();
if (jmx != null) {
gcList = jmx.getGarbageCollectorMXBeans();
}
}
return gcList;
}
String getJvmArgs() {
try {
RuntimeMXBean runtime = getRuntime();
if (runtime != null) {
StringBuilder buf = new StringBuilder();
List<String> args = runtime.getInputArguments();
for (String arg : args) {
buf.append(arg).append(' ');
}
return buf.toString();
}
return null;
} catch (Exception e) {
LOGGER.throwing(JmxSupport.class.getName(), "getJvmArgs", e); // NOI18N
return null;
}
}
MemoryPoolMXBean getPermGenPool() {
try {
if (permGenPool == null) {
JvmMXBeans jmx = getJvmMXBeans();
if (jmx != null) {
Collection<MemoryPoolMXBean> pools = jmx.getMemoryPoolMXBeans();
for (MemoryPoolMXBean pool : pools) {
MemoryType type = pool.getType();
String name = pool.getName();
if (MemoryType.NON_HEAP.equals(type) &&
(PERM_GEN.equals(name) ||
PS_PERM_GEN.equals(name) ||
CMS_PERM_GEN.equals(name) ||
G1_PERM_GEN.equals(name) ||
METASPACE.equals(name) ||
IBM_PERM_GEN.equals(name))) {
permGenPool = pool;
break;
}
}
}
}
return permGenPool;
} catch (Exception e) {
LOGGER.throwing(JmxSupport.class.getName(), "getPermGenPool", e); // NOI18N
return null;
}
}
String[] getGenName() {
if (genName == null) {
MemoryPoolMXBean permPool = getPermGenPool();
initGenName();
if (permPool != null) {
String label;
String name = permPool.getName();
if (METASPACE.equals(name)) {
label = NbBundle.getMessage(JmxSupport.class, "LBL_Meta"); // NOI18N
} else {
label = NbBundle.getMessage(JmxSupport.class, "LBL_PermGen"); // NOI18N
}
genName[1] = label;
}
}
return genName;
}
void initGenName() {
genName = new String[2];
genName[0] = NbBundle.getMessage(JmxSupport.class, "LBL_Heap"); // NOI18N
genName[1] = NbBundle.getMessage(JmxSupport.class, "LBL_NA"); // NOI18N
}
void initTimer() {
int interval = GlobalPreferences.sharedInstance().getMonitoredDataPoll() * 1000;
final JvmMXBeans jmx = getJvmMXBeans();
if (jmx != null) {
TimerTask task = new TimerTask() {
public void run() {
try {
MonitoredData data = new MonitoredDataImpl(JmxSupport.this, jmx);
jvm.notifyListeners(data);
} catch (UndeclaredThrowableException e) {
LOGGER.throwing(JmxSupport.class.getName(), "MonitoredDataImpl<init>", e); // NOI18N
}
}
};
timer = new Timer("JMX MonitoredData timer for "+application.getId()); // NOI18N
timer.schedule(task,INITIAL_DELAY,interval);
}
}
void disableTimer() {
if (timer != null) {
timer.cancel();
}
}
private static ObjectName getOSName() {
try {
return new ObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
} catch (MalformedObjectNameException ex) {
throw new RuntimeException(ex);
}
}
public void dataRemoved(Object dataSource) {
disableTimer();
}
}