1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache license, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the license for the specific language governing permissions and 15 * limitations under the license. 16 */ 17 18 package org.apache.commons.text.lookup; 19 20 import java.nio.charset.StandardCharsets; 21 import java.util.Base64; 22 import java.util.Collections; 23 import java.util.HashMap; 24 import java.util.Locale; 25 import java.util.Map; 26 import java.util.Properties; 27 import java.util.function.BiFunction; 28 import java.util.function.Function; 29 30 import javax.xml.xpath.XPathFactory; 31 32 import org.apache.commons.text.StringSubstitutor; 33 34 /** 35 * Create instances of string lookups or access singleton string lookups implemented in this package. 36 * <p> 37 * The "classic" look up is {@link #mapStringLookup(Map)}. 38 * </p> 39 * <p> 40 * The methods for variable interpolation (A.K.A. variable substitution) are: 41 * </p> 42 * <ul> 43 * <li>{@link #interpolatorStringLookup()}.</li> 44 * <li>{@link #interpolatorStringLookup(Map)}.</li> 45 * <li>{@link #interpolatorStringLookup(StringLookup)}.</li> 46 * <li>{@link #interpolatorStringLookup(Map, StringLookup, boolean)}.</li> 47 * </ul> 48 * <p> 49 * Unless explicitly requested otherwise, a set of default lookups are included for convenience with these 50 * variable interpolation methods. These defaults are listed in the table below. However, the exact lookups 51 * included can be configured through the use of the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property. 52 * If present, this system property will be parsed as a comma-separated list of lookup names, with the names 53 * being those defined by the {@link DefaultStringLookup} enum. For example, setting this system property to 54 * {@code "BASE64_ENCODER,ENVIRONMENT"} will only include the 55 * {@link DefaultStringLookup#BASE64_ENCODER BASE64_ENCODER} and {@link DefaultStringLookup#ENVIRONMENT ENVIRONMENT} 56 * lookups. Setting the property to the empty string will cause no defaults to be configured. 57 * Note that not all lookups defined here and in {@link DefaultStringLookup} are included by default. 58 * Specifically, lookups that can execute code (e.g., {@link DefaultStringLookup#SCRIPT SCRIPT}) and those 59 * that can result in contact with remote servers (e.g., {@link DefaultStringLookup#URL URL} and 60 * {@link DefaultStringLookup#DNS DNS}) are not included by default. The current set of default lookups can 61 * be accessed directly with {@link #addDefaultStringLookups(Map)}. 62 * </p> 63 * <table> 64 * <caption>Default String Lookups</caption> 65 * <tr> 66 * <th>Key</th> 67 * <th>Interface</th> 68 * <th>Factory Method</th> 69 * <th>Since</th> 70 * </tr> 71 * <tr> 72 * <td>{@value #KEY_BASE64_DECODER}</td> 73 * <td>{@link StringLookup}</td> 74 * <td>{@link #base64DecoderStringLookup()}</td> 75 * <td>1.6</td> 76 * </tr> 77 * <tr> 78 * <td>{@value #KEY_BASE64_ENCODER}</td> 79 * <td>{@link StringLookup}</td> 80 * <td>{@link #base64EncoderStringLookup()}</td> 81 * <td>1.6</td> 82 * </tr> 83 * <tr> 84 * <td>{@value #KEY_CONST}</td> 85 * <td>{@link StringLookup}</td> 86 * <td>{@link #constantStringLookup()}</td> 87 * <td>1.5</td> 88 * </tr> 89 * <tr> 90 * <td>{@value #KEY_DATE}</td> 91 * <td>{@link StringLookup}</td> 92 * <td>{@link #dateStringLookup()}</td> 93 * <td>1.5</td> 94 * </tr> 95 * <tr> 96 * <td>{@value #KEY_ENV}</td> 97 * <td>{@link StringLookup}</td> 98 * <td>{@link #environmentVariableStringLookup()}</td> 99 * <td>1.3</td> 100 * </tr> 101 * <tr> 102 * <td>{@value #KEY_FILE}</td> 103 * <td>{@link StringLookup}</td> 104 * <td>{@link #fileStringLookup()}</td> 105 * <td>1.5</td> 106 * </tr> 107 * <tr> 108 * <td>{@value #KEY_JAVA}</td> 109 * <td>{@link StringLookup}</td> 110 * <td>{@link #javaPlatformStringLookup()}</td> 111 * <td>1.5</td> 112 * </tr> 113 * <tr> 114 * <td>{@value #KEY_LOCALHOST}</td> 115 * <td>{@link StringLookup}</td> 116 * <td>{@link #localHostStringLookup()}</td> 117 * <td>1.3</td> 118 * </tr> 119 * <tr> 120 * <td>{@value #KEY_PROPERTIES}</td> 121 * <td>{@link StringLookup}</td> 122 * <td>{@link #propertiesStringLookup()}</td> 123 * <td>1.5</td> 124 * </tr> 125 * <tr> 126 * <td>{@value #KEY_RESOURCE_BUNDLE}</td> 127 * <td>{@link StringLookup}</td> 128 * <td>{@link #resourceBundleStringLookup()}</td> 129 * <td>1.6</td> 130 * </tr> 131 * <tr> 132 * <td>{@value #KEY_SYS}</td> 133 * <td>{@link StringLookup}</td> 134 * <td>{@link #systemPropertyStringLookup()}</td> 135 * <td>1.3</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 * <tr> 156 * <td>{@value #KEY_XML_DECODER}</td> 157 * <td>{@link StringLookup}</td> 158 * <td>{@link #xmlDecoderStringLookup()}</td> 159 * <td>1.11.0</td> 160 * </tr> 161 * <tr> 162 * <td>{@value #KEY_XML_ENCODER}</td> 163 * <td>{@link StringLookup}</td> 164 * <td>{@link #xmlEncoderStringLookup()}</td> 165 * <td>1.11.0</td> 166 * </tr> 167 * </table> 168 * 169 * <table> 170 * <caption>Additional String Lookups (not included by default)</caption> 171 * <tr> 172 * <th>Key</th> 173 * <th>Interface</th> 174 * <th>Factory Method</th> 175 * <th>Since</th> 176 * </tr> 177 * <tr> 178 * <td>{@value #KEY_DNS}</td> 179 * <td>{@link StringLookup}</td> 180 * <td>{@link #dnsStringLookup()}</td> 181 * <td>1.8</td> 182 * </tr> 183 * <tr> 184 * <td>{@value #KEY_URL}</td> 185 * <td>{@link StringLookup}</td> 186 * <td>{@link #urlStringLookup()}</td> 187 * <td>1.5</td> 188 * </tr> 189 * <tr> 190 * <td>{@value #KEY_SCRIPT}</td> 191 * <td>{@link StringLookup}</td> 192 * <td>{@link #scriptStringLookup()}</td> 193 * <td>1.5</td> 194 * </tr> 195 * </table> 196 * 197 * <p> 198 * This class also provides functional lookups used as building blocks for other lookups. 199 * <table> 200 * <caption>Functional String Lookups</caption> 201 * <tr> 202 * <th>Interface</th> 203 * <th>Factory Method</th> 204 * <th>Since</th> 205 * </tr> 206 * <tr> 207 * <td>{@link BiStringLookup}</td> 208 * <td>{@link #biFunctionStringLookup(BiFunction)}</td> 209 * <td>1.9</td> 210 * </tr> 211 * <tr> 212 * <td>{@link StringLookup}</td> 213 * <td>{@link #functionStringLookup(Function)}</td> 214 * <td>1.9</td> 215 * </tr> 216 * </table> 217 * 218 * @since 1.3 219 */ 220 public final class StringLookupFactory { 221 222 /** 223 * Internal class used to construct the default {@link StringLookup} map used by 224 * {@link StringLookupFactory#addDefaultStringLookups(Map)}. 225 */ 226 static final class DefaultStringLookupsHolder { 227 228 /** Singleton instance, initialized with the system properties. */ 229 static final DefaultStringLookupsHolder INSTANCE = new DefaultStringLookupsHolder(System.getProperties()); 230 231 /** 232 * Add the key and string lookup from {@code lookup} to {@code map}, also adding any additional 233 * key aliases if needed. Keys are normalized using the {@link #toKey(String)} method. 234 * @param lookup lookup to add 235 * @param map map to add to 236 */ 237 private static void addLookup(final DefaultStringLookup lookup, final Map<String, StringLookup> map) { 238 map.put(toKey(lookup.getKey()), lookup.getStringLookup()); 239 240 if (DefaultStringLookup.BASE64_DECODER.equals(lookup)) { 241 // "base64" is deprecated in favor of KEY_BASE64_DECODER. 242 map.put(toKey("base64"), lookup.getStringLookup()); 243 } 244 } 245 246 /** 247 * Create the lookup map used when the user has requested no customization. 248 * @return default lookup map 249 */ 250 private static Map<String, StringLookup> createDefaultStringLookups() { 251 final Map<String, StringLookup> lookupMap = new HashMap<>(); 252 253 addLookup(DefaultStringLookup.BASE64_DECODER, lookupMap); 254 addLookup(DefaultStringLookup.BASE64_ENCODER, lookupMap); 255 addLookup(DefaultStringLookup.CONST, lookupMap); 256 addLookup(DefaultStringLookup.DATE, lookupMap); 257 addLookup(DefaultStringLookup.ENVIRONMENT, lookupMap); 258 addLookup(DefaultStringLookup.FILE, lookupMap); 259 addLookup(DefaultStringLookup.JAVA, lookupMap); 260 addLookup(DefaultStringLookup.LOCAL_HOST, lookupMap); 261 addLookup(DefaultStringLookup.PROPERTIES, lookupMap); 262 addLookup(DefaultStringLookup.RESOURCE_BUNDLE, lookupMap); 263 addLookup(DefaultStringLookup.SYSTEM_PROPERTIES, lookupMap); 264 addLookup(DefaultStringLookup.URL_DECODER, lookupMap); 265 addLookup(DefaultStringLookup.URL_ENCODER, lookupMap); 266 addLookup(DefaultStringLookup.XML, lookupMap); 267 addLookup(DefaultStringLookup.XML_DECODER, lookupMap); 268 addLookup(DefaultStringLookup.XML_ENCODER, lookupMap); 269 270 return lookupMap; 271 } 272 273 /** 274 * Construct a lookup map by parsing the given string. The string is expected to contain 275 * comma or space-separated names of values from the {@link DefaultStringLookup} enum. If 276 * the given string is null or empty, an empty map is returned. 277 * @param str string to parse; may be null or empty 278 * @return lookup map parsed from the given string 279 */ 280 private static Map<String, StringLookup> parseStringLookups(final String str) { 281 final Map<String, StringLookup> lookupMap = new HashMap<>(); 282 283 try { 284 for (final String lookupName : str.split("[\\s,]+")) { 285 if (!lookupName.isEmpty()) { 286 addLookup(DefaultStringLookup.valueOf(lookupName.toUpperCase()), lookupMap); 287 } 288 } 289 } catch (IllegalArgumentException exc) { 290 throw new IllegalArgumentException("Invalid default string lookups definition: " + str, exc); 291 } 292 293 return lookupMap; 294 } 295 296 /** Default string lookup map. */ 297 private final Map<String, StringLookup> defaultStringLookups; 298 299 /** 300 * Construct a new instance initialized with the given properties. 301 * @param props initialization properties 302 */ 303 DefaultStringLookupsHolder(final Properties props) { 304 final Map<String, StringLookup> lookups = 305 props.containsKey(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY) 306 ? parseStringLookups(props.getProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY)) 307 : createDefaultStringLookups(); 308 309 defaultStringLookups = Collections.unmodifiableMap(lookups); 310 } 311 312 /** 313 * Get the default string lookups map. 314 * @return default string lookups map 315 */ 316 Map<String, StringLookup> getDefaultStringLookups() { 317 return defaultStringLookups; 318 } 319 } 320 321 /** 322 * Defines the singleton for this class. 323 */ 324 public static final StringLookupFactory INSTANCE = new StringLookupFactory(); 325 326 /** 327 * Decodes Base64 Strings. 328 * <p> 329 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 330 * </p> 331 * 332 * <pre> 333 * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE="); 334 * </pre> 335 * <p> 336 * Using a {@link StringSubstitutor}: 337 * </p> 338 * 339 * <pre> 340 * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ...")); 341 * </pre> 342 * <p> 343 * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. 344 * </p> 345 */ 346 static final FunctionStringLookup<String> INSTANCE_BASE64_DECODER = FunctionStringLookup 347 .on(key -> new String(Base64.getDecoder().decode(key), StandardCharsets.ISO_8859_1)); 348 349 /** 350 * Encodes Base64 Strings. 351 * <p> 352 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 353 * </p> 354 * 355 * <pre> 356 * StringLookupFactory.INSTANCE.base64EncoderStringLookup().lookup("HelloWorld!"); 357 * </pre> 358 * <p> 359 * Using a {@link StringSubstitutor}: 360 * </p> 361 * 362 * <pre> 363 * StringSubstitutor.createInterpolator().replace("... ${base64Encoder:HelloWorld!} ...")); 364 * </pre> 365 * <p> 366 * The above examples convert {@code "HelloWorld!"} to {@code "SGVsbG9Xb3JsZCE="}. 367 * </p> 368 * Defines the singleton for this class. 369 */ 370 static final FunctionStringLookup<String> INSTANCE_BASE64_ENCODER = FunctionStringLookup 371 .on(key -> Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.ISO_8859_1))); 372 373 /** 374 * Looks up keys from environment variables. 375 * <p> 376 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 377 * </p> 378 * 379 * <pre> 380 * StringLookupFactory.INSTANCE.environmentVariableStringLookup().lookup("USER"); 381 * </pre> 382 * <p> 383 * Using a {@link StringSubstitutor}: 384 * </p> 385 * 386 * <pre> 387 * StringSubstitutor.createInterpolator().replace("... ${env:USER} ...")); 388 * </pre> 389 * <p> 390 * The above examples convert (on Linux) {@code "USER"} to the current user name. On Windows 10, you would use 391 * {@code "USERNAME"} to the same effect. 392 * </p> 393 */ 394 static final FunctionStringLookup<String> INSTANCE_ENVIRONMENT_VARIABLES = FunctionStringLookup.on(System::getenv); 395 396 /** 397 * Defines the FunctionStringLookup singleton that always returns null. 398 */ 399 static final FunctionStringLookup<String> INSTANCE_NULL = FunctionStringLookup.on(key -> null); 400 401 /** 402 * Defines the FunctionStringLookup singleton for looking up system properties. 403 */ 404 static final FunctionStringLookup<String> INSTANCE_SYSTEM_PROPERTIES = FunctionStringLookup.on(System::getProperty); 405 406 /** 407 * Default lookup key for interpolation {@value #KEY_BASE64_DECODER}. 408 * 409 * @since 1.6 410 */ 411 public static final String KEY_BASE64_DECODER = "base64Decoder"; 412 413 /** 414 * Default lookup key for interpolation {@value #KEY_BASE64_ENCODER}. 415 * 416 * @since 1.6 417 */ 418 public static final String KEY_BASE64_ENCODER = "base64Encoder"; 419 420 /** 421 * Default lookup key for interpolation {@value #KEY_CONST}. 422 * 423 * @since 1.6 424 */ 425 public static final String KEY_CONST = "const"; 426 427 /** 428 * Default lookup key for interpolation {@value #KEY_DATE}. 429 * 430 * @since 1.6 431 */ 432 public static final String KEY_DATE = "date"; 433 434 /** 435 * Default lookup key for interpolation {@value #KEY_DNS}. 436 * 437 * @since 1.8 438 */ 439 public static final String KEY_DNS = "dns"; 440 441 /** 442 * Default lookup key for interpolation {@value #KEY_ENV}. 443 * 444 * @since 1.6 445 */ 446 public static final String KEY_ENV = "env"; 447 448 /** 449 * Default lookup key for interpolation {@value #KEY_FILE}. 450 * 451 * @since 1.6 452 */ 453 public static final String KEY_FILE = "file"; 454 455 /** 456 * Default lookup key for interpolation {@value #KEY_JAVA}. 457 * 458 * @since 1.6 459 */ 460 public static final String KEY_JAVA = "java"; 461 462 /** 463 * Default lookup key for interpolation {@value #KEY_LOCALHOST}. 464 * 465 * @since 1.6 466 */ 467 public static final String KEY_LOCALHOST = "localhost"; 468 469 /** 470 * Default lookup key for interpolation {@value #KEY_PROPERTIES}. 471 * 472 * @since 1.6 473 */ 474 public static final String KEY_PROPERTIES = "properties"; 475 476 /** 477 * Default lookup key for interpolation {@value #KEY_RESOURCE_BUNDLE}. 478 * 479 * @since 1.6 480 */ 481 public static final String KEY_RESOURCE_BUNDLE = "resourceBundle"; 482 483 /** 484 * Default lookup key for interpolation {@value #KEY_SCRIPT}. 485 * 486 * @since 1.6 487 */ 488 public static final String KEY_SCRIPT = "script"; 489 490 /** 491 * Default lookup key for interpolation {@value #KEY_SYS}. 492 * 493 * @since 1.6 494 */ 495 public static final String KEY_SYS = "sys"; 496 497 /** 498 * Default lookup key for interpolation {@value #KEY_URL}. 499 * 500 * @since 1.6 501 */ 502 public static final String KEY_URL = "url"; 503 504 /** 505 * Default lookup key for interpolation {@value #KEY_URL_DECODER}. 506 * 507 * @since 1.6 508 */ 509 public static final String KEY_URL_DECODER = "urlDecoder"; 510 511 /** 512 * Default lookup key for interpolation {@value #KEY_URL_ENCODER}. 513 * 514 * @since 1.6 515 */ 516 public static final String KEY_URL_ENCODER = "urlEncoder"; 517 518 /** 519 * Default lookup key for interpolation {@value #KEY_XML}. 520 * 521 * @since 1.6 522 */ 523 public static final String KEY_XML = "xml"; 524 525 /** 526 * Default lookup key for interpolation {@value #KEY_XML_DECODER}. 527 * 528 * @since 1.11.0 529 */ 530 public static final String KEY_XML_DECODER = "xmlDecoder"; 531 532 /** 533 * Default lookup key for interpolation {@value #KEY_XML_ENCODER}. 534 * 535 * @since 1.11.0 536 */ 537 public static final String KEY_XML_ENCODER = "xmlEncoder"; 538 539 /** 540 * Name of the system property used to determine the string lookups added by the 541 * {@link #addDefaultStringLookups(Map)} method. Use of this property is only required 542 * in cases where the set of default lookups must be modified. (See the class documentation 543 * for details.) 544 * 545 * @since 1.10.0 546 */ 547 public static final String DEFAULT_STRING_LOOKUPS_PROPERTY = "org.apache.commons.text.lookup.StringLookupFactory.defaultStringLookups"; 548 549 /** 550 * Clears any static resources. 551 * 552 * @since 1.5 553 */ 554 public static void clear() { 555 ConstantStringLookup.clear(); 556 } 557 558 /** 559 * Get a string suitable for use as a key in the string lookup map. 560 * @param key string to convert to a string lookup map key 561 * @return string lookup map key 562 */ 563 static String toKey(final String key) { 564 return key.toLowerCase(Locale.ROOT); 565 } 566 567 /** 568 * Returns the given map if the input is non-null or an empty immutable map if the input is null. 569 * 570 * @param <K> the class of the map keys 571 * @param <V> the class of the map values 572 * @param map The map to test 573 * @return the given map if the input is non-null or an empty immutable map if the input is null. 574 */ 575 static <K, V> Map<K, V> toMap(final Map<K, V> map) { 576 return map == null ? Collections.emptyMap() : map; 577 } 578 579 /** 580 * No need to build instances for now. 581 */ 582 private StringLookupFactory() { 583 // empty 584 } 585 586 /** 587 * Adds the default string lookups for this class to {@code stringLookupMap}. The default string 588 * lookups are a set of built-in lookups added for convenience during string interpolation. The 589 * defaults may be configured using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property. 590 * See the class documentation for details and a list of lookups. 591 * 592 * @param stringLookupMap the map of string lookups to edit. 593 * @since 1.5 594 */ 595 public void addDefaultStringLookups(final Map<String, StringLookup> stringLookupMap) { 596 if (stringLookupMap != null) { 597 stringLookupMap.putAll(DefaultStringLookupsHolder.INSTANCE.getDefaultStringLookups()); 598 } 599 } 600 601 /** 602 * Returns the Base64DecoderStringLookup singleton instance to decode Base64 strings. 603 * <p> 604 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 605 * </p> 606 * 607 * <pre> 608 * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE="); 609 * </pre> 610 * <p> 611 * Using a {@link StringSubstitutor}: 612 * </p> 613 * 614 * <pre> 615 * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ...")); 616 * </pre> 617 * <p> 618 * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. 619 * </p> 620 * 621 * @return The Base64DecoderStringLookup singleton instance. 622 * @since 1.5 623 */ 624 public StringLookup base64DecoderStringLookup() { 625 return StringLookupFactory.INSTANCE_BASE64_DECODER; 626 } 627 628 /** 629 * Returns the Base64EncoderStringLookup singleton instance to encode strings to Base64. 630 * <p> 631 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 632 * </p> 633 * 634 * <pre> 635 * StringLookupFactory.INSTANCE.base64EncoderStringLookup().lookup("HelloWorld!"); 636 * </pre> 637 * <p> 638 * Using a {@link StringSubstitutor}: 639 * </p> 640 * 641 * <pre> 642 * StringSubstitutor.createInterpolator().replace("... ${base64Encoder:HelloWorld!} ...")); 643 * </pre> 644 * <p> 645 * The above examples convert {@code } to {@code "SGVsbG9Xb3JsZCE="}. 646 * </p> 647 * 648 * @return The Base64EncoderStringLookup singleton instance. 649 * @since 1.6 650 */ 651 public StringLookup base64EncoderStringLookup() { 652 return StringLookupFactory.INSTANCE_BASE64_ENCODER; 653 } 654 655 /** 656 * Returns the Base64DecoderStringLookup singleton instance to decode Base64 strings. 657 * <p> 658 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 659 * </p> 660 * 661 * <pre> 662 * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE="); 663 * </pre> 664 * <p> 665 * Using a {@link StringSubstitutor}: 666 * </p> 667 * 668 * <pre> 669 * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ...")); 670 * </pre> 671 * <p> 672 * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. 673 * </p> 674 * 675 * @return The Base64DecoderStringLookup singleton instance. 676 * @since 1.5 677 * @deprecated Use {@link #base64DecoderStringLookup()}. 678 */ 679 @Deprecated 680 public StringLookup base64StringLookup() { 681 return StringLookupFactory.INSTANCE_BASE64_DECODER; 682 } 683 684 /** 685 * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a 686 * lookup key. 687 * 688 * @param <R> the function return type. 689 * @param <U> the function's second parameter type. 690 * @param biFunction the function. 691 * @return a new MapStringLookup. 692 * @since 1.9 693 */ 694 public <R, U> BiStringLookup<U> biFunctionStringLookup(final BiFunction<String, U, R> biFunction) { 695 return BiFunctionStringLookup.on(biFunction); 696 } 697 698 /** 699 * Returns the ConstantStringLookup singleton instance to look up the value of a fully-qualified static final value. 700 * <p> 701 * Sometimes it is necessary in a configuration file to refer to a constant defined in a class. This can be done 702 * with this lookup implementation. Variable names must be in the format {@code apackage.AClass.AFIELD}. The 703 * {@code lookup(String)} method will split the passed in string at the last dot, separating the fully qualified 704 * class name and the name of the constant (i.e. <b>static final</b>) member field. Then the class is loaded and the 705 * field's value is obtained using reflection. 706 * </p> 707 * <p> 708 * Once retrieved values are cached for fast access. This class is thread-safe. It can be used as a standard (i.e. 709 * global) lookup object and serve multiple clients concurrently. 710 * </p> 711 * <p> 712 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 713 * </p> 714 * 715 * <pre> 716 * StringLookupFactory.INSTANCE.constantStringLookup().lookup("java.awt.event.KeyEvent.VK_ESCAPE"); 717 * </pre> 718 * <p> 719 * Using a {@link StringSubstitutor}: 720 * </p> 721 * 722 * <pre> 723 * StringSubstitutor.createInterpolator().replace("... ${const:java.awt.event.KeyEvent.VK_ESCAPE} ...")); 724 * </pre> 725 * <p> 726 * The above examples convert {@code java.awt.event.KeyEvent.VK_ESCAPE} to {@code "27"}. 727 * </p> 728 * 729 * @return The ConstantStringLookup singleton instance. 730 * @since 1.5 731 */ 732 public StringLookup constantStringLookup() { 733 return ConstantStringLookup.INSTANCE; 734 } 735 736 /** 737 * Returns the DateStringLookup singleton instance to format the current date with the format given in the key in a 738 * format compatible with {@link java.text.SimpleDateFormat}. 739 * <p> 740 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 741 * </p> 742 * 743 * <pre> 744 * StringLookupFactory.INSTANCE.dateStringLookup().lookup("yyyy-MM-dd"); 745 * </pre> 746 * <p> 747 * Using a {@link StringSubstitutor}: 748 * </p> 749 * 750 * <pre> 751 * StringSubstitutor.createInterpolator().replace("... ${date:yyyy-MM-dd} ...")); 752 * </pre> 753 * <p> 754 * The above examples convert {@code "yyyy-MM-dd"} to todays's date, for example, {@code "2019-08-04"}. 755 * </p> 756 * 757 * @return The DateStringLookup singleton instance. 758 */ 759 public StringLookup dateStringLookup() { 760 return DateStringLookup.INSTANCE; 761 } 762 763 /** 764 * Returns the DnsStringLookup singleton instance where the lookup key is one of: 765 * <ul> 766 * <li><b>name</b>: for the local host name, for example {@code EXAMPLE} but also {@code EXAMPLE.apache.org}.</li> 767 * <li><b>canonical-name</b>: for the local canonical host name, for example {@code EXAMPLE.apache.org}.</li> 768 * <li><b>address</b>: for the local host address, for example {@code 192.168.56.1}.</li> 769 * </ul> 770 * 771 * <p> 772 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 773 * </p> 774 * 775 * <pre> 776 * StringLookupFactory.INSTANCE.dnsStringLookup().lookup("address|apache.org"); 777 * </pre> 778 * <p> 779 * When used through a {@link StringSubstitutor}, this lookup must either be added programmatically 780 * (as below) or enabled as a default lookup using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property 781 * (see class documentation). 782 * </p> 783 * 784 * <pre> 785 * Map<String, StringLookup> lookupMap = new HashMap<>(); 786 * lookupMap.put("dns", StringLookupFactory.INSTANCE.dnsStringLookup()); 787 * 788 * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false); 789 * 790 * new StringSubstitutor(variableResolver).replace("... ${dns:address|apache.org} ..."); 791 * </pre> 792 * <p> 793 * The above examples convert {@code "address|apache.org"} to the IP address of {@code apache.org}. 794 * </p> 795 * 796 * @return the DnsStringLookup singleton instance. 797 * @since 1.8 798 */ 799 public StringLookup dnsStringLookup() { 800 return DnsStringLookup.INSTANCE; 801 } 802 803 /** 804 * Returns the EnvironmentVariableStringLookup singleton instance where the lookup key is an environment variable 805 * name. 806 * <p> 807 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 808 * </p> 809 * 810 * <pre> 811 * StringLookupFactory.INSTANCE.environmentVariableStringLookup().lookup("USER"); 812 * </pre> 813 * <p> 814 * Using a {@link StringSubstitutor}: 815 * </p> 816 * 817 * <pre> 818 * StringSubstitutor.createInterpolator().replace("... ${env:USER} ...")); 819 * </pre> 820 * <p> 821 * The above examples convert (on Linux) {@code "USER"} to the current user name. On Windows 10, you would use 822 * {@code "USERNAME"} to the same effect. 823 * </p> 824 * 825 * @return The EnvironmentVariableStringLookup singleton instance. 826 */ 827 public StringLookup environmentVariableStringLookup() { 828 return StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES; 829 } 830 831 /** 832 * Returns the FileStringLookup singleton instance. 833 * <p> 834 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 835 * </p> 836 * 837 * <pre> 838 * StringLookupFactory.INSTANCE.fileStringLookup().lookup("UTF-8:com/domain/document.properties"); 839 * </pre> 840 * <p> 841 * Using a {@link StringSubstitutor}: 842 * </p> 843 * 844 * <pre> 845 * StringSubstitutor.createInterpolator().replace("... ${file:UTF-8:com/domain/document.properties} ...")); 846 * </pre> 847 * <p> 848 * The above examples convert {@code "UTF-8:com/domain/document.properties"} to the contents of the file. 849 * </p> 850 * 851 * @return The FileStringLookup singleton instance. 852 * @since 1.5 853 */ 854 public StringLookup fileStringLookup() { 855 return FileStringLookup.INSTANCE; 856 } 857 858 /** 859 * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a 860 * lookup key. 861 * 862 * @param <R> the function return type. 863 * @param function the function. 864 * @return a new MapStringLookup. 865 * @since 1.9 866 */ 867 public <R> StringLookup functionStringLookup(final Function<String, R> function) { 868 return FunctionStringLookup.on(function); 869 } 870 871 /** 872 * Returns a {@link InterpolatorStringLookup} containing the configured 873 * {@link #addDefaultStringLookups(Map) default lookups}. See the class documentation for 874 * details on how these defaults are configured. 875 * <p> 876 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 877 * </p> 878 * 879 * <pre> 880 * StringLookupFactory.INSTANCE.interpolatorStringLookup().lookup("${sys:os.name}, ${env:USER}"); 881 * </pre> 882 * <p> 883 * Using a {@link StringSubstitutor}: 884 * </p> 885 * 886 * <pre> 887 * StringSubstitutor.createInterpolator().replace("... ${sys:os.name}, ${env:USER} ...")); 888 * </pre> 889 * <p> 890 * The above examples convert {@code "${sys:os.name}, ${env:USER}"} to the OS name and Linux user name. 891 * </p> 892 * 893 * @return the default {@link InterpolatorStringLookup}. 894 */ 895 public StringLookup interpolatorStringLookup() { 896 return InterpolatorStringLookup.INSTANCE; 897 } 898 899 /** 900 * Returns a new InterpolatorStringLookup. If {@code addDefaultLookups} is {@code true}, the configured 901 * {@link #addDefaultStringLookups(Map) default lookups} are included in addition to the ones 902 * provided in {@code stringLookupMap}. (See the class documentation for details on how default lookups 903 * are configured.) 904 * 905 * @param stringLookupMap the map of string lookups. 906 * @param defaultStringLookup the default string lookup; this lookup is used when a variable cannot be 907 * resolved using the lookups in {@code stringLookupMap} or the configured default lookups (if enabled) 908 * @param addDefaultLookups whether to use default lookups as described above. 909 * @return a new InterpolatorStringLookup. 910 * @since 1.4 911 */ 912 public StringLookup interpolatorStringLookup(final Map<String, StringLookup> stringLookupMap, 913 final StringLookup defaultStringLookup, final boolean addDefaultLookups) { 914 return new InterpolatorStringLookup(stringLookupMap, defaultStringLookup, addDefaultLookups); 915 } 916 917 /** 918 * Returns a new InterpolatorStringLookup using the given key-value pairs and the configured 919 * {@link #addDefaultStringLookups(Map) default lookups} to resolve variables. (See the class 920 * documentation for details on how default lookups are configured.) 921 * 922 * @param <V> the value type the default string lookup's map. 923 * @param map the default map for string lookups. 924 * @return a new InterpolatorStringLookup. 925 */ 926 public <V> StringLookup interpolatorStringLookup(final Map<String, V> map) { 927 return new InterpolatorStringLookup(map); 928 } 929 930 /** 931 * Returns a new InterpolatorStringLookup using the given lookup and the configured 932 * {@link #addDefaultStringLookups(Map) default lookups} to resolve variables. (See the class 933 * documentation for details on how default lookups are configured.) 934 * 935 * @param defaultStringLookup the default string lookup. 936 * @return a new InterpolatorStringLookup. 937 */ 938 public StringLookup interpolatorStringLookup(final StringLookup defaultStringLookup) { 939 return new InterpolatorStringLookup(defaultStringLookup); 940 } 941 942 /** 943 * Returns the JavaPlatformStringLookup singleton instance. Looks up keys related to Java: Java version, JRE 944 * version, VM version, and so on. 945 * <p> 946 * The lookup keys with examples are: 947 * </p> 948 * <ul> 949 * <li><b>version</b>: "Java version 1.8.0_181"</li> 950 * <li><b>runtime</b>: "Java(TM) SE Runtime Environment (build 1.8.0_181-b13) from Oracle Corporation"</li> 951 * <li><b>vm</b>: "Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)"</li> 952 * <li><b>os</b>: "Windows 10 10.0, architecture: amd64-64"</li> 953 * <li><b>hardware</b>: "processors: 4, architecture: amd64-64, instruction sets: amd64"</li> 954 * <li><b>locale</b>: "default locale: en_US, platform encoding: iso-8859-1"</li> 955 * </ul> 956 * 957 * <p> 958 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 959 * </p> 960 * 961 * <pre> 962 * StringLookupFactory.INSTANCE.javaPlatformStringLookup().lookup("version"); 963 * </pre> 964 * <p> 965 * Using a {@link StringSubstitutor}: 966 * </p> 967 * 968 * <pre> 969 * StringSubstitutor.createInterpolator().replace("... ${java:version} ...")); 970 * </pre> 971 * <p> 972 * The above examples convert {@code "version"} to the current VM version, for example, 973 * {@code "Java version 1.8.0_181"}. 974 * </p> 975 * 976 * @return The JavaPlatformStringLookup singleton instance. 977 */ 978 public StringLookup javaPlatformStringLookup() { 979 return JavaPlatformStringLookup.INSTANCE; 980 } 981 982 /** 983 * Returns the LocalHostStringLookup singleton instance where the lookup key is one of: 984 * <ul> 985 * <li><b>name</b>: for the local host name, for example {@code EXAMPLE}.</li> 986 * <li><b>canonical-name</b>: for the local canonical host name, for example {@code EXAMPLE.apache.org}.</li> 987 * <li><b>address</b>: for the local host address, for example {@code 192.168.56.1}.</li> 988 * </ul> 989 * 990 * <p> 991 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 992 * </p> 993 * 994 * <pre> 995 * StringLookupFactory.INSTANCE.localHostStringLookup().lookup("canonical-name"); 996 * </pre> 997 * <p> 998 * Using a {@link StringSubstitutor}: 999 * </p> 1000 * 1001 * <pre> 1002 * StringSubstitutor.createInterpolator().replace("... ${localhost:canonical-name} ...")); 1003 * </pre> 1004 * <p> 1005 * The above examples convert {@code "canonical-name"} to the current host name, for example, 1006 * {@code "EXAMPLE.apache.org"}. 1007 * </p> 1008 * 1009 * @return The DateStringLookup singleton instance. 1010 */ 1011 public StringLookup localHostStringLookup() { 1012 return LocalHostStringLookup.INSTANCE; 1013 } 1014 1015 /** 1016 * Returns a new map-based lookup where the request for a lookup is answered with the value for that key. 1017 * 1018 * @param <V> the map value type. 1019 * @param map the map. 1020 * @return a new MapStringLookup. 1021 */ 1022 public <V> StringLookup mapStringLookup(final Map<String, V> map) { 1023 return FunctionStringLookup.on(map); 1024 } 1025 1026 /** 1027 * Returns the NullStringLookup singleton instance which always returns null. 1028 * 1029 * @return The NullStringLookup singleton instance. 1030 */ 1031 public StringLookup nullStringLookup() { 1032 return StringLookupFactory.INSTANCE_NULL; 1033 } 1034 1035 /** 1036 * Returns the PropertiesStringLookup singleton instance. 1037 * <p> 1038 * Looks up the value for the key in the format "DocumentPath::MyKey". 1039 * </p> 1040 * <p> 1041 * Note the use of "::" instead of ":" to allow for "C:" drive letters in paths. 1042 * </p> 1043 * <p> 1044 * For example: "com/domain/document.properties::MyKey". 1045 * </p> 1046 * 1047 * <p> 1048 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1049 * </p> 1050 * 1051 * <pre> 1052 * StringLookupFactory.INSTANCE.propertiesStringLookup().lookup("com/domain/document.properties::MyKey"); 1053 * </pre> 1054 * <p> 1055 * Using a {@link StringSubstitutor}: 1056 * </p> 1057 * 1058 * <pre> 1059 * StringSubstitutor.createInterpolator().replace("... ${properties:com/domain/document.properties::MyKey} ...")); 1060 * </pre> 1061 * <p> 1062 * The above examples convert {@code "com/domain/document.properties::MyKey"} to the key value in the properties 1063 * file at the path "com/domain/document.properties". 1064 * </p> 1065 * 1066 * @return The PropertiesStringLookup singleton instance. 1067 * @since 1.5 1068 */ 1069 public StringLookup propertiesStringLookup() { 1070 return PropertiesStringLookup.INSTANCE; 1071 } 1072 1073 /** 1074 * Returns the ResourceBundleStringLookup singleton instance. 1075 * <p> 1076 * Looks up the value for a given key in the format "BundleName:BundleKey". 1077 * </p> 1078 * <p> 1079 * For example: "com.domain.messages:MyKey". 1080 * </p> 1081 * <p> 1082 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1083 * </p> 1084 * 1085 * <pre> 1086 * StringLookupFactory.INSTANCE.resourceBundleStringLookup().lookup("com.domain.messages:MyKey"); 1087 * </pre> 1088 * <p> 1089 * Using a {@link StringSubstitutor}: 1090 * </p> 1091 * 1092 * <pre> 1093 * StringSubstitutor.createInterpolator().replace("... ${resourceBundle:com.domain.messages:MyKey} ...")); 1094 * </pre> 1095 * <p> 1096 * The above examples convert {@code "com.domain.messages:MyKey"} to the key value in the resource bundle at 1097 * {@code "com.domain.messages"}. 1098 * </p> 1099 * 1100 * @return The ResourceBundleStringLookup singleton instance. 1101 */ 1102 public StringLookup resourceBundleStringLookup() { 1103 return ResourceBundleStringLookup.INSTANCE; 1104 } 1105 1106 /** 1107 * Returns a ResourceBundleStringLookup instance for the given bundle name. 1108 * <p> 1109 * Looks up the value for a given key in the format "MyKey". 1110 * </p> 1111 * <p> 1112 * For example: "MyKey". 1113 * </p> 1114 * <p> 1115 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1116 * </p> 1117 * 1118 * <pre> 1119 * StringLookupFactory.INSTANCE.resourceBundleStringLookup("com.domain.messages").lookup("MyKey"); 1120 * </pre> 1121 * <p> 1122 * The above example converts {@code "MyKey"} to the key value in the resource bundle at 1123 * {@code "com.domain.messages"}. 1124 * </p> 1125 * 1126 * @param bundleName Only lookup in this bundle. 1127 * @return a ResourceBundleStringLookup instance for the given bundle name. 1128 * @since 1.5 1129 */ 1130 public StringLookup resourceBundleStringLookup(final String bundleName) { 1131 return new ResourceBundleStringLookup(bundleName); 1132 } 1133 1134 /** 1135 * Returns the ScriptStringLookup singleton instance. NOTE: This lookup is not included 1136 * as a {@link #addDefaultStringLookups(Map) default lookup} unless explicitly enabled. See 1137 * the class level documentation for details. 1138 * <p> 1139 * Looks up the value for the key in the format "ScriptEngineName:Script". 1140 * </p> 1141 * <p> 1142 * For example: "javascript:3 + 4". 1143 * </p> 1144 * <p> 1145 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1146 * </p> 1147 * 1148 * <pre> 1149 * StringLookupFactory.INSTANCE.scriptStringLookup().lookup("javascript:3 + 4"); 1150 * </pre> 1151 * <p> 1152 * When used through a {@link StringSubstitutor}, this lookup must either be added programmatically 1153 * (as below) or enabled as a default lookup using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property 1154 * (see class documentation). 1155 * </p> 1156 * 1157 * <pre> 1158 * Map<String, StringLookup> lookupMap = new HashMap<>(); 1159 * lookupMap.put("script", StringLookupFactory.INSTANCE.scriptStringLookup()); 1160 * 1161 * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false); 1162 * 1163 * String value = new StringSubstitutor(variableResolver).replace("${script:javascript:3 + 4}"); 1164 * </pre> 1165 * <p> 1166 * The above examples convert {@code "javascript:3 + 4"} to {@code "7"}. 1167 * </p> 1168 * 1169 * @return The ScriptStringLookup singleton instance. 1170 * @since 1.5 1171 */ 1172 public StringLookup scriptStringLookup() { 1173 return ScriptStringLookup.INSTANCE; 1174 } 1175 1176 /** 1177 * Returns the SystemPropertyStringLookup singleton instance where the lookup key is a system property name. 1178 * 1179 * <p> 1180 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1181 * </p> 1182 * 1183 * <pre> 1184 * StringLookupFactory.INSTANCE.systemPropertyStringLookup().lookup("os.name"); 1185 * </pre> 1186 * <p> 1187 * Using a {@link StringSubstitutor}: 1188 * </p> 1189 * 1190 * <pre> 1191 * StringSubstitutor.createInterpolator().replace("... ${sys:os.name} ...")); 1192 * </pre> 1193 * <p> 1194 * The above examples convert {@code "os.name"} to the operating system name. 1195 * </p> 1196 * 1197 * @return The SystemPropertyStringLookup singleton instance. 1198 */ 1199 public StringLookup systemPropertyStringLookup() { 1200 return StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES; 1201 } 1202 1203 /** 1204 * Returns the UrlDecoderStringLookup singleton instance. 1205 * <p> 1206 * Decodes URL Strings using the UTF-8 encoding. 1207 * </p> 1208 * <p> 1209 * For example: "Hello%20World%21" becomes "Hello World!". 1210 * </p> 1211 * <p> 1212 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1213 * </p> 1214 * 1215 * <pre> 1216 * StringLookupFactory.INSTANCE.urlDecoderStringLookup().lookup("Hello%20World%21"); 1217 * </pre> 1218 * <p> 1219 * Using a {@link StringSubstitutor}: 1220 * </p> 1221 * 1222 * <pre> 1223 * StringSubstitutor.createInterpolator().replace("... ${urlDecoder:Hello%20World%21} ...")); 1224 * </pre> 1225 * <p> 1226 * The above examples convert {@code "Hello%20World%21"} to {@code "Hello World!"}. 1227 * </p> 1228 * 1229 * @return The UrlStringLookup singleton instance. 1230 * @since 1.6 1231 */ 1232 public StringLookup urlDecoderStringLookup() { 1233 return UrlDecoderStringLookup.INSTANCE; 1234 } 1235 1236 /** 1237 * Returns the UrlDecoderStringLookup singleton instance. 1238 * <p> 1239 * Decodes URL Strings using the UTF-8 encoding. 1240 * </p> 1241 * <p> 1242 * For example: "Hello World!" becomes "Hello+World%21". 1243 * </p> 1244 * <p> 1245 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1246 * </p> 1247 * 1248 * <pre> 1249 * StringLookupFactory.INSTANCE.urlEncoderStringLookup().lookup("Hello World!"); 1250 * </pre> 1251 * <p> 1252 * Using a {@link StringSubstitutor}: 1253 * </p> 1254 * 1255 * <pre> 1256 * StringSubstitutor.createInterpolator().replace("... ${urlEncoder:Hello World!} ...")); 1257 * </pre> 1258 * <p> 1259 * The above examples convert {@code "Hello World!"} to {@code "Hello%20World%21"}. 1260 * </p> 1261 * 1262 * @return The UrlStringLookup singleton instance. 1263 * @since 1.6 1264 */ 1265 public StringLookup urlEncoderStringLookup() { 1266 return UrlEncoderStringLookup.INSTANCE; 1267 } 1268 1269 /** 1270 * Returns the UrlStringLookup singleton instance. This lookup is not included 1271 * as a {@link #addDefaultStringLookups(Map) default lookup} unless explicitly enabled. See 1272 * the class level documentation for details. 1273 * <p> 1274 * Looks up the value for the key in the format "CharsetName:URL". 1275 * </p> 1276 * <p> 1277 * For example, using the HTTP scheme: "UTF-8:http://www.google.com" 1278 * </p> 1279 * <p> 1280 * For example, using the file scheme: 1281 * "UTF-8:file:///C:/somehome/commons/commons-text/src/test/resources/document.properties" 1282 * </p> 1283 * <p> 1284 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1285 * </p> 1286 * 1287 * <pre> 1288 * StringLookupFactory.INSTANCE.urlStringLookup().lookup("UTF-8:https://www.apache.org"); 1289 * </pre> 1290 * <p> 1291 * When used through a {@link StringSubstitutor}, this lookup must either be added programmatically 1292 * (as below) or enabled as a default lookup using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property 1293 * (see class documentation). 1294 * </p> 1295 * 1296 * <pre> 1297 * Map<String, StringLookup> lookupMap = new HashMap<>(); 1298 * lookupMap.put("url", StringLookupFactory.INSTANCE.urlStringLookup()); 1299 * 1300 * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false); 1301 * 1302 * String value = new StringSubstitutor(variableResolver).replace("${url:UTF-8:https://www.apache.org}"); 1303 * </pre> 1304 * <p> 1305 * The above examples convert {@code "UTF-8:https://www.apache.org"} to the contents of that page. 1306 * </p> 1307 * 1308 * @return The UrlStringLookup singleton instance. 1309 * @since 1.5 1310 */ 1311 public StringLookup urlStringLookup() { 1312 return UrlStringLookup.INSTANCE; 1313 } 1314 1315 /** 1316 * Returns the XmlDecoderStringLookup singleton instance. 1317 * <p> 1318 * Decodes strings according to the XML 1.0 specification. 1319 * </p> 1320 * <p> 1321 * For example: "&lt;element&gt;" becomes "<element>". 1322 * </p> 1323 * <p> 1324 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1325 * </p> 1326 * 1327 * <pre> 1328 * StringLookupFactory.INSTANCE.xmlDecoderStringLookup().lookup("&lt;element&gt;"); 1329 * </pre> 1330 * <p> 1331 * Using a {@link StringSubstitutor}: 1332 * </p> 1333 * 1334 * <pre> 1335 * StringSubstitutor.createInterpolator().replace("... ${xmlDecoder:&lt;element&gt;} ...")); 1336 * </pre> 1337 * <p> 1338 * The above examples convert {@code "<element>"} to {@code "<element>"}. 1339 * </p> 1340 * 1341 * @return The XmlDecoderStringLookup singleton instance. 1342 * @since 1.11.0 1343 */ 1344 public StringLookup xmlDecoderStringLookup() { 1345 return XmlDecoderStringLookup.INSTANCE; 1346 } 1347 1348 /** 1349 * Returns the XmlEncoderStringLookup singleton instance. 1350 * <p> 1351 * Encodes strings according to the XML 1.0 specification. 1352 * </p> 1353 * <p> 1354 * For example: "<element>" becomes "&lt;element&gt;". 1355 * </p> 1356 * <p> 1357 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1358 * </p> 1359 * 1360 * <pre> 1361 * StringLookupFactory.INSTANCE.xmlEncoderStringLookup().lookup("<element>"); 1362 * </pre> 1363 * <p> 1364 * Using a {@link StringSubstitutor}: 1365 * </p> 1366 * 1367 * <pre> 1368 * StringSubstitutor.createInterpolator().replace("... ${xmlEncoder:<element>} ...")); 1369 * </pre> 1370 * <p> 1371 * The above examples convert {@code "<element>"} to {@code "<element>"}. 1372 * </p> 1373 * 1374 * @return The XmlEncoderStringLookup singleton instance. 1375 * @since 1.11.0 1376 */ 1377 public StringLookup xmlEncoderStringLookup() { 1378 return XmlEncoderStringLookup.INSTANCE; 1379 } 1380 1381 /** 1382 * Returns the XmlStringLookup singleton instance. 1383 * <p> 1384 * Looks up the value for the key in the format "DocumentPath:XPath". 1385 * </p> 1386 * <p> 1387 * For example: "com/domain/document.xml:/path/to/node". 1388 * </p> 1389 * <p> 1390 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1391 * </p> 1392 * 1393 * <pre> 1394 * StringLookupFactory.INSTANCE.xmlStringLookup().lookup("com/domain/document.xml:/path/to/node"); 1395 * </pre> 1396 * <p> 1397 * Using a {@link StringSubstitutor}: 1398 * </p> 1399 * 1400 * <pre> 1401 * StringSubstitutor.createInterpolator().replace("... ${xml:com/domain/document.xml:/path/to/node} ...")); 1402 * </pre> 1403 * <p> 1404 * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML 1405 * document. 1406 * </p> 1407 * 1408 * @return The XmlStringLookup singleton instance. 1409 * @since 1.5 1410 */ 1411 public StringLookup xmlStringLookup() { 1412 return XmlStringLookup.INSTANCE; 1413 } 1414 1415 /** 1416 * Returns the XmlStringLookup singleton instance. 1417 * <p> 1418 * Looks up the value for the key in the format "DocumentPath:XPath". 1419 * </p> 1420 * <p> 1421 * For example: "com/domain/document.xml:/path/to/node". 1422 * </p> 1423 * <p> 1424 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1425 * </p> 1426 * 1427 * <pre> 1428 * StringLookupFactory.INSTANCE.xmlStringLookup().lookup("com/domain/document.xml:/path/to/node"); 1429 * </pre> 1430 * <p> 1431 * Using a {@link StringSubstitutor}: 1432 * </p> 1433 * 1434 * <pre> 1435 * StringSubstitutor.createInterpolator().replace("... ${xml:com/domain/document.xml:/path/to/node} ...")); 1436 * </pre> 1437 * <p> 1438 * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML 1439 * document. 1440 * </p> 1441 * 1442 * @param xPathFactoryFeatures XPathFactory features to set. 1443 * @return The XmlStringLookup singleton instance. 1444 * @see XPathFactory#setFeature(String, boolean) 1445 * @since 1.11.0 1446 */ 1447 public StringLookup xmlStringLookup(final Map<String, Boolean> xPathFactoryFeatures) { 1448 return new XmlStringLookup(xPathFactoryFeatures); 1449 } 1450 }