/* * Copyright (c) 2003, 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.monitoring.share; import nsk.share.log.Log; import nsk.share.TestBug; import nsk.share.ArgumentParser; import java.lang.management.*; /** * Parser for JSR-174 test's arguments. *
* ArgumentHandler
handles specific command line arguments
* related to way of execution of a test in addition to general arguments
* recognized by {@link ArgumentParser ArgumentParser
}.
*
* Following is the list of specific options for ArgumentHandler
:
*
-testMode="value"
, where value may take
* one of the following values: directly
-- to call methods in
* the MBean directly within the same JVM, server
-- to call
* methods through MBeanServer, proxy
-- to call methods
* through MBean proxy (not yet implemented).
* -MBeanServer="value"
, where value may take
* one of the following values: default
-- to execute test for
* default JMX implementation of MBeanServer or custom
-- for
* implementation provided by NSK J2SE SQE Team.
* -loadableClassCount=value
, where value defines
* amount of loadable classes. Default values is 100
.
* -loadersCount=value
, where value defines
* amount of class loaders. Default values is 100
.
* -singleClassloaderClass
specifies whether class loaders are
* instances of the same class.
* -memory="value"
, where value may take
* one of the following values: heap
-- to test heap memory,
* nonheap
to test nonheap memory, mixed
-- to
* test both heap and nonheap memory.
* -invocationType="value"
, where value may take
* one of the following values: java
-- to start java threads,
* native
-- to start native threads, mixed
-- to
* both java and native threads.
* -monitoring="value"
, where value may take
* one of the following values: polling
-- to start polling
* mechanism of monitoring, notification
-- to start
* notification mechanism of monitoring.
* -threshold="value"
, where value may take
* one of the following values: usage
-- to test usage
* thresholds, collection
-- to test collection usage
* thresholds.
* -depth=value
, where value defines
* depth of recursion. Default values is 1
.
* -threadCount=value
, where value defines
* number of threads to start. Default values is 1
.
* -timeout=value
, where value defines
* number of minutes to run the test.
*
* See also list of basic options recognized by ArgumentParser
.
*
* See also comments to ArgumentParser
how to work with
* command line arguments and options.
*
* @see ArgumentParser
*/
public class ArgumentHandler extends ArgumentParser {
static final String TEST_MODE = "testMode";
static final String DIRECTLY_MODE = "directly";
static final String SERVER_MODE = "server";
static final String PROXY_MODE = "proxy";
static final String SERVER_TYPE = "MBeanServer";
static final String DEFAULT_TYPE = "default";
static final String CUSTOM_TYPE = "custom";
static final String LOADABLE_CLASSES_COUNT = "loadableClassCount";
static final String LOADERS_COUNT = "loadersCount";
static final String SINGLE_CLASSLOADER_CLASS = "singleClassloaderClass";
static final String MEMORY_TYPE = "memory";
static final String MT_HEAP = "heap";
static final String MT_NONHEAP = "nonheap";
static final String MT_MIXED = "mixed";
static final String INVOCATION_TYPE = "invocationType";
static final String JAVA_TYPE = "java";
static final String NATIVE_TYPE = "native";
static final String MIXED_TYPE = "mixed";
static final String MONITORING = "monitoring";
static final String MON_POLLING = "polling";
static final String MON_NOTIF = "notification";
static final String THRESHOLD = "threshold";
static final String TH_USAGE = "usage";
static final String TH_COLLECTION = "collection";
static final String THREAD_DEPTH = "depth";
static final String THREAD_COUNT = "threadCount";
static final String TIMEOUT = "timeout";
static final String SCENARIO_TYPE = "scenarioType";
static final String ITERATIONS = "iterations";
/**
* 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 unknown option or illegal
* option value found
*
* @see ArgumentParser
*/
public ArgumentHandler(String args[]) {
super(args);
}
/**
* Returns the test mode.
*
* To access the metrics directly, testMode
option should
* be defined in command line -testMode="directly"
.
* To access the metrics via MBeanServer, "server"
should be
* assigned to -testMode="directly"
.
*
* If testMode
is not defined by command line, a test is
* executed in directly
mode.
*
* @return name of test mode.
*
*/
public String getTestMode() {
return options.getProperty(TEST_MODE, DIRECTLY_MODE);
}
/**
* Returns a type of MBean server if any.
* Two kinds of MBean servers are allowed: default and custom servers.
* Default server is an implementation of {@link
* javax.management.MBeanServer javax.management.MBeanServer}
* interface provided by JMX. Custom server is an implementation provided
* by NSK J2SE SQE Team. Server type is defined by MBeanServer
* key in command line -MBeanServer="default"
or
* -MBeanServer="custom"
*
* @return MBeanServer server type.
*
*/
public String getServerType() {
return options.getProperty(SERVER_TYPE, DEFAULT_TYPE);
}
/**
* Returns true if default implementation is used.
*
* @return true if default implementation is used.
*
* @see #getServerType()
*/
public boolean isDefaultServer() {
return getServerType().equals(DEFAULT_TYPE);
}
/**
* Returns amount of class loaders.
*
* @return loadersCount as an integer value
*/
public int getLoadersCount() {
String val = options.getProperty(LOADERS_COUNT, "100");
int number;
try {
number = Integer.parseInt(val);
} catch (NumberFormatException e) {
throw new TestBug("Not integer value of \"" + LOADERS_COUNT
+ "\" argument: " + val);
}
return number;
}
/**
* Returns true if class loaders, which perform class loading, are
* instances of the same class. If -singleClassloaderClass
key
* is not set in command line options, then false is returned.
*
* @return if class loaders are instances of the same class.
*
*/
public boolean singleClassloaderClass() {
return options.getProperty(SINGLE_CLASSLOADER_CLASS) != null;
}
/**
* Returns amount of loadable classes. If -loadableClassesCount
* key is not set with command line, 100
is returned.
*
* @return loadableClassesCount as an integer value
*
* @throws TestBug loadableClassesCount is non-numeric value.
*
*/
public int getLoadableClassesCount() {
String val = options.getProperty(LOADABLE_CLASSES_COUNT, "1");
int number;
try {
number = Integer.parseInt(val);
} catch (NumberFormatException e) {
throw new TestBug("Not integer value of \"" + LOADABLE_CLASSES_COUNT
+ "\" argument: " + val);
}
return number;
}
/**
* Returns invocation type.
*
* @return invocationType value
*
*/
public String getInvocationType() {
return options.getProperty(INVOCATION_TYPE, JAVA_TYPE);
}
/**
* Returns tested memory type.
*
* @return memory value
*
*/
public String getTestedMemory() {
return options.getProperty(MEMORY_TYPE, MT_HEAP);
}
/**
* Returns timeout.
*
* @return timeout value
*
*/
public int getTimeout() {
String value = options.getProperty(TIMEOUT, "30");
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new TestBug("Not integer value of \"" + TIMEOUT
+ "\" argument: " + value);
}
}
/**
* Returns recursion depth.
*
* @return depth value
*
*/
public int getThreadDepth() {
String value = options.getProperty(THREAD_DEPTH, "1");
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new TestBug("Not integer value of \"" + THREAD_DEPTH
+ "\" argument: " + value);
}
}
/**
* Returns number of threads.
*
* @return threadCount value
*
*/
public int getThreadCount() {
String value = options.getProperty(THREAD_COUNT, "1");
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new TestBug("Not integer value of \"" + THREAD_COUNT
+ "\" argument: " + value);
}
}
/**
* Returns type of monitoring.
*
* @return monitoring value
*
*/
public String getMonitoring() {
return options.getProperty(MONITORING, MON_NOTIF);
}
/**
* Returns type of threshold.
*
* @return threshold value
*
*/
public String getThreshold() {
return options.getProperty(THRESHOLD, TH_USAGE);
}
/**
* Returns thread type to create.
*/
public String getScenarioType() {
return options.getProperty(SCENARIO_TYPE, "running");
}
public int getIterations() {
return Integer.parseInt(options.getProperty(ITERATIONS, "3"));
}
/**
* Checks if an option is allowed and has proper value.
* This method is invoked by parseArguments()
*
* @param option option name
* @param value string representation of value
* (could be an empty string too)
* null if this option has no value
* @return true if option is allowed and has proper value
* false if otion is not admissible
*
* @throws BadOption if option has an illegal value
*
* @see nsk.share.ArgumentParser#parseArguments
*/
protected boolean checkOption(String option, String value) {
// defines directly, server or proxytest mode
if (option.equals(TEST_MODE)) {
if ( (!value.equals(DIRECTLY_MODE)) &&
(!value.equals(SERVER_MODE)) &&
(!value.equals(PROXY_MODE))
) {
throw new BadOption(option + ": must be one of: "
+ "\"" + DIRECTLY_MODE + "\", "
+ "\"" + SERVER_MODE + "\", "
+ "\"" + PROXY_MODE + "\"");
}
return true;
}
// defines invocation type for stack filling
if (option.equals(INVOCATION_TYPE)) {
if ( (!value.equals(JAVA_TYPE)) &&
(!value.equals(NATIVE_TYPE)) &&
(!value.equals(MIXED_TYPE))
) {
throw new BadOption(option + ": must be one of: "
+ "\"" + JAVA_TYPE + "\", "
+ "\"" + NATIVE_TYPE + "\", "
+ "\"" + MIXED_TYPE + "\"");
}
return true;
}
// defines default or custom MBean server
if (option.equals(SERVER_TYPE)) {
if ((!value.equals(DEFAULT_TYPE))
&& (!value.equals(CUSTOM_TYPE))) {
throw new BadOption(option + ": must be one of: \""
+ DEFAULT_TYPE + "\", \""
+ CUSTOM_TYPE + "\"");
}
return true;
}
// defines loadable classes and loaders counts
if (option.equals(LOADABLE_CLASSES_COUNT) ||
option.equals(LOADERS_COUNT) ||
option.equals(THREAD_DEPTH) || option.equals(THREAD_COUNT)) {
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;
}
// defines timeout
if (option.equals(TIMEOUT)) {
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;
}
// defines if classloader class is single
if (option.equals(SINGLE_CLASSLOADER_CLASS)) {
if (!(value == null || value.length() <= 0)) {
throw new BadOption(option + ": no value must be specified");
}
return true;
}
// defines memory types
if (option.equals(MEMORY_TYPE)) {
if ( (!value.equals(MT_HEAP)) &&
(!value.equals(MT_NONHEAP)) &&
(!value.equals(MT_MIXED))
)
throw new BadOption(option + ": must be one of: "
+ "\"" + MT_HEAP + "\", "
+ "\"" + MT_NONHEAP + "\", "
+ "\"" + MT_MIXED + "\"");
return true;
}
// defines type of monitoring
if (option.equals(MONITORING)) {
if ( (!value.equals(MON_POLLING)) &&
(!value.equals(MON_NOTIF))
)
throw new BadOption(option + ": must be one of: "
+ "\"" + MON_POLLING + "\", "
+ "\"" + MON_NOTIF + "\"");
return true;
}
// defines threshold
if (option.equals(THRESHOLD)) {
if ( (!value.equals(TH_USAGE)) &&
(!value.equals(TH_COLLECTION))
)
throw new BadOption(option + ": must be one of: "
+ "\"" + TH_USAGE + "\", "
+ "\"" + TH_COLLECTION + "\"");
return true;
}
if (option.equals(SCENARIO_TYPE)) {
return true;
}
if (option.equals(ITERATIONS)) {
try {
int number = Integer.parseInt(value);
if (number < 0)
throw new BadOption(option + ": value must be a positive "
+ "integer");
return true;
} catch (NumberFormatException e) {
throw new BadOption(option + ": value must be an integer");
}
}
return super.checkOption(option, value);
}
/**
* Check if the values of all options are consistent.
* This method is invoked by parseArguments()
*
* @throws BadOption if options have inconsistent values
*
* @see nsk.share.ArgumentParser#parseArguments
*/
protected void checkOptions() {
super.checkOptions();
}
public void dump(Log log) {
log.info("Test mode: " + getTestMode());
log.info("Server type: " + getServerType());
log.info("loadableClassesCount: " + getLoadableClassesCount());
log.info("loadersCount: " + getLoadersCount());
log.info("singleClassloaderClass: " + singleClassloaderClass());
}
} // ArgumentHandler