--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/options/Options.java 2020-04-15 18:51:19.000000000 +0530 +++ /dev/null 2020-04-15 18:51:19.000000000 +0530 @@ -1,728 +0,0 @@ -/* - * Copyright (c) 2010, 2013, 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 jdk.nashorn.internal.runtime.options; - -import java.io.PrintWriter; -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.Permissions; -import java.security.PrivilegedAction; -import java.security.ProtectionDomain; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.MissingResourceException; -import java.util.Objects; -import java.util.PropertyPermission; -import java.util.ResourceBundle; -import java.util.StringTokenizer; -import java.util.TimeZone; -import java.util.TreeMap; -import java.util.TreeSet; -import jdk.nashorn.internal.runtime.QuotedStringTokenizer; - -/** - * Manages global runtime options. - */ -public final class Options { - // permission to just read nashorn.* System properties - private static AccessControlContext createPropertyReadAccCtxt() { - final Permissions perms = new Permissions(); - perms.add(new PropertyPermission("nashorn.*", "read")); - return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); - } - - private static final AccessControlContext READ_PROPERTY_ACC_CTXT = createPropertyReadAccCtxt(); - - /** Resource tag. */ - private final String resource; - - /** Error writer. */ - private final PrintWriter err; - - /** File list. */ - private final List files; - - /** Arguments list */ - private final List arguments; - - /** The options map of enabled options */ - private final TreeMap> options; - - /** System property that can be used to prepend options to the explicitly specified command line. */ - private static final String NASHORN_ARGS_PREPEND_PROPERTY = "nashorn.args.prepend"; - - /** System property that can be used to append options to the explicitly specified command line. */ - private static final String NASHORN_ARGS_PROPERTY = "nashorn.args"; - - /** - * Constructor - * - * Options will use System.err as the output stream for any errors - * - * @param resource resource prefix for options e.g. "nashorn" - */ - public Options(final String resource) { - this(resource, new PrintWriter(System.err, true)); - } - - /** - * Constructor - * - * @param resource resource prefix for options e.g. "nashorn" - * @param err error stream for reporting parse errors - */ - public Options(final String resource, final PrintWriter err) { - this.resource = resource; - this.err = err; - this.files = new ArrayList<>(); - this.arguments = new ArrayList<>(); - this.options = new TreeMap<>(); - - // set all default values - for (final OptionTemplate t : Options.validOptions) { - if (t.getDefaultValue() != null) { - // populate from system properties - final String v = getStringProperty(t.getKey(), null); - if (v != null) { - set(t.getKey(), createOption(t, v)); - } else if (t.getDefaultValue() != null) { - set(t.getKey(), createOption(t, t.getDefaultValue())); - } - } - } - } - - /** - * Get the resource for this Options set, e.g. "nashorn" - * @return the resource - */ - public String getResource() { - return resource; - } - - @Override - public String toString() { - return options.toString(); - } - - private static void checkPropertyName(final String name) { - if (! Objects.requireNonNull(name).startsWith("nashorn.")) { - throw new IllegalArgumentException(name); - } - } - - /** - * Convenience function for getting system properties in a safe way - - * @param name of boolean property - * @param defValue default value of boolean property - * @return true if set to true, default value if unset or set to false - */ - public static boolean getBooleanProperty(final String name, final Boolean defValue) { - checkPropertyName(name); - return AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public Boolean run() { - try { - final String property = System.getProperty(name); - if (property == null && defValue != null) { - return defValue; - } - return property != null && !"false".equalsIgnoreCase(property); - } catch (final SecurityException e) { - // if no permission to read, assume false - return false; - } - } - }, READ_PROPERTY_ACC_CTXT); - } - - /** - * Convenience function for getting system properties in a safe way - - * @param name of boolean property - * @return true if set to true, false if unset or set to false - */ - public static boolean getBooleanProperty(final String name) { - return getBooleanProperty(name, null); - } - - /** - * Convenience function for getting system properties in a safe way - * - * @param name of string property - * @param defValue the default value if unset - * @return string property if set or default value - */ - public static String getStringProperty(final String name, final String defValue) { - checkPropertyName(name); - return AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public String run() { - try { - return System.getProperty(name, defValue); - } catch (final SecurityException e) { - // if no permission to read, assume the default value - return defValue; - } - } - }, READ_PROPERTY_ACC_CTXT); - } - - /** - * Convenience function for getting system properties in a safe way - * - * @param name of integer property - * @param defValue the default value if unset - * @return integer property if set or default value - */ - public static int getIntProperty(final String name, final int defValue) { - checkPropertyName(name); - return AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public Integer run() { - try { - return Integer.getInteger(name, defValue); - } catch (final SecurityException e) { - // if no permission to read, assume the default value - return defValue; - } - } - }, READ_PROPERTY_ACC_CTXT); - } - - /** - * Return an option given its resource key. If the key doesn't begin with - * {@literal }.option it will be completed using the resource from this - * instance - * - * @param key key for option - * @return an option value - */ - public Option get(final String key) { - return options.get(key(key)); - } - - /** - * Return an option as a boolean - * - * @param key key for option - * @return an option value - */ - public boolean getBoolean(final String key) { - final Option option = get(key); - return option != null ? (Boolean)option.getValue() : false; - } - - /** - * Return an option as a integer - * - * @param key key for option - * @return an option value - */ - public int getInteger(final String key) { - final Option option = get(key); - return option != null ? (Integer)option.getValue() : 0; - } - - /** - * Return an option as a String - * - * @param key key for option - * @return an option value - */ - public String getString(final String key) { - final Option option = get(key); - if (option != null) { - final String value = (String)option.getValue(); - if(value != null) { - return value.intern(); - } - } - return null; - } - - /** - * Set an option, overwriting an existing state if one exists - * - * @param key option key - * @param option option - */ - public void set(final String key, final Option option) { - options.put(key(key), option); - } - - /** - * Set an option as a boolean value, overwriting an existing state if one exists - * - * @param key option key - * @param option option - */ - public void set(final String key, final boolean option) { - set(key, new Option<>(option)); - } - - /** - * Set an option as a String value, overwriting an existing state if one exists - * - * @param key option key - * @param option option - */ - public void set(final String key, final String option) { - set(key, new Option<>(option)); - } - - /** - * Return the user arguments to the program, i.e. those trailing "--" after - * the filename - * - * @return a list of user arguments - */ - public List getArguments() { - return Collections.unmodifiableList(this.arguments); - } - - /** - * Return the JavaScript files passed to the program - * - * @return a list of files - */ - public List getFiles() { - return Collections.unmodifiableList(files); - } - - /** - * Return the option templates for all the valid option supported. - * - * @return a collection of OptionTemplate objects. - */ - public static Collection getValidOptions() { - return Collections.unmodifiableCollection(validOptions); - } - - /** - * Make sure a key is fully qualified for table lookups - * - * @param shortKey key for option - * @return fully qualified key - */ - private String key(final String shortKey) { - String key = shortKey; - while (key.startsWith("-")) { - key = key.substring(1, key.length()); - } - key = key.replace("-", "."); - final String keyPrefix = this.resource + ".option."; - if (key.startsWith(keyPrefix)) { - return key; - } - return keyPrefix + key; - } - - static String getMsg(final String msgId, final String... args) { - try { - final String msg = Options.bundle.getString(msgId); - if (args.length == 0) { - return msg; - } - return new MessageFormat(msg).format(args); - } catch (final MissingResourceException e) { - throw new IllegalArgumentException(e); - } - } - - /** - * Display context sensitive help - * - * @param e exception that caused a parse error - */ - public void displayHelp(final IllegalArgumentException e) { - if (e instanceof IllegalOptionException) { - final OptionTemplate template = ((IllegalOptionException)e).getTemplate(); - if (template.isXHelp()) { - // display extended help information - displayHelp(true); - } else { - err.println(((IllegalOptionException)e).getTemplate()); - } - return; - } - - if (e != null && e.getMessage() != null) { - err.println(getMsg("option.error.invalid.option", - e.getMessage(), - helpOptionTemplate.getShortName(), - helpOptionTemplate.getName())); - err.println(); - return; - } - - displayHelp(false); - } - - /** - * Display full help - * - * @param extended show the extended help for all options, including undocumented ones - */ - public void displayHelp(final boolean extended) { - for (final OptionTemplate t : Options.validOptions) { - if ((extended || !t.isUndocumented()) && t.getResource().equals(resource)) { - err.println(t); - err.println(); - } - } - } - - /** - * Processes the arguments and stores their information. Throws - * IllegalArgumentException on error. The message can be analyzed by the - * displayHelp function to become more context sensitive - * - * @param args arguments from command line - */ - public void process(final String[] args) { - final LinkedList argList = new LinkedList<>(); - addSystemProperties(NASHORN_ARGS_PREPEND_PROPERTY, argList); - processArgList(argList); - assert argList.isEmpty(); - Collections.addAll(argList, args); - processArgList(argList); - assert argList.isEmpty(); - addSystemProperties(NASHORN_ARGS_PROPERTY, argList); - processArgList(argList); - assert argList.isEmpty(); - } - - private void processArgList(final LinkedList argList) { - while (!argList.isEmpty()) { - final String arg = argList.remove(0); - Objects.requireNonNull(arg); - - // skip empty args - if (arg.isEmpty()) { - continue; - } - - // user arguments to the script - if ("--".equals(arg)) { - arguments.addAll(argList); - argList.clear(); - continue; - } - - // If it doesn't start with -, it's a file. But, if it is just "-", - // then it is a file representing standard input. - if (!arg.startsWith("-") || arg.length() == 1) { - files.add(arg); - continue; - } - - if (arg.startsWith(definePropPrefix)) { - final String value = arg.substring(definePropPrefix.length()); - final int eq = value.indexOf('='); - if (eq != -1) { - // -Dfoo=bar Set System property "foo" with value "bar" - System.setProperty(value.substring(0, eq), value.substring(eq + 1)); - } else { - // -Dfoo is fine. Set System property "foo" with "" as it's value - if (!value.isEmpty()) { - System.setProperty(value, ""); - } else { - // do not allow empty property name - throw new IllegalOptionException(definePropTemplate); - } - } - continue; - } - - // it is an argument, it and assign key, value and template - final ParsedArg parg = new ParsedArg(arg); - - // check if the value of this option is passed as next argument - if (parg.template.isValueNextArg()) { - if (argList.isEmpty()) { - throw new IllegalOptionException(parg.template); - } - parg.value = argList.remove(0); - } - - // -h [args...] - if (parg.template.isHelp()) { - // check if someone wants help on an explicit arg - if (!argList.isEmpty()) { - try { - final OptionTemplate t = new ParsedArg(argList.get(0)).template; - throw new IllegalOptionException(t); - } catch (final IllegalArgumentException e) { - throw e; - } - } - throw new IllegalArgumentException(); // show help for - // everything - } - - if (parg.template.isXHelp()) { - throw new IllegalOptionException(parg.template); - } - - if (parg.template.isRepeated()) { - assert parg.template.getType().equals("string"); - - final String key = key(parg.template.getKey()); - final String value = options.containsKey(key)? - (options.get(key).getValue() + "," + parg.value) : Objects.toString(parg.value); - options.put(key, new Option<>(value)); - } else { - set(parg.template.getKey(), createOption(parg.template, parg.value)); - } - - // Arg may have a dependency to set other args, e.g. - // scripting->anon.functions - if (parg.template.getDependency() != null) { - argList.addFirst(parg.template.getDependency()); - } - } - } - - private static void addSystemProperties(final String sysPropName, final List argList) { - final String sysArgs = getStringProperty(sysPropName, null); - if (sysArgs != null) { - final StringTokenizer st = new StringTokenizer(sysArgs); - while (st.hasMoreTokens()) { - argList.add(st.nextToken()); - } - } - } - - /** - * Retrieves an option template identified by key. - * @param shortKey the short (that is without the e.g. "nashorn.option." part) key - * @return the option template identified by the key - * @throws IllegalArgumentException if the key doesn't specify an existing template - */ - public OptionTemplate getOptionTemplateByKey(final String shortKey) { - final String fullKey = key(shortKey); - for(final OptionTemplate t: validOptions) { - if(t.getKey().equals(fullKey)) { - return t; - } - } - throw new IllegalArgumentException(shortKey); - } - - private static OptionTemplate getOptionTemplateByName(final String name) { - for (final OptionTemplate t : Options.validOptions) { - if (t.nameMatches(name)) { - return t; - } - } - return null; - } - - private static Option createOption(final OptionTemplate t, final String value) { - switch (t.getType()) { - case "string": - // default value null - return new Option<>(value); - case "timezone": - // default value "TimeZone.getDefault()" - return new Option<>(TimeZone.getTimeZone(value)); - case "locale": - return new Option<>(Locale.forLanguageTag(value)); - case "keyvalues": - return new KeyValueOption(value); - case "log": - return new LoggingOption(value); - case "boolean": - return new Option<>(value != null && Boolean.parseBoolean(value)); - case "integer": - try { - return new Option<>(value == null ? 0 : Integer.parseInt(value)); - } catch (final NumberFormatException nfe) { - throw new IllegalOptionException(t); - } - case "properties": - //swallow the properties and set them - initProps(new KeyValueOption(value)); - return null; - default: - break; - } - throw new IllegalArgumentException(value); - } - - private static void initProps(final KeyValueOption kv) { - for (final Map.Entry entry : kv.getValues().entrySet()) { - System.setProperty(entry.getKey(), entry.getValue()); - } - } - - /** - * Resource name for properties file - */ - private static final String MESSAGES_RESOURCE = "jdk.nashorn.internal.runtime.resources.Options"; - - /** - * Resource bundle for properties file - */ - private static ResourceBundle bundle; - - /** - * Usages per resource from properties file - */ - private static HashMap usage; - - /** - * Valid options from templates in properties files - */ - private static Collection validOptions; - - /** - * Help option - */ - private static OptionTemplate helpOptionTemplate; - - /** - * Define property option template. - */ - private static OptionTemplate definePropTemplate; - - /** - * Prefix of "define property" option. - */ - private static String definePropPrefix; - - static { - Options.bundle = ResourceBundle.getBundle(Options.MESSAGES_RESOURCE, Locale.getDefault()); - Options.validOptions = new TreeSet<>(); - Options.usage = new HashMap<>(); - - for (final Enumeration keys = Options.bundle.getKeys(); keys.hasMoreElements(); ) { - final String key = keys.nextElement(); - final StringTokenizer st = new StringTokenizer(key, "."); - String resource = null; - String type = null; - - if (st.countTokens() > 0) { - resource = st.nextToken(); // e.g. "nashorn" - } - - if (st.countTokens() > 0) { - type = st.nextToken(); // e.g. "option" - } - - if ("option".equals(type)) { - String helpKey = null; - String xhelpKey = null; - String definePropKey = null; - try { - helpKey = Options.bundle.getString(resource + ".options.help.key"); - xhelpKey = Options.bundle.getString(resource + ".options.xhelp.key"); - definePropKey = Options.bundle.getString(resource + ".options.D.key"); - } catch (final MissingResourceException e) { - //ignored: no help - } - final boolean isHelp = key.equals(helpKey); - final boolean isXHelp = key.equals(xhelpKey); - final OptionTemplate t = new OptionTemplate(resource, key, Options.bundle.getString(key), isHelp, isXHelp); - - Options.validOptions.add(t); - if (isHelp) { - helpOptionTemplate = t; - } - - if (key.equals(definePropKey)) { - definePropPrefix = t.getName(); - definePropTemplate = t; - } - } else if (resource != null && "options".equals(type)) { - Options.usage.put(resource, Options.bundle.getObject(key)); - } - } - } - - @SuppressWarnings("serial") - private static class IllegalOptionException extends IllegalArgumentException { - private final OptionTemplate template; - - IllegalOptionException(final OptionTemplate t) { - super(); - this.template = t; - } - - OptionTemplate getTemplate() { - return this.template; - } - } - - /** - * This is a resolved argument of the form key=value - */ - private static class ParsedArg { - /** The resolved option template this argument corresponds to */ - OptionTemplate template; - - /** The value of the argument */ - String value; - - ParsedArg(final String argument) { - final QuotedStringTokenizer st = new QuotedStringTokenizer(argument, "="); - if (!st.hasMoreTokens()) { - throw new IllegalArgumentException(); - } - - final String token = st.nextToken(); - this.template = getOptionTemplateByName(token); - if (this.template == null) { - throw new IllegalArgumentException(argument); - } - - value = ""; - if (st.hasMoreTokens()) { - while (st.hasMoreTokens()) { - value += st.nextToken(); - if (st.hasMoreTokens()) { - value += ':'; - } - } - } else if ("boolean".equals(this.template.getType())) { - value = "true"; - } - } - } -}