8154985: Add the ability to use main class as lookup (as jcmd) to jinfo, jmap, jstack
Reviewed-by: sla, dsamersoff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/common/ProcessArgumentMatcher.java Tue May 10 06:52:40 2016 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.tools.common;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+
+import sun.jvmstat.monitor.MonitorException;
+import sun.jvmstat.monitor.MonitoredHost;
+import sun.jvmstat.monitor.MonitoredVm;
+import sun.jvmstat.monitor.MonitoredVmUtil;
+import sun.jvmstat.monitor.VmIdentifier;
+
+/**
+ * Class for finding process matching a process argument,
+ * excluding tool it self and returning a list containing
+ * the process identifiers.
+ */
+public class ProcessArgumentMatcher {
+ private String excludeCls;
+ private String matchClass = null;
+ private String singlePid = null;
+ private boolean matchAll = false;
+
+ public ProcessArgumentMatcher(String pidArg, Class<?> excludeClass) {
+ excludeCls = excludeClass.getName();
+ if (pidArg == null || pidArg.isEmpty()) {
+ throw new IllegalArgumentException("Pid string is invalid");
+ }
+ if (pidArg.charAt(0) == '-') {
+ throw new IllegalArgumentException("Unrecognized " + pidArg);
+ }
+ try {
+ long pid = Long.parseLong(pidArg);
+ if (pid == 0) {
+ matchAll = true;
+ } else {
+ singlePid = String.valueOf(pid);
+ }
+ } catch (NumberFormatException nfe) {
+ matchClass = pidArg;
+ }
+ }
+
+ private boolean check(VirtualMachineDescriptor vmd) {
+ String mainClass = null;
+ try {
+ VmIdentifier vmId = new VmIdentifier(vmd.id());
+ MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
+ MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1);
+ mainClass = MonitoredVmUtil.mainClass(monitoredVm, true);
+ monitoredHost.detach(monitoredVm);
+ } catch (NullPointerException npe) {
+ // There is a potential race, where a running java app is being
+ // queried, unfortunately the java app has shutdown after this
+ // method is started but before getMonitoredVM is called.
+ // If this is the case, then the /tmp/hsperfdata_xxx/pid file
+ // will have disappeared and we will get a NullPointerException.
+ // Handle this gracefully....
+ return false;
+ } catch (MonitorException | URISyntaxException e) {
+ if (e.getMessage() != null) {
+ System.err.println(e.getMessage());
+ } else {
+ Throwable cause = e.getCause();
+ if ((cause != null) && (cause.getMessage() != null)) {
+ System.err.println(cause.getMessage());
+ } else {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ if (mainClass.equals(excludeCls)) {
+ return false;
+ }
+
+ if (matchAll || mainClass.indexOf(matchClass) != -1) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public Collection<String> getPids() {
+ Collection<String> pids = new ArrayList<>();
+ if (singlePid != null) {
+ pids.add(singlePid);
+ return pids;
+ }
+ List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
+ for (VirtualMachineDescriptor vmd : vmds) {
+ if (check(vmd)) {
+ pids.add(vmd.id());
+ }
+ }
+ return pids;
+ }
+}
--- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java Mon May 09 23:41:59 2016 +0300
+++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java Tue May 10 06:52:40 2016 +0200
@@ -33,16 +33,14 @@
private boolean listProcesses = false;
private boolean listCounters = false;
private boolean showUsage = false;
- private int pid = -1;
private String command = null;
- private String processSubstring;
+ private String processString = null;
public boolean isListProcesses() { return listProcesses; }
public boolean isListCounters() { return listCounters; }
public boolean isShowUsage() { return showUsage; }
- public int getPid() { return pid; }
public String getCommand() { return command; }
- public String getProcessSubstring() { return processSubstring; }
+ public String getProcessString() { return processString; }
public Arguments(String[] args) {
if (args.length == 0 || args[0].equals("-l")) {
@@ -55,15 +53,7 @@
return;
}
- try {
- pid = Integer.parseInt(args[0]);
- } catch (NumberFormatException ex) {
- // use as a partial class-name instead
- if (args[0].charAt(0) != '-') {
- // unless it starts with a '-'
- processSubstring = args[0];
- }
- }
+ processString = args[0];
StringBuilder sb = new StringBuilder();
for (int i = 1; i < args.length; i++) {
--- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java Mon May 09 23:41:59 2016 +0300
+++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java Tue May 10 06:52:40 2016 +0200
@@ -29,22 +29,22 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
-import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.net.URISyntaxException;
import com.sun.tools.attach.AttachOperationFailedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
-import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import sun.tools.attach.HotSpotVirtualMachine;
+import sun.tools.common.ProcessArgumentMatcher;
import sun.tools.jstat.JStatLogger;
import sun.jvmstat.monitor.Monitor;
import sun.jvmstat.monitor.MonitoredHost;
import sun.jvmstat.monitor.MonitoredVm;
-import sun.jvmstat.monitor.MonitoredVmUtil;
import sun.jvmstat.monitor.MonitorException;
import sun.jvmstat.monitor.VmIdentifier;
@@ -73,52 +73,18 @@
System.exit(0);
}
- List<String> pids = new ArrayList<String>();
- if (arg.getPid() == 0) {
- // find all VMs
- List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
- for (VirtualMachineDescriptor vmd : vmds) {
- if (!isJCmdProcess(vmd)) {
- pids.add(vmd.id());
- }
- }
- } else if (arg.getProcessSubstring() != null) {
- // use the partial class-name match
- List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
- for (VirtualMachineDescriptor vmd : vmds) {
- if (isJCmdProcess(vmd)) {
- continue;
- }
- try {
- String mainClass = getMainClass(vmd);
- if (mainClass != null
- && mainClass.indexOf(arg.getProcessSubstring()) != -1) {
- pids.add(vmd.id());
- }
- } catch (MonitorException|URISyntaxException e) {
- if (e.getMessage() != null) {
- System.err.println(e.getMessage());
- } else {
- Throwable cause = e.getCause();
- if ((cause != null) && (cause.getMessage() != null)) {
- System.err.println(cause.getMessage());
- } else {
- e.printStackTrace();
- }
- }
- }
- }
- if (pids.isEmpty()) {
- System.err.println("Could not find any processes matching : '"
- + arg.getProcessSubstring() + "'");
- System.exit(1);
- }
- } else if (arg.getPid() == -1) {
+ Collection<String> pids = Collections.emptyList();
+ try {
+ ProcessArgumentMatcher ap = new ProcessArgumentMatcher(arg.getProcessString(), JCmd.class);
+ pids = ap.getPids();
+ } catch (IllegalArgumentException iae) {
System.err.println("Invalid pid specified");
System.exit(1);
- } else {
- // Use the found pid
- pids.add(arg.getPid() + "");
+ }
+ if (pids.isEmpty()) {
+ System.err.println("Could not find any processes matching : '"
+ + arg.getProcessString() + "'");
+ System.exit(1);
}
boolean success = true;
@@ -199,36 +165,6 @@
}
}
- private static boolean isJCmdProcess(VirtualMachineDescriptor vmd) {
- try {
- String mainClass = getMainClass(vmd);
- return mainClass != null && mainClass.equals(JCmd.class.getName());
- } catch (URISyntaxException|MonitorException ex) {
- return false;
- }
- }
-
- private static String getMainClass(VirtualMachineDescriptor vmd)
- throws URISyntaxException, MonitorException {
- try {
- String mainClass = null;
- VmIdentifier vmId = new VmIdentifier(vmd.id());
- MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
- MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1);
- mainClass = MonitoredVmUtil.mainClass(monitoredVm, true);
- monitoredHost.detach(monitoredVm);
- return mainClass;
- } catch(NullPointerException e) {
- // There is a potential race, where a running java app is being
- // queried, unfortunately the java app has shutdown after this
- // method is started but before getMonitoredVM is called.
- // If this is the case, then the /tmp/hsperfdata_xxx/pid file
- // will have disappeared and we will get a NullPointerException.
- // Handle this gracefully....
- return null;
- }
- }
-
/**
* Class to compare two Monitor objects by name in ascending order.
* (from jstat)
--- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java Mon May 09 23:41:59 2016 +0300
+++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java Tue May 10 06:52:40 2016 +0200
@@ -25,13 +25,14 @@
package sun.tools.jinfo;
-import java.util.Arrays;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Collection;
import com.sun.tools.attach.VirtualMachine;
import sun.tools.attach.HotSpotVirtualMachine;
+import sun.tools.common.ProcessArgumentMatcher;
/*
* This class is the main class for the JInfo utility. It parses its arguments
@@ -82,28 +83,49 @@
// Next we check the parameter count. -flag allows extra parameters
int paramCount = args.length - optionCount;
- if ((doFlag && paramCount != 2) || (paramCount != 1)) {
+ if ((doFlag && paramCount != 2) || ((!doFlag && paramCount != 1))) {
usage(1);
}
if (!doFlag && !doFlags && !doSysprops) {
// Print flags and sysporps if no options given
- sysprops(args[optionCount]);
- System.out.println();
- flags(args[optionCount]);
- System.out.println();
- commandLine(args[optionCount]);
+ ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class);
+ Collection<String> pids = ap.getPids();
+ for (String pid : pids) {
+ if (pids.size() > 1) {
+ System.out.println("Pid:" + pid);
+ }
+ sysprops(pid);
+ System.out.println();
+ flags(pid);
+ System.out.println();
+ commandLine(pid);
+ }
}
if (doFlag) {
- flag(args[optionCount+1], args[optionCount]);
+ ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount+1], JInfo.class);
+ Collection<String> pids = ap.getPids();
+ for (String pid : pids) {
+ if (pids.size() > 1) {
+ System.out.println("Pid:" + pid);
+ }
+ flag(pid, args[optionCount]);
+ }
}
- else {
- if (doFlags) {
- flags(args[optionCount]);
- }
- else if (doSysprops) {
- sysprops(args[optionCount]);
+ else if (doFlags || doSysprops) {
+ ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class);
+ Collection<String> pids = ap.getPids();
+ for (String pid : pids) {
+ if (pids.size() > 1) {
+ System.out.println("Pid:" + pid);
+ }
+ if (doFlags) {
+ flags(pid);
+ }
+ else if (doSysprops) {
+ sysprops(pid);
+ }
}
}
}
@@ -193,24 +215,23 @@
private static void checkForUnsupportedOptions(String[] args) {
// Check arguments for -F, and non-numeric value
// and warn the user that SA is not supported anymore
-
+ int maxCount = 1;
int paramCount = 0;
for (String s : args) {
if (s.equals("-F")) {
SAOptionError("-F option used");
}
-
+ if (s.equals("-flag")) {
+ maxCount = 2;
+ }
if (! s.startsWith("-")) {
- if (! s.matches("[0-9]+")) {
- SAOptionError("non PID argument");
- }
paramCount += 1;
}
}
- if (paramCount > 1) {
- SAOptionError("More than one non-option argument");
+ if (paramCount > maxCount) {
+ SAOptionError("More than " + maxCount + " non-option argument");
}
}
--- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java Mon May 09 23:41:59 2016 +0300
+++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java Tue May 10 06:52:40 2016 +0200
@@ -29,10 +29,12 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
+import java.util.Collection;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.AttachNotSupportedException;
import sun.tools.attach.HotSpotVirtualMachine;
+import sun.tools.common.ProcessArgumentMatcher;
/*
* This class is the main class for the JMap utility. It parses its arguments
@@ -83,22 +85,29 @@
usage(1);
}
- String pid = args[1];
+ String pidArg = args[1];
// Here we handle the built-in options
// As more options are added we should create an abstract tool class and
// have a table to map the options
- if (option.equals("-histo")) {
- histo(pid, "");
- } else if (option.startsWith("-histo:")) {
- histo(pid, option.substring("-histo:".length()));
- } else if (option.startsWith("-dump:")) {
- dump(pid, option.substring("-dump:".length()));
- } else if (option.equals("-finalizerinfo")) {
- executeCommandForPid(pid, "jcmd", "GC.finalizer_info");
- } else if (option.equals("-clstats")) {
- executeCommandForPid(pid, "jcmd", "GC.class_stats");
- } else {
- usage(1);
+ ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg, JMap.class);
+ Collection<String> pids = ap.getPids();
+ for (String pid : pids) {
+ if (pids.size() > 1) {
+ System.out.println("Pid:" + pid);
+ }
+ if (option.equals("-histo")) {
+ histo(pid, "");
+ } else if (option.startsWith("-histo:")) {
+ histo(pid, option.substring("-histo:".length()));
+ } else if (option.startsWith("-dump:")) {
+ dump(pid, option.substring("-dump:".length()));
+ } else if (option.equals("-finalizerinfo")) {
+ executeCommandForPid(pid, "jcmd", "GC.finalizer_info");
+ } else if (option.equals("-clstats")) {
+ executeCommandForPid(pid, "jcmd", "GC.class_stats");
+ } else {
+ usage(1);
+ }
}
}
@@ -204,9 +213,6 @@
*/
if (! s.startsWith("-")) {
- if (! s.matches("[0-9]+")) {
- SAOptionError("non PID argument");
- }
paramCount += 1;
}
}
--- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java Mon May 09 23:41:59 2016 +0300
+++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java Tue May 10 06:52:40 2016 +0200
@@ -26,10 +26,11 @@
package sun.tools.jstack;
import java.io.InputStream;
+import java.util.Collection;
import com.sun.tools.attach.VirtualMachine;
-import com.sun.tools.attach.AttachNotSupportedException;
import sun.tools.attach.HotSpotVirtualMachine;
+import sun.tools.common.ProcessArgumentMatcher;
/*
* This class is the main class for the JStack utility. It parses its arguments
@@ -74,14 +75,21 @@
}
// pass -l to thread dump operation to get extra lock info
- String pid = args[optionCount];
+ String pidArg = args[optionCount];
String params[];
if (locks) {
params = new String[] { "-l" };
} else {
params = new String[0];
}
- runThreadDump(pid, params);
+ ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg, JStack.class);
+ Collection<String> pids = ap.getPids();
+ for (String pid : pids) {
+ if (pids.size() > 1) {
+ System.out.println("Pid:" + pid);
+ }
+ runThreadDump(pid, params);
+ }
}
// Attach to pid and perform a thread dump
@@ -133,9 +141,6 @@
}
if (! s.startsWith("-")) {
- if (! s.matches("[0-9]+")) {
- SAOptionError("non PID argument");
- }
paramCount += 1;
}
}