InterpolatorStringLookup.java

  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. package org.apache.commons.text.lookup;

  18. import java.util.Collections;
  19. import java.util.Map;
  20. import java.util.Map.Entry;
  21. import java.util.stream.Collectors;

  22. /**
  23.  * Proxies other {@link StringLookup}s using a keys within ${} markers using the format "${StringLookup:Key}".
  24.  * <p>
  25.  * Uses the {@link StringLookupFactory default lookups}.
  26.  * </p>
  27.  */
  28. final class InterpolatorStringLookup extends AbstractStringLookup {

  29.     /**
  30.      * Defines the singleton for this class.
  31.      *
  32.      * @since 1.6
  33.      */
  34.     static final AbstractStringLookup INSTANCE = new InterpolatorStringLookup();

  35.     /** Constant for the prefix separator. */
  36.     private static final char PREFIX_SEPARATOR = ':';

  37.     /** The default string lookup. */
  38.     private final StringLookup defaultStringLookup;

  39.     /** The map of String lookups keyed by prefix. */
  40.     private final Map<String, StringLookup> stringLookupMap;

  41.     /**
  42.      * Constructs an instance using only lookups that work without initial properties and are stateless.
  43.      * <p>
  44.      * Uses the {@link StringLookupFactory default lookups}.
  45.      * </p>
  46.      */
  47.     InterpolatorStringLookup() {
  48.         this((Map<String, String>) null);
  49.     }

  50.     /**
  51.      * Constructs a fully customized instance.
  52.      *
  53.      * @param stringLookupMap the map of string lookups.
  54.      * @param defaultStringLookup the default string lookup.
  55.      * @param addDefaultLookups whether the default lookups should be used.
  56.      */
  57.     InterpolatorStringLookup(final Map<String, StringLookup> stringLookupMap, final StringLookup defaultStringLookup,
  58.             final boolean addDefaultLookups) {
  59.         this.defaultStringLookup = defaultStringLookup;
  60.         this.stringLookupMap = stringLookupMap.entrySet().stream().collect(Collectors.toMap(e -> StringLookupFactory.toKey(e.getKey()), Entry::getValue));
  61.         if (addDefaultLookups) {
  62.             StringLookupFactory.INSTANCE.addDefaultStringLookups(this.stringLookupMap);
  63.         }
  64.     }

  65.     /**
  66.      * Constructs an instance using only lookups that work without initial properties and are stateless.
  67.      * <p>
  68.      * Uses the {@link StringLookupFactory default lookups}.
  69.      * </p>
  70.      *
  71.      * @param <V> the map's value type.
  72.      * @param defaultMap the default map for string lookups.
  73.      */
  74.     <V> InterpolatorStringLookup(final Map<String, V> defaultMap) {
  75.         this(StringLookupFactory.INSTANCE.mapStringLookup(defaultMap));
  76.     }

  77.     /**
  78.      * Constructs an instance with the given lookup.
  79.      *
  80.      * @param defaultStringLookup the default lookup.
  81.      */
  82.     InterpolatorStringLookup(final StringLookup defaultStringLookup) {
  83.         this(Collections.emptyMap(), defaultStringLookup, true);
  84.     }

  85.     /**
  86.      * Gets the lookup map.
  87.      *
  88.      * @return The lookup map.
  89.      */
  90.     public Map<String, StringLookup> getStringLookupMap() {
  91.         return stringLookupMap;
  92.     }

  93.     /**
  94.      * Resolves the specified variable. This implementation will try to extract a variable prefix from the given
  95.      * variable name (the first colon (':') is used as prefix separator). It then passes the name of the variable with
  96.      * the prefix stripped to the lookup object registered for this prefix. If no prefix can be found or if the
  97.      * associated lookup object cannot resolve this variable, the default lookup object will be used.
  98.      *
  99.      * @param key the name of the variable whose value is to be looked up
  100.      * @return The value of this variable or <strong>null</strong> if it cannot be resolved
  101.      */
  102.     @Override
  103.     public String lookup(String key) {
  104.         if (key == null) {
  105.             return null;
  106.         }

  107.         final int prefixPos = key.indexOf(PREFIX_SEPARATOR);
  108.         if (prefixPos >= 0) {
  109.             final String prefix = StringLookupFactory.toKey(key.substring(0, prefixPos));
  110.             final String name = key.substring(prefixPos + 1);
  111.             final StringLookup lookup = stringLookupMap.get(prefix);
  112.             String value = null;
  113.             if (lookup != null) {
  114.                 value = lookup.lookup(name);
  115.             }

  116.             if (value != null) {
  117.                 return value;
  118.             }
  119.             key = key.substring(prefixPos + 1);
  120.         }
  121.         if (defaultStringLookup != null) {
  122.             return defaultStringLookup.lookup(key);
  123.         }
  124.         return null;
  125.     }

  126.     @Override
  127.     public String toString() {
  128.         return super.toString() + " [stringLookupMap=" + stringLookupMap + ", defaultStringLookup="
  129.             + defaultStringLookup + "]";
  130.     }
  131. }