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}