Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/share/options/OptionsSetup.java
41155 views
/*1* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22package vm.share.options;2324import java.util.Map;25import java.util.LinkedHashMap;26import java.util.List;27import java.util.ArrayList;28import java.util.LinkedList;29import java.util.Iterator;30import java.lang.reflect.Field;31import java.lang.reflect.Modifier;32import java.io.PrintStream;33import nsk.share.TestBug;34import nsk.share.log.LogSupport;3536class OptionsSetup {37private LogSupport log = new LogSupport();38private boolean verbose = true;39private Object test;40private String[] args;41private OptionHandler unknownOptionHandler;4243private int argIndex = 0;44private Map<String, OptionDefinition> optionDefs = new LinkedHashMap<String, OptionDefinition>(); // Use LinkedHashMap to ensure order of options45private List<OptionDefinition> unconfiguredOptionsList = new ArrayList<OptionDefinition>();46private List<OptionDefinition> unconfiguredOptionList = new ArrayList<OptionDefinition>();47private Map<String, Object> optionValues = new LinkedHashMap<String, Object>();4849public OptionsSetup(Object test, String[] args, OptionHandler unknownOptionHandler) {50this.test = test;51this.args = args;52this.unknownOptionHandler = unknownOptionHandler;53log.setDebugEnabled(verbose);54}5556public void run() {57searchAnnotations(test, null);58while (argIndex < args.length) {59process1Arg();60}61setDefaultValues();62checkMandatoryOptions();63if (unconfiguredOptionsList.size() > 0) {64for (OptionDefinition optDef : unconfiguredOptionsList)65log.info("Unconfigured option: " + optDef);66throw new TestBug("Some options are unconfigured");67}68}6970private void checkMandatoryOptions() {71for (Map.Entry<String, OptionDefinition> e : optionDefs.entrySet()) {72String name = e.getKey();73OptionDefinition optDef = e.getValue();74if (optDef.getDefaultValue() == null && !optionValues.containsKey(name))75throw new TestBug("Mandatory option is not specified: -" + name);76}77}7879private void setDefaultValues() {80for (Iterator<OptionDefinition> it = unconfiguredOptionList.iterator(); it.hasNext(); ) {81OptionDefinition optDef = it.next();82String value = optDef.getDefaultValue();83if (value == null)84continue;85setOptionValue(optDef, value);86it.remove();87if (unconfiguredOptionsList.contains(optDef))88unconfiguredOptionsList.remove(optDef);89}9091for (Iterator<OptionDefinition> it = unconfiguredOptionsList.iterator(); it.hasNext(); ) {92OptionDefinition optDef = it.next();93if (optionsAnnotation(optDef.getOwner(), optDef.getField(), null, optDef, true))94it.remove();95}96}9798private void process1Arg() {99String arg = args[argIndex++];100//log.debug("Processing argument: " + arg);101if (!arg.startsWith("-")) {102processUnknownArg(arg);103return;104}105String opt = arg.substring(1);106String value = null;107int i = opt.indexOf('=');108if (i != -1) {109value = opt.substring(i + 1);110opt = opt.substring(0, i);111}112if (opt.equals("help")) {113printHelp();114throw new TestBug("-help was specified");115}116if (!optionDefs.containsKey(opt)) {117if (value == null && argIndex < args.length)118value = args[argIndex++];119// We need to try to resolve default values of all unconfigured fields because one of them may potentially have this option120setDefaultValues();121if (!optionDefs.containsKey(opt)) {122processUnknownOpt(opt, value);123return;124}125}126OptionDefinition optDef = optionDefs.get(opt);127Field f = optDef.getField();128// Handle boolean omitted value129if (value == null && (argIndex >= args.length || args[argIndex].startsWith("-"))) {130if (f.getType() == boolean.class || f.getType() == Boolean.class) {131value = "true";132}133}134if (value == null) {135if (argIndex >= args.length)136throw new TestBug("Missing value for option -" + opt);137value = args[argIndex++];138}139setOptionValue(optDef, value);140if (unconfiguredOptionList.contains(optDef)){141unconfiguredOptionList.remove(optDef);142}143}144145private void setOptionValue(OptionDefinition optDef, String value) {146Object ovalue = null;147if (optDef.hasFactory()) {148ovalue = optDef.getFactory().getObject(value);149} else {150ovalue = PrimitiveParser.parse(value, optDef.getField().getType());151}152optionValues.put(optDef.getName(), ovalue);153try {154Field f = optDef.getField();155Object o = optDef.getOwner();156f.set(o, ovalue);157if (f.isAnnotationPresent(Options.class)) {158if (!optionsAnnotation(o, f, optDef.getPrefix(), optDef, false))159throw new TestBug("Unexpected (bug in framework?): optionsAnnotation returned null: " + optDef);160if (unconfiguredOptionsList.contains(optDef))161unconfiguredOptionsList.remove(optDef);162}163} catch (IllegalArgumentException e) {164throw new TestBug("Exception setting field value for option " + optDef.getName(), e);165} catch (IllegalAccessException e) {166throw new TestBug("Exception setting field value for option " + optDef.getName(), e);167}168}169170private void processUnknownArg(String arg) {171if (unknownOptionHandler != null)172unknownOptionHandler.argument(arg);173else174throw new TestBug("Invalid argument: " + arg);175}176177private void processUnknownOpt(String opt, String value) {178if (unknownOptionHandler != null)179unknownOptionHandler.option(opt, value);180else181throw new TestBug("Invalid option: '" + opt + "', value: '" + value + "'");182}183184private void searchAnnotations(Object o, String prefix) {185Class<?> cl0 = o.getClass();186//log.debug("Looking for annotations for object " + o + ", class " + cl0);187List<Class> classes = new LinkedList<Class>();188while (cl0.getSuperclass() != null) {189classes.add(0, cl0); // Add to the beginning to ensure the option order is from superclass to subclass190cl0 = cl0.getSuperclass();191}192for (Class<?> cl : classes) {193for (Field f : cl.getDeclaredFields()) {194OptionDefinition optDef = null;195if (f.isAnnotationPresent(Option.class)) {196optDef = optionAnnotation(o, f, prefix);197if (optDef != null) {198unconfiguredOptionList.add(optDef);199}200}201if (f.isAnnotationPresent(Options.class)) {202if (!optionsAnnotation(o, f, prefix, optDef, false)) {203if (!unconfiguredOptionsList.contains(optDef))204unconfiguredOptionsList.add(optDef);205}206}207}208}209}210211private boolean optionsAnnotation(Object o, Field f, String prefix, OptionDefinition optDef, boolean useDefault) {212if (Modifier.isStatic(f.getModifiers()))213throw new OptionError("@Options annotation is not allowed at static field", optDef);214if (!Object.class.isAssignableFrom(f.getDeclaringClass()))215throw new OptionError("@Options annotation is only allowed on object types", optDef);216//log.debug("Processing @Options annotation: object " + o + ", field " + f + ", prefix " + prefix);217Object v = null;218try {219f.setAccessible(true);220v = f.get(o);221} catch (IllegalAccessException e) {222throw new OptionError("Exception getting value of field ", e, optDef);223}224if (v == null) {225if (optDef == null)226throw new OptionError("Value of field is null and no @Option annotation is present", optDef);227if (!optDef.hasFactory())228throw new OptionError("Value of field is null and no @Option annotation does not have factory", optDef);229if (useDefault) {230setOptionValue(optDef, optDef.getDefaultValue());231try {232v = f.get(o);233} catch (IllegalAccessException e) {234throw new OptionError("Exception getting value of field ", e, optDef);235}236}237if (v == null) {238// We cannot setup it right away, so it is stored until value is set239return false;240} else241return true; // setOption Value already searched annotations242}243Options opts = f.getAnnotation(Options.class);244String vprefix = opts.prefix();245if (vprefix.equals(Options.defPrefix))246vprefix = null;247if (vprefix != null) {248if (prefix != null)249prefix = prefix + "." + vprefix;250else251prefix = vprefix;252}253searchAnnotations(v, prefix);254return true;255}256257private OptionDefinition optionAnnotation(Object o, Field f, String prefix) {258//log.debug("Processing @Option annotation: object " + o + ", field " + f + ", prefix " + prefix);259f.setAccessible(true);260Option opt = f.getAnnotation(Option.class);261String name = opt.name();262if (name.equals(Option.defName))263name = f.getName(); // option name defaults to field name264if (prefix != null)265name = prefix + "." + name;266if (optionDefs.containsKey(name))267throw new TestBug("Option is already defined: " + name);268String defaultValue = opt.default_value();269if (defaultValue.equals(Option.defDefaultValue))270defaultValue = null; // default value defaults to null271String description = opt.description();272if (description.equals(Option.defDescription))273description = null;274if (description == null) {275if (name.equals("log") || name.endsWith(".log")) {276try {277f.set(o, log);278} catch (IllegalAccessException e) {279throw new TestBug("Exception setting log field of " + o, e);280}281return null;282} else283throw new TestBug("@Option annotation should always have description set: " + name + ", field: " + f);284}285Class<? extends OptionObjectFactory> factory = opt.factory();286//log.debug("Factory: " + factory);287if (factory.equals(OptionObjectFactory.class))288factory = null;289OptionDefinition optDef = new OptionDefinition(290prefix,291name,292description,293defaultValue,294factory,295f,296o297);298optionDefs.put(name, optDef);299//log.debug("Added option definition: " + optDef);300return optDef;301}302303private void printHelp() {304PrintStream out = System.out;305out.println(" Supported options:");306out.println(" -help");307out.println(" Show this help screen");308for (Map.Entry<String, OptionDefinition> entry : optionDefs.entrySet()) {309String opt = entry.getKey();310OptionDefinition optDef = entry.getValue();311out.println(" -" + opt + " <" + optDef.getPlaceHolder() + ">");312out.print(" " + optDef.getDescription() + " ");313if (optDef.getDefaultValue() != null) {314out.println("(default: " + optDef.getDefaultValue() + ")");315} else {316out.println("(mandatory)");317}318if (optDef.hasFactory()) {319OptionObjectFactory factory = optDef.getFactory();320for (String key : factory.getPossibleValues()) {321out.println(" " + key + ": " + factory.getParameterDescription(key));322}323}324}325}326}327328329