package scouter.util;
import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.getRuntimeMXBean;
import static java.lang.management.ManagementFactory.getThreadMXBean;
import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy;
import java.io.IOException;
import java.lang.management.LockInfo;
import java.lang.management.MonitorInfo;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
class StackUtil {
private MBeanServerConnection server;
private ThreadMXBean mXBean;
private ObjectName objName;
private String headerString;
private boolean hasDumpAllThreads;
public StackUtil(MBeanServerConnection server) throws IOException {
this.server = server;
this.mXBean = newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME, ThreadMXBean.class);
try {
objName = new ObjectName(THREAD_MXBEAN_NAME);
checkDumpAllThreads();
headerString = getHeaderString();
} catch ( Exception e ) {
InternalError ie = new InternalError(e.getMessage());
ie.initCause(e);
throw ie;
}
}
public StackUtil() {
this.mXBean = getThreadMXBean();
checkDumpAllThreads();
headerString = getHeaderString();
}
private Properties getSystemProperties() {
try {
RuntimeMXBean runtime = getRuntimeMXBean();
;
if ( runtime != null ) {
Properties prop = new Properties();
prop.putAll(runtime.getSystemProperties());
return prop;
}
return null;
} catch ( Exception e ) {
e.printStackTrace();
}
return null;
}
public String getHeaderString() {
Properties prop = getSystemProperties();
StringBuilder sb = new StringBuilder(100);
sb.append("Full thread dump ").append(prop.getProperty("java.vm.name")).append(" (").append(prop.getProperty("java.vm.version")).append(' ').append(prop.getProperty("java.vm.info"));
return sb.toString();
}
public List<String> takeThreadDump() throws Exception {
ThreadMXBean threadMXBean = this.mXBean;
if ( threadMXBean == null ) {
return null;
}
List<String> list = new ArrayList<String>(100);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
list.add(df.format(new Date()));
list.add(headerString);
ThreadInfo[] threads;
if ( hasDumpAllThreads ) {
threads = threadMXBean.dumpAllThreads(true, true);
} else {
long[] threadIds = threadMXBean.getAllThreadIds();
threads = threadMXBean.getThreadInfo(threadIds, 2147483647);
}
printThreads(list, threadMXBean, threads);
return list;
}
private void printThreads( List<String> list, ThreadMXBean threadMXBean, ThreadInfo[] threads ) {
boolean jdk16 = hasDumpAllThreads;
for ( ThreadInfo thread : threads ){
if ( thread != null ){
if ( jdk16 )
print16Thread(list, threadMXBean, thread);
else
print15Thread(list, thread);
}
}
}
private void print16Thread( List<String> list, ThreadMXBean threadMXBean, ThreadInfo thread )
{
MonitorInfo[] monitors = null;
if ( threadMXBean.isObjectMonitorUsageSupported() ) {
monitors = thread.getLockedMonitors();
}
list.add("");
list.add(new StringBuilder(100).append('\"').append(thread.getThreadName()).append("\" - Thread t@").append(thread.getThreadId()).toString());
list.add(" java.lang.Thread.State: " + thread.getThreadState());
int index = 0;
StringBuilder sb;
LockInfo lock = thread.getLockInfo();
String lockOwner = thread.getLockOwnerName();
for ( StackTraceElement st : thread.getStackTrace() ) {
list.add("\tat " + st.toString());
if ( index == 0 ) {
if ( ("java.lang.Object".equals(st.getClassName())) && ("wait".equals(st.getMethodName())) )
{
if ( lock != null ) {
sb = new StringBuilder(100);
sb.append("\t- waiting on ");
printLock(sb, lock);
list.add(sb.toString());
}
} else if ( lock != null ) {
if ( lockOwner == null ) {
sb = new StringBuilder(100);
sb.append("\t- parking to wait for ");
printLock(sb, lock);
} else {
sb = new StringBuilder(100);
sb.append("\t- waiting to lock ");
printLock(sb, lock);
sb.append(" owned by \"").append(lockOwner).append("\" t@").append(thread.getLockOwnerId());
printLock(sb, lock);
}
}
}
printMonitors(list, monitors, index);
index++;
}
}
private void printMonitors( List<String> list, MonitorInfo[] monitors, int index )
{
if ( monitors != null )
for ( MonitorInfo mi : monitors )
if ( mi.getLockedStackDepth() == index ) {
StringBuilder sb = new StringBuilder(100);
sb.append("\t- locked ");
printLock(sb, mi);
list.add(sb.toString());
}
}
private void print15Thread( List<String> list, ThreadInfo thread )
{
list.add("");
list.add(new StringBuilder(100).append('\"').append(thread.getThreadName()).append("\" - Thread t@").append(thread.getThreadId()).toString());
StringBuilder sb = new StringBuilder(100);
sb.append(" java.lang.Thread.State: ").append(thread.getThreadState());
if ( thread.getLockName() != null ) {
sb.append(" on ").append(thread.getLockName());
if ( thread.getLockOwnerName() != null ) {
sb.append(" owned by: ").append(thread.getLockOwnerName());
}
}
list.add(sb.toString());
for ( StackTraceElement st : thread.getStackTrace() )
list.add("\tat " + st.toString());
}
private void printLock( StringBuilder sb, LockInfo lock )
{
sb.append('<').append(Integer.toHexString(lock.getIdentityHashCode())).append("> (a ").append(lock.getClassName()).append(')');
}
private void checkDumpAllThreads() {
synchronized (this) {
hasDumpAllThreads = false;
if(server == null){
if(System.getProperty("java.version").compareTo("1.5") >= 0){
hasDumpAllThreads = true;
}
}else{
try {
MBeanOperationInfo[] mopis = server.getMBeanInfo(objName).getOperations();
if ( mopis != null ) {
for ( MBeanOperationInfo op : mopis ) {
if ( "dumpAllThreads".equals(op.getName()) ) {
hasDumpAllThreads = true;
break;
}
}
}
} catch ( Exception ex ) {
ex.printStackTrace();
}
}
}
}
}