From c63c9f6fcbf67d28f721ddec1eef89ee2c61b238 Mon Sep 17 00:00:00 2001 From: Franco Lombardo Date: Fri, 4 Dec 2015 16:06:40 +0100 Subject: [PATCH 01/27] Code formatted with Java conventions --- .gitignore | 3 + src/main/java/com/jvmtop/JvmTop.java | 582 ++--- src/main/java/com/jvmtop/monitor/VMInfo.java | 1014 ++++----- .../java/com/jvmtop/monitor/VMInfoState.java | 4 +- .../jvmtop/openjdk/tools/ConnectionState.java | 28 +- .../openjdk/tools/LocalVirtualMachine.java | 605 +++-- .../jvmtop/openjdk/tools/MemoryPoolStat.java | 201 +- .../com/jvmtop/openjdk/tools/ProxyClient.java | 1941 ++++++++--------- .../java/com/jvmtop/profiler/CPUSampler.java | 199 +- .../java/com/jvmtop/profiler/MethodStats.java | 169 +- .../com/jvmtop/view/AbstractConsoleView.java | 305 ++- .../java/com/jvmtop/view/ConsoleView.java | 46 +- .../java/com/jvmtop/view/VMDetailView.java | 423 ++-- .../java/com/jvmtop/view/VMOverviewView.java | 239 +- .../java/com/jvmtop/view/VMProfileView.java | 138 +- 15 files changed, 2632 insertions(+), 3265 deletions(-) diff --git a/.gitignore b/.gitignore index f087217..4e52dcc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ # Maven log/ target/ +/bin/ +/lib/ +/.settings/ diff --git a/src/main/java/com/jvmtop/JvmTop.java b/src/main/java/com/jvmtop/JvmTop.java index dd4165c..13fe5b3 100644 --- a/src/main/java/com/jvmtop/JvmTop.java +++ b/src/main/java/com/jvmtop/JvmTop.java @@ -44,361 +44,251 @@ /** * JvmTop entry point class. * - * - parses program arguments - * - selects console view - * - prints header - * - main "iteration loop" + * - parses program arguments - selects console view - prints header - main + * "iteration loop" * * TODO: refactor to split these tasks * * @author paru * */ -public class JvmTop -{ +public class JvmTop { - public static final String VERSION = "0.8.0 alpha"; + public static final String VERSION = "0.8.0 alpha"; - private Double delay_ = 1.0; + private Double delay_ = 1.0; - private Boolean supportsSystemAverage_; - - private java.lang.management.OperatingSystemMXBean localOSBean_; + private Boolean supportsSystemAverage_; - private final static String CLEAR_TERMINAL_ANSI_CMD = new String( - new byte[] { - (byte) 0x1b, (byte) 0x5b, (byte) 0x32, (byte) 0x4a, (byte) 0x1b, - (byte) 0x5b, (byte) 0x48 }); - - private int maxIterations_ = -1; - - private static Logger logger; - - private static OptionParser createOptionParser() - { - OptionParser parser = new OptionParser(); - parser.acceptsAll(Arrays.asList(new String[] { "help", "?", "h" }), - "shows this help").forHelp(); - parser - .accepts("once", - "jvmtop will exit after first output iteration [deprecated, use -n 1 instead]"); - parser - .acceptsAll(Arrays.asList(new String[] { "n", "iteration" }), - "jvmtop will exit after n output iterations").withRequiredArg() - .ofType(Integer.class); - parser - .acceptsAll(Arrays.asList(new String[] { "d", "delay" }), - "delay between each output iteration").withRequiredArg() - .ofType(Double.class); - parser.accepts("profile", "start CPU profiling at the specified jvm"); - parser.accepts("sysinfo", "outputs diagnostic information"); - parser.accepts("verbose", "verbose mode"); - parser.accepts("threadlimit", - "sets the number of displayed threads in detail mode") - .withRequiredArg().ofType(Integer.class); - parser - .accepts("disable-threadlimit", "displays all threads in detail mode"); - - parser - .acceptsAll(Arrays.asList(new String[] { "p", "pid" }), - "PID to connect to").withRequiredArg().ofType(Integer.class); - - parser - .acceptsAll(Arrays.asList(new String[] { "w", "width" }), - "Width in columns for the console display").withRequiredArg().ofType(Integer.class); - - parser - .accepts("threadnamewidth", - "sets displayed thread name length in detail mode (defaults to 30)") - .withRequiredArg().ofType(Integer.class); - - return parser; - } - - public static void main(String[] args) throws Exception - { - Locale.setDefault(Locale.US); - - logger = Logger.getLogger("jvmtop"); - - OptionParser parser = createOptionParser(); - OptionSet a = parser.parse(args); - - if (a.has("help")) - { - System.out.println("jvmtop - java monitoring for the command-line"); - System.out.println("Usage: jvmtop.sh [options...] [PID]"); - System.out.println(""); - parser.printHelpOn(System.out); - System.exit(0); - } - boolean sysInfoOption = a.has("sysinfo"); - - Integer pid = null; - - Integer width = null; - - double delay = 1.0; - - boolean profileMode = a.has("profile"); - - Integer iterations = a.has("once") ? 1 : -1; - - Integer threadlimit = null; - - boolean threadLimitEnabled = true; - - Integer threadNameWidth = null; - - if (a.hasArgument("delay")) - { - delay = (Double) (a.valueOf("delay")); - if (delay < 0.1d) - { - throw new IllegalArgumentException("Delay cannot be set below 0.1"); - } - } - - if (a.hasArgument("n")) - { - iterations = (Integer) a.valueOf("n"); - } - - //to support PID as non option argument - if (a.nonOptionArguments().size() > 0) - { - pid = Integer.valueOf((String) a.nonOptionArguments().get(0)); - } - - if (a.hasArgument("pid")) - { - pid = (Integer) a.valueOf("pid"); - } - - if (a.hasArgument("width")) - { - width = (Integer) a.valueOf("width"); - } - - if (a.hasArgument("threadlimit")) - { - threadlimit = (Integer) a.valueOf("threadlimit"); - } - - if (a.has("disable-threadlimit")) - { - threadLimitEnabled = false; - } - - if (a.has("verbose")) - { - fineLogging(); - logger.setLevel(Level.ALL); - logger.fine("Verbosity mode."); - } - - if (a.hasArgument("threadnamewidth")) - { - threadNameWidth = (Integer) a.valueOf("threadnamewidth"); - } - - if (sysInfoOption) - { - outputSystemProps(); - } - else - { - JvmTop jvmTop = new JvmTop(); - jvmTop.setDelay(delay); - jvmTop.setMaxIterations(iterations); - if (pid == null) - { - jvmTop.run(new VMOverviewView(width)); - } - else - { - if (profileMode) - { - jvmTop.run(new VMProfileView(pid, width)); - } - else - { - VMDetailView vmDetailView = new VMDetailView(pid, width); - vmDetailView.setDisplayedThreadLimit(threadLimitEnabled); - if (threadlimit != null) - { - vmDetailView.setNumberOfDisplayedThreads(threadlimit); - } - if (threadNameWidth != null) - { - vmDetailView.setThreadNameDisplayWidth(threadNameWidth); - } - jvmTop.run(vmDetailView); - - } - - } - } - } - - public int getMaxIterations() - { - return maxIterations_; - } - - public void setMaxIterations(int iterations) - { - maxIterations_ = iterations; - } - - private static void fineLogging() - { - //get the top Logger: - Logger topLogger = java.util.logging.Logger.getLogger(""); - - // Handler for console (reuse it if it already exists) - Handler consoleHandler = null; - //see if there is already a console handler - for (Handler handler : topLogger.getHandlers()) - { - if (handler instanceof ConsoleHandler) - { - //found the console handler - consoleHandler = handler; - break; - } - } - - if (consoleHandler == null) - { - //there was no console handler found, create a new one - consoleHandler = new ConsoleHandler(); - topLogger.addHandler(consoleHandler); - } - //set the console handler to fine: - consoleHandler.setLevel(java.util.logging.Level.FINEST); - } - - private static void outputSystemProps() - { - for (Object key : System.getProperties().keySet()) - { - System.out.println(key + "=" + System.getProperty(key + "")); - } - } - - protected void run(ConsoleView view) throws Exception - { - try - { - System.setOut(new PrintStream(new BufferedOutputStream( - new FileOutputStream(FileDescriptor.out)), false)); - int iterations = 0; - while (!view.shouldExit()) - { - if (maxIterations_ > 1 || maxIterations_ == -1) - { - clearTerminal(); - } - printTopBar(); - view.printView(); - System.out.flush(); - iterations++; - if (iterations >= maxIterations_ && maxIterations_ > 0) - { - break; - } - view.sleep((int) (delay_ * 1000)); - } - } - catch (NoClassDefFoundError e) - { - e.printStackTrace(System.err); - - System.err.println(""); - System.err.println("ERROR: Some JDK classes cannot be found."); - System.err - .println(" Please check if the JAVA_HOME environment variable has been set to a JDK path."); - System.err.println(""); - } - } - - /** - * - */ - private void clearTerminal() - { - if (System.getProperty("os.name").contains("Windows")) - { - //hack - System.out - .printf("%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n"); - } - else if (System.getProperty("jvmtop.altClear") != null) - { - System.out.print('\f'); - } - else - { - System.out.print(CLEAR_TERMINAL_ANSI_CMD); - } - } - - public JvmTop() - { - localOSBean_ = ManagementFactory.getOperatingSystemMXBean(); - } - - /** - * @throws NoSuchMethodException - * @throws SecurityException - * - */ - private void printTopBar() - { - System.out.printf(" JvmTop %s - %8tT, %6s, %2d cpus, %15.15s", VERSION, - new Date(), localOSBean_.getArch(), - localOSBean_.getAvailableProcessors(), localOSBean_.getName() + " " - + localOSBean_.getVersion()); - - if (supportSystemLoadAverage() && localOSBean_.getSystemLoadAverage() != -1) - { - System.out.printf(", load avg %3.2f%n", - localOSBean_.getSystemLoadAverage()); - } - else - { - System.out.println(); - } - System.out.println(" https://github.com/patric-r/jvmtop"); - System.out.println(); - } - - private boolean supportSystemLoadAverage() - { - if (supportsSystemAverage_ == null) - { - try - { - supportsSystemAverage_ = (localOSBean_.getClass().getMethod( - "getSystemLoadAverage") != null); - } - catch (Throwable e) - { - supportsSystemAverage_ = false; - } - } - return supportsSystemAverage_; - } - - public Double getDelay() - { - return delay_; - } - - public void setDelay(Double delay) - { - delay_ = delay; - } + private java.lang.management.OperatingSystemMXBean localOSBean_; + + private final static String CLEAR_TERMINAL_ANSI_CMD = new String(new byte[] { (byte) 0x1b, (byte) 0x5b, (byte) 0x32, (byte) 0x4a, (byte) 0x1b, (byte) 0x5b, (byte) 0x48 }); + + private int maxIterations_ = -1; + + private static Logger logger; + + private static OptionParser createOptionParser() { + OptionParser parser = new OptionParser(); + parser.acceptsAll(Arrays.asList(new String[] { "help", "?", "h" }), "shows this help").forHelp(); + parser.accepts("once", "jvmtop will exit after first output iteration [deprecated, use -n 1 instead]"); + parser.acceptsAll(Arrays.asList(new String[] { "n", "iteration" }), "jvmtop will exit after n output iterations").withRequiredArg().ofType(Integer.class); + parser.acceptsAll(Arrays.asList(new String[] { "d", "delay" }), "delay between each output iteration").withRequiredArg().ofType(Double.class); + parser.accepts("profile", "start CPU profiling at the specified jvm"); + parser.accepts("sysinfo", "outputs diagnostic information"); + parser.accepts("verbose", "verbose mode"); + parser.accepts("threadlimit", "sets the number of displayed threads in detail mode").withRequiredArg().ofType(Integer.class); + parser.accepts("disable-threadlimit", "displays all threads in detail mode"); + + parser.acceptsAll(Arrays.asList(new String[] { "p", "pid" }), "PID to connect to").withRequiredArg().ofType(Integer.class); + + parser.acceptsAll(Arrays.asList(new String[] { "w", "width" }), "Width in columns for the console display").withRequiredArg().ofType(Integer.class); + + parser.accepts("threadnamewidth", "sets displayed thread name length in detail mode (defaults to 30)").withRequiredArg().ofType(Integer.class); + + return parser; + } + + public static void main(String[] args) throws Exception { + Locale.setDefault(Locale.US); + + logger = Logger.getLogger("jvmtop"); + + OptionParser parser = createOptionParser(); + OptionSet a = parser.parse(args); + + if (a.has("help")) { + System.out.println("jvmtop - java monitoring for the command-line"); + System.out.println("Usage: jvmtop.sh [options...] [PID]"); + System.out.println(""); + parser.printHelpOn(System.out); + System.exit(0); + } + boolean sysInfoOption = a.has("sysinfo"); + + Integer pid = null; + + Integer width = null; + + double delay = 1.0; + + boolean profileMode = a.has("profile"); + + Integer iterations = a.has("once") ? 1 : -1; + + Integer threadlimit = null; + + boolean threadLimitEnabled = true; + + Integer threadNameWidth = null; + + if (a.hasArgument("delay")) { + delay = (Double) (a.valueOf("delay")); + if (delay < 0.1d) + throw new IllegalArgumentException("Delay cannot be set below 0.1"); + } + + if (a.hasArgument("n")) + iterations = (Integer) a.valueOf("n"); + + // to support PID as non option argument + if (a.nonOptionArguments().size() > 0) + pid = Integer.valueOf((String) a.nonOptionArguments().get(0)); + + if (a.hasArgument("pid")) + pid = (Integer) a.valueOf("pid"); + + if (a.hasArgument("width")) + width = (Integer) a.valueOf("width"); + + if (a.hasArgument("threadlimit")) + threadlimit = (Integer) a.valueOf("threadlimit"); + + if (a.has("disable-threadlimit")) + threadLimitEnabled = false; + + if (a.has("verbose")) { + fineLogging(); + logger.setLevel(Level.ALL); + logger.fine("Verbosity mode."); + } + + if (a.hasArgument("threadnamewidth")) + threadNameWidth = (Integer) a.valueOf("threadnamewidth"); + + if (sysInfoOption) + outputSystemProps(); + else { + JvmTop jvmTop = new JvmTop(); + jvmTop.setDelay(delay); + jvmTop.setMaxIterations(iterations); + if (pid == null) + jvmTop.run(new VMOverviewView(width)); + else if (profileMode) + jvmTop.run(new VMProfileView(pid, width)); + else { + VMDetailView vmDetailView = new VMDetailView(pid, width); + vmDetailView.setDisplayedThreadLimit(threadLimitEnabled); + if (threadlimit != null) + vmDetailView.setNumberOfDisplayedThreads(threadlimit); + if (threadNameWidth != null) + vmDetailView.setThreadNameDisplayWidth(threadNameWidth); + jvmTop.run(vmDetailView); + } + } + } + + public int getMaxIterations() { + return maxIterations_; + } + + public void setMaxIterations(int iterations) { + maxIterations_ = iterations; + } + + private static void fineLogging() { + // get the top Logger: + Logger topLogger = java.util.logging.Logger.getLogger(""); + + // Handler for console (reuse it if it already exists) + Handler consoleHandler = null; + // see if there is already a console handler + for (Handler handler : topLogger.getHandlers()) + if (handler instanceof ConsoleHandler) { + // found the console handler + consoleHandler = handler; + break; + } + + if (consoleHandler == null) { + // there was no console handler found, create a new one + consoleHandler = new ConsoleHandler(); + topLogger.addHandler(consoleHandler); + } + // set the console handler to fine: + consoleHandler.setLevel(java.util.logging.Level.FINEST); + } + + private static void outputSystemProps() { + for (Object key : System.getProperties().keySet()) + System.out.println(key + "=" + System.getProperty(key + "")); + } + + protected void run(ConsoleView view) throws Exception { + try (PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)), false)) { + System.setOut(ps); + int iterations = 0; + while (!view.shouldExit()) { + if (maxIterations_ > 1 || maxIterations_ == -1) + clearTerminal(); + printTopBar(); + view.printView(); + System.out.flush(); + iterations++; + if (iterations >= maxIterations_ && maxIterations_ > 0) + break; + view.sleep((int) (delay_ * 1000)); + } + } catch (NoClassDefFoundError e) { + e.printStackTrace(System.err); + + System.err.println(""); + System.err.println("ERROR: Some JDK classes cannot be found."); + System.err.println(" Please check if the JAVA_HOME environment variable has been set to a JDK path."); + System.err.println(""); + } + } + + /** + * + */ + private void clearTerminal() { + if (System.getProperty("os.name").contains("Windows")) + // hack + System.out.printf("%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n"); + else if (System.getProperty("jvmtop.altClear") != null) + System.out.print('\f'); + else + System.out.print(CLEAR_TERMINAL_ANSI_CMD); + } + + public JvmTop() { + localOSBean_ = ManagementFactory.getOperatingSystemMXBean(); + } + + /** + * @throws NoSuchMethodException + * @throws SecurityException + * + */ + private void printTopBar() { + System.out.printf(" JvmTop %s - %8tT, %6s, %2d cpus, %15.15s", VERSION, new Date(), localOSBean_.getArch(), localOSBean_.getAvailableProcessors(), localOSBean_.getName() + " " + + localOSBean_.getVersion()); + + if (supportSystemLoadAverage() && localOSBean_.getSystemLoadAverage() != -1) + System.out.printf(", load avg %3.2f%n", localOSBean_.getSystemLoadAverage()); + else + System.out.println(); + System.out.println(" https://github.com/patric-r/jvmtop"); + System.out.println(); + } + + private boolean supportSystemLoadAverage() { + if (supportsSystemAverage_ == null) + try { + supportsSystemAverage_ = (localOSBean_.getClass().getMethod("getSystemLoadAverage") != null); + } catch (Throwable e) { + supportsSystemAverage_ = false; + } + return supportsSystemAverage_; + } + + public Double getDelay() { + return delay_; + } + + public void setDelay(Double delay) { + delay_ = delay; + } } diff --git a/src/main/java/com/jvmtop/monitor/VMInfo.java b/src/main/java/com/jvmtop/monitor/VMInfo.java index 75ff47f..160468e 100644 --- a/src/main/java/com/jvmtop/monitor/VMInfo.java +++ b/src/main/java/com/jvmtop/monitor/VMInfo.java @@ -43,573 +43,481 @@ import com.sun.tools.attach.AttachNotSupportedException; /** - * VMInfo retrieves or updates the metrics for a specific remote jvm, - * using ProxyClient. + * VMInfo retrieves or updates the metrics for a specific remote jvm, using + * ProxyClient. * - * TODO: refactor this class, seperate: - * - connect / attach code - * - updating metrics - * - model + * TODO: refactor this class, seperate: - connect / attach code - updating + * metrics - model * * @author paru * */ -public class VMInfo -{ +public class VMInfo { - /** - * Comparator providing ordering of VMInfo objects by the current heap usage of their monitored jvms - * - * @author paru - * - */ - private static final class UsedHeapComparator implements Comparator - { - @Override - public int compare(VMInfo o1, VMInfo o2) - { - return Long.valueOf(o1.getHeapUsed()).compareTo( - Long.valueOf(o2.getHeapUsed())); - } - } + /** + * Comparator providing ordering of VMInfo objects by the current heap usage + * of their monitored jvms + * + * @author paru + * + */ + private static final class UsedHeapComparator implements Comparator { + @Override + public int compare(VMInfo o1, VMInfo o2) { + return Long.valueOf(o1.getHeapUsed()).compareTo(Long.valueOf(o2.getHeapUsed())); + } + } - /** - * Comparator providing ordering of VMInfo objects by the current CPU usage of their monitored jvms - * - * @author paru - * - */ - private static final class CPULoadComparator implements Comparator - { - @Override - public int compare(VMInfo o1, VMInfo o2) - { - return Double.valueOf(o2.getCpuLoad()).compareTo( - Double.valueOf(o1.getCpuLoad())); - } - } + /** + * Comparator providing ordering of VMInfo objects by the current CPU usage + * of their monitored jvms + * + * @author paru + * + */ + private static final class CPULoadComparator implements Comparator { + @Override + public int compare(VMInfo o1, VMInfo o2) { + return Double.valueOf(o2.getCpuLoad()).compareTo(Double.valueOf(o1.getCpuLoad())); + } + } - private ProxyClient proxyClient = null; + private ProxyClient proxyClient = null; - //private VirtualMachine vm = null; + // private VirtualMachine vm = null; - private OperatingSystemMXBean osBean; + private OperatingSystemMXBean osBean; - private RuntimeMXBean runtimeMXBean; + private RuntimeMXBean runtimeMXBean; - private Collection gcMXBeans; + private Collection gcMXBeans; - private long lastGcTime; + private long lastGcTime; - private long lastUpTime = -1; + private long lastUpTime = -1; - private long lastCPUTime = -1; + private long lastCPUTime = -1; - private long gcCount = 0; - - private double cpuLoad = 0.0; - - private double gcLoad = 0.0; - - private MemoryMXBean memoryMXBean; - - private MemoryUsage heapMemoryUsage; - - private MemoryUsage nonHeapMemoryUsage; - - private ThreadMXBean threadMXBean; - - private VMInfoState state_ = VMInfoState.INIT; - - private String rawId_ = null; - - private LocalVirtualMachine localVm_; - - public static final Comparator USED_HEAP_COMPARATOR = new UsedHeapComparator(); - - public static final Comparator CPU_LOAD_COMPARATOR = new CPULoadComparator(); - - private long deltaUptime_; - - private long deltaCpuTime_; - - private long deltaGcTime_; - - private int updateErrorCount_ = 0; - - private long totalLoadedClassCount_; - - private ClassLoadingMXBean classLoadingMXBean_; - - private boolean deadlocksDetected_ = false; - - private String vmVersion_ = null; - - private String osUser_; - - private long threadCount_; - - private Map systemProperties_; - - /** - * @param lastCPUProcessTime - * @param proxyClient - * @param vm - * @throws RuntimeException - */ - public VMInfo(ProxyClient proxyClient, LocalVirtualMachine localVm, - String rawId) throws Exception - { - super(); - localVm_ = localVm; - rawId_ = rawId; - this.proxyClient = proxyClient; - //this.vm = vm; - state_ = VMInfoState.ATTACHED; - update(); - } - - /** - * TODO: refactor to constructor? - * @param vmMap - * @param localvm - * @param vmid - * @param vmInfo - * @return - */ - public static VMInfo processNewVM(LocalVirtualMachine localvm, int vmid) - { - - try - { - if (localvm == null || !localvm.isAttachable()) - { - Logger.getLogger("jvmtop").log(Level.FINE, - "jvm is not attachable (PID=" + vmid + ")"); - return VMInfo.createDeadVM(vmid, localvm); - } - return attachToVM(localvm, vmid); - } - catch (Exception e) - { - Logger.getLogger("jvmtop").log(Level.FINE, - "error during attach (PID=" + vmid + ")", e); - return VMInfo.createDeadVM(vmid, localvm); - } - } - - /** - * - * Creates a new VMInfo which is attached to a given LocalVirtualMachine - * - * @param localvm - * @param vmid - * @return - * @throws AttachNotSupportedException - * @throws IOException - * @throws NoSuchMethodException - * @throws IllegalAccessException - * @throws InvocationTargetException - * @throws Exception - */ - private static VMInfo attachToVM(LocalVirtualMachine localvm, int vmid) - throws AttachNotSupportedException, IOException, NoSuchMethodException, - IllegalAccessException, InvocationTargetException, Exception - { - //VirtualMachine vm = VirtualMachine.attach("" + vmid); - try - { - - ProxyClient proxyClient = ProxyClient.getProxyClient(localvm); - proxyClient.connect(); - if (proxyClient.getConnectionState() == ConnectionState.DISCONNECTED) - { - Logger.getLogger("jvmtop").log(Level.FINE, - "connection refused (PID=" + vmid + ")"); - return createDeadVM(vmid, localvm); - } - return new VMInfo(proxyClient, localvm, vmid + ""); - } - catch (ConnectException rmiE) - { - if (rmiE.getMessage().contains("refused")) - { - Logger.getLogger("jvmtop").log(Level.FINE, - "connection refused (PID=" + vmid + ")", rmiE); - return createDeadVM(vmid, localvm, VMInfoState.CONNECTION_REFUSED); - } - rmiE.printStackTrace(System.err); - } - catch (IOException e) - { - if ((e.getCause() != null - && e.getCause() instanceof AttachNotSupportedException) - || e.getMessage().contains("Permission denied")) - { - Logger.getLogger("jvmtop").log(Level.FINE, - "could not attach (PID=" + vmid + ")", e); - return createDeadVM(vmid, localvm, VMInfoState.CONNECTION_REFUSED); - } - e.printStackTrace(System.err); - } - catch (Exception e) - { - Logger.getLogger("jvmtop").log(Level.WARNING, - "could not attach (PID=" + vmid + ")", e); - } - return createDeadVM(vmid, localvm); - } - - private VMInfo() - { - - } - - /** - * Creates a dead VMInfo, representing a jvm which cannot be attached or other monitoring issues occurred. - * - * @param vmid - * @param localVm - * @return - */ - public static VMInfo createDeadVM(int vmid, LocalVirtualMachine localVm) - { - return createDeadVM(vmid, localVm, VMInfoState.ERROR_DURING_ATTACH); - } - - /** - * Creates a dead VMInfo, representing a jvm in a given state - * which cannot be attached or other monitoring issues occurred. - * @param vmid - * @param localVm - * @return - */ - public static VMInfo createDeadVM(int vmid, LocalVirtualMachine localVm, - VMInfoState state) - { - VMInfo vmInfo = new VMInfo(); - vmInfo.state_ = state; - vmInfo.localVm_ = localVm; - return vmInfo; - } - - /** - * @return the state - */ - public VMInfoState getState() - { - return state_; - } - - /** - * Updates all jvm metrics to the most recent remote values - * - * @throws Exception - */ - public void update() throws Exception - { - if (state_ == VMInfoState.ERROR_DURING_ATTACH - || state_ == VMInfoState.DETACHED - || state_ == VMInfoState.CONNECTION_REFUSED) - { - return; - } - - if (proxyClient.isDead()) - { - state_ = VMInfoState.DETACHED; - return; - } - - try - { - proxyClient.flush(); - - osBean = proxyClient.getSunOperatingSystemMXBean(); - runtimeMXBean = proxyClient.getRuntimeMXBean(); - gcMXBeans = proxyClient.getGarbageCollectorMXBeans(); - classLoadingMXBean_ = proxyClient.getClassLoadingMXBean(); - memoryMXBean = proxyClient.getMemoryMXBean(); - heapMemoryUsage = memoryMXBean.getHeapMemoryUsage(); - nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage(); - threadMXBean = proxyClient.getThreadMXBean(); - - //TODO: fetch jvm-constant data only once - systemProperties_ = runtimeMXBean.getSystemProperties(); - vmVersion_ = extractShortVer(); - osUser_ = systemProperties_.get("user.name"); - updateInternal(); - - deadlocksDetected_ = threadMXBean.findDeadlockedThreads() != null - || threadMXBean.findMonitorDeadlockedThreads() != null; - - } - catch (Throwable e) - { - Logger.getLogger("jvmtop").log(Level.FINE, "error during update", e); - updateErrorCount_++; - if (updateErrorCount_ > 10) - { - state_ = VMInfoState.DETACHED; - } - else - { - state_ = VMInfoState.ATTACHED_UPDATE_ERROR; - } - } - } - - /** - * calculates internal delta metrics - * @throws Exception - */ - private void updateInternal() throws Exception - { - long uptime = runtimeMXBean.getUptime(); - - long cpuTime = proxyClient.getProcessCpuTime(); - //long cpuTime = osBean.getProcessCpuTime(); - long gcTime = sumGCTimes(); - gcCount = sumGCCount(); - if (lastUpTime > 0 && lastCPUTime > 0 && gcTime > 0) - { - deltaUptime_ = uptime - lastUpTime; - deltaCpuTime_ = (cpuTime - lastCPUTime) / 1000000; - deltaGcTime_ = gcTime - lastGcTime; - - gcLoad = calcLoad(deltaCpuTime_, deltaGcTime_); - cpuLoad = calcLoad(deltaUptime_, deltaCpuTime_); - } - - lastUpTime = uptime; - lastCPUTime = cpuTime; - lastGcTime = gcTime; - - totalLoadedClassCount_ = classLoadingMXBean_.getTotalLoadedClassCount(); - - threadCount_ = threadMXBean.getThreadCount(); - } - - /** - * calculates a "load", given on two deltas - * @param deltaUptime - * @param deltaTime - * @return - */ - private double calcLoad(double deltaUptime, double deltaTime) - { - if (deltaTime <= 0 || deltaUptime == 0) - { - return 0.0; - } - return Math.min(99.0, - deltaTime / (deltaUptime * osBean.getAvailableProcessors())); - } - - /** - * Returns the sum of all GC times - * @return - */ - private long sumGCTimes() - { - long sum = 0; - for (java.lang.management.GarbageCollectorMXBean mxBean : gcMXBeans) - { - sum += mxBean.getCollectionTime(); - } - return sum; - } - - /** - * Returns the sum of all GC invocations - * @return - */ - private long sumGCCount() - { - long sum = 0; - for (java.lang.management.GarbageCollectorMXBean mxBean : gcMXBeans) - { - sum += mxBean.getCollectionCount(); - } - return sum; - } - - public long getHeapUsed() - { - return heapMemoryUsage.getUsed(); - } - - public long getHeapMax() - { - return heapMemoryUsage.getMax(); - } - - public long getNonHeapUsed() - { - return nonHeapMemoryUsage.getUsed(); - } - - public long getNonHeapMax() - { - return nonHeapMemoryUsage.getMax(); - } - - public long getTotalLoadedClassCount() - { - return totalLoadedClassCount_; - } - - public boolean hasDeadlockThreads() - { - return deadlocksDetected_; - } - - public long getThreadCount() - { - return threadCount_; - } - - /** - * @return the cpuLoad - */ - public double getCpuLoad() - { - return cpuLoad; - } - - /** - * @return the gcLoad - */ - public double getGcLoad() - { - return gcLoad; - } - - /** - * @return the proxyClient - */ - public ProxyClient getProxyClient() - { - return proxyClient; - } - - public String getDisplayName() - { - return localVm_.displayName(); - } - - public Integer getId() - { - return localVm_.vmid(); - } - - public String getRawId() - { - return rawId_; - } - - public long getGcCount() - { - return gcCount; - } - - /** - * @return the vm - */ - /* - public VirtualMachine getVm() - { - return vm; - } - */ - - public String getVMVersion() - { - return vmVersion_; - } - - public String getOSUser() - { - return osUser_; - } - - public long getGcTime() - { - return lastGcTime; - } - - public RuntimeMXBean getRuntimeMXBean() - { - return runtimeMXBean; - } - - public Collection getGcMXBeans() - { - return gcMXBeans; - } - - public MemoryMXBean getMemoryMXBean() - { - return memoryMXBean; - } - - public ThreadMXBean getThreadMXBean() - { - return threadMXBean; - } - - public OperatingSystemMXBean getOSBean() - { - return osBean; - } - - public long getDeltaUptime() - { - return deltaUptime_; - } - - public long getDeltaCpuTime() - { - return deltaCpuTime_; - } - - public long getDeltaGcTime() - { - return deltaGcTime_; - } - - public Map getSystemProperties() - { - return systemProperties_; - } - - /** - * Extracts the jvmtop "short version" out of different properties - * TODO: should this be refactored? - * @param runtimeMXBean - * @return - */ - private String extractShortVer() - { - String vmVer = systemProperties_.get("java.runtime.version"); - - String vmVendor = systemProperties_.get("java.vendor"); - - Pattern pattern = Pattern.compile("[0-9]\\.([0-9])\\.0_([0-9]+)-.*"); - Matcher matcher = pattern.matcher(vmVer); - if (matcher.matches()) - { - return vmVendor.charAt(0) + matcher.group(1) + "U" + matcher.group(2); - } - else - { - pattern = Pattern.compile(".*-(.*)_.*"); - matcher = pattern.matcher(vmVer); - if (matcher.matches()) - { - return vmVendor.charAt(0) + matcher.group(1).substring(2, 6); - } - return vmVer; - } - } + private long gcCount = 0; + + private double cpuLoad = 0.0; + + private double gcLoad = 0.0; + + private MemoryMXBean memoryMXBean; + + private MemoryUsage heapMemoryUsage; + + private MemoryUsage nonHeapMemoryUsage; + + private ThreadMXBean threadMXBean; + + private VMInfoState state_ = VMInfoState.INIT; + + private String rawId_ = null; + + private LocalVirtualMachine localVm_; + + public static final Comparator USED_HEAP_COMPARATOR = new UsedHeapComparator(); + + public static final Comparator CPU_LOAD_COMPARATOR = new CPULoadComparator(); + + private long deltaUptime_; + + private long deltaCpuTime_; + + private long deltaGcTime_; + + private int updateErrorCount_ = 0; + + private long totalLoadedClassCount_; + + private ClassLoadingMXBean classLoadingMXBean_; + + private boolean deadlocksDetected_ = false; + + private String vmVersion_ = null; + + private String osUser_; + + private long threadCount_; + + private Map systemProperties_; + + /** + * @param lastCPUProcessTime + * @param proxyClient + * @param vm + * @throws RuntimeException + */ + public VMInfo(ProxyClient proxyClient, LocalVirtualMachine localVm, String rawId) throws Exception { + super(); + localVm_ = localVm; + rawId_ = rawId; + this.proxyClient = proxyClient; + // this.vm = vm; + state_ = VMInfoState.ATTACHED; + update(); + } + + /** + * TODO: refactor to constructor? + * + * @param vmMap + * @param localvm + * @param vmid + * @param vmInfo + * @return + */ + public static VMInfo processNewVM(LocalVirtualMachine localvm, int vmid) { + + try { + if (localvm == null || !localvm.isAttachable()) { + Logger.getLogger("jvmtop").log(Level.FINE, "jvm is not attachable (PID=" + vmid + ")"); + return VMInfo.createDeadVM(vmid, localvm); + } + return attachToVM(localvm, vmid); + } catch (Exception e) { + Logger.getLogger("jvmtop").log(Level.FINE, "error during attach (PID=" + vmid + ")", e); + return VMInfo.createDeadVM(vmid, localvm); + } + } + + /** + * + * Creates a new VMInfo which is attached to a given LocalVirtualMachine + * + * @param localvm + * @param vmid + * @return + * @throws AttachNotSupportedException + * @throws IOException + * @throws NoSuchMethodException + * @throws IllegalAccessException + * @throws InvocationTargetException + * @throws Exception + */ + private static VMInfo attachToVM(LocalVirtualMachine localvm, int vmid) throws AttachNotSupportedException, IOException, NoSuchMethodException, IllegalAccessException, + InvocationTargetException, Exception { + // VirtualMachine vm = VirtualMachine.attach("" + vmid); + try { + + ProxyClient proxyClient = ProxyClient.getProxyClient(localvm); + proxyClient.connect(); + if (proxyClient.getConnectionState() == ConnectionState.DISCONNECTED) { + Logger.getLogger("jvmtop").log(Level.FINE, "connection refused (PID=" + vmid + ")"); + return createDeadVM(vmid, localvm); + } + return new VMInfo(proxyClient, localvm, vmid + ""); + } catch (ConnectException rmiE) { + if (rmiE.getMessage().contains("refused")) { + Logger.getLogger("jvmtop").log(Level.FINE, "connection refused (PID=" + vmid + ")", rmiE); + return createDeadVM(vmid, localvm, VMInfoState.CONNECTION_REFUSED); + } + rmiE.printStackTrace(System.err); + } catch (IOException e) { + if ((e.getCause() != null && e.getCause() instanceof AttachNotSupportedException) || e.getMessage().contains("Permission denied")) { + Logger.getLogger("jvmtop").log(Level.FINE, "could not attach (PID=" + vmid + ")", e); + return createDeadVM(vmid, localvm, VMInfoState.CONNECTION_REFUSED); + } + e.printStackTrace(System.err); + } catch (Exception e) { + Logger.getLogger("jvmtop").log(Level.WARNING, "could not attach (PID=" + vmid + ")", e); + } + return createDeadVM(vmid, localvm); + } + + private VMInfo() { + + } + + /** + * Creates a dead VMInfo, representing a jvm which cannot be attached or + * other monitoring issues occurred. + * + * @param vmid + * @param localVm + * @return + */ + public static VMInfo createDeadVM(int vmid, LocalVirtualMachine localVm) { + return createDeadVM(vmid, localVm, VMInfoState.ERROR_DURING_ATTACH); + } + + /** + * Creates a dead VMInfo, representing a jvm in a given state which cannot + * be attached or other monitoring issues occurred. + * + * @param vmid + * @param localVm + * @return + */ + public static VMInfo createDeadVM(int vmid, LocalVirtualMachine localVm, VMInfoState state) { + VMInfo vmInfo = new VMInfo(); + vmInfo.state_ = state; + vmInfo.localVm_ = localVm; + return vmInfo; + } + + /** + * @return the state + */ + public VMInfoState getState() { + return state_; + } + + /** + * Updates all jvm metrics to the most recent remote values + * + * @throws Exception + */ + public void update() throws Exception { + if (state_ == VMInfoState.ERROR_DURING_ATTACH || state_ == VMInfoState.DETACHED || state_ == VMInfoState.CONNECTION_REFUSED) + return; + + if (proxyClient.isDead()) { + state_ = VMInfoState.DETACHED; + return; + } + + try { + proxyClient.flush(); + + osBean = proxyClient.getSunOperatingSystemMXBean(); + runtimeMXBean = proxyClient.getRuntimeMXBean(); + gcMXBeans = proxyClient.getGarbageCollectorMXBeans(); + classLoadingMXBean_ = proxyClient.getClassLoadingMXBean(); + memoryMXBean = proxyClient.getMemoryMXBean(); + heapMemoryUsage = memoryMXBean.getHeapMemoryUsage(); + nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage(); + threadMXBean = proxyClient.getThreadMXBean(); + + // TODO: fetch jvm-constant data only once + systemProperties_ = runtimeMXBean.getSystemProperties(); + vmVersion_ = extractShortVer(); + osUser_ = systemProperties_.get("user.name"); + updateInternal(); + + deadlocksDetected_ = threadMXBean.findDeadlockedThreads() != null || threadMXBean.findMonitorDeadlockedThreads() != null; + + } catch (Throwable e) { + Logger.getLogger("jvmtop").log(Level.FINE, "error during update", e); + updateErrorCount_++; + if (updateErrorCount_ > 10) + state_ = VMInfoState.DETACHED; + else + state_ = VMInfoState.ATTACHED_UPDATE_ERROR; + } + } + + /** + * calculates internal delta metrics + * + * @throws Exception + */ + private void updateInternal() throws Exception { + long uptime = runtimeMXBean.getUptime(); + + long cpuTime = proxyClient.getProcessCpuTime(); + // long cpuTime = osBean.getProcessCpuTime(); + long gcTime = sumGCTimes(); + gcCount = sumGCCount(); + if (lastUpTime > 0 && lastCPUTime > 0 && gcTime > 0) { + deltaUptime_ = uptime - lastUpTime; + deltaCpuTime_ = (cpuTime - lastCPUTime) / 1000000; + deltaGcTime_ = gcTime - lastGcTime; + + gcLoad = calcLoad(deltaCpuTime_, deltaGcTime_); + cpuLoad = calcLoad(deltaUptime_, deltaCpuTime_); + } + + lastUpTime = uptime; + lastCPUTime = cpuTime; + lastGcTime = gcTime; + + totalLoadedClassCount_ = classLoadingMXBean_.getTotalLoadedClassCount(); + + threadCount_ = threadMXBean.getThreadCount(); + } + + /** + * calculates a "load", given on two deltas + * + * @param deltaUptime + * @param deltaTime + * @return + */ + private double calcLoad(double deltaUptime, double deltaTime) { + if (deltaTime <= 0 || deltaUptime == 0) + return 0.0; + return Math.min(99.0, deltaTime / (deltaUptime * osBean.getAvailableProcessors())); + } + + /** + * Returns the sum of all GC times + * + * @return + */ + private long sumGCTimes() { + long sum = 0; + for (java.lang.management.GarbageCollectorMXBean mxBean : gcMXBeans) + sum += mxBean.getCollectionTime(); + return sum; + } + + /** + * Returns the sum of all GC invocations + * + * @return + */ + private long sumGCCount() { + long sum = 0; + for (java.lang.management.GarbageCollectorMXBean mxBean : gcMXBeans) + sum += mxBean.getCollectionCount(); + return sum; + } + + public long getHeapUsed() { + return heapMemoryUsage.getUsed(); + } + + public long getHeapMax() { + return heapMemoryUsage.getMax(); + } + + public long getNonHeapUsed() { + return nonHeapMemoryUsage.getUsed(); + } + + public long getNonHeapMax() { + return nonHeapMemoryUsage.getMax(); + } + + public long getTotalLoadedClassCount() { + return totalLoadedClassCount_; + } + + public boolean hasDeadlockThreads() { + return deadlocksDetected_; + } + + public long getThreadCount() { + return threadCount_; + } + + /** + * @return the cpuLoad + */ + public double getCpuLoad() { + return cpuLoad; + } + + /** + * @return the gcLoad + */ + public double getGcLoad() { + return gcLoad; + } + + /** + * @return the proxyClient + */ + public ProxyClient getProxyClient() { + return proxyClient; + } + + public String getDisplayName() { + return localVm_.displayName(); + } + + public Integer getId() { + return localVm_.vmid(); + } + + public String getRawId() { + return rawId_; + } + + public long getGcCount() { + return gcCount; + } + + /** + * @return the vm + */ + /* + * public VirtualMachine getVm() { return vm; } + */ + + public String getVMVersion() { + return vmVersion_; + } + + public String getOSUser() { + return osUser_; + } + + public long getGcTime() { + return lastGcTime; + } + + public RuntimeMXBean getRuntimeMXBean() { + return runtimeMXBean; + } + + public Collection getGcMXBeans() { + return gcMXBeans; + } + + public MemoryMXBean getMemoryMXBean() { + return memoryMXBean; + } + + public ThreadMXBean getThreadMXBean() { + return threadMXBean; + } + + public OperatingSystemMXBean getOSBean() { + return osBean; + } + + public long getDeltaUptime() { + return deltaUptime_; + } + + public long getDeltaCpuTime() { + return deltaCpuTime_; + } + + public long getDeltaGcTime() { + return deltaGcTime_; + } + + public Map getSystemProperties() { + return systemProperties_; + } + + /** + * Extracts the jvmtop "short version" out of different properties TODO: + * should this be refactored? + * + * @param runtimeMXBean + * @return + */ + private String extractShortVer() { + String vmVer = systemProperties_.get("java.runtime.version"); + + String vmVendor = systemProperties_.get("java.vendor"); + + Pattern pattern = Pattern.compile("[0-9]\\.([0-9])\\.0_([0-9]+)-.*"); + Matcher matcher = pattern.matcher(vmVer); + if (matcher.matches()) + return vmVendor.charAt(0) + matcher.group(1) + "U" + matcher.group(2); + else { + pattern = Pattern.compile(".*-(.*)_.*"); + matcher = pattern.matcher(vmVer); + if (matcher.matches()) + return vmVendor.charAt(0) + matcher.group(1).substring(2, 6); + return vmVer; + } + } } diff --git a/src/main/java/com/jvmtop/monitor/VMInfoState.java b/src/main/java/com/jvmtop/monitor/VMInfoState.java index a09a2e4..29c51b5 100644 --- a/src/main/java/com/jvmtop/monitor/VMInfoState.java +++ b/src/main/java/com/jvmtop/monitor/VMInfoState.java @@ -27,7 +27,5 @@ * */ public enum VMInfoState { - INIT, ERROR_DURING_ATTACH, ATTACHED, ATTACHED_UPDATE_ERROR, DETACHED, - CONNECTION_REFUSED, - UNKNOWN_ERROR + INIT, ERROR_DURING_ATTACH, ATTACHED, ATTACHED_UPDATE_ERROR, DETACHED, CONNECTION_REFUSED, UNKNOWN_ERROR } \ No newline at end of file diff --git a/src/main/java/com/jvmtop/openjdk/tools/ConnectionState.java b/src/main/java/com/jvmtop/openjdk/tools/ConnectionState.java index 54217ee..433b857 100644 --- a/src/main/java/com/jvmtop/openjdk/tools/ConnectionState.java +++ b/src/main/java/com/jvmtop/openjdk/tools/ConnectionState.java @@ -31,20 +31,20 @@ package com.jvmtop.openjdk.tools; /** - * Values for the {@linkplain #CONNECTION_STATE_PROPERTY - * ConnectionState} bound property. + * Values for the {@linkplain #CONNECTION_STATE_PROPERTY ConnectionState} + * bound property. */ public enum ConnectionState { - /** - * The connection has been successfully established. - */ - CONNECTED, - /** - * No connection present. - */ - DISCONNECTED, - /** - * The connection is being attempted. - */ - CONNECTING + /** + * The connection has been successfully established. + */ + CONNECTED, + /** + * No connection present. + */ + DISCONNECTED, + /** + * The connection is being attempted. + */ + CONNECTING } \ No newline at end of file diff --git a/src/main/java/com/jvmtop/openjdk/tools/LocalVirtualMachine.java b/src/main/java/com/jvmtop/openjdk/tools/LocalVirtualMachine.java index 37749b8..2b28971 100644 --- a/src/main/java/com/jvmtop/openjdk/tools/LocalVirtualMachine.java +++ b/src/main/java/com/jvmtop/openjdk/tools/LocalVirtualMachine.java @@ -54,349 +54,264 @@ // Sun specific // Sun private -public class LocalVirtualMachine -{ - private String address; - - private String commandLine; - - private String displayName; - - private int vmid; - - private boolean isAttachSupported; - - private static boolean J9Mode = false; - - static - { - if (System.getProperty("java.vm.name").contains("IBM J9")) - { - J9Mode = true; - System.setProperty("com.ibm.tools.attach.timeout", "5000"); - } - } - - public static boolean isJ9Mode() - { - return J9Mode; - } - - public LocalVirtualMachine(int vmid, String commandLine, boolean canAttach, - String connectorAddress) - { - this.vmid = vmid; - this.commandLine = commandLine; - this.address = connectorAddress; - this.isAttachSupported = canAttach; - this.displayName = getDisplayName(commandLine); - } - - private static String getDisplayName(String commandLine) - { - // trim the pathname of jar file if it's a jar - String[] res = commandLine.split(" ", 2); - if (res[0].endsWith(".jar")) - { - File jarfile = new File(res[0]); - String displayName = jarfile.getName(); - if (res.length == 2) - { - displayName += " " + res[1]; - } - return displayName; - } - return commandLine; - } - - public int vmid() - { - return vmid; - } - - public boolean isManageable() - { - return (address != null); - } - - public boolean isAttachable() - { - return isAttachSupported; - } - - public void startManagementAgent() throws IOException - { - if (address != null) - { - // already started - return; - } - - if (!isAttachable()) - { - throw new IOException("This virtual machine \"" + vmid - + "\" does not support dynamic attach."); - } - - loadManagementAgent(); - // fails to load or start the management agent - if (address == null) - { - // should never reach here - throw new IOException("Fails to find connector address"); - } - } - - public String connectorAddress() - { - // return null if not available or no JMX agent - return address; - } - - public String displayName() - { - return displayName; - } - - @Override - public String toString() - { - return commandLine; - } - - // This method returns the list of all virtual machines currently - // running on the machine - public static Map getAllVirtualMachines() - { - Map map = new HashMap(); - getMonitoredVMs(map, Collections.EMPTY_MAP); - getAttachableVMs(map, Collections.EMPTY_MAP); - return map; - } - - // This method returns the list of all virtual machines currently - // running on the machine but not contained in existingVmMap - public static Map getNewVirtualMachines( - Map existingVmMap) - { - Map map = new HashMap( - existingVmMap); - getMonitoredVMs(map, existingVmMap); - getAttachableVMs(map, existingVmMap); - return map; - } - - private static void getMonitoredVMs(Map map, - Map existingMap) - { - //Unsupported on J9 - if (J9Mode) - { - return; - } - MonitoredHost host; - Set vms; - try - { - host = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null)); - vms = host.activeVms(); - } - catch (java.net.URISyntaxException sx) - { - throw new InternalError(sx.getMessage()); - } - catch (MonitorException mx) - { - throw new InternalError(mx.getMessage()); - } - for (Object vmid : vms) - { - if (existingMap.containsKey(vmid)) - { - continue; - } - if (vmid instanceof Integer) - { - int pid = ((Integer) vmid).intValue(); - String name = vmid.toString(); // default to pid if name not available - boolean attachable = false; - String address = null; - try - { - MonitoredVm mvm = host.getMonitoredVm(new VmIdentifier(name)); - // use the command line as the display name - name = MonitoredVmUtil.commandLine(mvm); - attachable = MonitoredVmUtil.isAttachable(mvm); - address = ConnectorAddressLink.importFrom(pid); - mvm.detach(); - } - catch (Exception x) - { - // ignore - } - map.put((Integer) vmid, new LocalVirtualMachine(pid, name, attachable, - address)); - } - } - } - - private static final String LOCAL_CONNECTOR_ADDRESS_PROP = "com.sun.management.jmxremote.localConnectorAddress"; - - private static void getAttachableVMs(Map map, - Map existingVmMap) - { - List vms = VirtualMachine.list(); - for (VirtualMachineDescriptor vmd : vms) - { - try - { - Integer vmid = Integer.valueOf(vmd.id()); - if (!map.containsKey(vmid) && !existingVmMap.containsKey(vmid)) - { - boolean attachable = false; - String address = null; - try - { - VirtualMachine vm = VirtualMachine.attach(vmd); - attachable = true; - Properties agentProps = vm.getAgentProperties(); - address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); - vm.detach(); - } - catch (AttachNotSupportedException x) - { - // not attachable - x.printStackTrace(System.err); - } - catch (NullPointerException e) - { - e.printStackTrace(System.err); - } - catch (IOException x) - { - // ignore - } - map.put(vmid, - new LocalVirtualMachine(vmid.intValue(), vmd.displayName(), - attachable, address)); - } - } - catch (NumberFormatException e) - { - // do not support vmid different than pid - } - } - } - - public static LocalVirtualMachine getLocalVirtualMachine(int vmid) - throws Exception - { - Map map = getAllVirtualMachines(); - LocalVirtualMachine lvm = map.get(vmid); - if (lvm == null) - { - // Check if the VM is attachable but not included in the list - // if it's running with a different security context. - // For example, Windows services running - // local SYSTEM account are attachable if you have Adminstrator - // privileges. - boolean attachable = false; - String address = null; - String name = String.valueOf(vmid); // default display name to pid - - VirtualMachine vm = VirtualMachine.attach(name); - attachable = true; - Properties agentProps = vm.getAgentProperties(); - address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); - vm.detach(); - lvm = new LocalVirtualMachine(vmid, name, attachable, address); - - } - return lvm; - } - - public static LocalVirtualMachine getDelegateMachine(VirtualMachine vm) - throws IOException - { - // privileges. - boolean attachable = false; - String address = null; - String name = String.valueOf(vm.id()); // default display name to pid - - attachable = true; - Properties agentProps = vm.getAgentProperties(); - address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); - vm.detach(); - return new LocalVirtualMachine(Integer.parseInt(vm.id()), name, attachable, - address); - } - - // load the management agent into the target VM - private void loadManagementAgent() throws IOException - { - VirtualMachine vm = null; - String name = String.valueOf(vmid); - try - { - vm = VirtualMachine.attach(name); - } - catch (AttachNotSupportedException x) - { - IOException ioe = new IOException(x.getMessage()); - ioe.initCause(x); - throw ioe; - } - - String home = vm.getSystemProperties().getProperty("java.home"); - - // Normally in ${java.home}/jre/lib/management-agent.jar but might - // be in ${java.home}/lib in build environments. - - String agent = home + File.separator + "jre" + File.separator + "lib" - + File.separator + "management-agent.jar"; - File f = new File(agent); - if (!f.exists()) - { - agent = home + File.separator + "lib" + File.separator - + "management-agent.jar"; - f = new File(agent); - if (!f.exists()) - { - throw new IOException("Management agent not found"); - } - } - - agent = f.getCanonicalPath(); - try - { - vm.loadAgent(agent, "com.sun.management.jmxremote"); - } - catch (AgentLoadException x) - { - IOException ioe = new IOException(x.getMessage()); - ioe.initCause(x); - throw ioe; - } - catch (AgentInitializationException x) - { - IOException ioe = new IOException(x.getMessage()); - ioe.initCause(x); - throw ioe; - } - - // get the connector address - if (J9Mode) - { - Properties localProperties = vm.getSystemProperties(); - this.address = ((String) localProperties - .get("com.sun.management.jmxremote.localConnectorAddress")); - } - else - { - Properties agentProps = vm.getAgentProperties(); - address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); - } - - vm.detach(); - } +public class LocalVirtualMachine { + private String address; + + private String commandLine; + + private String displayName; + + private int vmid; + + private boolean isAttachSupported; + + private static boolean J9Mode = false; + + static { + if (System.getProperty("java.vm.name").contains("IBM J9")) { + J9Mode = true; + System.setProperty("com.ibm.tools.attach.timeout", "5000"); + } + } + + public static boolean isJ9Mode() { + return J9Mode; + } + + public LocalVirtualMachine(int vmid, String commandLine, boolean canAttach, String connectorAddress) { + this.vmid = vmid; + this.commandLine = commandLine; + this.address = connectorAddress; + this.isAttachSupported = canAttach; + this.displayName = getDisplayName(commandLine); + } + + private static String getDisplayName(String commandLine) { + // trim the pathname of jar file if it's a jar + String[] res = commandLine.split(" ", 2); + if (res[0].endsWith(".jar")) { + File jarfile = new File(res[0]); + String displayName = jarfile.getName(); + if (res.length == 2) + displayName += " " + res[1]; + return displayName; + } + return commandLine; + } + + public int vmid() { + return vmid; + } + + public boolean isManageable() { + return (address != null); + } + + public boolean isAttachable() { + return isAttachSupported; + } + + public void startManagementAgent() throws IOException { + if (address != null) + // already started + return; + + if (!isAttachable()) + throw new IOException("This virtual machine \"" + vmid + "\" does not support dynamic attach."); + + loadManagementAgent(); + // fails to load or start the management agent + if (address == null) + // should never reach here + throw new IOException("Fails to find connector address"); + } + + public String connectorAddress() { + // return null if not available or no JMX agent + return address; + } + + public String displayName() { + return displayName; + } + + @Override + public String toString() { + return commandLine; + } + + // This method returns the list of all virtual machines currently + // running on the machine + public static Map getAllVirtualMachines() { + Map map = new HashMap(); + getMonitoredVMs(map, Collections.EMPTY_MAP); + getAttachableVMs(map, Collections.EMPTY_MAP); + return map; + } + + // This method returns the list of all virtual machines currently + // running on the machine but not contained in existingVmMap + public static Map getNewVirtualMachines(Map existingVmMap) { + Map map = new HashMap(existingVmMap); + getMonitoredVMs(map, existingVmMap); + getAttachableVMs(map, existingVmMap); + return map; + } + + private static void getMonitoredVMs(Map map, Map existingMap) { + // Unsupported on J9 + if (J9Mode) + return; + MonitoredHost host; + Set vms; + try { + host = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null)); + vms = host.activeVms(); + } catch (java.net.URISyntaxException sx) { + throw new InternalError(sx.getMessage()); + } catch (MonitorException mx) { + throw new InternalError(mx.getMessage()); + } + for (Object vmid : vms) { + if (existingMap.containsKey(vmid)) + continue; + if (vmid instanceof Integer) { + int pid = ((Integer) vmid).intValue(); + String name = vmid.toString(); // default to pid if name not + // available + boolean attachable = false; + String address = null; + try { + MonitoredVm mvm = host.getMonitoredVm(new VmIdentifier(name)); + // use the command line as the display name + name = MonitoredVmUtil.commandLine(mvm); + attachable = MonitoredVmUtil.isAttachable(mvm); + address = ConnectorAddressLink.importFrom(pid); + mvm.detach(); + } catch (Exception x) { + // ignore + } + map.put((Integer) vmid, new LocalVirtualMachine(pid, name, attachable, address)); + } + } + } + + private static final String LOCAL_CONNECTOR_ADDRESS_PROP = "com.sun.management.jmxremote.localConnectorAddress"; + + private static void getAttachableVMs(Map map, Map existingVmMap) { + List vms = VirtualMachine.list(); + for (VirtualMachineDescriptor vmd : vms) + try { + Integer vmid = Integer.valueOf(vmd.id()); + if (!map.containsKey(vmid) && !existingVmMap.containsKey(vmid)) { + boolean attachable = false; + String address = null; + try { + VirtualMachine vm = VirtualMachine.attach(vmd); + attachable = true; + Properties agentProps = vm.getAgentProperties(); + address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); + vm.detach(); + } catch (AttachNotSupportedException x) { + // not attachable + x.printStackTrace(System.err); + } catch (NullPointerException e) { + e.printStackTrace(System.err); + } catch (IOException x) { + // ignore + } + map.put(vmid, new LocalVirtualMachine(vmid.intValue(), vmd.displayName(), attachable, address)); + } + } catch (NumberFormatException e) { + // do not support vmid different than pid + } + } + + public static LocalVirtualMachine getLocalVirtualMachine(int vmid) throws Exception { + Map map = getAllVirtualMachines(); + LocalVirtualMachine lvm = map.get(vmid); + if (lvm == null) { + // Check if the VM is attachable but not included in the list + // if it's running with a different security context. + // For example, Windows services running + // local SYSTEM account are attachable if you have Adminstrator + // privileges. + boolean attachable = false; + String address = null; + String name = String.valueOf(vmid); // default display name to pid + + VirtualMachine vm = VirtualMachine.attach(name); + attachable = true; + Properties agentProps = vm.getAgentProperties(); + address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); + vm.detach(); + lvm = new LocalVirtualMachine(vmid, name, attachable, address); + + } + return lvm; + } + + public static LocalVirtualMachine getDelegateMachine(VirtualMachine vm) throws IOException { + // privileges. + boolean attachable = false; + String address = null; + String name = String.valueOf(vm.id()); // default display name to pid + + attachable = true; + Properties agentProps = vm.getAgentProperties(); + address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); + vm.detach(); + return new LocalVirtualMachine(Integer.parseInt(vm.id()), name, attachable, address); + } + + // load the management agent into the target VM + private void loadManagementAgent() throws IOException { + VirtualMachine vm = null; + String name = String.valueOf(vmid); + try { + vm = VirtualMachine.attach(name); + } catch (AttachNotSupportedException x) { + IOException ioe = new IOException(x.getMessage()); + ioe.initCause(x); + throw ioe; + } + + String home = vm.getSystemProperties().getProperty("java.home"); + + // Normally in ${java.home}/jre/lib/management-agent.jar but might + // be in ${java.home}/lib in build environments. + + String agent = home + File.separator + "jre" + File.separator + "lib" + File.separator + "management-agent.jar"; + File f = new File(agent); + if (!f.exists()) { + agent = home + File.separator + "lib" + File.separator + "management-agent.jar"; + f = new File(agent); + if (!f.exists()) + throw new IOException("Management agent not found"); + } + + agent = f.getCanonicalPath(); + try { + vm.loadAgent(agent, "com.sun.management.jmxremote"); + } catch (AgentLoadException x) { + IOException ioe = new IOException(x.getMessage()); + ioe.initCause(x); + throw ioe; + } catch (AgentInitializationException x) { + IOException ioe = new IOException(x.getMessage()); + ioe.initCause(x); + throw ioe; + } + + // get the connector address + if (J9Mode) { + Properties localProperties = vm.getSystemProperties(); + this.address = ((String) localProperties.get("com.sun.management.jmxremote.localConnectorAddress")); + } else { + Properties agentProps = vm.getAgentProperties(); + address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); + } + + vm.detach(); + } } diff --git a/src/main/java/com/jvmtop/openjdk/tools/MemoryPoolStat.java b/src/main/java/com/jvmtop/openjdk/tools/MemoryPoolStat.java index 356a2d9..f870879 100644 --- a/src/main/java/com/jvmtop/openjdk/tools/MemoryPoolStat.java +++ b/src/main/java/com/jvmtop/openjdk/tools/MemoryPoolStat.java @@ -32,107 +32,102 @@ import java.lang.management.MemoryUsage; public class MemoryPoolStat { - private String poolName; - private long usageThreshold; - private MemoryUsage usage; - private long lastGcId; - private long lastGcStartTime; - private long lastGcEndTime; - private long collectThreshold; - private MemoryUsage beforeGcUsage; - private MemoryUsage afterGcUsage; - - MemoryPoolStat(String name, - long usageThreshold, - MemoryUsage usage, - long lastGcId, - long lastGcStartTime, - long lastGcEndTime, - long collectThreshold, - MemoryUsage beforeGcUsage, - MemoryUsage afterGcUsage) { - this.poolName = name; - this.usageThreshold = usageThreshold; - this.usage = usage; - this.lastGcId = lastGcId; - this.lastGcStartTime = lastGcStartTime; - this.lastGcEndTime = lastGcEndTime; - this.collectThreshold = collectThreshold; - this.beforeGcUsage = beforeGcUsage; - this.afterGcUsage = afterGcUsage; - } - - /** - * Returns the memory pool name. - */ - public String getPoolName() { - return poolName; - } - - /** - * Returns the current memory usage. - */ - public MemoryUsage getUsage() { - return usage; - } - - /** - * Returns the current usage threshold. - * -1 if not supported. - */ - public long getUsageThreshold() { - return usageThreshold; - } - - /** - * Returns the current collection usage threshold. - * -1 if not supported. - */ - public long getCollectionUsageThreshold() { - return collectThreshold; - } - - /** - * Returns the Id of GC. - */ - public long getLastGcId() { - return lastGcId; - } - - - /** - * Returns the start time of the most recent GC on - * the memory pool for this statistics in milliseconds. - * - * Return 0 if no GC occurs. - */ - public long getLastGcStartTime() { - return lastGcStartTime; - } - - /** - * Returns the end time of the most recent GC on - * the memory pool for this statistics in milliseconds. - * - * Return 0 if no GC occurs. - */ - public long getLastGcEndTime() { - return lastGcEndTime; - } - - /** - * Returns the memory usage before the most recent GC started. - * null if no GC occurs. - */ - public MemoryUsage getBeforeGcUsage() { - return beforeGcUsage; - } - - /** - * Returns the memory usage after the most recent GC finished. - * null if no GC occurs. - */ - public MemoryUsage getAfterGcUsage() { - return beforeGcUsage; - } + private String poolName; + + private long usageThreshold; + + private MemoryUsage usage; + + private long lastGcId; + + private long lastGcStartTime; + + private long lastGcEndTime; + + private long collectThreshold; + + private MemoryUsage beforeGcUsage; + + MemoryPoolStat(String name, long usageThreshold, MemoryUsage usage, long lastGcId, long lastGcStartTime, long lastGcEndTime, long collectThreshold, MemoryUsage beforeGcUsage, + MemoryUsage afterGcUsage) { + this.poolName = name; + this.usageThreshold = usageThreshold; + this.usage = usage; + this.lastGcId = lastGcId; + this.lastGcStartTime = lastGcStartTime; + this.lastGcEndTime = lastGcEndTime; + this.collectThreshold = collectThreshold; + this.beforeGcUsage = beforeGcUsage; + } + + /** + * Returns the memory pool name. + */ + public String getPoolName() { + return poolName; + } + + /** + * Returns the current memory usage. + */ + public MemoryUsage getUsage() { + return usage; + } + + /** + * Returns the current usage threshold. -1 if not supported. + */ + public long getUsageThreshold() { + return usageThreshold; + } + + /** + * Returns the current collection usage threshold. -1 if not supported. + */ + public long getCollectionUsageThreshold() { + return collectThreshold; + } + + /** + * Returns the Id of GC. + */ + public long getLastGcId() { + return lastGcId; + } + + /** + * Returns the start time of the most recent GC on the memory pool for this + * statistics in milliseconds. + * + * Return 0 if no GC occurs. + */ + public long getLastGcStartTime() { + return lastGcStartTime; + } + + /** + * Returns the end time of the most recent GC on the memory pool for this + * statistics in milliseconds. + * + * Return 0 if no GC occurs. + */ + public long getLastGcEndTime() { + return lastGcEndTime; + } + + /** + * Returns the memory usage before the most recent GC started. null if no GC + * occurs. + */ + public MemoryUsage getBeforeGcUsage() { + return beforeGcUsage; + } + + /** + * Returns the memory usage after the most recent GC finished. null if no GC + * occurs. + */ + public MemoryUsage getAfterGcUsage() { + return beforeGcUsage; + } } diff --git a/src/main/java/com/jvmtop/openjdk/tools/ProxyClient.java b/src/main/java/com/jvmtop/openjdk/tools/ProxyClient.java index e5ca84d..7472c14 100644 --- a/src/main/java/com/jvmtop/openjdk/tools/ProxyClient.java +++ b/src/main/java/com/jvmtop/openjdk/tools/ProxyClient.java @@ -29,7 +29,14 @@ */ package com.jvmtop.openjdk.tools; -import static java.lang.management.ManagementFactory.*; +import static java.lang.management.ManagementFactory.CLASS_LOADING_MXBEAN_NAME; +import static java.lang.management.ManagementFactory.COMPILATION_MXBEAN_NAME; +import static java.lang.management.ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE; +import static java.lang.management.ManagementFactory.MEMORY_MXBEAN_NAME; +import static java.lang.management.ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME; +import static java.lang.management.ManagementFactory.RUNTIME_MXBEAN_NAME; +import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME; +import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -89,1033 +96,907 @@ import sun.rmi.server.UnicastRef2; import sun.rmi.transport.LiveRef; -public class ProxyClient -{ - - private ConnectionState connectionState = ConnectionState.DISCONNECTED; - - - private static Map cache = - Collections.synchronizedMap(new HashMap()); - - private volatile boolean isDead = true; - private String hostName = null; - private int port = 0; - private String userName = null; - private String password = null; - private boolean hasPlatformMXBeans = false; - private boolean hasHotSpotDiagnosticMXBean= false; - private boolean hasCompilationMXBean = false; - private boolean supportsLockUsage = false; - - // REVISIT: VMPanel and other places relying using getUrl(). - - // set only if it's created for local monitoring - private LocalVirtualMachine lvm; - - // set only if it's created from a given URL via the Advanced tab - private String advancedUrl = null; - - private JMXServiceURL jmxUrl = null; - private MBeanServerConnection mbsc = null; - private SnapshotMBeanServerConnection server = null; - private JMXConnector jmxc = null; - private RMIServer stub = null; - private static final SslRMIClientSocketFactory sslRMIClientSocketFactory = - new SslRMIClientSocketFactory(); - private String registryHostName = null; - private int registryPort = 0; - private boolean vmConnector = false; - private boolean sslRegistry = false; - private boolean sslStub = false; - final private String connectionName; - final private String displayName; - - private ClassLoadingMXBean classLoadingMBean = null; - private CompilationMXBean compilationMBean = null; - private MemoryMXBean memoryMBean = null; - private OperatingSystemMXBean operatingSystemMBean = null; - private RuntimeMXBean runtimeMBean = null; - private ThreadMXBean threadMBean = null; - - private java.lang.management.OperatingSystemMXBean sunOperatingSystemMXBean = null; - - // private HotSpotDiagnosticMXBean hotspotDiagnosticMXBean = null; - - private List garbageCollectorMBeans = null; - - final static private String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME = - "com.sun.management:type=HotSpotDiagnostic"; - - private ProxyClient(String hostName, int port, - String userName, String password) throws IOException { - this.connectionName = getConnectionName(hostName, port, userName); - this.displayName = connectionName; - if (hostName.equals("localhost") && port == 0) { - // Monitor self - this.hostName = hostName; - this.port = port; - } else { - // Create an RMI connector client and connect it to - // the RMI connector server - final String urlPath = "/jndi/rmi://" + hostName + ":" + port + - "/jmxrmi"; - JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath); - setParameters(url, userName, password); - vmConnector = true; - registryHostName = hostName; - registryPort = port; - checkSslConfig(); - } - } - - private ProxyClient(String url, - String userName, String password) throws IOException { - this.advancedUrl = url; - this.connectionName = getConnectionName(url, userName); - this.displayName = connectionName; - setParameters(new JMXServiceURL(url), userName, password); - } - - private ProxyClient(LocalVirtualMachine lvm) throws IOException { - this.lvm = lvm; - this.connectionName = getConnectionName(lvm); - this.displayName = "pid: " + lvm.vmid() + " " + lvm.displayName(); - } - - private void setParameters(JMXServiceURL url, String userName, String password) { - this.jmxUrl = url; - this.hostName = jmxUrl.getHost(); - this.port = jmxUrl.getPort(); - this.userName = userName; - this.password = password; - } - - private static void checkStub(Remote stub, - Class stubClass) { - // Check remote stub is from the expected class. - // - if (stub.getClass() != stubClass) { - if (!Proxy.isProxyClass(stub.getClass())) { - throw new SecurityException( - "Expecting a " + stubClass.getName() + " stub!"); - } else { - InvocationHandler handler = Proxy.getInvocationHandler(stub); - if (handler.getClass() != RemoteObjectInvocationHandler.class) { - throw new SecurityException( - "Expecting a dynamic proxy instance with a " + - RemoteObjectInvocationHandler.class.getName() + - " invocation handler!"); - } else { - stub = (Remote) handler; - } - } - } - // Check RemoteRef in stub is from the expected class - // "sun.rmi.server.UnicastRef2". - // - RemoteRef ref = ((RemoteObject)stub).getRef(); - if (ref.getClass() != UnicastRef2.class) { - throw new SecurityException( - "Expecting a " + UnicastRef2.class.getName() + - " remote reference in stub!"); - } - // Check RMIClientSocketFactory in stub is from the expected class - // "javax.rmi.ssl.SslRMIClientSocketFactory". - // - LiveRef liveRef = ((UnicastRef2)ref).getLiveRef(); - RMIClientSocketFactory csf = liveRef.getClientSocketFactory(); - if (csf == null || csf.getClass() != SslRMIClientSocketFactory.class) { - throw new SecurityException( - "Expecting a " + SslRMIClientSocketFactory.class.getName() + - " RMI client socket factory in stub!"); - } - } - - private static final String rmiServerImplStubClassName = - "javax.management.remote.rmi.RMIServerImpl_Stub"; - private static final Class rmiServerImplStubClass; - - static { - // FIXME: RMIServerImpl_Stub is generated at build time - // after jconsole is built. We need to investigate if - // the Makefile can be fixed to build jconsole in the - // right order. As a workaround for now, we dynamically - // load RMIServerImpl_Stub class instead of statically - // referencing it. - Class serverStubClass = null; - try { - serverStubClass = Class.forName(rmiServerImplStubClassName).asSubclass(Remote.class); - } catch (ClassNotFoundException e) { - // should never reach here - throw (InternalError) new InternalError(e.getMessage()).initCause(e); - } - rmiServerImplStubClass = serverStubClass; - } - - private void checkSslConfig() throws IOException { - // Get the reference to the RMI Registry and lookup RMIServer stub - // - Registry registry; - try { - registry = - LocateRegistry.getRegistry(registryHostName, registryPort, - sslRMIClientSocketFactory); - try { - stub = (RMIServer) registry.lookup("jmxrmi"); - } catch (NotBoundException nbe) { - throw (IOException) - new IOException(nbe.getMessage()).initCause(nbe); - } - sslRegistry = true; - } catch (IOException e) { - registry = - LocateRegistry.getRegistry(registryHostName, registryPort); - try { - stub = (RMIServer) registry.lookup("jmxrmi"); - } catch (NotBoundException nbe) { - throw (IOException) - new IOException(nbe.getMessage()).initCause(nbe); - } - sslRegistry = false; - } - // Perform the checks for secure stub - // - try { - checkStub(stub, rmiServerImplStubClass); - sslStub = true; - } catch (SecurityException e) { - sslStub = false; - } - } - - /** - * Returns true if the underlying RMI registry is SSL-protected. - * - * @exception UnsupportedOperationException If this {@code ProxyClient} - * does not denote a JMX connector for a JMX VM agent. - */ - public boolean isSslRmiRegistry() { - // Check for VM connector - // - if (!isVmConnector()) { - throw new UnsupportedOperationException( - "ProxyClient.isSslRmiRegistry() is only supported if this " + - "ProxyClient is a JMX connector for a JMX VM agent"); - } - return sslRegistry; - } - - /** - * Returns true if the retrieved RMI stub is SSL-protected. - * - * @exception UnsupportedOperationException If this {@code ProxyClient} - * does not denote a JMX connector for a JMX VM agent. - */ - public boolean isSslRmiStub() { - // Check for VM connector - // - if (!isVmConnector()) { - throw new UnsupportedOperationException( - "ProxyClient.isSslRmiStub() is only supported if this " + - "ProxyClient is a JMX connector for a JMX VM agent"); - } - return sslStub; - } - - /** - * Returns true if this {@code ProxyClient} denotes - * a JMX connector for a JMX VM agent. - */ - public boolean isVmConnector() { - return vmConnector; - } - - private void setConnectionState(ConnectionState state) { - ConnectionState oldState = this.connectionState; - this.connectionState = state; - } - - public ConnectionState getConnectionState() { - return this.connectionState; - } - - public void flush() - { - if (server != null) { - server.flush(); - } - } - - public void connect() throws Exception - { - setConnectionState(ConnectionState.CONNECTING); - try { - tryConnect(); - setConnectionState(ConnectionState.CONNECTED); - } catch (Exception e) { - setConnectionState(ConnectionState.DISCONNECTED); - throw e; - } - } - - private void tryConnect() throws IOException { - if (jmxUrl == null && "localhost".equals(hostName) && port == 0) { - // Monitor self - this.jmxc = null; - this.mbsc = ManagementFactory.getPlatformMBeanServer(); - this.server = Snapshot.newSnapshot(mbsc); - } else { - // Monitor another process - if (lvm != null) { - if (!lvm.isManageable()) { - lvm.startManagementAgent(); - if (!lvm.isManageable()) { - // FIXME: what to throw - throw new IOException(lvm + "not manageable"); - } - } - if (this.jmxUrl == null) { - this.jmxUrl = new JMXServiceURL(lvm.connectorAddress()); - } - } - // Need to pass in credentials ? - if (userName == null && password == null) { - if (isVmConnector()) { - // Check for SSL config on reconnection only - if (stub == null) { - checkSslConfig(); - } - this.jmxc = new RMIConnector(stub, null); - jmxc.connect(); - } else { - this.jmxc = JMXConnectorFactory.connect(jmxUrl); - } - } else { - Map env = new HashMap(); - env.put(JMXConnector.CREDENTIALS, - new String[] {userName, password}); - if (isVmConnector()) { - // Check for SSL config on reconnection only - if (stub == null) { - checkSslConfig(); - } - this.jmxc = new RMIConnector(stub, null); - jmxc.connect(env); - } else { - this.jmxc = JMXConnectorFactory.connect(jmxUrl, env); - } - } - this.mbsc = jmxc.getMBeanServerConnection(); - this.server = Snapshot.newSnapshot(mbsc); - } - this.isDead = false; - - try { - ObjectName on = new ObjectName(THREAD_MXBEAN_NAME); - this.hasPlatformMXBeans = server.isRegistered(on); - this.hasHotSpotDiagnosticMXBean = - server.isRegistered(new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME)); - // check if it has 6.0 new APIs - if (this.hasPlatformMXBeans) { - MBeanOperationInfo[] mopis = server.getMBeanInfo(on).getOperations(); - // look for findDeadlockedThreads operations; - for (MBeanOperationInfo op : mopis) { - if (op.getName().equals("findDeadlockedThreads")) { - this.supportsLockUsage = true; - break; - } - } - - on = new ObjectName(COMPILATION_MXBEAN_NAME); - this.hasCompilationMXBean = server.isRegistered(on); - } - } catch (MalformedObjectNameException e) { - // should not reach here - throw new InternalError(e.getMessage()); - } catch (IntrospectionException e) { - InternalError ie = new InternalError(e.getMessage()); - ie.initCause(e); - throw ie; - } catch (InstanceNotFoundException e) { - InternalError ie = new InternalError(e.getMessage()); - ie.initCause(e); - throw ie; - } catch (ReflectionException e) { - InternalError ie = new InternalError(e.getMessage()); - ie.initCause(e); - throw ie; - } - - if (hasPlatformMXBeans) { - // WORKAROUND for bug 5056632 - // Check if the access role is correct by getting a RuntimeMXBean - getRuntimeMXBean(); - } - } - - /** - * Gets a proxy client for a given local virtual machine. - */ - public static ProxyClient getProxyClient(LocalVirtualMachine lvm) - throws IOException { - final String key = getCacheKey(lvm); - ProxyClient proxyClient = cache.get(key); - if (proxyClient == null) { - proxyClient = new ProxyClient(lvm); - cache.put(key, proxyClient); - } - return proxyClient; - } - - public static String getConnectionName(LocalVirtualMachine lvm) { - return Integer.toString(lvm.vmid()); - } - - private static String getCacheKey(LocalVirtualMachine lvm) { - return Integer.toString(lvm.vmid()); - } - - /** - * Gets a proxy client for a given JMXServiceURL. - */ - public static ProxyClient getProxyClient(String url, - String userName, String password) - throws IOException { - final String key = getCacheKey(url, userName, password); - ProxyClient proxyClient = cache.get(key); - if (proxyClient == null) { - proxyClient = new ProxyClient(url, userName, password); - cache.put(key, proxyClient); - } - return proxyClient; - } - - public static String getConnectionName(String url, - String userName) { - if (userName != null && userName.length() > 0) { - return userName + "@" + url; - } else { - return url; - } - } - - private static String getCacheKey(String url, - String userName, String password) { - return (url == null ? "" : url) + ":" + - (userName == null ? "" : userName) + ":" + - (password == null ? "" : password); - } - - /** - * Gets a proxy client for a given "hostname:port". - */ - public static ProxyClient getProxyClient(String hostName, int port, - String userName, String password) - throws IOException { - final String key = getCacheKey(hostName, port, userName, password); - ProxyClient proxyClient = cache.get(key); - if (proxyClient == null) { - proxyClient = new ProxyClient(hostName, port, userName, password); - cache.put(key, proxyClient); - } - return proxyClient; - } - - public static String getConnectionName(String hostName, int port, - String userName) { - String name = hostName + ":" + port; - if (userName != null && userName.length() > 0) { - return userName + "@" + name; - } else { - return name; - } - } - - private static String getCacheKey(String hostName, int port, - String userName, String password) { - return (hostName == null ? "" : hostName) + ":" + - port + ":" + - (userName == null ? "" : userName) + ":" + - (password == null ? "" : password); - } - - public String connectionName() { - return connectionName; - } - - public String getDisplayName() { - return displayName; - } - - @Override - public String toString() { - return displayName; - } - - public MBeanServerConnection getMBeanServerConnection() { - return mbsc; - } - - public SnapshotMBeanServerConnection getSnapshotMBeanServerConnection() { - return server; - } - - public String getUrl() { - return advancedUrl; - } - - public String getHostName() { - return hostName; - } - - public int getPort() { - return port; - } - - public int getVmid() { - return (lvm != null) ? lvm.vmid() : 0; - } - - public String getUserName() { - return userName; - } - - public String getPassword() { - return password; - } - - public void disconnect() { - // Reset remote stub - stub = null; - // Close MBeanServer connection - if (jmxc != null) { - try { - jmxc.close(); - } catch (IOException e) { - // Ignore ??? - } - } - // Reset platform MBean references - classLoadingMBean = null; - compilationMBean = null; - memoryMBean = null; - operatingSystemMBean = null; - runtimeMBean = null; - threadMBean = null; - sunOperatingSystemMXBean = null; - garbageCollectorMBeans = null; - // Set connection state to DISCONNECTED - if (!isDead) { - isDead = true; - setConnectionState(ConnectionState.DISCONNECTED); - } - } - - /** - * Returns the list of domains in which any MBean is - * currently registered. - */ - public String[] getDomains() throws IOException { - return server.getDomains(); - } - - /** - * Returns a map of MBeans with ObjectName as the key and MBeanInfo value - * of a given domain. If domain is null, all MBeans - * are returned. If no MBean found, an empty map is returned. - * - */ - public Map getMBeans(String domain) - throws IOException { - - ObjectName name = null; - if (domain != null) { - try { - name = new ObjectName(domain + ":*"); - } catch (MalformedObjectNameException e) { - // should not reach here - assert(false); - } - } - Set mbeans = server.queryNames(name, null); - Map result = - new HashMap(mbeans.size()); - Iterator iterator = mbeans.iterator(); - while (iterator.hasNext()) { - Object object = iterator.next(); - if (object instanceof ObjectName) { - ObjectName o = (ObjectName)object; - try { - MBeanInfo info = server.getMBeanInfo(o); - result.put(o, info); - } catch (IntrospectionException e) { - // TODO: should log the error - } catch (InstanceNotFoundException e) { - // TODO: should log the error - } catch (ReflectionException e) { - // TODO: should log the error - } - } - } - return result; - } - - /** - * Returns a list of attributes of a named MBean. - * - */ - public AttributeList getAttributes(ObjectName name, String[] attributes) - throws IOException { - AttributeList list = null; - try { - list = server.getAttributes(name, attributes); - } catch (InstanceNotFoundException e) { - // TODO: A MBean may have been unregistered. - // need to set up listener to listen for MBeanServerNotification. - } catch (ReflectionException e) { - // TODO: should log the error - } - return list; - } - - /** - * Set the value of a specific attribute of a named MBean. - */ - public void setAttribute(ObjectName name, Attribute attribute) - throws InvalidAttributeValueException, - MBeanException, - IOException { - try { - server.setAttribute(name, attribute); - } catch (InstanceNotFoundException e) { - // TODO: A MBean may have been unregistered. - } catch (AttributeNotFoundException e) { - assert(false); - } catch (ReflectionException e) { - // TODO: should log the error - } - } - - /** - * Invokes an operation of a named MBean. - * - * @throws MBeanException Wraps an exception thrown by - * the MBean's invoked method. - */ - public Object invoke(ObjectName name, String operationName, - Object[] params, String[] signature) - throws IOException, MBeanException { - Object result = null; - try { - result = server.invoke(name, operationName, params, signature); - } catch (InstanceNotFoundException e) { - // TODO: A MBean may have been unregistered. - } catch (ReflectionException e) { - // TODO: should log the error - } - return result; - } - - public synchronized ClassLoadingMXBean getClassLoadingMXBean() throws IOException { - if (hasPlatformMXBeans && classLoadingMBean == null) { - classLoadingMBean = - newPlatformMXBeanProxy(server, CLASS_LOADING_MXBEAN_NAME, - ClassLoadingMXBean.class); - } - return classLoadingMBean; - } - - public synchronized CompilationMXBean getCompilationMXBean() throws IOException { - if (hasCompilationMXBean && compilationMBean == null) { - compilationMBean = - newPlatformMXBeanProxy(server, COMPILATION_MXBEAN_NAME, - CompilationMXBean.class); - } - return compilationMBean; - } - - - public synchronized Collection getGarbageCollectorMXBeans() - throws IOException { - - // TODO: How to deal with changes to the list?? - if (garbageCollectorMBeans == null) { - ObjectName gcName = null; - try { - gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*"); - } catch (MalformedObjectNameException e) { - // should not reach here - assert(false); - } - Set mbeans = server.queryNames(gcName, null); - if (mbeans != null) { - garbageCollectorMBeans = new ArrayList(); - Iterator iterator = mbeans.iterator(); - while (iterator.hasNext()) { - ObjectName on = (ObjectName) iterator.next(); - String name = GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + - ",name=" + on.getKeyProperty("name"); - - GarbageCollectorMXBean mBean = - newPlatformMXBeanProxy(server, name, - GarbageCollectorMXBean.class); - garbageCollectorMBeans.add(mBean); - } - } - } - return garbageCollectorMBeans; - } - - public synchronized MemoryMXBean getMemoryMXBean() throws IOException { - if (hasPlatformMXBeans && memoryMBean == null) { - memoryMBean = - newPlatformMXBeanProxy(server, MEMORY_MXBEAN_NAME, - MemoryMXBean.class); - } - return memoryMBean; - } - - public synchronized RuntimeMXBean getRuntimeMXBean() throws IOException { - if (hasPlatformMXBeans && runtimeMBean == null) { - runtimeMBean = - newPlatformMXBeanProxy(server, RUNTIME_MXBEAN_NAME, - RuntimeMXBean.class); - } - return runtimeMBean; - } - - - public synchronized ThreadMXBean getThreadMXBean() throws IOException { - if (hasPlatformMXBeans && threadMBean == null) { - threadMBean = - newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME, - ThreadMXBean.class); - } - return threadMBean; - } - - public synchronized OperatingSystemMXBean getOperatingSystemMXBean() throws IOException { - if (hasPlatformMXBeans && operatingSystemMBean == null) { - operatingSystemMBean = - newPlatformMXBeanProxy(server, OPERATING_SYSTEM_MXBEAN_NAME, - OperatingSystemMXBean.class); - } - return operatingSystemMBean; - } - - public synchronized java.lang.management.OperatingSystemMXBean - getSunOperatingSystemMXBean() throws IOException { - - try { - ObjectName on = new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME); - if (sunOperatingSystemMXBean == null) { - if (server.isInstanceOf(on, - "java.lang.management.OperatingSystemMXBean")) - { - sunOperatingSystemMXBean = - newPlatformMXBeanProxy(server, - OPERATING_SYSTEM_MXBEAN_NAME, - // com.sun.management.OperatingSystemMXBean.class); - java.lang.management.OperatingSystemMXBean.class); - } - } - } catch (InstanceNotFoundException e) { - return null; - } catch (MalformedObjectNameException e) { - return null; // should never reach here - } - return sunOperatingSystemMXBean; - } - - /* - public synchronized HotSpotDiagnosticMXBean getHotSpotDiagnosticMXBean() throws IOException { - if (hasHotSpotDiagnosticMXBean && hotspotDiagnosticMXBean == null) { - hotspotDiagnosticMXBean = - newPlatformMXBeanProxy(server, HOTSPOT_DIAGNOSTIC_MXBEAN_NAME, - HotSpotDiagnosticMXBean.class); - } - return hotspotDiagnosticMXBean; - } - */ - - public T getMXBean(ObjectName objName, Class interfaceClass) - throws IOException { - return newPlatformMXBeanProxy(server, - objName.toString(), - interfaceClass); - - } - - // Return thread IDs of deadlocked threads or null if any. - // It finds deadlocks involving only monitors if it's a Tiger VM. - // Otherwise, it finds deadlocks involving both monitors and - // the concurrent locks. - public long[] findDeadlockedThreads() throws IOException { - ThreadMXBean tm = getThreadMXBean(); - if (supportsLockUsage && tm.isSynchronizerUsageSupported()) { - return tm.findDeadlockedThreads(); - } else { - return tm.findMonitorDeadlockedThreads(); - } - } - - public synchronized void markAsDead() { - disconnect(); - } - - public boolean isDead() { - return isDead; - } - - boolean isConnected() { - return !isDead(); - } - - boolean hasPlatformMXBeans() { - return this.hasPlatformMXBeans; - } - - boolean hasHotSpotDiagnosticMXBean() { - return this.hasHotSpotDiagnosticMXBean; - } - - boolean isLockUsageSupported() { - return supportsLockUsage; - } - - public boolean isRegistered(ObjectName name) throws IOException { - return server.isRegistered(name); - } - - public void addPropertyChangeListener(PropertyChangeListener listener) - { - - } - - public void addWeakPropertyChangeListener(PropertyChangeListener listener) - { - if (!(listener instanceof WeakPCL)) - { - listener = new WeakPCL(listener); - } - - } - - public void removePropertyChangeListener(PropertyChangeListener listener) - { - - } - - /** - * The PropertyChangeListener is handled via a WeakReference - * so as not to pin down the listener. - */ - private class WeakPCL extends WeakReference - implements PropertyChangeListener { - WeakPCL(PropertyChangeListener referent) { - super(referent); - } - - public void propertyChange(PropertyChangeEvent pce) { - PropertyChangeListener pcl = get(); - - if (pcl == null) { - // The referent listener was GC'ed, we're no longer - // interested in PropertyChanges, remove the listener. - dispose(); - } else { - pcl.propertyChange(pce); - } - } - - private void dispose() { - removePropertyChangeListener(this); - } - } - - // - // Snapshot MBeanServerConnection: - // - // This is an object that wraps an existing MBeanServerConnection and adds - // caching to it, as follows: - // - // - The first time an attribute is called in a given MBean, the result is - // cached. Every subsequent time getAttribute is called for that attribute - // the cached result is returned. - // - // - Before every call to VMPanel.update() or when the Refresh button in the - // Attributes table is pressed down the attributes cache is flushed. Then - // any subsequent call to getAttribute will retrieve all the values for - // the attributes that are known to the cache. - // - // - The attributes cache uses a learning approach and only the attributes - // that are in the cache will be retrieved between two subsequent updates. - // - - public interface SnapshotMBeanServerConnection - extends MBeanServerConnection { - /** - * Flush all cached values of attributes. - */ - public void flush(); - } - - public static class Snapshot { - private Snapshot() { - } - public static SnapshotMBeanServerConnection - newSnapshot(MBeanServerConnection mbsc) { - final InvocationHandler ih = new SnapshotInvocationHandler(mbsc); - return (SnapshotMBeanServerConnection) Proxy.newProxyInstance( - Snapshot.class.getClassLoader(), - new Class[] {SnapshotMBeanServerConnection.class}, - ih); - } - } - - static class SnapshotInvocationHandler implements InvocationHandler { - - private final MBeanServerConnection conn; - private Map cachedValues = newMap(); - private Map> cachedNames = newMap(); - - @SuppressWarnings("serial") - private static final class NameValueMap - extends HashMap {} - - SnapshotInvocationHandler(MBeanServerConnection conn) { - this.conn = conn; - } - - synchronized void flush() { - cachedValues = newMap(); - } - - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { - final String methodName = method.getName(); - if (methodName.equals("getAttribute")) { - return getAttribute((ObjectName) args[0], (String) args[1]); - } else if (methodName.equals("getAttributes")) { - return getAttributes((ObjectName) args[0], (String[]) args[1]); - } else if (methodName.equals("flush")) { - flush(); - return null; - } else { - try { - return method.invoke(conn, args); - } catch (InvocationTargetException e) { - throw e.getCause(); - } - } - } - - private Object getAttribute(ObjectName objName, String attrName) - throws MBeanException, InstanceNotFoundException, - AttributeNotFoundException, ReflectionException, IOException { - final NameValueMap values = getCachedAttributes( - objName, Collections.singleton(attrName)); - Object value = values.get(attrName); - if (value != null || values.containsKey(attrName)) { - return value; - } - // Not in cache, presumably because it was omitted from the - // getAttributes result because of an exception. Following - // call will probably provoke the same exception. - return conn.getAttribute(objName, attrName); - } - - private AttributeList getAttributes( - ObjectName objName, String[] attrNames) throws - InstanceNotFoundException, ReflectionException, IOException { - final NameValueMap values = getCachedAttributes( - objName, - new TreeSet(Arrays.asList(attrNames))); - final AttributeList list = new AttributeList(); - for (String attrName : attrNames) { - final Object value = values.get(attrName); - if (value != null || values.containsKey(attrName)) { - list.add(new Attribute(attrName, value)); - } - } - return list; - } - - private synchronized NameValueMap getCachedAttributes( - ObjectName objName, Set attrNames) throws - InstanceNotFoundException, ReflectionException, IOException { - NameValueMap values = cachedValues.get(objName); - if (values != null && values.keySet().containsAll(attrNames)) { - return values; - } - attrNames = new TreeSet(attrNames); - Set oldNames = cachedNames.get(objName); - if (oldNames != null) { - attrNames.addAll(oldNames); - } - values = new NameValueMap(); - final AttributeList attrs = conn.getAttributes( - objName, - attrNames.toArray(new String[attrNames.size()])); - for (Attribute attr : attrs.asList()) { - values.put(attr.getName(), attr.getValue()); - } - cachedValues.put(objName, values); - cachedNames.put(objName, attrNames); - return values; - } - - // See http://www.artima.com/weblogs/viewpost.jsp?thread=79394 - private static Map newMap() { - return new HashMap(); - } - } - - /** - * @return - */ - public long getProcessCpuTime() throws Exception - { - try - { - String osMXBeanClassName = "com.sun.management.OperatingSystemMXBean"; - if (lvm.isJ9Mode()) - { - osMXBeanClassName = "com.ibm.lang.management.OperatingSystemMXBean"; - } - - if (Proxy.isProxyClass(getOperatingSystemMXBean().getClass())) - { - Long cpuTime = (Long) Proxy - .getInvocationHandler(getOperatingSystemMXBean()) - .invoke( - getOperatingSystemMXBean(), - Class.forName(osMXBeanClassName).getMethod("getProcessCpuTime"), - null); - - if (lvm.isJ9Mode()) - { - //this is very strange, J9 does return the value in "100ns units" - //which violates the management spec - //see http://publib.boulder.ibm.com/infocenter/javasdk/v6r0/index.jsp?topic=%2Fcom.ibm.java.api.60.doc%2Fcom.ibm.lang.management%2Fcom%2Fibm%2Flang%2Fmanagement%2FOperatingSystemMXBean.html - return cpuTime * 100; - } - else - { - return cpuTime; - } - - } - else - { - throw new UnsupportedOperationException( - "Unsupported JDK, please report bug"); - } - } - catch (Throwable e) - { - throw new RuntimeException(e); - } - } +public class ProxyClient { + + private ConnectionState connectionState = ConnectionState.DISCONNECTED; + + private static Map cache = Collections.synchronizedMap(new HashMap()); + + private volatile boolean isDead = true; + + private String hostName = null; + + private int port = 0; + + private String userName = null; + + private String password = null; + + private boolean hasPlatformMXBeans = false; + + private boolean hasHotSpotDiagnosticMXBean = false; + + private boolean hasCompilationMXBean = false; + + private boolean supportsLockUsage = false; + + // REVISIT: VMPanel and other places relying using getUrl(). + + // set only if it's created for local monitoring + private LocalVirtualMachine lvm; + + // set only if it's created from a given URL via the Advanced tab + private String advancedUrl = null; + + private JMXServiceURL jmxUrl = null; + + private MBeanServerConnection mbsc = null; + + private SnapshotMBeanServerConnection server = null; + + private JMXConnector jmxc = null; + + private RMIServer stub = null; + + private static final SslRMIClientSocketFactory sslRMIClientSocketFactory = new SslRMIClientSocketFactory(); + + private String registryHostName = null; + + private int registryPort = 0; + + private boolean vmConnector = false; + + private boolean sslRegistry = false; + + private boolean sslStub = false; + + final private String connectionName; + + final private String displayName; + + private ClassLoadingMXBean classLoadingMBean = null; + + private CompilationMXBean compilationMBean = null; + + private MemoryMXBean memoryMBean = null; + + private OperatingSystemMXBean operatingSystemMBean = null; + + private RuntimeMXBean runtimeMBean = null; + + private ThreadMXBean threadMBean = null; + + private java.lang.management.OperatingSystemMXBean sunOperatingSystemMXBean = null; + + // private HotSpotDiagnosticMXBean hotspotDiagnosticMXBean = null; + + private List garbageCollectorMBeans = null; + + final static private String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME = "com.sun.management:type=HotSpotDiagnostic"; + + private ProxyClient(String hostName, int port, String userName, String password) throws IOException { + this.connectionName = getConnectionName(hostName, port, userName); + this.displayName = connectionName; + if (hostName.equals("localhost") && port == 0) { + // Monitor self + this.hostName = hostName; + this.port = port; + } else { + // Create an RMI connector client and connect it to + // the RMI connector server + final String urlPath = "/jndi/rmi://" + hostName + ":" + port + "/jmxrmi"; + JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath); + setParameters(url, userName, password); + vmConnector = true; + registryHostName = hostName; + registryPort = port; + checkSslConfig(); + } + } + + private ProxyClient(String url, String userName, String password) throws IOException { + this.advancedUrl = url; + this.connectionName = getConnectionName(url, userName); + this.displayName = connectionName; + setParameters(new JMXServiceURL(url), userName, password); + } + + private ProxyClient(LocalVirtualMachine lvm) throws IOException { + this.lvm = lvm; + this.connectionName = getConnectionName(lvm); + this.displayName = "pid: " + lvm.vmid() + " " + lvm.displayName(); + } + + private void setParameters(JMXServiceURL url, String userName, String password) { + this.jmxUrl = url; + this.hostName = jmxUrl.getHost(); + this.port = jmxUrl.getPort(); + this.userName = userName; + this.password = password; + } + + private static void checkStub(Remote stub, Class stubClass) { + // Check remote stub is from the expected class. + // + if (stub.getClass() != stubClass) + if (!Proxy.isProxyClass(stub.getClass())) + throw new SecurityException("Expecting a " + stubClass.getName() + " stub!"); + else { + InvocationHandler handler = Proxy.getInvocationHandler(stub); + if (handler.getClass() != RemoteObjectInvocationHandler.class) + throw new SecurityException("Expecting a dynamic proxy instance with a " + RemoteObjectInvocationHandler.class.getName() + " invocation handler!"); + else + stub = (Remote) handler; + } + // Check RemoteRef in stub is from the expected class + // "sun.rmi.server.UnicastRef2". + // + RemoteRef ref = ((RemoteObject) stub).getRef(); + if (ref.getClass() != UnicastRef2.class) + throw new SecurityException("Expecting a " + UnicastRef2.class.getName() + " remote reference in stub!"); + // Check RMIClientSocketFactory in stub is from the expected class + // "javax.rmi.ssl.SslRMIClientSocketFactory". + // + LiveRef liveRef = ((UnicastRef2) ref).getLiveRef(); + RMIClientSocketFactory csf = liveRef.getClientSocketFactory(); + if (csf == null || csf.getClass() != SslRMIClientSocketFactory.class) + throw new SecurityException("Expecting a " + SslRMIClientSocketFactory.class.getName() + " RMI client socket factory in stub!"); + } + + private static final String rmiServerImplStubClassName = "javax.management.remote.rmi.RMIServerImpl_Stub"; + + private static final Class rmiServerImplStubClass; + + static { + // FIXME: RMIServerImpl_Stub is generated at build time + // after jconsole is built. We need to investigate if + // the Makefile can be fixed to build jconsole in the + // right order. As a workaround for now, we dynamically + // load RMIServerImpl_Stub class instead of statically + // referencing it. + Class serverStubClass = null; + try { + serverStubClass = Class.forName(rmiServerImplStubClassName).asSubclass(Remote.class); + } catch (ClassNotFoundException e) { + // should never reach here + throw (InternalError) new InternalError(e.getMessage()).initCause(e); + } + rmiServerImplStubClass = serverStubClass; + } + + private void checkSslConfig() throws IOException { + // Get the reference to the RMI Registry and lookup RMIServer stub + // + Registry registry; + try { + registry = LocateRegistry.getRegistry(registryHostName, registryPort, sslRMIClientSocketFactory); + try { + stub = (RMIServer) registry.lookup("jmxrmi"); + } catch (NotBoundException nbe) { + throw (IOException) new IOException(nbe.getMessage()).initCause(nbe); + } + sslRegistry = true; + } catch (IOException e) { + registry = LocateRegistry.getRegistry(registryHostName, registryPort); + try { + stub = (RMIServer) registry.lookup("jmxrmi"); + } catch (NotBoundException nbe) { + throw (IOException) new IOException(nbe.getMessage()).initCause(nbe); + } + sslRegistry = false; + } + // Perform the checks for secure stub + // + try { + checkStub(stub, rmiServerImplStubClass); + sslStub = true; + } catch (SecurityException e) { + sslStub = false; + } + } + + /** + * Returns true if the underlying RMI registry is SSL-protected. + * + * @exception UnsupportedOperationException + * If this {@code ProxyClient} does not denote a JMX + * connector for a JMX VM agent. + */ + public boolean isSslRmiRegistry() { + // Check for VM connector + // + if (!isVmConnector()) + throw new UnsupportedOperationException("ProxyClient.isSslRmiRegistry() is only supported if this " + "ProxyClient is a JMX connector for a JMX VM agent"); + return sslRegistry; + } + + /** + * Returns true if the retrieved RMI stub is SSL-protected. + * + * @exception UnsupportedOperationException + * If this {@code ProxyClient} does not denote a JMX + * connector for a JMX VM agent. + */ + public boolean isSslRmiStub() { + // Check for VM connector + // + if (!isVmConnector()) + throw new UnsupportedOperationException("ProxyClient.isSslRmiStub() is only supported if this " + "ProxyClient is a JMX connector for a JMX VM agent"); + return sslStub; + } + + /** + * Returns true if this {@code ProxyClient} denotes a JMX connector for a + * JMX VM agent. + */ + public boolean isVmConnector() { + return vmConnector; + } + + private void setConnectionState(ConnectionState state) { + this.connectionState = state; + } + + public ConnectionState getConnectionState() { + return this.connectionState; + } + + public void flush() { + if (server != null) + server.flush(); + } + + public void connect() throws Exception { + setConnectionState(ConnectionState.CONNECTING); + try { + tryConnect(); + setConnectionState(ConnectionState.CONNECTED); + } catch (Exception e) { + setConnectionState(ConnectionState.DISCONNECTED); + throw e; + } + } + + private void tryConnect() throws IOException { + if (jmxUrl == null && "localhost".equals(hostName) && port == 0) { + // Monitor self + this.jmxc = null; + this.mbsc = ManagementFactory.getPlatformMBeanServer(); + this.server = Snapshot.newSnapshot(mbsc); + } else { + // Monitor another process + if (lvm != null) { + if (!lvm.isManageable()) { + lvm.startManagementAgent(); + if (!lvm.isManageable()) + // FIXME: what to throw + throw new IOException(lvm + "not manageable"); + } + if (this.jmxUrl == null) + this.jmxUrl = new JMXServiceURL(lvm.connectorAddress()); + } + // Need to pass in credentials ? + if (userName == null && password == null) { + if (isVmConnector()) { + // Check for SSL config on reconnection only + if (stub == null) + checkSslConfig(); + this.jmxc = new RMIConnector(stub, null); + jmxc.connect(); + } else + this.jmxc = JMXConnectorFactory.connect(jmxUrl); + } else { + Map env = new HashMap(); + env.put(JMXConnector.CREDENTIALS, new String[] { userName, password }); + if (isVmConnector()) { + // Check for SSL config on reconnection only + if (stub == null) + checkSslConfig(); + this.jmxc = new RMIConnector(stub, null); + jmxc.connect(env); + } else + this.jmxc = JMXConnectorFactory.connect(jmxUrl, env); + } + this.mbsc = jmxc.getMBeanServerConnection(); + this.server = Snapshot.newSnapshot(mbsc); + } + this.isDead = false; + + try { + ObjectName on = new ObjectName(THREAD_MXBEAN_NAME); + this.hasPlatformMXBeans = server.isRegistered(on); + this.hasHotSpotDiagnosticMXBean = server.isRegistered(new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME)); + // check if it has 6.0 new APIs + if (this.hasPlatformMXBeans) { + MBeanOperationInfo[] mopis = server.getMBeanInfo(on).getOperations(); + // look for findDeadlockedThreads operations; + for (MBeanOperationInfo op : mopis) + if (op.getName().equals("findDeadlockedThreads")) { + this.supportsLockUsage = true; + break; + } + + on = new ObjectName(COMPILATION_MXBEAN_NAME); + this.hasCompilationMXBean = server.isRegistered(on); + } + } catch (MalformedObjectNameException e) { + // should not reach here + throw new InternalError(e.getMessage()); + } catch (IntrospectionException e) { + InternalError ie = new InternalError(e.getMessage()); + ie.initCause(e); + throw ie; + } catch (InstanceNotFoundException e) { + InternalError ie = new InternalError(e.getMessage()); + ie.initCause(e); + throw ie; + } catch (ReflectionException e) { + InternalError ie = new InternalError(e.getMessage()); + ie.initCause(e); + throw ie; + } + + if (hasPlatformMXBeans) + // WORKAROUND for bug 5056632 + // Check if the access role is correct by getting a RuntimeMXBean + getRuntimeMXBean(); + } + + /** + * Gets a proxy client for a given local virtual machine. + */ + public static ProxyClient getProxyClient(LocalVirtualMachine lvm) throws IOException { + final String key = getCacheKey(lvm); + ProxyClient proxyClient = cache.get(key); + if (proxyClient == null) { + proxyClient = new ProxyClient(lvm); + cache.put(key, proxyClient); + } + return proxyClient; + } + + public static String getConnectionName(LocalVirtualMachine lvm) { + return Integer.toString(lvm.vmid()); + } + + private static String getCacheKey(LocalVirtualMachine lvm) { + return Integer.toString(lvm.vmid()); + } + + /** + * Gets a proxy client for a given JMXServiceURL. + */ + public static ProxyClient getProxyClient(String url, String userName, String password) throws IOException { + final String key = getCacheKey(url, userName, password); + ProxyClient proxyClient = cache.get(key); + if (proxyClient == null) { + proxyClient = new ProxyClient(url, userName, password); + cache.put(key, proxyClient); + } + return proxyClient; + } + + public static String getConnectionName(String url, String userName) { + if (userName != null && userName.length() > 0) + return userName + "@" + url; + else + return url; + } + + private static String getCacheKey(String url, String userName, String password) { + return (url == null ? "" : url) + ":" + (userName == null ? "" : userName) + ":" + (password == null ? "" : password); + } + + /** + * Gets a proxy client for a given "hostname:port". + */ + public static ProxyClient getProxyClient(String hostName, int port, String userName, String password) throws IOException { + final String key = getCacheKey(hostName, port, userName, password); + ProxyClient proxyClient = cache.get(key); + if (proxyClient == null) { + proxyClient = new ProxyClient(hostName, port, userName, password); + cache.put(key, proxyClient); + } + return proxyClient; + } + + public static String getConnectionName(String hostName, int port, String userName) { + String name = hostName + ":" + port; + if (userName != null && userName.length() > 0) + return userName + "@" + name; + else + return name; + } + + private static String getCacheKey(String hostName, int port, String userName, String password) { + return (hostName == null ? "" : hostName) + ":" + port + ":" + (userName == null ? "" : userName) + ":" + (password == null ? "" : password); + } + + public String connectionName() { + return connectionName; + } + + public String getDisplayName() { + return displayName; + } + + @Override + public String toString() { + return displayName; + } + + public MBeanServerConnection getMBeanServerConnection() { + return mbsc; + } + + public SnapshotMBeanServerConnection getSnapshotMBeanServerConnection() { + return server; + } + + public String getUrl() { + return advancedUrl; + } + + public String getHostName() { + return hostName; + } + + public int getPort() { + return port; + } + + public int getVmid() { + return (lvm != null) ? lvm.vmid() : 0; + } + + public String getUserName() { + return userName; + } + + public String getPassword() { + return password; + } + + public void disconnect() { + // Reset remote stub + stub = null; + // Close MBeanServer connection + if (jmxc != null) + try { + jmxc.close(); + } catch (IOException e) { + // Ignore ??? + } + // Reset platform MBean references + classLoadingMBean = null; + compilationMBean = null; + memoryMBean = null; + operatingSystemMBean = null; + runtimeMBean = null; + threadMBean = null; + sunOperatingSystemMXBean = null; + garbageCollectorMBeans = null; + // Set connection state to DISCONNECTED + if (!isDead) { + isDead = true; + setConnectionState(ConnectionState.DISCONNECTED); + } + } + + /** + * Returns the list of domains in which any MBean is currently registered. + */ + public String[] getDomains() throws IOException { + return server.getDomains(); + } + + /** + * Returns a map of MBeans with ObjectName as the key and MBeanInfo value of + * a given domain. If domain is null, all MBeans are returned. If + * no MBean found, an empty map is returned. + * + */ + public Map getMBeans(String domain) throws IOException { + + ObjectName name = null; + if (domain != null) + try { + name = new ObjectName(domain + ":*"); + } catch (MalformedObjectNameException e) { + // should not reach here + assert (false); + } + Set mbeans = server.queryNames(name, null); + Map result = new HashMap(mbeans.size()); + Iterator iterator = mbeans.iterator(); + while (iterator.hasNext()) { + Object object = iterator.next(); + if (object instanceof ObjectName) { + ObjectName o = (ObjectName) object; + try { + MBeanInfo info = server.getMBeanInfo(o); + result.put(o, info); + } catch (IntrospectionException e) { + // TODO: should log the error + } catch (InstanceNotFoundException e) { + // TODO: should log the error + } catch (ReflectionException e) { + // TODO: should log the error + } + } + } + return result; + } + + /** + * Returns a list of attributes of a named MBean. + * + */ + public AttributeList getAttributes(ObjectName name, String[] attributes) throws IOException { + AttributeList list = null; + try { + list = server.getAttributes(name, attributes); + } catch (InstanceNotFoundException e) { + // TODO: A MBean may have been unregistered. + // need to set up listener to listen for MBeanServerNotification. + } catch (ReflectionException e) { + // TODO: should log the error + } + return list; + } + + /** + * Set the value of a specific attribute of a named MBean. + */ + public void setAttribute(ObjectName name, Attribute attribute) throws InvalidAttributeValueException, MBeanException, IOException { + try { + server.setAttribute(name, attribute); + } catch (InstanceNotFoundException e) { + // TODO: A MBean may have been unregistered. + } catch (AttributeNotFoundException e) { + assert (false); + } catch (ReflectionException e) { + // TODO: should log the error + } + } + + /** + * Invokes an operation of a named MBean. + * + * @throws MBeanException + * Wraps an exception thrown by the MBean's invoked method. + */ + public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature) throws IOException, MBeanException { + Object result = null; + try { + result = server.invoke(name, operationName, params, signature); + } catch (InstanceNotFoundException e) { + // TODO: A MBean may have been unregistered. + } catch (ReflectionException e) { + // TODO: should log the error + } + return result; + } + + public synchronized ClassLoadingMXBean getClassLoadingMXBean() throws IOException { + if (hasPlatformMXBeans && classLoadingMBean == null) + classLoadingMBean = newPlatformMXBeanProxy(server, CLASS_LOADING_MXBEAN_NAME, ClassLoadingMXBean.class); + return classLoadingMBean; + } + + public synchronized CompilationMXBean getCompilationMXBean() throws IOException { + if (hasCompilationMXBean && compilationMBean == null) + compilationMBean = newPlatformMXBeanProxy(server, COMPILATION_MXBEAN_NAME, CompilationMXBean.class); + return compilationMBean; + } + + public synchronized Collection getGarbageCollectorMXBeans() throws IOException { + + // TODO: How to deal with changes to the list?? + if (garbageCollectorMBeans == null) { + ObjectName gcName = null; + try { + gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*"); + } catch (MalformedObjectNameException e) { + // should not reach here + assert (false); + } + Set mbeans = server.queryNames(gcName, null); + if (mbeans != null) { + garbageCollectorMBeans = new ArrayList(); + Iterator iterator = mbeans.iterator(); + while (iterator.hasNext()) { + ObjectName on = (ObjectName) iterator.next(); + String name = GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",name=" + on.getKeyProperty("name"); + + GarbageCollectorMXBean mBean = newPlatformMXBeanProxy(server, name, GarbageCollectorMXBean.class); + garbageCollectorMBeans.add(mBean); + } + } + } + return garbageCollectorMBeans; + } + + public synchronized MemoryMXBean getMemoryMXBean() throws IOException { + if (hasPlatformMXBeans && memoryMBean == null) + memoryMBean = newPlatformMXBeanProxy(server, MEMORY_MXBEAN_NAME, MemoryMXBean.class); + return memoryMBean; + } + + public synchronized RuntimeMXBean getRuntimeMXBean() throws IOException { + if (hasPlatformMXBeans && runtimeMBean == null) + runtimeMBean = newPlatformMXBeanProxy(server, RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); + return runtimeMBean; + } + + public synchronized ThreadMXBean getThreadMXBean() throws IOException { + if (hasPlatformMXBeans && threadMBean == null) + threadMBean = newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME, ThreadMXBean.class); + return threadMBean; + } + + public synchronized OperatingSystemMXBean getOperatingSystemMXBean() throws IOException { + if (hasPlatformMXBeans && operatingSystemMBean == null) + operatingSystemMBean = newPlatformMXBeanProxy(server, OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class); + return operatingSystemMBean; + } + + public synchronized java.lang.management.OperatingSystemMXBean getSunOperatingSystemMXBean() throws IOException { + + try { + ObjectName on = new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME); + if (sunOperatingSystemMXBean == null) + if (server.isInstanceOf(on, "java.lang.management.OperatingSystemMXBean")) + sunOperatingSystemMXBean = newPlatformMXBeanProxy(server, OPERATING_SYSTEM_MXBEAN_NAME, + // com.sun.management.OperatingSystemMXBean.class); + java.lang.management.OperatingSystemMXBean.class); + } catch (InstanceNotFoundException e) { + return null; + } catch (MalformedObjectNameException e) { + return null; // should never reach here + } + return sunOperatingSystemMXBean; + } + + /* + * public synchronized HotSpotDiagnosticMXBean getHotSpotDiagnosticMXBean() + * throws IOException { if (hasHotSpotDiagnosticMXBean && + * hotspotDiagnosticMXBean == null) { hotspotDiagnosticMXBean = + * newPlatformMXBeanProxy(server, HOTSPOT_DIAGNOSTIC_MXBEAN_NAME, + * HotSpotDiagnosticMXBean.class); } return hotspotDiagnosticMXBean; } + */ + + public T getMXBean(ObjectName objName, Class interfaceClass) throws IOException { + return newPlatformMXBeanProxy(server, objName.toString(), interfaceClass); + + } + + // Return thread IDs of deadlocked threads or null if any. + // It finds deadlocks involving only monitors if it's a Tiger VM. + // Otherwise, it finds deadlocks involving both monitors and + // the concurrent locks. + public long[] findDeadlockedThreads() throws IOException { + ThreadMXBean tm = getThreadMXBean(); + if (supportsLockUsage && tm.isSynchronizerUsageSupported()) + return tm.findDeadlockedThreads(); + else + return tm.findMonitorDeadlockedThreads(); + } + + public synchronized void markAsDead() { + disconnect(); + } + + public boolean isDead() { + return isDead; + } + + boolean isConnected() { + return !isDead(); + } + + boolean hasPlatformMXBeans() { + return this.hasPlatformMXBeans; + } + + boolean hasHotSpotDiagnosticMXBean() { + return this.hasHotSpotDiagnosticMXBean; + } + + boolean isLockUsageSupported() { + return supportsLockUsage; + } + + public boolean isRegistered(ObjectName name) throws IOException { + return server.isRegistered(name); + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + + } + + public void addWeakPropertyChangeListener(PropertyChangeListener listener) { + if (!(listener instanceof WeakPCL)) + listener = new WeakPCL(listener); + + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + + } + + /** + * The PropertyChangeListener is handled via a WeakReference so as not to + * pin down the listener. + */ + private class WeakPCL extends WeakReference implements PropertyChangeListener { + WeakPCL(PropertyChangeListener referent) { + super(referent); + } + + @Override + public void propertyChange(PropertyChangeEvent pce) { + PropertyChangeListener pcl = get(); + + if (pcl == null) + // The referent listener was GC'ed, we're no longer + // interested in PropertyChanges, remove the listener. + dispose(); + else + pcl.propertyChange(pce); + } + + private void dispose() { + removePropertyChangeListener(this); + } + } + + // + // Snapshot MBeanServerConnection: + // + // This is an object that wraps an existing MBeanServerConnection and adds + // caching to it, as follows: + // + // - The first time an attribute is called in a given MBean, the result is + // cached. Every subsequent time getAttribute is called for that attribute + // the cached result is returned. + // + // - Before every call to VMPanel.update() or when the Refresh button in the + // Attributes table is pressed down the attributes cache is flushed. Then + // any subsequent call to getAttribute will retrieve all the values for + // the attributes that are known to the cache. + // + // - The attributes cache uses a learning approach and only the attributes + // that are in the cache will be retrieved between two subsequent updates. + // + + public interface SnapshotMBeanServerConnection extends MBeanServerConnection { + /** + * Flush all cached values of attributes. + */ + public void flush(); + } + + public static class Snapshot { + private Snapshot() { + } + + public static SnapshotMBeanServerConnection newSnapshot(MBeanServerConnection mbsc) { + final InvocationHandler ih = new SnapshotInvocationHandler(mbsc); + return (SnapshotMBeanServerConnection) Proxy.newProxyInstance(Snapshot.class.getClassLoader(), new Class[] { SnapshotMBeanServerConnection.class }, ih); + } + } + + static class SnapshotInvocationHandler implements InvocationHandler { + + private final MBeanServerConnection conn; + + private Map cachedValues = newMap(); + + private Map> cachedNames = newMap(); + + @SuppressWarnings("serial") + private static final class NameValueMap extends HashMap { + } + + SnapshotInvocationHandler(MBeanServerConnection conn) { + this.conn = conn; + } + + synchronized void flush() { + cachedValues = newMap(); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + final String methodName = method.getName(); + if (methodName.equals("getAttribute")) + return getAttribute((ObjectName) args[0], (String) args[1]); + else if (methodName.equals("getAttributes")) + return getAttributes((ObjectName) args[0], (String[]) args[1]); + else if (methodName.equals("flush")) { + flush(); + return null; + } else + try { + return method.invoke(conn, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } + + private Object getAttribute(ObjectName objName, String attrName) throws MBeanException, InstanceNotFoundException, AttributeNotFoundException, ReflectionException, IOException { + final NameValueMap values = getCachedAttributes(objName, Collections.singleton(attrName)); + Object value = values.get(attrName); + if (value != null || values.containsKey(attrName)) + return value; + // Not in cache, presumably because it was omitted from the + // getAttributes result because of an exception. Following + // call will probably provoke the same exception. + return conn.getAttribute(objName, attrName); + } + + private AttributeList getAttributes(ObjectName objName, String[] attrNames) throws InstanceNotFoundException, ReflectionException, IOException { + final NameValueMap values = getCachedAttributes(objName, new TreeSet(Arrays.asList(attrNames))); + final AttributeList list = new AttributeList(); + for (String attrName : attrNames) { + final Object value = values.get(attrName); + if (value != null || values.containsKey(attrName)) + list.add(new Attribute(attrName, value)); + } + return list; + } + + private synchronized NameValueMap getCachedAttributes(ObjectName objName, Set attrNames) throws InstanceNotFoundException, ReflectionException, IOException { + NameValueMap values = cachedValues.get(objName); + if (values != null && values.keySet().containsAll(attrNames)) + return values; + attrNames = new TreeSet(attrNames); + Set oldNames = cachedNames.get(objName); + if (oldNames != null) + attrNames.addAll(oldNames); + values = new NameValueMap(); + final AttributeList attrs = conn.getAttributes(objName, attrNames.toArray(new String[attrNames.size()])); + for (Attribute attr : attrs.asList()) + values.put(attr.getName(), attr.getValue()); + cachedValues.put(objName, values); + cachedNames.put(objName, attrNames); + return values; + } + + // See http://www.artima.com/weblogs/viewpost.jsp?thread=79394 + private static Map newMap() { + return new HashMap(); + } + } + + /** + * @return + */ + public long getProcessCpuTime() throws Exception { + try { + String osMXBeanClassName = "com.sun.management.OperatingSystemMXBean"; + if (LocalVirtualMachine.isJ9Mode()) + osMXBeanClassName = "com.ibm.lang.management.OperatingSystemMXBean"; + + if (Proxy.isProxyClass(getOperatingSystemMXBean().getClass())) { + Long cpuTime = (Long) Proxy.getInvocationHandler(getOperatingSystemMXBean()) + .invoke(getOperatingSystemMXBean(), Class.forName(osMXBeanClassName).getMethod("getProcessCpuTime"), null); + + if (LocalVirtualMachine.isJ9Mode()) + // this is very strange, J9 does return the value in + // "100ns units" + // which violates the management spec + // see + // http://publib.boulder.ibm.com/infocenter/javasdk/v6r0/index.jsp?topic=%2Fcom.ibm.java.api.60.doc%2Fcom.ibm.lang.management%2Fcom%2Fibm%2Flang%2Fmanagement%2FOperatingSystemMXBean.html + return cpuTime * 100; + else + return cpuTime; + + } else + throw new UnsupportedOperationException("Unsupported JDK, please report bug"); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/java/com/jvmtop/profiler/CPUSampler.java b/src/main/java/com/jvmtop/profiler/CPUSampler.java index 708ba89..dc82d3f 100644 --- a/src/main/java/com/jvmtop/profiler/CPUSampler.java +++ b/src/main/java/com/jvmtop/profiler/CPUSampler.java @@ -42,119 +42,88 @@ * @author paru * */ -public class CPUSampler -{ - private ThreadMXBean threadMxBean_ = null; - - private ConcurrentMap data_ = new ConcurrentHashMap(); - - private long beginCPUTime_ = 0; - - private AtomicLong totalThreadCPUTime_ = new AtomicLong( - 0); - - - //TODO: these exception list should be expanded to the most common 3rd-party library packages - private List filter = Arrays - .asList(new String[] { - "org.eclipse.", "org.apache.", "java.", "sun.", "com.sun.", "javax.", - "oracle.", "com.trilead.", "org.junit.", "org.mockito.", - "org.hibernate.", "com.ibm.", "com.caucho." - - }); - - private ConcurrentMap threadCPUTime = new ConcurrentHashMap(); - - private AtomicLong updateCount_ = new AtomicLong( - 0); - - private VMInfo vmInfo_; - - /** - * @param threadMxBean - * @throws Exception - */ - public CPUSampler(VMInfo vmInfo) throws Exception - { - super(); - threadMxBean_ = vmInfo.getThreadMXBean(); - beginCPUTime_ = vmInfo.getProxyClient().getProcessCpuTime(); - vmInfo_ = vmInfo; - } - - public List getTop(int limit) - { - ArrayList statList = new ArrayList(data_.values()); - Collections.sort(statList); - return statList.subList(0, Math.min(limit, statList.size())); - } - - public long getTotal() - { - return totalThreadCPUTime_.get(); - } - - public void update() throws Exception - { - boolean samplesAcquired = false; - for (ThreadInfo ti : threadMxBean_.dumpAllThreads(false, false)) - { - long cpuTime = threadMxBean_.getThreadCpuTime(ti.getThreadId()); - Long tCPUTime = threadCPUTime.get(ti.getThreadId()); - if (tCPUTime == null) - { - tCPUTime = 0L; - } - else - { - Long deltaCpuTime = (cpuTime - tCPUTime); - - if (ti.getStackTrace().length > 0 - && ti.getThreadState() == State.RUNNABLE - ) { - for (StackTraceElement stElement : ti.getStackTrace()) { - if (isReallySleeping(stElement)) { - break; - } - if (isFiltered(stElement)) { - continue; - } - String key = stElement.getClassName() + "." - + stElement.getMethodName(); - data_.putIfAbsent(key, new MethodStats(stElement.getClassName(), - stElement.getMethodName())); - data_.get(key).getHits().addAndGet(deltaCpuTime); - totalThreadCPUTime_.addAndGet(deltaCpuTime); - samplesAcquired = true; - break; - } - } - } - threadCPUTime.put(ti.getThreadId(), cpuTime); - } - if (samplesAcquired) -{ - updateCount_.incrementAndGet(); +public class CPUSampler { + private ThreadMXBean threadMxBean_ = null; + + private ConcurrentMap data_ = new ConcurrentHashMap(); + + private long beginCPUTime_ = 0; + + private AtomicLong totalThreadCPUTime_ = new AtomicLong(0); + + // TODO: these exception list should be expanded to the most common + // 3rd-party library packages + private List filter = Arrays.asList(new String[] { "org.eclipse.", "org.apache.", "java.", "sun.", "com.sun.", "javax.", "oracle.", "com.trilead.", "org.junit.", "org.mockito.", + "org.hibernate.", "com.ibm.", "com.caucho." + + }); + + private ConcurrentMap threadCPUTime = new ConcurrentHashMap(); + + private AtomicLong updateCount_ = new AtomicLong(0); + + /** + * @param threadMxBean + * @throws Exception + */ + public CPUSampler(VMInfo vmInfo) throws Exception { + super(); + threadMxBean_ = vmInfo.getThreadMXBean(); + beginCPUTime_ = vmInfo.getProxyClient().getProcessCpuTime(); + } + + public List getTop(int limit) { + ArrayList statList = new ArrayList(data_.values()); + Collections.sort(statList); + return statList.subList(0, Math.min(limit, statList.size())); + } + + public long getTotal() { + return totalThreadCPUTime_.get(); + } + + public void update() throws Exception { + boolean samplesAcquired = false; + for (ThreadInfo ti : threadMxBean_.dumpAllThreads(false, false)) { + long cpuTime = threadMxBean_.getThreadCpuTime(ti.getThreadId()); + Long tCPUTime = threadCPUTime.get(ti.getThreadId()); + if (tCPUTime == null) + tCPUTime = 0L; + else { + Long deltaCpuTime = (cpuTime - tCPUTime); + + if (ti.getStackTrace().length > 0 && ti.getThreadState() == State.RUNNABLE) + for (StackTraceElement stElement : ti.getStackTrace()) { + if (isReallySleeping(stElement)) + break; + if (isFiltered(stElement)) + continue; + String key = stElement.getClassName() + "." + stElement.getMethodName(); + data_.putIfAbsent(key, new MethodStats(stElement.getClassName(), stElement.getMethodName())); + data_.get(key).getHits().addAndGet(deltaCpuTime); + totalThreadCPUTime_.addAndGet(deltaCpuTime); + samplesAcquired = true; + break; + } + } + threadCPUTime.put(ti.getThreadId(), cpuTime); + } + if (samplesAcquired) + updateCount_.incrementAndGet(); + } + + public Long getUpdateCount() { + return updateCount_.get(); + } + + private boolean isReallySleeping(StackTraceElement se) { + return se.getClassName().equals("sun.nio.ch.EPollArrayWrapper") && se.getMethodName().equals("epollWait"); + } + + public boolean isFiltered(StackTraceElement se) { + for (String filteredPackage : filter) + if (se.getClassName().startsWith(filteredPackage)) + return true; + return false; + } } - } - - public Long getUpdateCount() - { - return updateCount_.get(); - } - - private boolean isReallySleeping(StackTraceElement se) { - return se.getClassName().equals("sun.nio.ch.EPollArrayWrapper") && - se.getMethodName().equals("epollWait"); - } - - public boolean isFiltered(StackTraceElement se) { - for (String filteredPackage : filter) { - if (se.getClassName().startsWith(filteredPackage)) { - return true; - } - } - return false; - } -} - diff --git a/src/main/java/com/jvmtop/profiler/MethodStats.java b/src/main/java/com/jvmtop/profiler/MethodStats.java index 9f39c99..425fed5 100644 --- a/src/main/java/com/jvmtop/profiler/MethodStats.java +++ b/src/main/java/com/jvmtop/profiler/MethodStats.java @@ -28,107 +28,72 @@ * @author paru * */ -public class MethodStats implements Comparable -{ - private AtomicLong hits_ = new AtomicLong(0); - - private String className_ = null; - - private String methodName_ = null; - - /** - * @param className - * @param methodName - */ - public MethodStats(String className, String methodName) - { - super(); - className_ = className; - methodName_ = methodName; - } - - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result - + ((className_ == null) ? 0 : className_.hashCode()); - result = prime * result - + ((methodName_ == null) ? 0 : methodName_.hashCode()); - return result; - } - - - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - MethodStats other = (MethodStats) obj; - if (className_ == null) - { - if (other.className_ != null) - { - return false; - } - } - else if (!className_.equals(other.className_)) - { - return false; - } - if (methodName_ == null) - { - if (other.methodName_ != null) - { - return false; - } - } - else if (!methodName_.equals(other.methodName_)) - { - return false; - } - return true; - } - - - - @Override - /** - * Compares a MethodStats object by its hits - */ - public int compareTo(MethodStats o) - { - return Long.valueOf(o.hits_.get()).compareTo(hits_.get()); - } - - public AtomicLong getHits() - { - return hits_; - } - - public String getClassName() - { - return className_; - } - - public String getMethodName() - { - return methodName_; - } - - +public class MethodStats implements Comparable { + private AtomicLong hits_ = new AtomicLong(0); + + private String className_ = null; + + private String methodName_ = null; + + /** + * @param className + * @param methodName + */ + public MethodStats(String className, String methodName) { + super(); + className_ = className; + methodName_ = methodName; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((className_ == null) ? 0 : className_.hashCode()); + result = prime * result + ((methodName_ == null) ? 0 : methodName_.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MethodStats other = (MethodStats) obj; + if (className_ == null) { + if (other.className_ != null) + return false; + } else if (!className_.equals(other.className_)) + return false; + if (methodName_ == null) { + if (other.methodName_ != null) + return false; + } else if (!methodName_.equals(other.methodName_)) + return false; + return true; + } + + @Override + /** + * Compares a MethodStats object by its hits + */ + public int compareTo(MethodStats o) { + return Long.valueOf(o.hits_.get()).compareTo(hits_.get()); + } + + public AtomicLong getHits() { + return hits_; + } + + public String getClassName() { + return className_; + } + + public String getMethodName() { + return methodName_; + } } \ No newline at end of file diff --git a/src/main/java/com/jvmtop/view/AbstractConsoleView.java b/src/main/java/com/jvmtop/view/AbstractConsoleView.java index 6f4de12..e7812e7 100644 --- a/src/main/java/com/jvmtop/view/AbstractConsoleView.java +++ b/src/main/java/com/jvmtop/view/AbstractConsoleView.java @@ -29,169 +29,154 @@ import java.util.List; import java.util.Map; - /** - * Base class for all console views, providing some helper methods - * for formatting. + * Base class for all console views, providing some helper methods for + * formatting. * * @author paru * */ -public abstract class AbstractConsoleView implements ConsoleView -{ - - private static final int MIN_WIDTH = 80; - - private boolean shouldExit_ = false; - - protected final int width; - - /** - * - */ - public AbstractConsoleView(Integer width) - { - super(); - if (width == null) width = MIN_WIDTH; - if (width < MIN_WIDTH) width = MIN_WIDTH; - this.width = width; - } - - /** - * Formats a long value containing "number of bytes" to its megabyte representation. - * If the value is negative, "n/a" will be returned. - * - * TODO: implement automatic scale to bigger units if this makes sense - * (e.g. output 4.3g instead of 4324m) - * - * @param bytes - * @return - */ - public String toMB(long bytes) - { - if(bytes<0) - { - return "n/a"; - } - return "" + (bytes / 1024 / 1024) + "m"; - } - - /** - * Formats number of milliseconds to a HH:MM representation - * - * TODO: implement automatic scale (e.g. 1d 7h instead of 31:13m) - * @param millis - * @return - */ - public String toHHMM(long millis) - { - StringBuilder sb = new StringBuilder(); - Formatter formatter = new Formatter(sb); - formatter -.format("%2d:%2dm", millis / 1000 / 3600, - (millis / 1000 / 60) % 60); - return sb.toString(); - } - - /** - * Returns a substring of the given string, representing the 'length' most-right characters - * @param str - * @param length - * @return - */ - public String rightStr(String str, int length) - { - return str.substring(Math.max(0, str.length() - length)); - } - - /** - * Returns a substring of the given string, representing the 'length' most-left characters - * @param str - * @param length - * @return - */ - public String leftStr(String str, int length) - { - return str.substring(0, Math.min(str.length(), length)); - } - - /** - * Joins the given list of strings using the given delimiter delim - * @param list - * @param delim - * @return - */ - public String join(List list, String delim) - { - - StringBuilder sb = new StringBuilder(); - - String loopDelim = ""; - - for (String s : list) - { - - sb.append(loopDelim); - sb.append(s); - - loopDelim = delim; - } - - return sb.toString(); - } - - @Override - public boolean shouldExit() - { - return shouldExit_; - } - - /** - * Requests the disposal of this view - it should be called again. - * TODO: refactor / remove this functional, use proper exception handling instead. - */ - protected void exit() - { - shouldExit_ = true; - } - - /** - * Sorts a Map by its values, using natural ordering. - * - * @param map - * @param reverse - * @return - */ - public Map sortByValue(Map map, boolean reverse) - { - List list = new LinkedList(map.entrySet()); - Collections.sort(list, new Comparator() - { - @Override - public int compare(Object o1, Object o2) - { - return ((Comparable) ((Map.Entry) (o1)).getValue()) - .compareTo(((Map.Entry) (o2)).getValue()); - } - }); - - if (reverse) - { - Collections.reverse(list); - } - - Map result = new LinkedHashMap(); - for (Iterator it = list.iterator(); it.hasNext();) - { - Map.Entry entry = (Map.Entry) it.next(); - result.put(entry.getKey(), entry.getValue()); - } - return result; - } - - @Override - public void sleep(long millis) throws Exception - { - Thread.sleep(millis); - } +public abstract class AbstractConsoleView implements ConsoleView { + + private static final int MIN_WIDTH = 80; + + private boolean shouldExit_ = false; + + protected final int width; + + /** + * + */ + public AbstractConsoleView(Integer width) { + super(); + if (width == null) + width = MIN_WIDTH; + if (width < MIN_WIDTH) + width = MIN_WIDTH; + this.width = width; + } + + /** + * Formats a long value containing "number of bytes" to its megabyte + * representation. If the value is negative, "n/a" will be returned. + * + * TODO: implement automatic scale to bigger units if this makes sense (e.g. + * output 4.3g instead of 4324m) + * + * @param bytes + * @return + */ + public String toMB(long bytes) { + if (bytes < 0) + return "n/a"; + return "" + (bytes / 1024 / 1024) + "m"; + } + + /** + * Formats number of milliseconds to a HH:MM representation + * + * TODO: implement automatic scale (e.g. 1d 7h instead of 31:13m) + * + * @param millis + * @return + */ + public String toHHMM(long millis) { + StringBuilder sb = new StringBuilder(); + Formatter formatter = new Formatter(sb); + formatter.format("%2d:%2dm", millis / 1000 / 3600, (millis / 1000 / 60) % 60); + return sb.toString(); + } + + /** + * Returns a substring of the given string, representing the 'length' + * most-right characters + * + * @param str + * @param length + * @return + */ + public String rightStr(String str, int length) { + return str.substring(Math.max(0, str.length() - length)); + } + + /** + * Returns a substring of the given string, representing the 'length' + * most-left characters + * + * @param str + * @param length + * @return + */ + public String leftStr(String str, int length) { + return str.substring(0, Math.min(str.length(), length)); + } + + /** + * Joins the given list of strings using the given delimiter delim + * + * @param list + * @param delim + * @return + */ + public String join(List list, String delim) { + + StringBuilder sb = new StringBuilder(); + + String loopDelim = ""; + + for (String s : list) { + + sb.append(loopDelim); + sb.append(s); + + loopDelim = delim; + } + + return sb.toString(); + } + + @Override + public boolean shouldExit() { + return shouldExit_; + } + + /** + * Requests the disposal of this view - it should be called again. TODO: + * refactor / remove this functional, use proper exception handling instead. + */ + protected void exit() { + shouldExit_ = true; + } + + /** + * Sorts a Map by its values, using natural ordering. + * + * @param map + * @param reverse + * @return + */ + public Map sortByValue(Map map, boolean reverse) { + List list = new LinkedList(map.entrySet()); + Collections.sort(list, new Comparator() { + @Override + public int compare(Object o1, Object o2) { + return ((Comparable) ((Map.Entry) (o1)).getValue()).compareTo(((Map.Entry) (o2)).getValue()); + } + }); + + if (reverse) + Collections.reverse(list); + + Map result = new LinkedHashMap(); + for (Iterator it = list.iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + result.put(entry.getKey(), entry.getValue()); + } + return result; + } + + @Override + public void sleep(long millis) throws Exception { + Thread.sleep(millis); + } } diff --git a/src/main/java/com/jvmtop/view/ConsoleView.java b/src/main/java/com/jvmtop/view/ConsoleView.java index 482f495..1e60a11 100644 --- a/src/main/java/com/jvmtop/view/ConsoleView.java +++ b/src/main/java/com/jvmtop/view/ConsoleView.java @@ -27,29 +27,29 @@ * @author paru * */ -public interface ConsoleView -{ - /** - * Prints the view to STDOUT. - * - * @throws Exception - */ - public void printView() throws Exception; +public interface ConsoleView { + /** + * Prints the view to STDOUT. + * + * @throws Exception + */ + public void printView() throws Exception; - /** - * Notifies that this view encountered issues - * and should be called again (e.g. due to exceptions) - * - * TODO: remove this method and use proper exception instead. - * - * @return - */ - public boolean shouldExit(); + /** + * Notifies that this view encountered issues and should be called again + * (e.g. due to exceptions) + * + * TODO: remove this method and use proper exception instead. + * + * @return + */ + public boolean shouldExit(); - /** - * Requests the view to sleep (defined as "not outputting anything"). - * However, the view is allowed to do some work / telemtry retrieval during sleep. - * - */ - public void sleep(long millis) throws Exception; + /** + * Requests the view to sleep (defined as "not outputting anything"). + * However, the view is allowed to do some work / telemtry retrieval during + * sleep. + * + */ + public void sleep(long millis) throws Exception; } diff --git a/src/main/java/com/jvmtop/view/VMDetailView.java b/src/main/java/com/jvmtop/view/VMDetailView.java index 21a40f0..34b2611 100644 --- a/src/main/java/com/jvmtop/view/VMDetailView.java +++ b/src/main/java/com/jvmtop/view/VMDetailView.java @@ -33,258 +33,181 @@ import com.jvmtop.openjdk.tools.LocalVirtualMachine; /** - * "detail" view, printing detail metrics of a specific jvm. - * Also printing the top threads (based on the current CPU usage) + * "detail" view, printing detail metrics of a specific jvm. Also printing the + * top threads (based on the current CPU usage) * * @author paru * */ -public class VMDetailView extends AbstractConsoleView -{ - - private VMInfo vmInfo_; - - private boolean sortByTotalCPU_ = false; - - private int numberOfDisplayedThreads_ = 10; - - private int threadNameDisplayWidth_ = 30; - - private boolean displayedThreadLimit_ = true; - - //TODO: refactor - private Map previousThreadCPUMillis = new HashMap(); - - public VMDetailView(int vmid, Integer width) throws Exception - { - super(width); - LocalVirtualMachine localVirtualMachine = LocalVirtualMachine - .getLocalVirtualMachine(vmid); - vmInfo_ = VMInfo.processNewVM(localVirtualMachine, vmid); - } - - public boolean isSortByTotalCPU() - { - return sortByTotalCPU_; - } - - public void setSortByTotalCPU(boolean sortByTotalCPU) - { - sortByTotalCPU_ = sortByTotalCPU; - } - - @Override - public void printView() throws Exception - { - vmInfo_.update(); - - if (vmInfo_.getState() == VMInfoState.ATTACHED_UPDATE_ERROR) - { - System.out - .println("ERROR: Could not fetch telemetries - Process terminated?"); - exit(); - return; - } - if (vmInfo_.getState() != VMInfoState.ATTACHED) - { - System.out.println("ERROR: Could not attach to process."); - exit(); - return; - } - - Map properties = vmInfo_.getSystemProperties(); - - String command = properties.get("sun.java.command"); - if (command != null) - { - String[] commandArray = command.split(" "); - - List commandList = Arrays.asList(commandArray); - commandList = commandList.subList(1, commandList.size()); - - System.out.printf(" PID %d: %s %n", vmInfo_.getId(), commandArray[0]); - - String argJoin = join(commandList, " "); - if (argJoin.length() > 67) - { - System.out.printf(" ARGS: %s[...]%n", leftStr(argJoin, 67)); - } - else - { - System.out.printf(" ARGS: %s%n", argJoin); - } - } - else - { - System.out.printf(" PID %d: %n", vmInfo_.getId()); - System.out.printf(" ARGS: [UNKNOWN] %n"); - } - - String join = join(vmInfo_.getRuntimeMXBean().getInputArguments(), " "); - if (join.length() > 65) - { - System.out.printf(" VMARGS: %s[...]%n", leftStr(join, 65)); - } - else - { - System.out.printf(" VMARGS: %s%n", join); - } - - System.out.printf(" VM: %s %s %s%n", properties.get("java.vendor"), - properties.get("java.vm.name"), properties.get("java.version")); - System.out.printf( - " UP: %-7s #THR: %-4d #THRPEAK: %-4d #THRCREATED: %-4d USER: %-12s%n", - toHHMM(vmInfo_.getRuntimeMXBean().getUptime()), vmInfo_ - .getThreadCount(), vmInfo_.getThreadMXBean().getPeakThreadCount(), - vmInfo_.getThreadMXBean().getTotalStartedThreadCount(), vmInfo_ - .getOSUser()); - - System.out.printf( - " GC-Time: %-7s #GC-Runs: %-8d #TotalLoadedClasses: %-8d%n", - toHHMM(vmInfo_.getGcTime()), vmInfo_.getGcCount(), - vmInfo_.getTotalLoadedClassCount()); - - System.out.printf( - " CPU: %5.2f%% GC: %5.2f%% HEAP:%5s /%5s NONHEAP:%5s /%5s%n", - vmInfo_.getCpuLoad() * 100, vmInfo_.getGcLoad() * 100, - toMB(vmInfo_.getHeapUsed()), toMB(vmInfo_.getHeapMax()), - toMB(vmInfo_.getNonHeapUsed()), toMB(vmInfo_.getNonHeapMax())); - - System.out.println(); - - printTopThreads(); - - } - - /** - * @throws Exception - */ - private void printTopThreads() throws Exception - { - System.out.printf(" %6s %-" + threadNameDisplayWidth_ - + "s %13s %8s %8s %5s %n", "TID", "NAME", "STATE", "CPU", - "TOTALCPU", "BLOCKEDBY"); - - if (vmInfo_.getThreadMXBean().isThreadCpuTimeSupported()) - { - - //TODO: move this into VMInfo? - Map newThreadCPUMillis = new HashMap(); - - Map cpuTimeMap = new TreeMap(); - - for (Long tid : vmInfo_.getThreadMXBean().getAllThreadIds()) - { - long threadCpuTime = vmInfo_.getThreadMXBean().getThreadCpuTime(tid); - long deltaThreadCpuTime = 0; - if (previousThreadCPUMillis.containsKey(tid)) - { - deltaThreadCpuTime = threadCpuTime - previousThreadCPUMillis.get(tid); - - cpuTimeMap.put(tid, deltaThreadCpuTime); - } - newThreadCPUMillis.put(tid, threadCpuTime); - } - - cpuTimeMap = sortByValue(cpuTimeMap, true); - - int displayedThreads = 0; - for (Long tid : cpuTimeMap.keySet()) - { - ThreadInfo info = vmInfo_.getThreadMXBean().getThreadInfo(tid); - displayedThreads++; - if (displayedThreads > numberOfDisplayedThreads_ - && displayedThreadLimit_) - { - break; - } - if (info != null) - { - System.out.printf( - " %6d %-" + threadNameDisplayWidth_ - + "s %13s %5.2f%% %5.2f%% %5s %n", - tid, - leftStr(info.getThreadName(), threadNameDisplayWidth_), - info.getThreadState(), - getThreadCPUUtilization(cpuTimeMap.get(tid), - vmInfo_.getDeltaUptime()), - getThreadCPUUtilization(vmInfo_.getThreadMXBean() - .getThreadCpuTime(tid), vmInfo_.getProxyClient() - .getProcessCpuTime(), 1), getBlockedThread(info)); - } - } - if (newThreadCPUMillis.size() >= numberOfDisplayedThreads_ - && displayedThreadLimit_) - { - - System.out.printf( - " Note: Only top %d threads (according cpu load) are shown!", - numberOfDisplayedThreads_); - } - previousThreadCPUMillis = newThreadCPUMillis; - } - else - { - - System.out - .printf("%n -Thread CPU telemetries are not available on the monitored jvm/platform-%n"); - } - } - - private String getBlockedThread(ThreadInfo info) - { - if (info.getLockOwnerId() >= 0) - { - return "" + info.getLockOwnerId(); - } - else - { - return ""; - } - } - - public int getNumberOfDisplayedThreads() - { - return numberOfDisplayedThreads_; - } - - public void setNumberOfDisplayedThreads(int numberOfDisplayedThreads) - { - numberOfDisplayedThreads_ = numberOfDisplayedThreads; - } - - public boolean isDisplayedThreadLimit() - { - return displayedThreadLimit_; - } - - public void setDisplayedThreadLimit(boolean displayedThreadLimit) - { - displayedThreadLimit_ = displayedThreadLimit; - } - - public int getThreadNameDisplayWidth() - { - return threadNameDisplayWidth_; - } - - public void setThreadNameDisplayWidth(int threadNameDisplayWidth_) - { - this.threadNameDisplayWidth_ = threadNameDisplayWidth_; - } - - private double getThreadCPUUtilization(long deltaThreadCpuTime, long totalTime) - { - return getThreadCPUUtilization(deltaThreadCpuTime, totalTime, 1000 * 1000); - } - - private double getThreadCPUUtilization(long deltaThreadCpuTime, - long totalTime, double factor) - { - if (totalTime == 0) - { - return 0; - } - return deltaThreadCpuTime / factor / totalTime * 100d; - } +public class VMDetailView extends AbstractConsoleView { + + private VMInfo vmInfo_; + + private boolean sortByTotalCPU_ = false; + + private int numberOfDisplayedThreads_ = 10; + + private int threadNameDisplayWidth_ = 30; + + private boolean displayedThreadLimit_ = true; + + // TODO: refactor + private Map previousThreadCPUMillis = new HashMap(); + + public VMDetailView(int vmid, Integer width) throws Exception { + super(width); + LocalVirtualMachine localVirtualMachine = LocalVirtualMachine.getLocalVirtualMachine(vmid); + vmInfo_ = VMInfo.processNewVM(localVirtualMachine, vmid); + } + + public boolean isSortByTotalCPU() { + return sortByTotalCPU_; + } + + public void setSortByTotalCPU(boolean sortByTotalCPU) { + sortByTotalCPU_ = sortByTotalCPU; + } + + @Override + public void printView() throws Exception { + vmInfo_.update(); + + if (vmInfo_.getState() == VMInfoState.ATTACHED_UPDATE_ERROR) { + System.out.println("ERROR: Could not fetch telemetries - Process terminated?"); + exit(); + return; + } + if (vmInfo_.getState() != VMInfoState.ATTACHED) { + System.out.println("ERROR: Could not attach to process."); + exit(); + return; + } + + Map properties = vmInfo_.getSystemProperties(); + + String command = properties.get("sun.java.command"); + if (command != null) { + String[] commandArray = command.split(" "); + + List commandList = Arrays.asList(commandArray); + commandList = commandList.subList(1, commandList.size()); + + System.out.printf(" PID %d: %s %n", vmInfo_.getId(), commandArray[0]); + + String argJoin = join(commandList, " "); + if (argJoin.length() > 67) + System.out.printf(" ARGS: %s[...]%n", leftStr(argJoin, 67)); + else + System.out.printf(" ARGS: %s%n", argJoin); + } else { + System.out.printf(" PID %d: %n", vmInfo_.getId()); + System.out.printf(" ARGS: [UNKNOWN] %n"); + } + + String join = join(vmInfo_.getRuntimeMXBean().getInputArguments(), " "); + if (join.length() > 65) + System.out.printf(" VMARGS: %s[...]%n", leftStr(join, 65)); + else + System.out.printf(" VMARGS: %s%n", join); + + System.out.printf(" VM: %s %s %s%n", properties.get("java.vendor"), properties.get("java.vm.name"), properties.get("java.version")); + System.out.printf(" UP: %-7s #THR: %-4d #THRPEAK: %-4d #THRCREATED: %-4d USER: %-12s%n", toHHMM(vmInfo_.getRuntimeMXBean().getUptime()), vmInfo_.getThreadCount(), vmInfo_.getThreadMXBean() + .getPeakThreadCount(), vmInfo_.getThreadMXBean().getTotalStartedThreadCount(), vmInfo_.getOSUser()); + + System.out.printf(" GC-Time: %-7s #GC-Runs: %-8d #TotalLoadedClasses: %-8d%n", toHHMM(vmInfo_.getGcTime()), vmInfo_.getGcCount(), vmInfo_.getTotalLoadedClassCount()); + + System.out.printf(" CPU: %5.2f%% GC: %5.2f%% HEAP:%5s /%5s NONHEAP:%5s /%5s%n", vmInfo_.getCpuLoad() * 100, vmInfo_.getGcLoad() * 100, toMB(vmInfo_.getHeapUsed()), + toMB(vmInfo_.getHeapMax()), toMB(vmInfo_.getNonHeapUsed()), toMB(vmInfo_.getNonHeapMax())); + + System.out.println(); + + printTopThreads(); + + } + + /** + * @throws Exception + */ + private void printTopThreads() throws Exception { + System.out.printf(" %6s %-" + threadNameDisplayWidth_ + "s %13s %8s %8s %5s %n", "TID", "NAME", "STATE", "CPU", "TOTALCPU", "BLOCKEDBY"); + + if (vmInfo_.getThreadMXBean().isThreadCpuTimeSupported()) { + + // TODO: move this into VMInfo? + Map newThreadCPUMillis = new HashMap(); + + Map cpuTimeMap = new TreeMap(); + + for (Long tid : vmInfo_.getThreadMXBean().getAllThreadIds()) { + long threadCpuTime = vmInfo_.getThreadMXBean().getThreadCpuTime(tid); + long deltaThreadCpuTime = 0; + if (previousThreadCPUMillis.containsKey(tid)) { + deltaThreadCpuTime = threadCpuTime - previousThreadCPUMillis.get(tid); + + cpuTimeMap.put(tid, deltaThreadCpuTime); + } + newThreadCPUMillis.put(tid, threadCpuTime); + } + + cpuTimeMap = sortByValue(cpuTimeMap, true); + + int displayedThreads = 0; + for (Long tid : cpuTimeMap.keySet()) { + ThreadInfo info = vmInfo_.getThreadMXBean().getThreadInfo(tid); + displayedThreads++; + if (displayedThreads > numberOfDisplayedThreads_ && displayedThreadLimit_) + break; + if (info != null) + System.out.printf(" %6d %-" + threadNameDisplayWidth_ + "s %13s %5.2f%% %5.2f%% %5s %n", tid, leftStr(info.getThreadName(), threadNameDisplayWidth_), info.getThreadState(), + getThreadCPUUtilization(cpuTimeMap.get(tid), vmInfo_.getDeltaUptime()), + getThreadCPUUtilization(vmInfo_.getThreadMXBean().getThreadCpuTime(tid), vmInfo_.getProxyClient().getProcessCpuTime(), 1), getBlockedThread(info)); + } + if (newThreadCPUMillis.size() >= numberOfDisplayedThreads_ && displayedThreadLimit_) + System.out.printf(" Note: Only top %d threads (according cpu load) are shown!", numberOfDisplayedThreads_); + previousThreadCPUMillis = newThreadCPUMillis; + } else + System.out.printf("%n -Thread CPU telemetries are not available on the monitored jvm/platform-%n"); + } + + private String getBlockedThread(ThreadInfo info) { + if (info.getLockOwnerId() >= 0) { + return "" + info.getLockOwnerId(); + } else { + return ""; + } + } + + public int getNumberOfDisplayedThreads() { + return numberOfDisplayedThreads_; + } + + public void setNumberOfDisplayedThreads(int numberOfDisplayedThreads) { + numberOfDisplayedThreads_ = numberOfDisplayedThreads; + } + + public boolean isDisplayedThreadLimit() { + return displayedThreadLimit_; + } + + public void setDisplayedThreadLimit(boolean displayedThreadLimit) { + displayedThreadLimit_ = displayedThreadLimit; + } + + public int getThreadNameDisplayWidth() { + return threadNameDisplayWidth_; + } + + public void setThreadNameDisplayWidth(int threadNameDisplayWidth_) { + this.threadNameDisplayWidth_ = threadNameDisplayWidth_; + } + + private double getThreadCPUUtilization(long deltaThreadCpuTime, long totalTime) { + return getThreadCPUUtilization(deltaThreadCpuTime, totalTime, 1000 * 1000); + } + + private double getThreadCPUUtilization(long deltaThreadCpuTime, long totalTime, double factor) { + if (totalTime == 0) + return 0; + return deltaThreadCpuTime / factor / totalTime * 100d; + } } diff --git a/src/main/java/com/jvmtop/view/VMOverviewView.java b/src/main/java/com/jvmtop/view/VMOverviewView.java index 6f8d862..6a48a66 100644 --- a/src/main/java/com/jvmtop/view/VMOverviewView.java +++ b/src/main/java/com/jvmtop/view/VMOverviewView.java @@ -33,149 +33,108 @@ import com.jvmtop.openjdk.tools.LocalVirtualMachine; /** - * "overview" view, providing the most-important metrics of all accessible jvms in a top-like manner. + * "overview" view, providing the most-important metrics of all accessible jvms + * in a top-like manner. * * @author paru * */ -public class VMOverviewView extends AbstractConsoleView -{ - - private List vmInfoList = new ArrayList(); - - private Map vmMap = new HashMap(); - - public VMOverviewView(Integer width) { - super(width); - } - - public void printView() throws Exception - { - printHeader(); - - //to reduce cpu effort, scan only every 5 iterations for new vms - scanForNewVMs(); - - updateVMs(vmInfoList); - - Collections.sort(vmInfoList, VMInfo.CPU_LOAD_COMPARATOR); - - for (VMInfo vmInfo : vmInfoList) - { - if (vmInfo.getState() == VMInfoState.ATTACHED -) - { - printVM(vmInfo); - } - else if (vmInfo.getState() == VMInfoState.ATTACHED_UPDATE_ERROR) - { - System.out - .printf( - "%5d %-15.15s [ERROR: Could not fetch telemetries (Process DEAD?)] %n", - vmInfo.getId(), getEntryPointClass(vmInfo.getDisplayName())); - - } - else if (vmInfo.getState() == VMInfoState.ERROR_DURING_ATTACH) - { - System.out.printf("%5d %-15.15s [ERROR: Could not attach to VM] %n", - vmInfo.getId(), getEntryPointClass(vmInfo.getDisplayName())); - } - else if (vmInfo.getState() == VMInfoState.CONNECTION_REFUSED) - { - System.out.printf( - "%5d %-15.15s [ERROR: Connection refused/access denied] %n", - vmInfo.getId(), getEntryPointClass(vmInfo.getDisplayName())); - } - - } - } - - /** - * @param name - * @return - */ - private String getEntryPointClass(String name) - { - if (name.indexOf(' ') > 0) - { - name = name.substring(0, name.indexOf(' ')); - } - return rightStr(name, 15); - } - - /** - * @param localvm - * @param vmid - * @param vmInfo - * @return - * @throws Exception - */ - private void printVM(VMInfo vmInfo) throws Exception - { - - String deadlockState = ""; - if (vmInfo.hasDeadlockThreads()) - { - deadlockState = "!D"; - } - - System.out - .printf( - "%5d %-15.15s %5s %5s %5s %5s %5.2f%% %5.2f%% %-5.5s %8.8s %4d %2.2s%n", - vmInfo.getId(), getEntryPointClass(vmInfo.getDisplayName()), - toMB(vmInfo.getHeapUsed()), toMB(vmInfo.getHeapMax()), - toMB(vmInfo.getNonHeapUsed()), toMB(vmInfo.getNonHeapMax()), - vmInfo.getCpuLoad() * 100, vmInfo.getGcLoad() * 100, - vmInfo.getVMVersion(), vmInfo.getOSUser(), vmInfo.getThreadCount(), - deadlockState); - - } - - /** - * @param vmList - * @throws Exception - */ - private void updateVMs(List vmList) throws Exception - { - for (VMInfo vmInfo : vmList) - { - vmInfo.update(); - } - } - - /** - * @param vmMap - * @param vmMap - * @param set - */ - private void scanForNewVMs() - { - Map machines = LocalVirtualMachine - .getNewVirtualMachines(vmMap); - Set> set = machines.entrySet(); - - for (Entry entry : set) - { - LocalVirtualMachine localvm = entry.getValue(); - int vmid = localvm.vmid(); - - if (!vmMap.containsKey(vmid)) - { - VMInfo vmInfo = VMInfo.processNewVM(localvm, vmid); - vmInfoList.add(vmInfo); - } - } - vmMap = machines; - } - - /** - * - */ - private void printHeader() - { - System.out.printf("%5s %-15.15s %5s %5s %5s %5s %6s %6s %5s %8s %4s %2s%n", - "PID", "MAIN-CLASS", "HPCUR", "HPMAX", "NHCUR", "NHMAX", "CPU", "GC", - "VM", "USERNAME", "#T", "DL"); - } +public class VMOverviewView extends AbstractConsoleView { + + private List vmInfoList = new ArrayList(); + + private Map vmMap = new HashMap(); + + public VMOverviewView(Integer width) { + super(width); + } + + @Override + public void printView() throws Exception { + printHeader(); + + // to reduce cpu effort, scan only every 5 iterations for new vms + scanForNewVMs(); + + updateVMs(vmInfoList); + + Collections.sort(vmInfoList, VMInfo.CPU_LOAD_COMPARATOR); + + for (VMInfo vmInfo : vmInfoList) + if (vmInfo.getState() == VMInfoState.ATTACHED) + printVM(vmInfo); + else if (vmInfo.getState() == VMInfoState.ATTACHED_UPDATE_ERROR) + System.out.printf("%5d %-15.15s [ERROR: Could not fetch telemetries (Process DEAD?)] %n", vmInfo.getId(), getEntryPointClass(vmInfo.getDisplayName())); + else if (vmInfo.getState() == VMInfoState.ERROR_DURING_ATTACH) + System.out.printf("%5d %-15.15s [ERROR: Could not attach to VM] %n", vmInfo.getId(), getEntryPointClass(vmInfo.getDisplayName())); + else if (vmInfo.getState() == VMInfoState.CONNECTION_REFUSED) + System.out.printf("%5d %-15.15s [ERROR: Connection refused/access denied] %n", vmInfo.getId(), getEntryPointClass(vmInfo.getDisplayName())); + } + + /** + * @param name + * @return + */ + private String getEntryPointClass(String name) { + if (name.indexOf(' ') > 0) + name = name.substring(0, name.indexOf(' ')); + return rightStr(name, 15); + } + + /** + * @param localvm + * @param vmid + * @param vmInfo + * @return + * @throws Exception + */ + private void printVM(VMInfo vmInfo) throws Exception { + + String deadlockState = ""; + if (vmInfo.hasDeadlockThreads()) + deadlockState = "!D"; + + System.out.printf("%5d %-15.15s %5s %5s %5s %5s %5.2f%% %5.2f%% %-5.5s %8.8s %4d %2.2s%n", vmInfo.getId(), getEntryPointClass(vmInfo.getDisplayName()), toMB(vmInfo.getHeapUsed()), + toMB(vmInfo.getHeapMax()), toMB(vmInfo.getNonHeapUsed()), toMB(vmInfo.getNonHeapMax()), vmInfo.getCpuLoad() * 100, vmInfo.getGcLoad() * 100, vmInfo.getVMVersion(), + vmInfo.getOSUser(), vmInfo.getThreadCount(), deadlockState); + + } + + /** + * @param vmList + * @throws Exception + */ + private void updateVMs(List vmList) throws Exception { + for (VMInfo vmInfo : vmList) + vmInfo.update(); + } + + /** + * @param vmMap + * @param vmMap + * @param set + */ + private void scanForNewVMs() { + Map machines = LocalVirtualMachine.getNewVirtualMachines(vmMap); + Set> set = machines.entrySet(); + + for (Entry entry : set) { + LocalVirtualMachine localvm = entry.getValue(); + int vmid = localvm.vmid(); + + if (!vmMap.containsKey(vmid)) { + VMInfo vmInfo = VMInfo.processNewVM(localvm, vmid); + vmInfoList.add(vmInfo); + } + } + vmMap = machines; + } + + /** + * + */ + private void printHeader() { + System.out.printf("%5s %-15.15s %5s %5s %5s %5s %6s %6s %5s %8s %4s %2s%n", "PID", "MAIN-CLASS", "HPCUR", "HPMAX", "NHCUR", "NHMAX", "CPU", "GC", "VM", "USERNAME", "#T", "DL"); + } } diff --git a/src/main/java/com/jvmtop/view/VMProfileView.java b/src/main/java/com/jvmtop/view/VMProfileView.java index aba76ac..2b47861 100644 --- a/src/main/java/com/jvmtop/view/VMProfileView.java +++ b/src/main/java/com/jvmtop/view/VMProfileView.java @@ -20,8 +20,6 @@ */ package com.jvmtop.view; -import java.util.Iterator; - import com.jvmtop.monitor.VMInfo; import com.jvmtop.monitor.VMInfoState; import com.jvmtop.openjdk.tools.LocalVirtualMachine; @@ -34,93 +32,71 @@ * @author paru * */ -public class VMProfileView extends AbstractConsoleView -{ +public class VMProfileView extends AbstractConsoleView { - private CPUSampler cpuSampler_; + private CPUSampler cpuSampler_; - private VMInfo vmInfo_; + private VMInfo vmInfo_; - public VMProfileView(int vmid, Integer width) throws Exception - { - super(width); - LocalVirtualMachine localVirtualMachine = LocalVirtualMachine - .getLocalVirtualMachine(vmid); - vmInfo_ = VMInfo.processNewVM(localVirtualMachine, vmid); - cpuSampler_ = new CPUSampler(vmInfo_); - } + public VMProfileView(int vmid, Integer width) throws Exception { + super(width); + LocalVirtualMachine localVirtualMachine = LocalVirtualMachine.getLocalVirtualMachine(vmid); + vmInfo_ = VMInfo.processNewVM(localVirtualMachine, vmid); + cpuSampler_ = new CPUSampler(vmInfo_); + } - @Override - public void sleep(long millis) throws Exception - { - long cur = System.currentTimeMillis(); - cpuSampler_.update(); - while (cur + millis > System.currentTimeMillis()) - { - cpuSampler_.update(); - super.sleep(100); - } + @Override + public void sleep(long millis) throws Exception { + long cur = System.currentTimeMillis(); + cpuSampler_.update(); + while (cur + millis > System.currentTimeMillis()) { + cpuSampler_.update(); + super.sleep(100); + } - } + } - @Override - public void printView() throws Exception - { - if (vmInfo_.getState() == VMInfoState.ATTACHED_UPDATE_ERROR) - { - System.out - .println("ERROR: Could not fetch telemetries - Process terminated?"); - exit(); - return; - } - if (vmInfo_.getState() != VMInfoState.ATTACHED) - { - System.out.println("ERROR: Could not attach to process."); - exit(); - return; - } + @Override + public void printView() throws Exception { + if (vmInfo_.getState() == VMInfoState.ATTACHED_UPDATE_ERROR) { + System.out.println("ERROR: Could not fetch telemetries - Process terminated?"); + exit(); + return; + } + if (vmInfo_.getState() != VMInfoState.ATTACHED) { + System.out.println("ERROR: Could not attach to process."); + exit(); + return; + } - int w = width - 40; - System.out.printf(" Profiling PID %d: %40s %n%n", vmInfo_.getId(), - leftStr(vmInfo_.getDisplayName(), w)); + int w = width - 40; + System.out.printf(" Profiling PID %d: %40s %n%n", vmInfo_.getId(), leftStr(vmInfo_.getDisplayName(), w)); - // these are the spaces taken up by the formatting, the rest is usable - // for printing out the method name - w = width - (1 + 6 + 3 + 9 + 3 + 2); - for (Iterator iterator = cpuSampler_.getTop(20).iterator(); iterator - .hasNext();) - { - MethodStats stats = iterator.next(); - double wallRatio = (double) stats.getHits().get() - / cpuSampler_.getTotal() * 100; - if (!Double.isNaN(wallRatio)) - { - System.out.printf(" %6.2f%% (%9.2fs) %s()%n", wallRatio, wallRatio - / 100d - * cpuSampler_.getUpdateCount() * 0.1d, - shortFQN(stats.getClassName(), stats.getMethodName(), w)); - } - } - } + // these are the spaces taken up by the formatting, the rest is usable + // for printing out the method name + w = width - (1 + 6 + 3 + 9 + 3 + 2); + for (MethodStats stats : cpuSampler_.getTop(20)) { + double wallRatio = (double) stats.getHits().get() / cpuSampler_.getTotal() * 100; + if (!Double.isNaN(wallRatio)) + System.out.printf(" %6.2f%% (%9.2fs) %s()%n", wallRatio, wallRatio / 100d * cpuSampler_.getUpdateCount() * 0.1d, shortFQN(stats.getClassName(), stats.getMethodName(), w)); + } + } - /** - * Shortens a full qualified class name if it exceeds the size. - * TODO: improve method to shorten middle packages first, - * maybe abbreviating the package by its first character. - * - * @param fqn - * @param method - * @param size - * @return - */ - private String shortFQN(String fqn, String method, int size) - { - String line = fqn + "." + method; - if (line.length() > size) - { - line = "..." + line.substring(3, size); - } - return line; - } + /** + * Shortens a full qualified class name if it exceeds the size. TODO: + * improve method to shorten middle packages first, maybe abbreviating the + * package by its first character. + * + * @param fqn + * @param method + * @param size + * @return + */ + private String shortFQN(String fqn, String method, int size) { + String line = fqn + "." + method; + if (line.length() > size) + line = "..." + line.substring(3, size); + return line; + } } From e12951b7cb9b0242499ae1755f096d9192258e08 Mon Sep 17 00:00:00 2001 From: Franco Lombardo Date: Fri, 4 Dec 2015 16:07:43 +0100 Subject: [PATCH 02/27] Ignored Eclipse settings --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4e52dcc..78d3a37 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Eclipse .classpath .project +.settings/ # Intellij .idea/ From 5376b8aae70a7a8bd714b4016697b0e8762779bb Mon Sep 17 00:00:00 2001 From: Franco Lombardo Date: Fri, 4 Dec 2015 16:09:42 +0100 Subject: [PATCH 03/27] Added compatibility with ANSICON --- src/main/java/com/jvmtop/JvmTop.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/jvmtop/JvmTop.java b/src/main/java/com/jvmtop/JvmTop.java index 13fe5b3..6390225 100644 --- a/src/main/java/com/jvmtop/JvmTop.java +++ b/src/main/java/com/jvmtop/JvmTop.java @@ -243,7 +243,7 @@ protected void run(ConsoleView view) throws Exception { * */ private void clearTerminal() { - if (System.getProperty("os.name").contains("Windows")) + if (System.getProperty("os.name").contains("Windows") && System.getenv("ANSICON") == null) // hack System.out.printf("%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n%n"); else if (System.getProperty("jvmtop.altClear") != null) From 25aff56d304eae0c52fc5844fd82c01c19ecc237 Mon Sep 17 00:00:00 2001 From: Franco Lombardo Date: Fri, 4 Dec 2015 16:14:18 +0100 Subject: [PATCH 04/27] Some changes in .gitignore --- .gitignore | 3 +- .settings/org.eclipse.jdt.core.prefs | 389 --------------------------- .settings/org.eclipse.jdt.ui.prefs | 8 - 3 files changed, 1 insertion(+), 399 deletions(-) delete mode 100644 .settings/org.eclipse.jdt.core.prefs delete mode 100644 .settings/org.eclipse.jdt.ui.prefs diff --git a/.gitignore b/.gitignore index 78d3a37..44345f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # Eclipse .classpath .project -.settings/ +/.settings/* # Intellij .idea/ @@ -16,4 +16,3 @@ log/ target/ /bin/ /lib/ -/.settings/ diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 90bb979..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,389 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.codeComplete.argumentPrefixes= -org.eclipse.jdt.core.codeComplete.argumentSuffixes= -org.eclipse.jdt.core.codeComplete.fieldPrefixes= -org.eclipse.jdt.core.codeComplete.fieldSuffixes=_ -org.eclipse.jdt.core.codeComplete.localPrefixes= -org.eclipse.jdt.core.codeComplete.localSuffixes= -org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= -org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= -org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= -org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= -org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore -org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull -org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault -org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable -org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.autoboxing=ignore -org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning -org.eclipse.jdt.core.compiler.problem.deadCode=warning -org.eclipse.jdt.core.compiler.problem.deprecation=warning -org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled -org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled -org.eclipse.jdt.core.compiler.problem.discouragedReference=ignore -org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore -org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore -org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled -org.eclipse.jdt.core.compiler.problem.fieldHiding=warning -org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning -org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning -org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore -org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning -org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled -org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning -org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning -org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore -org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning -org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning -org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore -org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore -org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled -org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore -org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore -org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled -org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore -org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore -org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning -org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning -org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore -org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error -org.eclipse.jdt.core.compiler.problem.nullReference=ignore -org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error -org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning -org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning -org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore -org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore -org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore -org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning -org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning -org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning -org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning -org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore -org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore -org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore -org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning -org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled -org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning -org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled -org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled -org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore -org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning -org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled -org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning -org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning -org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore -org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning -org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning -org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled -org.eclipse.jdt.core.compiler.problem.unusedImport=warning -org.eclipse.jdt.core.compiler.problem.unusedLabel=warning -org.eclipse.jdt.core.compiler.problem.unusedLocal=warning -org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore -org.eclipse.jdt.core.compiler.problem.unusedParameter=warning -org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=disabled -org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled -org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled -org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning -org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning -org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.6 -org.eclipse.jdt.core.formatter.align_type_members_on_columns=true -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_assignment=0 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 -org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 -org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_after_package=1 -org.eclipse.jdt.core.formatter.blank_lines_before_field=1 -org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 -org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 -org.eclipse.jdt.core.formatter.blank_lines_before_method=1 -org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=0 -org.eclipse.jdt.core.formatter.blank_lines_before_package=0 -org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 -org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 -org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line -org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line -org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block=next_line -org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line -org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line -org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line -org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false -org.eclipse.jdt.core.formatter.comment.format_block_comments=false -org.eclipse.jdt.core.formatter.comment.format_header=false -org.eclipse.jdt.core.formatter.comment.format_html=true -org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false -org.eclipse.jdt.core.formatter.comment.format_line_comments=false -org.eclipse.jdt.core.formatter.comment.format_source_code=true -org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true -org.eclipse.jdt.core.formatter.comment.indent_root_tags=true -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert -org.eclipse.jdt.core.formatter.comment.line_length=80 -org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true -org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true -org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false -org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=2 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 -org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off -org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on -org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true -org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=false -org.eclipse.jdt.core.formatter.indent_empty_lines=false -org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true -org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true -org.eclipse.jdt.core.formatter.indentation.size=2 -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert -org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert -org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert -org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.join_lines_in_comments=true -org.eclipse.jdt.core.formatter.join_wrapped_lines=true -org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false -org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false -org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false -org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false -org.eclipse.jdt.core.formatter.lineSplit=80 -org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false -org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 -org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 -org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true -org.eclipse.jdt.core.formatter.tabulation.char=space -org.eclipse.jdt.core.formatter.tabulation.size=2 -org.eclipse.jdt.core.formatter.use_on_off_tags=false -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true -org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true -org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs deleted file mode 100644 index 6308202..0000000 --- a/.settings/org.eclipse.jdt.ui.prefs +++ /dev/null @@ -1,8 +0,0 @@ -eclipse.preferences.version=1 -formatter_settings_version=12 -org.eclipse.jdt.ui.exception.name=e -org.eclipse.jdt.ui.gettersetter.use.is=true -org.eclipse.jdt.ui.javadoc=true -org.eclipse.jdt.ui.keywordthis=false -org.eclipse.jdt.ui.overrideannotation=true -org.eclipse.jdt.ui.text.custom_code_templates=