/* |
|
* Copyright (c) 2004, 2010, 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.jstat; |
|
import java.io.*; |
|
import java.net.*; |
|
import java.util.*; |
|
import java.util.regex.*; |
|
import sun.jvmstat.monitor.Monitor; |
|
import sun.jvmstat.monitor.VmIdentifier; |
|
/** |
|
* Class for processing command line arguments and providing method |
|
* level access to arguments. |
|
* |
|
* @author Brian Doherty |
|
* @since 1.5 |
|
*/ |
|
public class Arguments { |
|
private static final boolean debug = Boolean.getBoolean("jstat.debug"); |
|
private static final boolean showUnsupported = |
|
Boolean.getBoolean("jstat.showUnsupported"); |
|
private static final String JVMSTAT_USERDIR = ".jvmstat"; |
|
private static final String OPTIONS_FILENAME = "jstat_options"; |
|
private static final String UNSUPPORTED_OPTIONS_FILENAME = "jstat_unsupported_options"; |
|
private static final String ALL_NAMES = "\\w*"; |
|
private Comparator<Monitor> comparator; |
|
private int headerRate; |
|
private boolean help; |
|
private boolean list; |
|
private boolean options; |
|
private boolean constants; |
|
private boolean constantsOnly; |
|
private boolean strings; |
|
private boolean timestamp; |
|
private boolean snap; |
|
private boolean verbose; |
|
private String specialOption; |
|
private String names; |
|
private OptionFormat optionFormat; |
|
private int count = -1; |
|
private int interval = -1; |
|
private String vmIdString; |
|
private VmIdentifier vmId; |
|
public static void printUsage(PrintStream ps) { |
|
ps.println("Usage: jstat -help|-options"); |
|
ps.println(" jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]"); |
|
ps.println(); |
|
ps.println("Definitions:"); |
|
ps.println(" <option> An option reported by the -options option"); |
|
ps.println(" <vmid> Virtual Machine Identifier. A vmid takes the following form:"); |
|
ps.println(" <lvmid>[@<hostname>[:<port>]]"); |
|
ps.println(" Where <lvmid> is the local vm identifier for the target"); |
|
ps.println(" Java virtual machine, typically a process id; <hostname> is"); |
|
ps.println(" the name of the host running the target Java virtual machine;"); |
|
ps.println(" and <port> is the port number for the rmiregistry on the"); |
|
ps.println(" target host. See the jvmstat documentation for a more complete"); |
|
ps.println(" description of the Virtual Machine Identifier."); |
|
ps.println(" <lines> Number of samples between header lines."); |
|
ps.println(" <interval> Sampling interval. The following forms are allowed:"); |
|
ps.println(" <n>[\"ms\"|\"s\"]"); |
|
ps.println(" Where <n> is an integer and the suffix specifies the units as "); |
|
ps.println(" milliseconds(\"ms\") or seconds(\"s\"). The default units are \"ms\"."); |
|
ps.println(" <count> Number of samples to take before terminating."); |
|
ps.println(" -J<flag> Pass <flag> directly to the runtime system."); |
|
// undocumented options: |
|
// -list [<vmid>] - list counter names |
|
// -snap <vmid> - snapshot counter values as name=value pairs |
|
// -name <pattern> - output counters matching given pattern |
|
// -a - sort in ascending order (default) |
|
// -d - sort in descending order |
|
// -v - verbose output (-snap) |
|
// -constants - output constants with -name output |
|
// -strings - output strings with -name output |
|
} |
|
private static int toMillis(String s) throws IllegalArgumentException { |
|
String[] unitStrings = { "ms", "s" }; // ordered from most specific to |
|
// least specific |
|
String unitString = null; |
|
String valueString = s; |
|
for (int i = 0; i < unitStrings.length; i++) { |
|
int index = s.indexOf(unitStrings[i]); |
|
if (index > 0) { |
|
unitString = s.substring(index); |
|
valueString = s.substring(0, index); |
|
break; |
|
} |
|
} |
|
try { |
|
int value = Integer.parseInt(valueString); |
|
if (unitString == null || unitString.compareTo("ms") == 0) { |
|
return value; |
|
} else if (unitString.compareTo("s") == 0) { |
|
return value * 1000; |
|
} else { |
|
throw new IllegalArgumentException( |
|
"Unknow time unit: " + unitString); |
|
} |
|
} catch (NumberFormatException e) { |
|
throw new IllegalArgumentException( |
|
"Could not convert interval: " + s); |
|
} |
|
} |
|
public Arguments(String[] args) throws IllegalArgumentException { |
|
int argc = 0; |
|
if (args.length < 1) { |
|
throw new IllegalArgumentException("invalid argument count"); |
|
} |
|
if ((args[0].compareTo("-?") == 0) |
|
|| (args[0].compareTo("-help") == 0)) { |
|
help = true; |
|
return; |
|
} else if (args[0].compareTo("-options") == 0) { |
|
options = true; |
|
return; |
|
} else if (args[0].compareTo("-list") == 0) { |
|
list = true; |
|
if (args.length > 2) { |
|
throw new IllegalArgumentException("invalid argument count"); |
|
} |
|
// list can take one arg - a vmid - fall through for arg processing |
|
argc++; |
|
} |
|
for ( ; (argc < args.length) && (args[argc].startsWith("-")); argc++) { |
|
String arg = args[argc]; |
|
if (arg.compareTo("-a") == 0) { |
|
comparator = new AscendingMonitorComparator(); |
|
} else if (arg.compareTo("-d") == 0) { |
|
comparator = new DescendingMonitorComparator(); |
|
} else if (arg.compareTo("-t") == 0) { |
|
timestamp = true; |
|
} else if (arg.compareTo("-v") == 0) { |
|
verbose = true; |
|
} else if ((arg.compareTo("-constants") == 0) |
|
|| (arg.compareTo("-c") == 0)) { |
|
constants = true; |
|
} else if ((arg.compareTo("-strings") == 0) |
|
|| (arg.compareTo("-s") == 0)) { |
|
strings = true; |
|
} else if (arg.startsWith("-h")) { |
|
String value; |
|
if (arg.compareTo("-h") != 0) { |
|
value = arg.substring(2); |
|
} else { |
|
argc++; |
|
if (argc >= args.length) { |
|
throw new IllegalArgumentException( |
|
"-h requires an integer argument"); |
|
} |
|
value = args[argc]; |
|
} |
|
try { |
|
headerRate = Integer.parseInt(value); |
|
} catch (NumberFormatException e) { |
|
headerRate = -1; |
|
} |
|
if (headerRate < 0) { |
|
throw new IllegalArgumentException( |
|
"illegal -h argument: " + value); |
|
} |
|
} else if (arg.startsWith("-name")) { |
|
if (arg.startsWith("-name=")) { |
|
names = arg.substring(7); |
|
} else { |
|
argc++; |
|
if (argc >= args.length) { |
|
throw new IllegalArgumentException( |
|
"option argument expected"); |
|
} |
|
names = args[argc]; |
|
} |
|
} else { |
|
/* |
|
* there are scenarios here: special jstat_options file option |
|
* or the rare case of a negative lvmid. The negative lvmid |
|
* can occur in some operating environments (such as Windows |
|
* 95/98/ME), so we provide for this case here by checking if |
|
* the argument has any numerical characters. This assumes that |
|
* there are no special jstat_options that contain numerical |
|
* characters in their name. |
|
*/ |
|
// extract the lvmid part of possible lvmid@host.domain:port |
|
String lvmidStr = null; |
|
int at_index = args[argc].indexOf('@'); |
|
if (at_index < 0) { |
|
lvmidStr = args[argc]; |
|
} else { |
|
lvmidStr = args[argc].substring(0, at_index); |
|
} |
|
// try to parse the lvmid part as an integer |
|
try { |
|
int vmid = Integer.parseInt(lvmidStr); |
|
// it parsed, assume a negative lvmid and continue |
|
break; |
|
} catch (NumberFormatException nfe) { |
|
// it didn't parse. check for the -snap or jstat_options |
|
// file options. |
|
if ((argc == 0) && (args[argc].compareTo("-snap") == 0)) { |
|
snap = true; |
|
} else if (argc == 0) { |
|
specialOption = args[argc].substring(1); |
|
} else { |
|
throw new IllegalArgumentException( |
|
"illegal argument: " + args[argc]); |
|
} |
|
} |
|
} |
|
} |
|
// prevent 'jstat <pid>' from being accepted as a valid argument |
|
if (!(specialOption != null || list || snap || names != null)) { |
|
throw new IllegalArgumentException("-<option> required"); |
|
} |
|
switch (args.length - argc) { |
|
case 3: |
|
if (snap) { |
|
throw new IllegalArgumentException("invalid argument count"); |
|
} |
|
try { |
|
count = Integer.parseInt(args[args.length-1]); |
|
} catch (NumberFormatException e) { |
|
throw new IllegalArgumentException("illegal count value: " |
|
+ args[args.length-1]); |
|
} |
|
interval = toMillis(args[args.length-2]); |
|
vmIdString = args[args.length-3]; |
|
break; |
|
case 2: |
|
if (snap) { |
|
throw new IllegalArgumentException("invalid argument count"); |
|
} |
|
interval = toMillis(args[args.length-1]); |
|
vmIdString = args[args.length-2]; |
|
break; |
|
case 1: |
|
vmIdString = args[args.length-1]; |
|
break; |
|
case 0: |
|
if (!list) { |
|
throw new IllegalArgumentException("invalid argument count"); |
|
} |
|
break; |
|
default: |
|
throw new IllegalArgumentException("invalid argument count"); |
|
} |
|
// set count and interval to their default values if not set above. |
|
if (count == -1 && interval == -1) { |
|
// default is for a single sample |
|
count = 1; |
|
interval = 0; |
|
} |
|
// validate arguments |
|
if (comparator == null) { |
|
comparator = new AscendingMonitorComparator(); |
|
} |
|
// allow ',' characters to separate names, convert to '|' chars |
|
names = (names == null) ? ALL_NAMES : names.replace(',', '|'); |
|
// verify that the given pattern parses without errors |
|
try { |
|
Pattern pattern = Pattern.compile(names); |
|
} catch (PatternSyntaxException e) { |
|
throw new IllegalArgumentException("Bad name pattern: " |
|
+ e.getMessage()); |
|
} |
|
// verify that the special option is valid and get it's formatter |
|
if (specialOption != null) { |
|
OptionFinder finder = new OptionFinder(optionsSources()); |
|
optionFormat = finder.getOptionFormat(specialOption, timestamp); |
|
if (optionFormat == null) { |
|
throw new IllegalArgumentException("Unknown option: -" |
|
+ specialOption); |
|
} |
|
} |
|
// verify that the vm identifier is valied |
|
try { |
|
vmId = new VmIdentifier(vmIdString); |
|
} catch (URISyntaxException e) { |
|
IllegalArgumentException iae = new IllegalArgumentException( |
|
"Malformed VM Identifier: " + vmIdString); |
|
iae.initCause(e); |
|
throw iae; |
|
} |
|
} |
|
public Comparator<Monitor> comparator() { |
|
return comparator; |
|
} |
|
public boolean isHelp() { |
|
return help; |
|
} |
|
public boolean isList() { |
|
return list; |
|
} |
|
public boolean isSnap() { |
|
return snap; |
|
} |
|
public boolean isOptions() { |
|
return options; |
|
} |
|
public boolean isVerbose() { |
|
return verbose; |
|
} |
|
public boolean printConstants() { |
|
return constants; |
|
} |
|
public boolean isConstantsOnly() { |
|
return constantsOnly; |
|
} |
|
public boolean printStrings() { |
|
return strings; |
|
} |
|
public boolean showUnsupported() { |
|
return showUnsupported; |
|
} |
|
public int headerRate() { |
|
return headerRate; |
|
} |
|
public String counterNames() { |
|
return names; |
|
} |
|
public VmIdentifier vmId() { |
|
return vmId; |
|
} |
|
public String vmIdString() { |
|
return vmIdString; |
|
} |
|
public int sampleInterval() { |
|
return interval; |
|
} |
|
public int sampleCount() { |
|
return count; |
|
} |
|
public boolean isTimestamp() { |
|
return timestamp; |
|
} |
|
public boolean isSpecialOption() { |
|
return specialOption != null; |
|
} |
|
public String specialOption() { |
|
return specialOption; |
|
} |
|
public OptionFormat optionFormat() { |
|
return optionFormat; |
|
} |
|
public List<URL> optionsSources() { |
|
List<URL> sources = new ArrayList<URL>(); |
|
int i = 0; |
|
String filename = OPTIONS_FILENAME; |
|
try { |
|
String userHome = System.getProperty("user.home"); |
|
String userDir = userHome + "/" + JVMSTAT_USERDIR; |
|
File home = new File(userDir + "/" + filename); |
|
sources.add(home.toURI().toURL()); |
|
} catch (Exception e) { |
|
if (debug) { |
|
System.err.println(e.getMessage()); |
|
e.printStackTrace(); |
|
} |
|
throw new IllegalArgumentException("Internal Error: Bad URL: " |
|
+ e.getMessage()); |
|
} |
|
URL u = this.getClass().getResource("resources/" + filename); |
|
assert u != null; |
|
sources.add(u); |
|
if (showUnsupported) { |
|
u = this.getClass().getResource("resources/" + UNSUPPORTED_OPTIONS_FILENAME); |
|
assert u != null; |
|
sources.add(u); |
|
} |
|
return sources; |
|
} |
|
} |