| /* |
| * Copyright (c) 2001, 2018, 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. |
| * |
| * 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 nsk.share; |
| |
| import java.util.*; |
| |
| import nsk.share.test.StressOptions; |
| import nsk.share.test.Stresser; |
| |
| /** |
| * Parser for JDI test's command-line arguments. |
| * <p> |
| * Test's command line may contain two kind of arguments, namely: |
| * <ul> |
| * <li> options for ArgumentParser |
| * <li> other arguments for the test itself |
| * </ul> |
| * <p> |
| * We call <i>raw arguments</i> the <code>args[]</code> array |
| * passed to the test's method <code>main(String args[])</code>. |
| * ArgumentParser instance initialized with raw arguments serves to parse |
| * these two kinds of arguments. Use <code>ArgumentParser(args[])</code> |
| * constructor, or <code>setRawArguments(args[])</code> method |
| * to initialize a ArgumentParser instance with particular raw arguments. |
| * <p> |
| * Arguments, started with ``<code>-</code>'' symbol are called <i>options</i>. |
| * They are recognized by ArgumentParser and are used by support classes |
| * (such as Log, Binder, etc.). |
| * These options should be specified in the following general form: |
| * <ul> |
| * <li> <code>-option=<i>value</i></code> |
| * </ul> |
| * or |
| * <ul> |
| * <li> <code>-option <i>value</i></code> |
| * </ul> |
| * List of the recognized options with their values may be obtained by |
| * invoking method <code>getOptions()</code> that returnes |
| * a <code>Properties</code> object with options values. |
| * It is not recommended to get options value directly. An appropriate methods |
| * such as <code>verbose()</code>, <code>getArch()</code>, etc. should be used |
| * instead. |
| * Options may appear in the test command line in any order. |
| * <p> |
| * All the other arguments of command line are called <i>test arguments</i> |
| * (or simply <i>arguments</i>). These arguments should be handled by test itself. |
| * Full list of the test arguments in the same order as they appears in the command line |
| * may be obtained by invoking method <code>getArguments()</code>. |
| * <p> |
| * Following is the list of basic options accepted by AgrumentParser: |
| * <ul> |
| * <li> <code>-arch=</code><<i>${ARCH}</i>> - |
| * architecture name |
| * <li> <code>-waittime=</code><<i>minutes</i>> - |
| * timeout in minutes for waiting events or so |
| * <li> <code>-verbose</code> - |
| * verbose Log mode (default is quiet) |
| * <li> <code>-trace.time</code> - |
| * prefix log messages with timestamps (default is no) |
| * </ul> |
| * Also AgrumentParser supports following stress options (see nsk.share.test.StressOptions for details): |
| * <ul> |
| * <li> <code>-stressTime</code> |
| * <li> <code>-stressIterationsFactor</code> |
| * <li> <code>-stressThreadsFactor</code> |
| * <li> <code>-stressDebug</code> |
| * </ul> |
| * <p> |
| * Note, that the tests from the particular subsuites have its own argument handlers |
| * wich accepts additional options. See <code>jpda.DebugeeArgumentHandler</code>, |
| * <code>jdi.ArgumentHandler</code>, <code>jdwp.ArgumentHandler</code>. |
| * |
| * @see #setRawArguments(String[]) |
| * @see #getRawArguments() |
| * @see #getArguments() |
| * @see #getOptions() |
| * |
| * @see nsk.share.jpda.DebugeeArgumentHandler |
| * @see nsk.share.jdwp.ArgumentHandler |
| * @see nsk.share.jdi.ArgumentHandler |
| * @see nsk.share.jvmti.ArgumentHandler |
| * @see nsk.monitoring.share.ArgumentHandler |
| */ |
| public class ArgumentParser { |
| |
| /** |
| * Raw array of command-line arguments. |
| * |
| * @see #setRawArguments(String[]) |
| * @see #getRawArguments() |
| */ |
| protected String rawArguments[] = null; |
| |
| /** |
| * Refined arguments -- raw arguments but options. |
| * |
| * @see #options |
| * @see #getArguments() |
| */ |
| protected String arguments[] = null; |
| |
| /** |
| * Recognized options for ArgumentParser class. |
| * |
| * @see #arguments |
| * @see #getOptions() |
| */ |
| protected Properties options = new Properties(); |
| |
| /** |
| * Make new ArgumentParser object with default values of otions. |
| * This constructor is used only to obtain default values of options. |
| * |
| * @see #setRawArguments(String[]) |
| */ |
| protected ArgumentParser() { |
| String[] args = new String[0]; |
| setRawArguments(args); |
| } |
| |
| /** |
| * Keep a copy of raw command-line arguments and parse them; |
| * but throw an exception on parsing error. |
| * |
| * @param args Array of the raw command-line arguments. |
| * |
| * @throws BadOption If option values are invalid. |
| * |
| * @see #setRawArguments(String[]) |
| * @see BadOption |
| */ |
| public ArgumentParser(String args[]) { |
| setRawArguments(args); |
| } |
| |
| /** |
| * Return a copy of the raw command-line arguments kept by |
| * this ArgumentParser instance. |
| * |
| * @throws NullPointerException If raw arguments were not |
| * set for this instance. |
| * |
| * @see #setRawArguments(String[]) |
| */ |
| public String[] getRawArguments() { |
| return (String[]) rawArguments.clone(); |
| } |
| |
| /** |
| * Return given raw command-line argument. |
| * |
| * @param index index of argument |
| * @return value of raw argument |
| */ |
| public String getRawArgument(int index) { |
| return rawArguments[index]; |
| } |
| |
| /** |
| * Return refined array of test arguments (only those of the raw |
| * arguments which are not recognized as options for ArgumentParser). |
| * |
| * <p>Note, that sintax of test arguments was not checked; |
| * while syntax of arguments describing ArgumentParser's options |
| * was checked while raw arguments were set to this ArgumentParser |
| * instance. |
| * |
| * @throws NullPointerException If raw arguments were not |
| * set for this instance. |
| * |
| * @see #setRawArguments(String[]) |
| * @see #getOptions() |
| */ |
| public String[] getArguments() { |
| return (String[]) arguments.clone(); |
| } |
| |
| /** |
| * Return list of recognized otions with their values in the form of |
| * <code>Properties</code> object. |
| * If no options has been recognized, this list will be empty. |
| * |
| * @see #setRawArguments(String[]) |
| * @see #getArguments() |
| */ |
| public Properties getOptions() { |
| return (Properties) options.clone(); |
| } |
| |
| /** |
| * Join specified arguments into one line using given quoting |
| * and separator symbols. |
| * |
| * @param args Array of the command-line arguments |
| * @param quote Symbol used to quote each argument |
| * @param separator Symbol used as separator between argumnets |
| * @return Single line with arguments |
| */ |
| static public String joinArguments(String args[], String quote, String separator) { |
| if (args.length <= 0) { |
| return ""; |
| } |
| String line = quote + args[0] + quote; |
| for (int i = 1; i < args.length; i++) { |
| line += separator + quote + args[i] + quote; |
| } |
| return line; |
| } |
| |
| /** |
| * Join specified arguments into one line using given quoting symbol |
| * and space as a separator symbol. |
| * |
| * @param args Array of the command-line arguments |
| * @param quote Symbol used to quote each argument |
| * @return Single line with arguments |
| */ |
| static public String joinArguments(String args[], String quote) { |
| return joinArguments(args, quote, " "); |
| } |
| |
| /** |
| * Keep a copy of command-line arguments and parse them; |
| * but throw an exception on parsing error. |
| * |
| * @param args Array of the raw command-line arguments. |
| * |
| * @throws BadOption If an option has invalid value. |
| * |
| * @see #getRawArguments() |
| * @see #getArguments() |
| */ |
| public void setRawArguments(String args[]) { |
| this.rawArguments = (String[]) args.clone(); |
| parseArguments(); |
| } |
| |
| /** |
| * Add or replace given option value in options list and in raw arguments list. |
| * Use specified <code>rawPrefix</code> while adding to raw arguments list. |
| * |
| * @see #getRawArguments() |
| * @see #getOptions() |
| */ |
| public void setOption(String rawPrefix, String name, String value) { |
| String prefix = rawPrefix + name + "="; |
| String arg = prefix + value; |
| |
| options.setProperty(name, value); |
| |
| int length = rawArguments.length; |
| boolean found = false; |
| for (int i = 0; i < length; i++) { |
| if (rawArguments[i].startsWith(prefix)) { |
| found = true; |
| rawArguments[i] = arg; |
| break; |
| } |
| } |
| |
| if (!found) { |
| String[] newRawArguments = new String[length + 1]; |
| for (int i = 0; i < length; i++) { |
| newRawArguments[i] = rawArguments[i]; |
| } |
| newRawArguments[length] = arg; |
| rawArguments = newRawArguments; |
| } |
| } |
| |
| /** |
| * Return current architecture name from ArgumentParser's |
| * options. |
| * |
| * <p>Note that null string is returning if test argument |
| * <code>-arch</code> has not been set. |
| * |
| * @see #setRawArguments(String[]) |
| */ |
| public String getArch() { |
| return options.getProperty("arch"); |
| } |
| |
| /** |
| * Timeout (in minutes) for test's critical section like: |
| * (a) awaiting for an event, or conversly (b) making sure |
| * that there is no unexpected event. |
| * |
| * <p>By default, <i>2</i> minutes is returned if option |
| * <code>-waittime</code> is not set with command line. |
| * |
| * @see TimeoutHandler |
| */ |
| public int getWaitTime() { |
| String val = options.getProperty("waittime", "2"); |
| int minutes; |
| try { |
| minutes = Integer.parseInt(val); |
| } catch (NumberFormatException e) { |
| throw new TestBug("Not integer value of \"waittime\" argument: " + val); |
| } |
| return minutes; |
| } |
| |
| /** |
| * Return boolean value of current Log mode: |
| * <ul> |
| * <li><i>true</i> if Log mode is verbose. |
| * <li><i>false</i> otherwise. |
| * |
| * <p>Note that default Log mode is quiet if test argument |
| * <code>-verbose</code> has not been set. |
| * |
| * @see #setRawArguments(String[]) |
| */ |
| public boolean verbose() { |
| return options.getProperty("verbose") != null; |
| } |
| |
| /** |
| * Return boolean value of setting of timestamp for log messages: |
| * <ul> |
| * <li><i>true</i> if Log messages are timestamp'ed. |
| * <li><i>false</i> otherwise. |
| * |
| * <p>Note that by default Log messages won't be timestamp'ed until |
| * <code>-trace.time</code> has not been set. |
| * |
| * @see #setRawArguments(String[]) |
| */ |
| public boolean isTimestamp() { |
| return options.getProperty("trace.time") != null; |
| } |
| |
| /** |
| * Return level of printing tracing mesages for debugging purpose. |
| * Level <i>0</i> means no tracing messages at all. |
| * |
| * <p>Note that by default no tracing messages will be printed out |
| * until <code>-trace.level</code> has not been set. |
| * |
| * @see #setRawArguments(String[]) |
| */ |
| public int getTraceLevel() { |
| String value = options.getProperty("trace.level", Integer.toString(Log.TraceLevel.DEFAULT)); |
| try { |
| int level = Integer.parseInt(value); |
| return level; |
| } catch (NumberFormatException e) { |
| throw new Failure("Not integer value of -trace.level option: " + value); |
| } |
| } |
| |
| /** |
| * Parse arguments from rawArgumnets, extact recognized options, |
| * check legality of options values options and store non-option |
| * arguments. |
| * |
| * @throws NullPointerException If raw arguments were not set |
| * for this ArgumentParser instance. |
| * @throws BadOption If Option name is not accepted or |
| * option has illegal value. |
| * |
| * @see #setRawArguments(String[]) |
| * @see #checkOption(String, String) |
| * @see #checkOptions() |
| */ |
| protected void parseArguments() { |
| String selected[] = new String [rawArguments.length]; |
| Properties properties = new Properties(); |
| int count = 0; |
| for (int i=0; i<rawArguments.length; i++) { |
| String argument = rawArguments[i]; |
| if (argument.startsWith("-")) { |
| int pos = argument.indexOf("=", 1); |
| String option, value; |
| if (pos < 0) { |
| option = argument.substring(1); |
| if (i + 1 < rawArguments.length && !rawArguments[i + 1].startsWith("-")) { |
| value = rawArguments[i + 1]; |
| ++i; |
| } else |
| value = ""; |
| } else { |
| option = argument.substring(1, pos); |
| value = argument.substring(pos + 1); |
| } |
| if (!checkOption(option, value)) { |
| throw new BadOption("Unrecognized command line option: " + argument); |
| } |
| properties.setProperty(option, value); |
| } else { |
| selected[count++] = rawArguments[i]; |
| } |
| } |
| // Strip away the dummy tail of the selected[] array: |
| arguments = new String [count]; |
| System.arraycopy(selected,0,arguments,0,count); |
| options = properties; |
| checkOptions(); |
| } |
| |
| public StressOptions getStressOptions() { |
| return new StressOptions(rawArguments); |
| } |
| |
| /** |
| * Check if the specified option is allowed and has legal value. |
| * <p> |
| * Derived classes for hadling test arguments in particular sub-suites |
| * override this method to allow to accept sub-suite specific options. |
| * However, they should invoke this method of the base class to enshure |
| * that the basic options will be accepted too. |
| * |
| * @return <i>true</i> if option is allowed and has legel value |
| * <i>false</I> if option is unknown |
| * |
| * @throws BadOption If value of the allowed option is illegal. |
| * |
| * @see #setRawArguments(String[]) |
| * @see #parseArguments() |
| */ |
| protected boolean checkOption(String option, String value) { |
| |
| // accept arguments of nsk.share.test.StressOptions |
| if (StressOptions.isValidStressOption(option)) |
| return true; |
| |
| // options with any string value |
| if (option.equals("arch")) { |
| return true; |
| } |
| |
| // options with positive integer value |
| if (option.equals("waittime") |
| || option.equals("trace.level")) { |
| try { |
| int number = Integer.parseInt(value); |
| if (number < 0) { |
| throw new BadOption(option + ": value must be a positive integer"); |
| } |
| } catch (NumberFormatException e) { |
| throw new BadOption(option + ": value must be an integer"); |
| } |
| return true; |
| } |
| |
| // options without any value |
| if (option.equals("verbose") |
| || option.equals("vbs") |
| || option.equals("trace.time")) { |
| if (!(value == null || value.length() <= 0)) { |
| throw new BadOption(option + ": no value must be specified"); |
| } |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Check that the value of all options are not inconsistent. |
| * This method is invoked by <code>parseArguments()</code> |
| * |
| * @throws BadOption If value of the options are inconsistent |
| * |
| * @see #parseArguments() |
| */ |
| protected void checkOptions() { |
| // do nothing |
| } |
| |
| /** |
| * Thrown if invalid option or option value is found. |
| */ |
| public static class BadOption extends IllegalArgumentException { |
| /** |
| * Explain the reason. |
| * |
| * @param message Printing message. |
| */ |
| public BadOption(String message) { |
| super(message); |
| } |
| } |
| } |