    001/**
    002 *   Copyright (C) 2011-2012 Typesafe Inc. <http://typesafe.com>
    003 */
    004package com.typesafe.config;
    005
    006/**
    007 * A set of options related to resolving substitutions. Substitutions use the
    008 * <code>${foo.bar}</code> syntax and are documented in the <a
    009 * href="https://github.com/lightbend/config/blob/master/HOCON.md">HOCON</a>
    010 * spec.
    011 * <p>
    012 * Typically this class would be used with the method
    013 * {@link Config#resolve(ConfigResolveOptions)}.
    014 * <p>
    015 * This object is immutable, so the "setters" return a new object.
    016 * <p>
    017 * Here is an example of creating a custom {@code ConfigResolveOptions}:
    018 *
    019 * <pre>
    020 *     ConfigResolveOptions options = ConfigResolveOptions.defaults()
    021 *         .setUseSystemEnvironment(false)
    022 * </pre>
    023 * <p>
    024 * In addition to {@link ConfigResolveOptions#defaults}, there's a prebuilt
    025 * {@link ConfigResolveOptions#noSystem} which avoids looking at any system
    026 * environment variables or other external system information. (Right now,
    027 * environment variables are the only example.)
    028 */
    029public final class ConfigResolveOptions {
    030    private final boolean useSystemEnvironment;
    031    private final boolean allowUnresolved;
    032    private final ConfigResolver resolver;
    033
    034    private ConfigResolveOptions(boolean useSystemEnvironment, boolean allowUnresolved,
    035                                 ConfigResolver resolver) {
    036        this.useSystemEnvironment = useSystemEnvironment;
    037        this.allowUnresolved = allowUnresolved;
    038        this.resolver = resolver;
    039    }
    040
    041    /**
    042     * Returns the default resolve options. By default the system environment
    043     * will be used and unresolved substitutions are not allowed.
    044     *
    045     * @return the default resolve options
    046     */
    047    public static ConfigResolveOptions defaults() {
    048        return new ConfigResolveOptions(true, false, NULL_RESOLVER);
    049    }
    050
    051    /**
    052     * Returns resolve options that disable any reference to "system" data
    053     * (currently, this means environment variables).
    054     *
    055     * @return the resolve options with env variables disabled
    056     */
    057    public static ConfigResolveOptions noSystem() {
    058        return defaults().setUseSystemEnvironment(false);
    059    }
    060
    061    /**
    062     * Returns options with use of environment variables set to the given value.
    063     *
    064     * @param value
    065     *            true to resolve substitutions falling back to environment
    066     *            variables.
    067     * @return options with requested setting for use of environment variables
    068     */
    069    public ConfigResolveOptions setUseSystemEnvironment(boolean value) {
    070        return new ConfigResolveOptions(value, allowUnresolved, resolver);
    071    }
    072
    073    /**
    074     * Returns whether the options enable use of system environment variables.
    075     * This method is mostly used by the config lib internally, not by
    076     * applications.
    077     *
    078     * @return true if environment variables should be used
    079     */
    080    public boolean getUseSystemEnvironment() {
    081        return useSystemEnvironment;
    082    }
    083
    084    /**
    085     * Returns options with "allow unresolved" set to the given value. By
    086     * default, unresolved substitutions are an error. If unresolved
    087     * substitutions are allowed, then a future attempt to use the unresolved
    088     * value may fail, but {@link Config#resolve(ConfigResolveOptions)} itself
    089     * will not throw.
    090     *
    091     * @param value
    092     *            true to silently ignore unresolved substitutions.
    093     * @return options with requested setting for whether to allow substitutions
    094     * @since 1.2.0
    095     */
    096    public ConfigResolveOptions setAllowUnresolved(boolean value) {
    097        return new ConfigResolveOptions(useSystemEnvironment, value, resolver);
    098    }
    099
    100    /**
    101     * Returns options where the given resolver used as a fallback if a
    102     * reference cannot be otherwise resolved. This resolver will only be called
    103     * after resolution has failed to substitute with a value from within the
    104     * config itself and with any other resolvers that have been appended before
    105     * this one. Multiple resolvers can be added using,
    106     *
    107     *  <pre>
    108     *     ConfigResolveOptions options = ConfigResolveOptions.defaults()
    109     *         .appendResolver(primary)
    110     *         .appendResolver(secondary)
    111     *         .appendResolver(tertiary);
    112     * </pre>
    113     *
    114     * With this config unresolved references will first be resolved with the
    115     * primary resolver, if that fails then the secondary, and finally if that
    116     * also fails the tertiary.
    117     *
    118     * If all fallbacks fail to return a substitution "allow unresolved"
    119     * determines whether resolution fails or continues.
    120     *`
    121     * @param value the resolver to fall back to
    122     * @return options that use the given resolver as a fallback
    123     * @since 1.3.2
    124     */
    125    public ConfigResolveOptions appendResolver(ConfigResolver value) {
    126        if (value == null) {
    127            throw new ConfigException.BugOrBroken("null resolver passed to appendResolver");
    128        } else if (value == this.resolver) {
    129            return this;
    130        } else {
    131            return new ConfigResolveOptions(useSystemEnvironment, allowUnresolved,
    132                    this.resolver.withFallback(value));
    133        }
    134    }
    135
    136    /**
    137     * Returns the resolver to use as a fallback if a substitution cannot be
    138     * otherwise resolved. Never returns null. This method is mostly used by the
    139     * config lib internally, not by applications.
    140     *
    141     * @return the non-null fallback resolver
    142     * @since 1.3.2
    143     */
    144    public ConfigResolver getResolver() {
    145        return this.resolver;
    146    }
    147
    148    /**
    149     * Returns whether the options allow unresolved substitutions. This method
    150     * is mostly used by the config lib internally, not by applications.
    151     *
    152     * @return true if unresolved substitutions are allowed
    153     * @since 1.2.0
    154     */
    155    public boolean getAllowUnresolved() {
    156        return allowUnresolved;
    157    }
    158
    159    /**
    160     * Singleton resolver that never resolves paths.
    161     */
    162    private static final ConfigResolver NULL_RESOLVER = new ConfigResolver() {
    163
    164        @Override
    165        public ConfigValue lookup(String path) {
    166            return null;
    167        }
    168
    169        @Override
    170        public ConfigResolver withFallback(ConfigResolver fallback) {
    171            return fallback;
    172        }
    173
    174    };
    175
    176}