/* | 
|
 * 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;  | 
|
}  | 
|
}  |