package org.jboss.system.server;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.jboss.logging.Logger;
import org.jboss.mx.server.ServerConstants;
import org.jboss.mx.util.ObjectNameFactory;
import org.jboss.util.MuInteger;
import org.jboss.util.platform.Java;
public class ServerInfo
implements ServerInfoMBean, MBeanRegistration
{
public static final ObjectName DEFAULT_LOADER_REPOSITORY = ObjectNameFactory.create(ServerConstants.DEFAULT_LOADER_NAME);
private static final Logger log = Logger.getLogger(ServerInfo.class);
private MBeanServer server;
private String hostName;
private String hostAddress;
private Object threadMXBean;
private Method getMemoryPoolMXBeans;
private Method getName;
private Method getType;
private Method getUsage;
private Method getPeakUsage;
private Method getInit;
private Method getUsed;
private Method getCommitted;
private Method getMax;
private Method getThreadInfo;
private Method getThreadState;
private Method getLockName;
private Method getStackTrace;
private Method getThreadId;
public ObjectName preRegister(MBeanServer server, ObjectName name)
throws Exception
{
this.server = server;
log.info("Java version: " +
System.getProperty("java.version") + "," +
System.getProperty("java.vendor"));
log.info("Java VM: " +
System.getProperty("java.vm.name") + " " +
System.getProperty("java.vm.version") + "," +
System.getProperty("java.vm.vendor"));
log.info("OS-System: " +
System.getProperty("os.name") + " " +
System.getProperty("os.version") + "," +
System.getProperty("os.arch"));
log.debug("Full System Properties Dump");
Enumeration names = System.getProperties().propertyNames();
while (names.hasMoreElements())
{
String pname = (String)names.nextElement();
log.debug(" " + pname + ": " + System.getProperty(pname));
}
if (Java.isCompatible(Java.VERSION_1_5))
{
try
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class clazz = cl.loadClass("java.lang.management.ManagementFactory");
Method method = clazz.getMethod("getThreadMXBean", null);
this.threadMXBean = method.invoke(null, null);
this.getMemoryPoolMXBeans = clazz.getMethod("getMemoryPoolMXBeans", null);
clazz = cl.loadClass("java.lang.management.MemoryPoolMXBean");
this.getName = clazz.getMethod("getName", null);
this.getType = clazz.getMethod("getType", null);
this.getUsage = clazz.getMethod("getUsage", null);
this.getPeakUsage = clazz.getMethod("getPeakUsage", null);
clazz = cl.loadClass("java.lang.management.MemoryUsage");
this.getInit = clazz.getMethod("getInit", null);
this.getUsed = clazz.getMethod("getUsed", null);
this.getCommitted = clazz.getMethod("getCommitted", null);
this.getMax = clazz.getMethod("getMax", null);
clazz = cl.loadClass("java.lang.management.ThreadMXBean");
this.getThreadInfo = clazz.getMethod("getThreadInfo", new Class[] { Long.TYPE, Integer.TYPE } );
clazz = cl.loadClass("java.lang.management.ThreadInfo");
this.getThreadState = clazz.getMethod("getThreadState", null);
this.getLockName = clazz.getMethod("getLockName", null);
this.getStackTrace = clazz.getMethod("getStackTrace", null);
clazz = Thread.class;
this.getThreadId = clazz.getMethod("getId", null);
}
catch (Exception e)
{
log.debug("Cannot access platform ThreadMXBean", e);
}
}
return name == null ? OBJECT_NAME : name;
}
public void postRegister(Boolean registrationDone)
{
}
public void preDeregister() throws Exception
{
}
public void postDeregister()
{
}
public String getJavaVersion()
{
return System.getProperty("java.version");
}
public String getJavaVendor()
{
return System.getProperty("java.vendor");
}
public String getJavaVMName()
{
return System.getProperty("java.vm.name");
}
public String getJavaVMVersion()
{
return System.getProperty("java.vm.version");
}
public String getJavaVMVendor()
{
return System.getProperty("java.vm.vendor");
}
public String getOSName()
{
return System.getProperty("os.name");
}
public String getOSVersion()
{
return System.getProperty("os.version");
}
public String getOSArch()
{
return System.getProperty("os.arch");
}
public Long getTotalMemory()
{
return new Long(Runtime.getRuntime().totalMemory());
}
public Long getFreeMemory()
{
return new Long(Runtime.getRuntime().freeMemory());
}
public Long getMaxMemory()
{
if (Java.isCompatible(Java.VERSION_1_4)) {
try {
Runtime rt = Runtime.getRuntime();
Method m = rt.getClass().getMethod("maxMemory", new Class[0]);
return (Long)m.invoke(rt, new Object[0]);
}
catch (Exception e) {
log.error("Operation failed", e);
}
}
return new Long(-1);
}
public Integer getAvailableProcessors()
{
if (Java.isCompatible(Java.VERSION_1_4)) {
try {
Runtime rt = Runtime.getRuntime();
Method m = rt.getClass().getMethod("availableProcessors", new Class[0]);
return (Integer)m.invoke(rt, new Object[0]);
}
catch (Exception e) {
log.error("Operation failed", e);
}
}
return new Integer(-1);
}
public String getHostName()
{
if (hostName == null)
{
try
{
hostName = java.net.InetAddress.getLocalHost().getHostName();
}
catch (java.net.UnknownHostException e)
{
log.error("Error looking up local hostname", e);
hostName = "<unknown>";
}
}
return hostName;
}
public String getHostAddress()
{
if (hostAddress == null)
{
try
{
hostAddress = java.net.InetAddress.getLocalHost().getHostAddress();
}
catch (java.net.UnknownHostException e)
{
log.error("Error looking up local address", e);
hostAddress = "<unknown>";
}
}
return hostAddress;
}
public String listMemoryPools(boolean fancy)
{
if (getMemoryPoolMXBeans != null)
{
StringBuffer sbuf = new StringBuffer(4196);
try
{
List poolList = (List)getMemoryPoolMXBeans.invoke(null, null);
sbuf.append("<b>Total Memory Pools:</b> ").append(poolList.size());
sbuf.append("<blockquote>");
for (Iterator i = poolList.iterator(); i.hasNext(); )
{
Object pool = i.next();
String name = (String)getName.invoke(pool, null);
Object type = getType.invoke(pool, null);
sbuf.append("<b>Pool: ").append(name);
sbuf.append("</b> (").append(type).append(")");
Object peakUsage = getPeakUsage.invoke(pool, null);
Object usage = getUsage.invoke(pool, null);
sbuf.append("<blockquote>");
if (usage != null && peakUsage != null)
{
Long init = (Long)getInit.invoke(peakUsage, null);
Long used = (Long)getUsed.invoke(peakUsage, null);
Long committed = (Long)getCommitted.invoke(peakUsage, null);
Long max = (Long)getMax.invoke(peakUsage, null);
sbuf.append("Peak Usage : ");
sbuf.append("init:").append(init);
sbuf.append(", used:").append(used);
sbuf.append(", committed:").append(committed);
sbuf.append(", max:").append(max);
sbuf.append("<br>");
init = (Long)getInit.invoke(usage, null);
used = (Long)getUsed.invoke(usage, null);
committed = (Long)getCommitted.invoke(usage, null);
max = (Long)getMax.invoke(usage, null);
sbuf.append("Current Usage : ");
sbuf.append("init:").append(init);
sbuf.append(", used:").append(used);
sbuf.append(", committed:").append(committed);
sbuf.append(", max:").append(max);
if (fancy)
{
TextGraphHelper.poolUsage(sbuf, used.longValue(), committed.longValue(), max.longValue());
}
}
else
{
sbuf.append("Memory pool NOT valid!");
}
sbuf.append("</blockquote><br>");
}
sbuf.append("</blockquote>");
}
catch (Exception e)
{
}
return sbuf.toString();
}
else
{
return "<b>Memory pool information available only under a JDK5+ compatible JVM!</b>";
}
}
public Integer getActiveThreadCount()
{
return new Integer(getRootThreadGroup().activeCount());
}
public Integer getActiveThreadGroupCount()
{
return new Integer(getRootThreadGroup().activeGroupCount());
}
public String listThreadDump()
{
ThreadGroup root = getRootThreadGroup();
MuInteger activeThreads = new MuInteger(0);
MuInteger activeGroups = new MuInteger(0);
String threadGroupInfo = getThreadGroupInfo(root, activeGroups, activeThreads);
String threadDump =
"<b>Total Threads:</b> " + activeThreads + "<br>" +
"<b>Total Thread Groups:</b> " + activeGroups + "<br>" +
threadGroupInfo;
return threadDump;
}
private ThreadGroup getRootThreadGroup()
{
ThreadGroup group = Thread.currentThread().getThreadGroup();
while (group.getParent() != null)
{
group = group.getParent();
}
return group;
}
private String getThreadGroupInfo(ThreadGroup group, MuInteger groupCount, MuInteger threadCount)
{
StringBuffer rc = new StringBuffer();
groupCount.increment();
rc.append("<br><b>");
rc.append("Thread Group: " + group.getName());
rc.append("</b> : ");
rc.append("max priority:" + group.getMaxPriority() +
", demon:" + group.isDaemon());
rc.append("<blockquote>");
Thread threads[]= new Thread[group.activeCount()];
group.enumerate(threads, false);
for (int i= 0; i < threads.length && threads[i] != null; i++)
{
threadCount.increment();
rc.append("<b>");
rc.append("Thread: " + threads[i].getName());
rc.append("</b> : ");
rc.append("priority:" + threads[i].getPriority() +
", demon:" + threads[i].isDaemon());
outputJdk5ThreadMXBeanInfo(rc, threads[i]);
}
ThreadGroup groups[]= new ThreadGroup[group.activeGroupCount()];
group.enumerate(groups, false);
for (int i= 0; i < groups.length && groups[i] != null; i++)
{
rc.append(getThreadGroupInfo(groups[i], groupCount, threadCount));
}
rc.append("</blockquote>");
return rc.toString();
}
private void outputJdk5ThreadMXBeanInfo(StringBuffer sbuf, Thread thread)
{
if (threadMXBean != null)
{
try
{
Long threadId = (Long)getThreadId.invoke(thread, null);
Object threadInfo = getThreadInfo.invoke(threadMXBean,
new Object[] { threadId, new Integer(Integer.MAX_VALUE) });
Object threadState = getThreadState.invoke(threadInfo, null); String threadLockName = (String)getLockName.invoke(threadInfo, null);
Object[] stackTrace = (Object[])getStackTrace.invoke(threadInfo, null);
sbuf.append(", threadId:").append(threadId);
sbuf.append(", threadState:").append(threadState);
sbuf.append(", threadLockName:").append(threadLockName);
sbuf.append("<br>");
if (stackTrace.length > 0)
{
sbuf.append("<blockquote>");
for (int i = 0; i < stackTrace.length; i++)
{
sbuf.append(stackTrace[i]).append("<br>");
}
sbuf.append("</blockquote>");
}
}
catch (Exception ignore)
{
}
}
else
{
sbuf.append("<br>");
}
}
public String displayPackageInfo(String pkgName)
{
Package pkg = Package.getPackage(pkgName);
if( pkg == null )
return "<h2>Package:"+pkgName+" Not Found!</h2>";
StringBuffer info = new StringBuffer("<h2>Package: "+pkgName+"</h2>");
displayPackageInfo(pkg, info);
return info.toString();
}
public String displayInfoForClass(String className) throws Exception
{
Class clazz = (Class)server.invoke(DEFAULT_LOADER_REPOSITORY,
"findClass",
new Object[] {className},
new String[] {String.class.getName()});
if( clazz == null )
return "<h2>Class:"+className+" Not Found!</h2>";
Package pkg = clazz.getPackage();
if( pkg == null )
return "<h2>Class:"+className+" has no Package info</h2>";
StringBuffer info = new StringBuffer("<h1>Class: "+pkg.getName()+"</h1>");
ClassLoader cl = clazz.getClassLoader();
info.append("<h2>ClassLoader: "+cl+"</h2>\n");
info.append("<h3>ProtectionDomain</h3>\n");
info.append("<pre>\n"+clazz.getProtectionDomain()+"</pre>\n");
info.append("<h2>Package: "+pkg.getName()+"</h2>");
displayPackageInfo(pkg, info);
return info.toString();
}
public String displayAllPackageInfo()
{
return "Broken right now";
}
private void displayPackageInfo(Package pkg, StringBuffer info)
{
info.append("<pre>\n");
info.append("SpecificationTitle: "+pkg.getSpecificationTitle());
info.append("\nSpecificationVersion: "+pkg.getSpecificationVersion());
info.append("\nSpecificationVendor: "+pkg.getSpecificationVendor());
info.append("\nImplementationTitle: "+pkg.getImplementationTitle());
info.append("\nImplementationVersion: "+pkg.getImplementationVersion());
info.append("\nImplementationVendor: "+pkg.getImplementationVendor());
info.append("\nisSealed: "+pkg.isSealed());
info.append("</pre>\n");
}
private static class TextGraphHelper
{
static final DecimalFormat formatter = new DecimalFormat("#.##");
static final long KILO = 1024;
static final long MEGA = 1024 * 1024;
static final long GIGA = 1024 * 1024 * 1024;
static final int factor = 70;
static char[] fixedline;
static char[] baseline;
static char[] barline;
static char[] spaces;
static
{
StringBuffer sbuf0 = new StringBuffer();
StringBuffer sbuf1 = new StringBuffer();
StringBuffer sbuf2 = new StringBuffer();
StringBuffer sbuf3 = new StringBuffer();
sbuf0.append('+');
sbuf1.append('|');
sbuf2.append('|');
for (int i = 1; i < factor; i++)
{
sbuf0.append('-');
sbuf1.append('-');
sbuf2.append('/');
sbuf3.append(' ');
}
sbuf0.append('+');
fixedline = sbuf0.toString().toCharArray();
baseline = sbuf1.toString().toCharArray();
barline = sbuf2.toString().toCharArray();
spaces = sbuf3.toString().toCharArray();
}
private TextGraphHelper()
{
}
public static void poolUsage(StringBuffer sbuf, long used, long committed, long max)
{
long assumedMax = (max == -1) ? committed : max;
int localUsed = (int)(factor * used / assumedMax);
int localCommitted = (int)(factor * committed / assumedMax);
int localMax = factor;
sbuf.append("<blockquote><br>");
sbuf.append(baseline, 0, localCommitted).append("| committed:").append(outputNumber(committed)).append("<br>");
sbuf.append(fixedline).append("<br>");
sbuf.append(barline, 0, localUsed);
if (localUsed < localCommitted)
{
sbuf.append(localUsed > 0 ? '/' : '|');
sbuf.append(spaces, 0, localCommitted - localUsed - 1);
}
sbuf.append('|');
if (localCommitted < localMax)
{
sbuf.append(spaces, 0, localMax - localCommitted - 1);
sbuf.append('|');
}
sbuf.append(" max:").append(outputNumber(max)).append("<br>");
sbuf.append(fixedline).append("<br>");
sbuf.append(baseline, 0, localUsed).append("| used:").append(outputNumber(used));
sbuf.append("</blockquote>");
}
private static String outputNumber(long value)
{
if (value >= GIGA)
{
return formatter.format((double)value / GIGA) + "Gb";
}
else if (value >= MEGA)
{
return formatter.format((double)value / MEGA) + "Mb";
}
else if (value >= KILO)
{
return formatter.format((double)value / KILO) + "Kb";
}
else if (value >= 0)
{
return value + "b";
}
else
{
return Long.toString(value);
}
}
}
}