package org.jblooming.system; import org.jblooming.PlatformRuntimeException; import java.lang.reflect.Method; import java.text.NumberFormat; import java.text.DecimalFormat; import java.util.Enumeration; /** * @author Pietro Polsinelli ppolsinelli@open-lab.com */ public class ServerInfo { static final DecimalFormat formatter = new DecimalFormat("#.##"); static final long KILO = 1024; static final long MEGA = 1024 * 1024; static final long GIGA = 1024 * 1024 * 1024; // public static final ObjectName DEFAULT_LOADER_REPOSITORY = ObjectNameFactory.create(ServerConstants.DEFAULT_LOADER_NAME); /** * The cached host name for the server. */ private String hostName; /** * The cached host address for the server. */ private String hostAddress; public String lineBreak = "<br>"; /////////////////////////////////////////////////////////////////////////// // JMX Hooks // /////////////////////////////////////////////////////////////////////////// public StringBuffer systemProps(boolean fullDump) { StringBuffer sb = new StringBuffer(512); // Dump out basic JVM & OS info as INFO priority msgs sb.append("Java version: " + System.getProperty("java.version") + "," + System.getProperty("java.vendor") + lineBreak); sb.append("Java VM: " + System.getProperty("java.vm.name") + " " + System.getProperty("java.vm.version") + "," + System.getProperty("java.vm.vendor") + lineBreak); sb.append("OS-System: " + System.getProperty("os.name") + " " + System.getProperty("os.version") + "," + System.getProperty("os.arch") + lineBreak); // Dump out the entire system properties if debug is enabled if (fullDump) { sb.append("Full System Properties Dump" + lineBreak); Enumeration names = System.getProperties().propertyNames(); while (names.hasMoreElements()) { String pname = (String) names.nextElement(); sb.append(" " + pname + ": " + System.getProperty(pname) + lineBreak); } } return sb; } /** * Constants and mappings needed to internationalize this are already existing (i18n.jsp,I18n.java). * * @return * @throws Exception */ public StringBuffer systemState() { StringBuffer sb = new StringBuffer(512); NumberFormat nf = NumberFormat.getInstance(); sb.append("Available processors: " + getAvailableProcessors() + lineBreak); sb.append("Total used memory: " + nf.format((getTotalMemory() / 1024)) + " KB" + lineBreak); sb.append("Total free memory: " + nf.format((getFreeMemory() / 1024)) + " KB" + lineBreak); sb.append("Max available memory: " + nf.format((getMaxMemory() / 1024)) + " KB" + lineBreak); return sb; } public long getTotalMemory() { return Runtime.getRuntime().totalMemory(); } public long getFreeMemory() { return Runtime.getRuntime().freeMemory(); } /** * Returns <tt>Runtime.getRuntime().maxMemory()<tt> on * JDK 1.4 vms or -1 on previous versions. */ public long getMaxMemory() { if (JavaInfo.isCompatible(JavaInfo.VERSION_1_4)) { // Uncomment when JDK 1.4 is the base JVM // return new Long(Runtime.getRuntime().maxMemory()); // until then use reflection to do the job try { Runtime rt = Runtime.getRuntime(); Method m = rt.getClass().getMethod("maxMemory", new Class[0]); return ((Long) m.invoke(rt, new Object[0])).longValue(); } catch (Exception e) { throw new PlatformRuntimeException(e); } } return -1; } /** * Returns <tt>Runtime.getRuntime().availableProcessors()</tt> on * JDK 1.4 vms or -1 on previous versions. */ public Integer getAvailableProcessors() { if (JavaInfo.isCompatible(JavaInfo.VERSION_1_4)) { // Uncomment when JDK 1.4 is the base JVM // return new Integer(Runtime.getRuntime().availableProcessors()); // until then use reflection to do the job 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) { throw new PlatformRuntimeException(e); } } return new Integer(-1); } /** * Returns InetAddress.getLocalHost().getHostName(); */ public String getHostName() { if (hostName == null) { try { hostName = java.net.InetAddress.getLocalHost().getHostName(); } catch (java.net.UnknownHostException e) { hostName = "<unknown>"; } } return hostName; } /** * Returns InetAddress.getLocalHost().getHostAddress(); */ public String getHostAddress() { if (hostAddress == null) { try { hostAddress = java.net.InetAddress.getLocalHost().getHostAddress(); } catch (java.net.UnknownHostException e) { hostAddress = "<unknown>"; } } return hostAddress; } private ThreadGroup getRootThreadGroup() { ThreadGroup group = Thread.currentThread().getThreadGroup(); while (group.getParent() != null) { group = group.getParent(); } return group; } public Integer getActiveThreadCount() { // See first comment in listThreadDump() return new Integer(getRootThreadGroup().activeCount() - 1); } public Integer getActiveThreadGroupCount() { // See second comment in listThreadDump() return new Integer(getRootThreadGroup().activeGroupCount() + 1); } /** * Return a listing of the active threads and thread groups. */ public String listThreadDump() { ThreadGroup root = getRootThreadGroup(); // I'm not sure why what gets reported is off by +1, // but I'm adjusting so that it is consistent with the display // N.B. this comment is referenced in getActiveThreadCount() int activeThreads = root.activeCount() - 1; // I'm not sure why what gets reported is off by -1 // but I'm adjusting so that it is consistent with the display // N.B. this comment is referenced in getActiveThreadGroupCount() int activeGroups = root.activeGroupCount() + 1; String rc = "Total Threads: <b>" + activeThreads + "</b>" + lineBreak + "Total Thread Groups: " + activeGroups + lineBreak + getThreadGroupInfo(root); return rc; } private String getThreadGroupInfo(ThreadGroup group) { StringBuffer rc = new StringBuffer(); rc.append(lineBreak); rc.append("Thread Group: " + group.getName()); rc.append(" : "); 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++) { rc.append(""); rc.append("Thread: " + threads[i].getName()); rc.append(" : "); rc.append("priority:" + threads[i].getPriority() + ", demon:" + threads[i].isDaemon()); rc.append(lineBreak); rc.append("trace:" + threads[i].getStackTrace().toString()); rc.append(lineBreak); } 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])); } rc.append("</blockquote>"); return rc.toString(); } /** * Display the java.lang.Package info for the pkgName */ 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(); } /** * Display the ClassLoader, ProtectionDomain and Package information for * the specified class. * * @return a simple html report of this information */ public String displayInfoForClass(String className) { /* 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(); */ return ""; } /** * This does not work as expected because the thread context class loader * is not used to determine which class loader the package list is obtained * from. */ public String displayAllPackageInfo() { return "Broken right now"; /* ClassLoader entryCL = Thread.currentThread().getContextClassLoader(); ServiceLibraries libraries = ServiceLibraries.getLibraries(); ClassLoader[] classLoaders = libraries.getClassLoaders(); StringBuffer info = new StringBuffer(); for(int c = 0; c < classLoaders.length; c ++) { ClassLoader cl = classLoaders[c]; Thread.currentThread().setContextClassLoader(cl); try { info.append("<h1>ClassLoader: "+cl+"</h1>\n"); Package[] pkgs = Package.getPackages(); for(int p = 0; p < pkgs.length; p ++) { Package pkg = pkgs[p]; info.append("<h2>Package: "+pkg.getName()+"</h2>\n"); displayPackageInfo(pkg, info); } } catch(Throwable e) { } } Thread.currentThread().setContextClassLoader(entryCL); return info.toString(); */ } 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"); } public 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); } } }