/* * Copyright (c) 2008, 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. */ /** * This framework allows one to automate parsing of the test command line * arguments (it automatically sets the corresponding fields of the * test class).
> java Test -iterations 10or via
java Testin the last case iterations defaults to 100.
We want to achieve this by annotating fields of the Test class by a special @Option annotation.
For simplicity suppose @Option is defined as follows:
@interface Option
{ //here all the annotation fields are mandatory
String name();
String default();
String description();
}
The test class uses an API like:
public class OptionSupport {
public static void setup(Object test, String[] args);
}
Now a simple example:
public class Test {
@Option( name="iterations",
default="100",
description="Number of iterations")
int iterations;
public void run() {
// ..do actual testing here..
}
public static void main(String args) {
Test test = new Test();
OptionsSupport.setup(test, args); // instead of manually
// parsing arguments
// now test.iterations is set to 10 or 100.
test.run();
}
}
This test can be also run via
- java Test -helpThen OptionSupport.setup() shows help and exits (by throwing exception?):
Supported options:
-iterations
Number of iterations (mandatory)
We also want to be able to apply this to fields of non-simple types (via
factories) and to other classes recursively (see @Options annotation
below).
Please, see {@link vm.share.options.test.SimpleExample} for a working version of this. *
public class StressOptions {
// [2]
@Option(name="stressTime",
default_value="60",
description="Stress time")
private long stressTime;
...
}
we want to use command line like
java Test -stressTime 50here 50 is passed to the StressOptions.stressTime field. see {@link vm.share.options.Options} below.
public class Test {
// [1]
@Options
StressOptions stressOptions = new StressOptions();
// [2]
@Option(name="iterations",
default_value="100",
description="Number of iterations")
int iterations;
// [3]
@Option(
name="garbageProducer",
default="byteArr",
description="Garbage producer",
factory="nsk.share.gc.gp.GarbageProducerFactory")
GarbageProducer garbageProducer;
...
// [4]
@Option(name="logger",
description="Logger",
factory="nsk.share.log.LogFactory")
Log log;
public void run() {
log.info("Start test");
log.info("Finish test");
}
public static void main(String[] args) {
Test test = new Test();
OptionsSupport.setup(test, args);
test.run();
}
}
The API is invoked via a call to {@link vm.share.options.OptionSupport#setup(Object, String[])}). Also there is {@link vm.share.options.OptionSupport#setup(Object, String[], OptionHandler)}) method. It allows the caller to pass a handler which takes care of the options not defined via @Option annotation.
- The following field types are supported out-of-box: [2]
All non-static fields (including private and protected) of class and it's superclasses are scanned for annotations.
(Possibly) Same annotations for setter methods ? (NOT IMPLEMENTED)
It is possible to inherit options of the field type through @Options annotations, see {@link vm.share.options.Options}, and [1] above.
Option.name defaults to the name of the field.
Object options are supported using {@link vm.share.options.OptionObjectFactory}, see [3] above. Please see {@link vm.share.options.OptionObjectFactory} interface, it should be implemented by the user and specified in the Option.factory attribute.
As a shortcut we provide BasicOptionObjectFactory class, which allows user to create a factory via @{@link vm.share.options.Factory} annotation:
@Factory (
placeholder_text="garbage producer", //used for generating <..> in the help message
default_value="byteArr",
classlist={
@FClass(key="byteArr",
type="nsk.share.gc.gp.array.ByteArrayProducer",
description="byte array producer")
@FClass(key="charArr",
type="nsk.share.gc.gp.array.CharArrayProducer",
description="char array producer")
...
}
)
public class GarbageProducerFactory extends BasicOptionObjectFactory {
}
If there is no unknownOptionHandler then in case of unsupported option, a Runtime exception is thrown.
If there is no 'default' annotation attribute and there is no default for OptionObjectFactory, then option is mandatory and a Runtime exception is thrown if it's missing.
Both '-option value' and '-option=value' formats are supported.
If main class is given '-help', OptionSupport.setup() shows help and exits (by throwing a Runtime exception):
Supported options:
-iterations
Number of iterations (mandatory)
-stressTime
Stress time (default 60)
-garbageProducer
Garbage producer (default byteArr). Supported keys:
byteArr byte array producer
charArr char array producer
...
...
The object created via factory is also scanned for @Option annotations
(like in the @Options case), i.e. it inherits options from the Test class.