    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements. See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache license, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License. You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the license for the specific language governing permissions and
    015 * limitations under the license.
    016 */
    017
    018package org.apache.commons.text.lookup;
    019
    020import java.nio.charset.StandardCharsets;
    021import java.util.Base64;
    022import java.util.Map;
    023import java.util.function.BiFunction;
    024import java.util.function.Function;
    025
    026import org.apache.commons.text.StringSubstitutor;
    027
    028/**
    029 * Create instances of string lookups or access singleton string lookups implemented in this package.
    030 * <p>
    031 * The "classic" look up is {@link #mapStringLookup(Map)}.
    032 * </p>
    033 * <p>
    034 * The methods for variable interpolation (A.K.A. variable substitution) are:
    035 * </p>
    036 * <ul>
    037 * <li>{@link #interpolatorStringLookup()}.</li>
    038 * <li>{@link #interpolatorStringLookup(Map)}.</li>
    039 * <li>{@link #interpolatorStringLookup(StringLookup)}.</li>
    040 * <li>{@link #interpolatorStringLookup(Map, StringLookup, boolean)}.</li>
    041 * </ul>
    042 * <p>
    043 * The default lookups are:
    044 * </p>
    045 * <table>
    046 * <caption>Default String Lookups</caption>
    047 * <tr>
    048 * <th>Key</th>
    049 * <th>Interface</th>
    050 * <th>Factory Method</th>
    051 * <th>Since</th>
    052 * </tr>
    053 * <tr>
    054 * <td>{@value #KEY_BASE64_DECODER}</td>
    055 * <td>{@link StringLookup}</td>
    056 * <td>{@link #base64DecoderStringLookup()}</td>
    057 * <td>1.6</td>
    058 * </tr>
    059 * <tr>
    060 * <td>{@value #KEY_BASE64_ENCODER}</td>
    061 * <td>{@link StringLookup}</td>
    062 * <td>{@link #base64EncoderStringLookup()}</td>
    063 * <td>1.6</td>
    064 * </tr>
    065 * <tr>
    066 * <td>{@value #KEY_CONST}</td>
    067 * <td>{@link StringLookup}</td>
    068 * <td>{@link #constantStringLookup()}</td>
    069 * <td>1.5</td>
    070 * </tr>
    071 * <tr>
    072 * <td>{@value #KEY_DATE}</td>
    073 * <td>{@link StringLookup}</td>
    074 * <td>{@link #dateStringLookup()}</td>
    075 * <td>1.5</td>
    076 * </tr>
    077 * <tr>
    078 * <td>{@value #KEY_DNS}</td>
    079 * <td>{@link StringLookup}</td>
    080 * <td>{@link #dnsStringLookup()}</td>
    081 * <td>1.8</td>
    082 * </tr>
    083 * <tr>
    084 * <td>{@value #KEY_ENV}</td>
    085 * <td>{@link StringLookup}</td>
    086 * <td>{@link #environmentVariableStringLookup()}</td>
    087 * <td>1.3</td>
    088 * </tr>
    089 * <tr>
    090 * <td>{@value #KEY_FILE}</td>
    091 * <td>{@link StringLookup}</td>
    092 * <td>{@link #fileStringLookup()}</td>
    093 * <td>1.5</td>
    094 * </tr>
    095 * <tr>
    096 * <td>{@value #KEY_JAVA}</td>
    097 * <td>{@link StringLookup}</td>
    098 * <td>{@link #javaPlatformStringLookup()}</td>
    099 * <td>1.5</td>
    100 * </tr>
    101 * <tr>
    102 * <td>{@value #KEY_LOCALHOST}</td>
    103 * <td>{@link StringLookup}</td>
    104 * <td>{@link #localHostStringLookup()}</td>
    105 * <td>1.3</td>
    106 * </tr>
    107 * <tr>
    108 * <td>{@value #KEY_PROPERTIES}</td>
    109 * <td>{@link StringLookup}</td>
    110 * <td>{@link #propertiesStringLookup()}</td>
    111 * <td>1.5</td>
    112 * </tr>
    113 * <tr>
    114 * <td>{@value #KEY_RESOURCE_BUNDLE}</td>
    115 * <td>{@link StringLookup}</td>
    116 * <td>{@link #resourceBundleStringLookup()}</td>
    117 * <td>1.6</td>
    118 * </tr>
    119 * <tr>
    120 * <td>{@value #KEY_SCRIPT}</td>
    121 * <td>{@link StringLookup}</td>
    122 * <td>{@link #scriptStringLookup()}</td>
    123 * <td>1.5</td>
    124 * </tr>
    125 * <tr>
    126 * <td>{@value #KEY_SYS}</td>
    127 * <td>{@link StringLookup}</td>
    128 * <td>{@link #systemPropertyStringLookup()}</td>
    129 * <td>1.3</td>
    130 * </tr>
    131 * <tr>
    132 * <td>{@value #KEY_URL}</td>
    133 * <td>{@link StringLookup}</td>
    134 * <td>{@link #urlStringLookup()}</td>
    135 * <td>1.5</td>
    136 * </tr>
    137 * <tr>
    138 * <td>{@value #KEY_URL_DECODER}</td>
    139 * <td>{@link StringLookup}</td>
    140 * <td>{@link #urlDecoderStringLookup()}</td>
    141 * <td>1.5</td>
    142 * </tr>
    143 * <tr>
    144 * <td>{@value #KEY_URL_ENCODER}</td>
    145 * <td>{@link StringLookup}</td>
    146 * <td>{@link #urlEncoderStringLookup()}</td>
    147 * <td>1.5</td>
    148 * </tr>
    149 * <tr>
    150 * <td>{@value #KEY_XML}</td>
    151 * <td>{@link StringLookup}</td>
    152 * <td>{@link #xmlStringLookup()}</td>
    153 * <td>1.5</td>
    154 * </tr>
    155 * </table>
    156 * <p>
    157 * We also provide functional lookups used as building blocks for other lookups.
    158 * <table>
    159 * <caption>Functional String Lookups</caption>
    160 * <tr>
    161 * <th>Interface</th>
    162 * <th>Factory Method</th>
    163 * <th>Since</th>
    164 * </tr>
    165 * <tr>
    166 * <td>{@link BiStringLookup}</td>
    167 * <td>{@link #biFunctionStringLookup(BiFunction)}</td>
    168 * <td>1.9</td>
    169 * </tr>
    170 * <tr>
    171 * <td>{@link StringLookup}</td>
    172 * <td>{@link #functionStringLookup(Function)}</td>
    173 * <td>1.9</td>
    174 * </tr>
    175 * </table>
    176 *
    177 * @since 1.3
    178 */
    179public final class StringLookupFactory {
    180
    181    /**
    182     * Defines the singleton for this class.
    183     */
    184    public static final StringLookupFactory INSTANCE = new StringLookupFactory();
    185
    186    /**
    187     * Decodes Base64 Strings.
    188     * <p>
    189     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    190     * </p>
    191     *
    192     * <pre>
    193     * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE=");
    194     * </pre>
    195     * <p>
    196     * Using a {@link StringSubstitutor}:
    197     * </p>
    198     *
    199     * <pre>
    200     * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ..."));
    201     * </pre>
    202     * <p>
    203     * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}.
    204     * </p>
    205     */
    206    static final FunctionStringLookup<String> INSTANCE_BASE64_DECODER = FunctionStringLookup
    207        .on(key -> new String(Base64.getDecoder().decode(key), StandardCharsets.ISO_8859_1));
    208
    209    /**
    210     * Encodes Base64 Strings.
    211     * <p>
    212     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    213     * </p>
    214     *
    215     * <pre>
    216     * StringLookupFactory.INSTANCE.base64EncoderStringLookup().lookup("HelloWorld!");
    217     * </pre>
    218     * <p>
    219     * Using a {@link StringSubstitutor}:
    220     * </p>
    221     *
    222     * <pre>
    223     * StringSubstitutor.createInterpolator().replace("... ${base64Encoder:HelloWorld!} ..."));
    224     * </pre>
    225     * <p>
    226     * The above examples convert {@code "HelloWorld!"} to {@code "SGVsbG9Xb3JsZCE="}.
    227     * </p>
    228     * Defines the singleton for this class.
    229     */
    230    static final FunctionStringLookup<String> INSTANCE_BASE64_ENCODER = FunctionStringLookup
    231        .on(key -> Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.ISO_8859_1)));
    232
    233    /**
    234     * Looks up keys from environment variables.
    235     * <p>
    236     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    237     * </p>
    238     *
    239     * <pre>
    240     * StringLookupFactory.INSTANCE.dateStringLookup().lookup("USER");
    241     * </pre>
    242     * <p>
    243     * Using a {@link StringSubstitutor}:
    244     * </p>
    245     *
    246     * <pre>
    247     * StringSubstitutor.createInterpolator().replace("... ${env:USER} ..."));
    248     * </pre>
    249     * <p>
    250     * The above examples convert (on Linux) {@code "USER"} to the current user name. On Windows 10, you would use
    251     * {@code "USERNAME"} to the same effect.
    252     * </p>
    253     */
    254    static final FunctionStringLookup<String> INSTANCE_ENVIRONMENT_VARIABLES = FunctionStringLookup.on(System::getenv);
    255
    256    /**
    257     * Defines the FunctionStringLookup singleton that always returns null.
    258     */
    259    static final FunctionStringLookup<String> INSTANCE_NULL = FunctionStringLookup.on(key -> null);
    260
    261    /**
    262     * Defines the FunctionStringLookup singleton for looking up system properties.
    263     */
    264    static final FunctionStringLookup<String> INSTANCE_SYSTEM_PROPERTIES = FunctionStringLookup.on(System::getProperty);
    265
    266    /**
    267     * Default lookup key for interpolation {@value #KEY_BASE64_DECODER}.
    268     *
    269     * @since 1.6
    270     */
    271    public static final String KEY_BASE64_DECODER = "base64Decoder";
    272
    273    /**
    274     * Default lookup key for interpolation {@value #KEY_BASE64_ENCODER}.
    275     *
    276     * @since 1.6
    277     */
    278    public static final String KEY_BASE64_ENCODER = "base64Encoder";
    279
    280    /**
    281     * Default lookup key for interpolation {@value #KEY_CONST}.
    282     *
    283     * @since 1.6
    284     */
    285    public static final String KEY_CONST = "const";
    286
    287    /**
    288     * Default lookup key for interpolation {@value #KEY_DATE}.
    289     *
    290     * @since 1.6
    291     */
    292    public static final String KEY_DATE = "date";
    293
    294    /**
    295     * Default lookup key for interpolation {@value #KEY_DNS}.
    296     *
    297     * @since 1.8
    298     */
    299    public static final String KEY_DNS = "dns";
    300
    301    /**
    302     * Default lookup key for interpolation {@value #KEY_ENV}.
    303     *
    304     * @since 1.6
    305     */
    306    public static final String KEY_ENV = "env";
    307
    308    /**
    309     * Default lookup key for interpolation {@value #KEY_FILE}.
    310     *
    311     * @since 1.6
    312     */
    313    public static final String KEY_FILE = "file";
    314
    315    /**
    316     * Default lookup key for interpolation {@value #KEY_JAVA}.
    317     *
    318     * @since 1.6
    319     */
    320    public static final String KEY_JAVA = "java";
    321
    322    /**
    323     * Default lookup key for interpolation {@value #KEY_LOCALHOST}.
    324     *
    325     * @since 1.6
    326     */
    327    public static final String KEY_LOCALHOST = "localhost";
    328
    329    /**
    330     * Default lookup key for interpolation {@value #KEY_PROPERTIES}.
    331     *
    332     * @since 1.6
    333     */
    334    public static final String KEY_PROPERTIES = "properties";
    335
    336    /**
    337     * Default lookup key for interpolation {@value #KEY_RESOURCE_BUNDLE}.
    338     *
    339     * @since 1.6
    340     */
    341    public static final String KEY_RESOURCE_BUNDLE = "resourceBundle";
    342
    343    /**
    344     * Default lookup key for interpolation {@value #KEY_SCRIPT}.
    345     *
    346     * @since 1.6
    347     */
    348    public static final String KEY_SCRIPT = "script";
    349
    350    /**
    351     * Default lookup key for interpolation {@value #KEY_SYS}.
    352     *
    353     * @since 1.6
    354     */
    355    public static final String KEY_SYS = "sys";
    356
    357    /**
    358     * Default lookup key for interpolation {@value #KEY_URL}.
    359     *
    360     * @since 1.6
    361     */
    362    public static final String KEY_URL = "url";
    363
    364    /**
    365     * Default lookup key for interpolation {@value #KEY_URL_DECODER}.
    366     *
    367     * @since 1.6
    368     */
    369    public static final String KEY_URL_DECODER = "urlDecoder";
    370
    371    /**
    372     * Default lookup key for interpolation {@value #KEY_URL_ENCODER}.
    373     *
    374     * @since 1.6
    375     */
    376    public static final String KEY_URL_ENCODER = "urlEncoder";
    377
    378    /**
    379     * Default lookup key for interpolation {@value #KEY_XML}.
    380     *
    381     * @since 1.6
    382     */
    383    public static final String KEY_XML = "xml";
    384
    385    /**
    386     * Clears any static resources.
    387     *
    388     * @since 1.5
    389     */
    390    public static void clear() {
    391        ConstantStringLookup.clear();
    392    }
    393
    394    /**
    395     * No need to build instances for now.
    396     */
    397    private StringLookupFactory() {
    398        // empty
    399    }
    400
    401    /**
    402     * Adds the {@link StringLookupFactory default lookups}.
    403     *
    404     * @param stringLookupMap the map of string lookups.
    405     * @since 1.5
    406     */
    407    public void addDefaultStringLookups(final Map<String, StringLookup> stringLookupMap) {
    408        if (stringLookupMap != null) {
    409            // "base64" is deprecated in favor of KEY_BASE64_DECODER.
    410            stringLookupMap.put("base64", StringLookupFactory.INSTANCE_BASE64_DECODER);
    411            for (final DefaultStringLookup stringLookup : DefaultStringLookup.values()) {
    412                stringLookupMap.put(InterpolatorStringLookup.toKey(stringLookup.getKey()),
    413                    stringLookup.getStringLookup());
    414            }
    415        }
    416    }
    417
    418    /**
    419     * Returns the Base64DecoderStringLookup singleton instance to decode Base64 strings.
    420     * <p>
    421     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    422     * </p>
    423     *
    424     * <pre>
    425     * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE=");
    426     * </pre>
    427     * <p>
    428     * Using a {@link StringSubstitutor}:
    429     * </p>
    430     *
    431     * <pre>
    432     * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ..."));
    433     * </pre>
    434     * <p>
    435     * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}.
    436     * </p>
    437     *
    438     * @return The DateStringLookup singleton instance.
    439     * @since 1.5
    440     */
    441    public StringLookup base64DecoderStringLookup() {
    442        return StringLookupFactory.INSTANCE_BASE64_DECODER;
    443    }
    444
    445    /**
    446     * Returns the Base64EncoderStringLookup singleton instance to encode strings to Base64.
    447     * <p>
    448     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    449     * </p>
    450     *
    451     * <pre>
    452     * StringLookupFactory.INSTANCE.base64EncoderStringLookup().lookup("HelloWorld!");
    453     * </pre>
    454     * <p>
    455     * Using a {@link StringSubstitutor}:
    456     * </p>
    457     *
    458     * <pre>
    459     * StringSubstitutor.createInterpolator().replace("... ${base64Encoder:HelloWorld!} ..."));
    460     * </pre>
    461     * <p>
    462     * The above examples convert {@code } to {@code "SGVsbG9Xb3JsZCE="}.
    463     * </p>
    464     *
    465     * @return The DateStringLookup singleton instance.
    466     * @since 1.6
    467     */
    468    public StringLookup base64EncoderStringLookup() {
    469        return StringLookupFactory.INSTANCE_BASE64_ENCODER;
    470    }
    471
    472    /**
    473     * Returns the Base64DecoderStringLookup singleton instance to decode Base64 strings.
    474     * <p>
    475     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    476     * </p>
    477     *
    478     * <pre>
    479     * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE=");
    480     * </pre>
    481     * <p>
    482     * Using a {@link StringSubstitutor}:
    483     * </p>
    484     *
    485     * <pre>
    486     * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ..."));
    487     * </pre>
    488     * <p>
    489     * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}.
    490     * </p>
    491     *
    492     * @return The DateStringLookup singleton instance.
    493     * @since 1.5
    494     * @deprecated Use {@link #base64DecoderStringLookup()}.
    495     */
    496    @Deprecated
    497    public StringLookup base64StringLookup() {
    498        return StringLookupFactory.INSTANCE_BASE64_DECODER;
    499    }
    500
    501    /**
    502     * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a
    503     * lookup key.
    504     *
    505     * @param <R> the function return type.
    506     * @param <U> the function's second parameter type.
    507     * @param biFunction the function.
    508     * @return a new MapStringLookup.
    509     * @since 1.9
    510     */
    511    public <R, U> BiStringLookup<U> biFunctionStringLookup(final BiFunction<String, U, R> biFunction) {
    512        return BiFunctionStringLookup.on(biFunction);
    513    }
    514
    515    /**
    516     * Returns the ConstantStringLookup singleton instance to look up the value of a fully-qualified static final value.
    517     * <p>
    518     * Sometimes it is necessary in a configuration file to refer to a constant defined in a class. This can be done
    519     * with this lookup implementation. Variable names must be in the format {@code apackage.AClass.AFIELD}. The
    520     * {@code lookup(String)} method will split the passed in string at the last dot, separating the fully qualified
    521     * class name and the name of the constant (i.e. <b>static final</b>) member field. Then the class is loaded and the
    522     * field's value is obtained using reflection.
    523     * </p>
    524     * <p>
    525     * Once retrieved values are cached for fast access. This class is thread-safe. It can be used as a standard (i.e.
    526     * global) lookup object and serve multiple clients concurrently.
    527     * </p>
    528     * <p>
    529     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    530     * </p>
    531     *
    532     * <pre>
    533     * StringLookupFactory.INSTANCE.constantStringLookup().lookup("java.awt.event.KeyEvent.VK_ESCAPE");
    534     * </pre>
    535     * <p>
    536     * Using a {@link StringSubstitutor}:
    537     * </p>
    538     *
    539     * <pre>
    540     * StringSubstitutor.createInterpolator().replace("... ${const:java.awt.event.KeyEvent.VK_ESCAPE} ..."));
    541     * </pre>
    542     * <p>
    543     * The above examples convert {@code java.awt.event.KeyEvent.VK_ESCAPE} to {@code "27"}.
    544     * </p>
    545     *
    546     * @return The DateStringLookup singleton instance.
    547     * @since 1.5
    548     */
    549    public StringLookup constantStringLookup() {
    550        return ConstantStringLookup.INSTANCE;
    551    }
    552
    553    /**
    554     * Returns the DateStringLookup singleton instance to format the current date with the format given in the key in a
    555     * format compatible with {@link java.text.SimpleDateFormat}.
    556     * <p>
    557     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    558     * </p>
    559     *
    560     * <pre>
    561     * StringLookupFactory.INSTANCE.dateStringLookup().lookup("yyyy-MM-dd");
    562     * </pre>
    563     * <p>
    564     * Using a {@link StringSubstitutor}:
    565     * </p>
    566     *
    567     * <pre>
    568     * StringSubstitutor.createInterpolator().replace("... ${date:yyyy-MM-dd} ..."));
    569     * </pre>
    570     * <p>
    571     * The above examples convert {@code "yyyy-MM-dd"} to todays's date, for example, {@code "2019-08-04"}.
    572     * </p>
    573     *
    574     * @return The DateStringLookup singleton instance.
    575     */
    576    public StringLookup dateStringLookup() {
    577        return DateStringLookup.INSTANCE;
    578    }
    579
    580    /**
    581     * Returns the DnsStringLookup singleton instance where the lookup key is one of:
    582     * <ul>
    583     * <li><b>name</b>: for the local host name, for example {@code EXAMPLE} but also {@code EXAMPLE.apache.org}.</li>
    584     * <li><b>canonical-name</b>: for the local canonical host name, for example {@code EXAMPLE.apache.org}.</li>
    585     * <li><b>address</b>: for the local host address, for example {@code 192.168.56.1}.</li>
    586     * </ul>
    587     *
    588     * <p>
    589     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    590     * </p>
    591     *
    592     * <pre>
    593     * StringLookupFactory.INSTANCE.dnsStringLookup().lookup("address|apache.org");
    594     * </pre>
    595     * <p>
    596     * Using a {@link StringSubstitutor}:
    597     * </p>
    598     *
    599     * <pre>
    600     * StringSubstitutor.createInterpolator().replace("... ${dns:address|apache.org} ..."));
    601     * </pre>
    602     * <p>
    603     * The above examples convert {@code "address|apache.org"} to {@code "95.216.24.32} (or {@code "40.79.78.1"}).
    604     * </p>
    605     *
    606     * @return the DateStringLookup singleton instance.
    607     * @since 1.8
    608     */
    609    public StringLookup dnsStringLookup() {
    610        return DnsStringLookup.INSTANCE;
    611    }
    612
    613    /**
    614     * Returns the EnvironmentVariableStringLookup singleton instance where the lookup key is an environment variable
    615     * name.
    616     * <p>
    617     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    618     * </p>
    619     *
    620     * <pre>
    621     * StringLookupFactory.INSTANCE.dateStringLookup().lookup("USER");
    622     * </pre>
    623     * <p>
    624     * Using a {@link StringSubstitutor}:
    625     * </p>
    626     *
    627     * <pre>
    628     * StringSubstitutor.createInterpolator().replace("... ${env:USER} ..."));
    629     * </pre>
    630     * <p>
    631     * The above examples convert (on Linux) {@code "USER"} to the current user name. On Windows 10, you would use
    632     * {@code "USERNAME"} to the same effect.
    633     * </p>
    634     *
    635     * @return The EnvironmentVariableStringLookup singleton instance.
    636     */
    637    public StringLookup environmentVariableStringLookup() {
    638        return StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES;
    639    }
    640
    641    /**
    642     * Returns the FileStringLookup singleton instance.
    643     * <p>
    644     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    645     * </p>
    646     *
    647     * <pre>
    648     * StringLookupFactory.INSTANCE.fileStringLookup().lookup("UTF-8:com/domain/document.properties");
    649     * </pre>
    650     * <p>
    651     * Using a {@link StringSubstitutor}:
    652     * </p>
    653     *
    654     * <pre>
    655     * StringSubstitutor.createInterpolator().replace("... ${file:UTF-8:com/domain/document.properties} ..."));
    656     * </pre>
    657     * <p>
    658     * The above examples convert {@code "UTF-8:com/domain/document.properties"} to the contents of the file.
    659     * </p>
    660     *
    661     * @return The FileStringLookup singleton instance.
    662     * @since 1.5
    663     */
    664    public StringLookup fileStringLookup() {
    665        return FileStringLookup.INSTANCE;
    666    }
    667
    668    /**
    669     * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a
    670     * lookup key.
    671     *
    672     * @param <R> the function return type.
    673     * @param function the function.
    674     * @return a new MapStringLookup.
    675     * @since 1.9
    676     */
    677    public <R> StringLookup functionStringLookup(final Function<String, R> function) {
    678        return FunctionStringLookup.on(function);
    679    }
    680
    681    /**
    682     * Returns a new InterpolatorStringLookup using the {@link StringLookupFactory default lookups}.
    683     * <p>
    684     * The lookups available to an interpolator are defined in
    685     * </p>
    686     * <p>
    687     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    688     * </p>
    689     *
    690     * <pre>
    691     * StringLookupFactory.INSTANCE.interpolatorStringLookup().lookup("${sys:os.name}, ${env:USER}");
    692     * </pre>
    693     * <p>
    694     * Using a {@link StringSubstitutor}:
    695     * </p>
    696     *
    697     * <pre>
    698     * StringSubstitutor.createInterpolator().replace("... ${sys:os.name}, ${env:USER} ..."));
    699     * </pre>
    700     * <p>
    701     * The above examples convert {@code "${sys:os.name}, ${env:USER}"} to the OS name and Linux user name.
    702     * </p>
    703     *
    704     * @return a new InterpolatorStringLookup.
    705     */
    706    public StringLookup interpolatorStringLookup() {
    707        return InterpolatorStringLookup.INSTANCE;
    708    }
    709
    710    /**
    711     * Returns a new InterpolatorStringLookup using the {@link StringLookupFactory default lookups}.
    712     * <p>
    713     * If {@code addDefaultLookups} is true, the following lookups are used in addition to the ones provided in
    714     * {@code stringLookupMap}:
    715     * </p>
    716     *
    717     * @param stringLookupMap the map of string lookups.
    718     * @param defaultStringLookup the default string lookup.
    719     * @param addDefaultLookups whether to use lookups as described above.
    720     * @return a new InterpolatorStringLookup.
    721     * @since 1.4
    722     */
    723    public StringLookup interpolatorStringLookup(final Map<String, StringLookup> stringLookupMap,
    724        final StringLookup defaultStringLookup, final boolean addDefaultLookups) {
    725        return new InterpolatorStringLookup(stringLookupMap, defaultStringLookup, addDefaultLookups);
    726    }
    727
    728    /**
    729     * Returns a new InterpolatorStringLookup using the {@link StringLookupFactory default lookups}.
    730     *
    731     * @param <V> the value type the default string lookup's map.
    732     * @param map the default map for string lookups.
    733     * @return a new InterpolatorStringLookup.
    734     */
    735    public <V> StringLookup interpolatorStringLookup(final Map<String, V> map) {
    736        return new InterpolatorStringLookup(map);
    737    }
    738
    739    /**
    740     * Returns a new InterpolatorStringLookup using the {@link StringLookupFactory default lookups}.
    741     *
    742     * @param defaultStringLookup the default string lookup.
    743     * @return a new InterpolatorStringLookup.
    744     */
    745    public StringLookup interpolatorStringLookup(final StringLookup defaultStringLookup) {
    746        return new InterpolatorStringLookup(defaultStringLookup);
    747    }
    748
    749    /**
    750     * Returns the JavaPlatformStringLookup singleton instance. Looks up keys related to Java: Java version, JRE
    751     * version, VM version, and so on.
    752     * <p>
    753     * The lookup keys with examples are:
    754     * </p>
    755     * <ul>
    756     * <li><b>version</b>: "Java version 1.8.0_181"</li>
    757     * <li><b>runtime</b>: "Java(TM) SE Runtime Environment (build 1.8.0_181-b13) from Oracle Corporation"</li>
    758     * <li><b>vm</b>: "Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)"</li>
    759     * <li><b>os</b>: "Windows 10 10.0, architecture: amd64-64"</li>
    760     * <li><b>hardware</b>: "processors: 4, architecture: amd64-64, instruction sets: amd64"</li>
    761     * <li><b>locale</b>: "default locale: en_US, platform encoding: iso-8859-1"</li>
    762     * </ul>
    763     *
    764     * <p>
    765     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    766     * </p>
    767     *
    768     * <pre>
    769     * StringLookupFactory.INSTANCE.javaPlatformStringLookup().lookup("version");
    770     * </pre>
    771     * <p>
    772     * Using a {@link StringSubstitutor}:
    773     * </p>
    774     *
    775     * <pre>
    776     * StringSubstitutor.createInterpolator().replace("... ${java:version} ..."));
    777     * </pre>
    778     * <p>
    779     * The above examples convert {@code "version"} to the current VM version, for example,
    780     * {@code "Java version 1.8.0_181"}.
    781     * </p>
    782     *
    783     * @return The JavaPlatformStringLookup singleton instance.
    784     */
    785    public StringLookup javaPlatformStringLookup() {
    786        return JavaPlatformStringLookup.INSTANCE;
    787    }
    788
    789    /**
    790     * Returns the LocalHostStringLookup singleton instance where the lookup key is one of:
    791     * <ul>
    792     * <li><b>name</b>: for the local host name, for example {@code EXAMPLE}.</li>
    793     * <li><b>canonical-name</b>: for the local canonical host name, for example {@code EXAMPLE.apache.org}.</li>
    794     * <li><b>address</b>: for the local host address, for example {@code 192.168.56.1}.</li>
    795     * </ul>
    796     *
    797     * <p>
    798     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    799     * </p>
    800     *
    801     * <pre>
    802     * StringLookupFactory.INSTANCE.localHostStringLookup().lookup("canonical-name");
    803     * </pre>
    804     * <p>
    805     * Using a {@link StringSubstitutor}:
    806     * </p>
    807     *
    808     * <pre>
    809     * StringSubstitutor.createInterpolator().replace("... ${localhost:canonical-name} ..."));
    810     * </pre>
    811     * <p>
    812     * The above examples convert {@code "canonical-name"} to the current host name, for example,
    813     * {@code "EXAMPLE.apache.org"}.
    814     * </p>
    815     *
    816     * @return The DateStringLookup singleton instance.
    817     */
    818    public StringLookup localHostStringLookup() {
    819        return LocalHostStringLookup.INSTANCE;
    820    }
    821
    822    /**
    823     * Returns a new map-based lookup where the request for a lookup is answered with the value for that key.
    824     *
    825     * @param <V> the map value type.
    826     * @param map the map.
    827     * @return a new MapStringLookup.
    828     */
    829    public <V> StringLookup mapStringLookup(final Map<String, V> map) {
    830        return FunctionStringLookup.on(map);
    831    }
    832
    833    /**
    834     * Returns the NullStringLookup singleton instance which always returns null.
    835     *
    836     * @return The NullStringLookup singleton instance.
    837     */
    838    public StringLookup nullStringLookup() {
    839        return StringLookupFactory.INSTANCE_NULL;
    840    }
    841
    842    /**
    843     * Returns the PropertiesStringLookup singleton instance.
    844     * <p>
    845     * Looks up the value for the key in the format "DocumentPath::MyKey".
    846     * </p>
    847     * <p>
    848     * Note the use of "::" instead of ":" to allow for "C:" drive letters in paths.
    849     * </p>
    850     * <p>
    851     * For example: "com/domain/document.properties::MyKey".
    852     * </p>
    853     *
    854     * <p>
    855     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    856     * </p>
    857     *
    858     * <pre>
    859     * StringLookupFactory.INSTANCE.propertiesStringLookup().lookup("com/domain/document.properties::MyKey");
    860     * </pre>
    861     * <p>
    862     * Using a {@link StringSubstitutor}:
    863     * </p>
    864     *
    865     * <pre>
    866     * StringSubstitutor.createInterpolator().replace("... ${properties:com/domain/document.properties::MyKey} ..."));
    867     * </pre>
    868     * <p>
    869     * The above examples convert {@code "com/domain/document.properties::MyKey"} to the key value in the properties
    870     * file at the path "com/domain/document.properties".
    871     * </p>
    872     *
    873     * @return The PropertiesStringLookup singleton instance.
    874     * @since 1.5
    875     */
    876    public StringLookup propertiesStringLookup() {
    877        return PropertiesStringLookup.INSTANCE;
    878    }
    879
    880    /**
    881     * Returns the ResourceBundleStringLookup singleton instance.
    882     * <p>
    883     * Looks up the value for a given key in the format "BundleName:BundleKey".
    884     * </p>
    885     * <p>
    886     * For example: "com.domain.messages:MyKey".
    887     * </p>
    888     * <p>
    889     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    890     * </p>
    891     *
    892     * <pre>
    893     * StringLookupFactory.INSTANCE.resourceBundleStringLookup().lookup("com.domain.messages:MyKey");
    894     * </pre>
    895     * <p>
    896     * Using a {@link StringSubstitutor}:
    897     * </p>
    898     *
    899     * <pre>
    900     * StringSubstitutor.createInterpolator().replace("... ${resourceBundle:com.domain.messages:MyKey} ..."));
    901     * </pre>
    902     * <p>
    903     * The above examples convert {@code "com.domain.messages:MyKey"} to the key value in the resource bundle at
    904     * {@code "com.domain.messages"}.
    905     * </p>
    906     *
    907     * @return The ResourceBundleStringLookup singleton instance.
    908     */
    909    public StringLookup resourceBundleStringLookup() {
    910        return ResourceBundleStringLookup.INSTANCE;
    911    }
    912
    913    /**
    914     * Returns a ResourceBundleStringLookup instance for the given bundle name.
    915     * <p>
    916     * Looks up the value for a given key in the format "MyKey".
    917     * </p>
    918     * <p>
    919     * For example: "MyKey".
    920     * </p>
    921     * <p>
    922     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    923     * </p>
    924     *
    925     * <pre>
    926     * StringLookupFactory.INSTANCE.resourceBundleStringLookup("com.domain.messages").lookup("MyKey");
    927     * </pre>
    928     * <p>
    929     * The above example converts {@code "MyKey"} to the key value in the resource bundle at
    930     * {@code "com.domain.messages"}.
    931     * </p>
    932     *
    933     * @param bundleName Only lookup in this bundle.
    934     * @return a ResourceBundleStringLookup instance for the given bundle name.
    935     * @since 1.5
    936     */
    937    public StringLookup resourceBundleStringLookup(final String bundleName) {
    938        return new ResourceBundleStringLookup(bundleName);
    939    }
    940
    941    /**
    942     * Returns the ScriptStringLookup singleton instance.
    943     * <p>
    944     * Looks up the value for the key in the format "ScriptEngineName:Script".
    945     * </p>
    946     * <p>
    947     * For example: "javascript:3 + 4".
    948     * </p>
    949     * <p>
    950     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    951     * </p>
    952     *
    953     * <pre>
    954     * StringLookupFactory.INSTANCE.scriptStringLookup().lookup("javascript:3 + 4");
    955     * </pre>
    956     * <p>
    957     * Using a {@link StringSubstitutor}:
    958     * </p>
    959     *
    960     * <pre>
    961     * StringSubstitutor.createInterpolator().replace("... ${javascript:3 + 4} ..."));
    962     * </pre>
    963     * <p>
    964     * The above examples convert {@code "javascript:3 + 4"} to {@code "7"}.
    965     * </p>
    966     *
    967     * @return The ScriptStringLookup singleton instance.
    968     * @since 1.5
    969     */
    970    public StringLookup scriptStringLookup() {
    971        return ScriptStringLookup.INSTANCE;
    972    }
    973
    974    /**
    975     * Returns the SystemPropertyStringLookup singleton instance where the lookup key is a system property name.
    976     *
    977     * <p>
    978     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    979     * </p>
    980     *
    981     * <pre>
    982     * StringLookupFactory.INSTANCE.systemPropertyStringLookup().lookup("os.name");
    983     * </pre>
    984     * <p>
    985     * Using a {@link StringSubstitutor}:
    986     * </p>
    987     *
    988     * <pre>
    989     * StringSubstitutor.createInterpolator().replace("... ${sys:os.name} ..."));
    990     * </pre>
    991     * <p>
    992     * The above examples convert {@code "os.name"} to the operating system name.
    993     * </p>
    994     *
    995     * @return The SystemPropertyStringLookup singleton instance.
    996     */
    997    public StringLookup systemPropertyStringLookup() {
    998        return StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES;
    999    }
    1000
    1001    /**
    1002     * Returns the UrlDecoderStringLookup singleton instance.
    1003     * <p>
    1004     * Decodes URL Strings using the UTF-8 encoding.
    1005     * </p>
    1006     * <p>
    1007     * For example: "Hello%20World%21" becomes "Hello World!".
    1008     * </p>
    1009     * <p>
    1010     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    1011     * </p>
    1012     *
    1013     * <pre>
    1014     * StringLookupFactory.INSTANCE.urlDecoderStringLookup().lookup("Hello%20World%21");
    1015     * </pre>
    1016     * <p>
    1017     * Using a {@link StringSubstitutor}:
    1018     * </p>
    1019     *
    1020     * <pre>
    1021     * StringSubstitutor.createInterpolator().replace("... ${urlDecoder:Hello%20World%21} ..."));
    1022     * </pre>
    1023     * <p>
    1024     * The above examples convert {@code "Hello%20World%21"} to {@code "Hello World!"}.
    1025     * </p>
    1026     *
    1027     * @return The UrlStringLookup singleton instance.
    1028     * @since 1.6
    1029     */
    1030    public StringLookup urlDecoderStringLookup() {
    1031        return UrlDecoderStringLookup.INSTANCE;
    1032    }
    1033
    1034    /**
    1035     * Returns the UrlDecoderStringLookup singleton instance.
    1036     * <p>
    1037     * Decodes URL Strings using the UTF-8 encoding.
    1038     * </p>
    1039     * <p>
    1040     * For example: "Hello World!" becomes "Hello+World%21".
    1041     * </p>
    1042     * <p>
    1043     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    1044     * </p>
    1045     *
    1046     * <pre>
    1047     * StringLookupFactory.INSTANCE.urlEncoderStringLookup().lookup("Hello World!");
    1048     * </pre>
    1049     * <p>
    1050     * Using a {@link StringSubstitutor}:
    1051     * </p>
    1052     *
    1053     * <pre>
    1054     * StringSubstitutor.createInterpolator().replace("... ${urlEncoder:Hello World!} ..."));
    1055     * </pre>
    1056     * <p>
    1057     * The above examples convert {@code "Hello World!"} to {@code "Hello%20World%21"}.
    1058     * </p>
    1059     *
    1060     * @return The UrlStringLookup singleton instance.
    1061     * @since 1.6
    1062     */
    1063    public StringLookup urlEncoderStringLookup() {
    1064        return UrlEncoderStringLookup.INSTANCE;
    1065    }
    1066
    1067    /**
    1068     * Returns the UrlStringLookup singleton instance.
    1069     * <p>
    1070     * Looks up the value for the key in the format "CharsetName:URL".
    1071     * </p>
    1072     * <p>
    1073     * For example, using the HTTP scheme: "UTF-8:http://www.google.com"
    1074     * </p>
    1075     * <p>
    1076     * For example, using the file scheme:
    1077     * "UTF-8:file:///C:/somehome/commons/commons-text/src/test/resources/document.properties"
    1078     * </p>
    1079     * <p>
    1080     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    1081     * </p>
    1082     *
    1083     * <pre>
    1084     * StringLookupFactory.INSTANCE.urlStringLookup().lookup("UTF-8:https://www.apache.org");
    1085     * </pre>
    1086     * <p>
    1087     * Using a {@link StringSubstitutor}:
    1088     * </p>
    1089     *
    1090     * <pre>
    1091     * StringSubstitutor.createInterpolator().replace("... ${url:UTF-8:https://www.apache.org} ..."));
    1092     * </pre>
    1093     * <p>
    1094     * The above examples convert {@code "UTF-8:https://www.apache.org"} to the contents of that page.
    1095     * </p>
    1096     *
    1097     * @return The UrlStringLookup singleton instance.
    1098     * @since 1.5
    1099     */
    1100    public StringLookup urlStringLookup() {
    1101        return UrlStringLookup.INSTANCE;
    1102    }
    1103
    1104    /**
    1105     * Returns the XmlStringLookup singleton instance.
    1106     * <p>
    1107     * Looks up the value for the key in the format "DocumentPath:XPath".
    1108     * </p>
    1109     * <p>
    1110     * For example: "com/domain/document.xml:/path/to/node".
    1111     * </p>
    1112     * <p>
    1113     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
    1114     * </p>
    1115     *
    1116     * <pre>
    1117     * StringLookupFactory.INSTANCE.xmlStringLookup().lookup("com/domain/document.xml:/path/to/node");
    1118     * </pre>
    1119     * <p>
    1120     * Using a {@link StringSubstitutor}:
    1121     * </p>
    1122     *
    1123     * <pre>
    1124     * StringSubstitutor.createInterpolator().replace("... ${xml:com/domain/document.xml:/path/to/node} ..."));
    1125     * </pre>
    1126     * <p>
    1127     * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML
    1128     * document.
    1129     * </p>
    1130     *
    1131     * @return The XmlStringLookup singleton instance.
    1132     * @since 1.5
    1133     */
    1134    public StringLookup xmlStringLookup() {
    1135        return XmlStringLookup.INSTANCE;
    1136    }
    1137
    1138}