code: private String lookupRecursively(String base, Set<String> seen)
        throws UnresolvablePropertyException {
      // check argument
      if (base == null) {
        throw new UnresolvablePropertyException("Can't resolve property with null value");
      }
  
      String resolved = base;
      // Lets find pattern match to ${key}.
      // TODO(hsaputra): Consider using Apache Commons StrSubstitutor.
      Matcher matcher = CONF_REGEX.matcher(base);
      while (matcher.find()) {
        String match = matcher.group(2).trim();
        if (!seen.add(match)) {
          throw new RuntimeException(ExceptionMessage.KEY_CIRCULAR_DEPENDENCY.getMessage(match));
        }
        if (!PropertyKey.isValid(match)) {
          throw new RuntimeException(ExceptionMessage.INVALID_CONFIGURATION_KEY.getMessage(match));
        }
        String value = lookupRecursively(mProperties.get(PropertyKey.fromString(match)), seen);
        seen.remove(match);
        if (value == null) {
          throw new UnresolvablePropertyException(ExceptionMessage
              .UNDEFINED_CONFIGURATION_KEY.getMessage(match));
        }
        LOG.debug("Replacing {} with {}", matcher.group(1), value);
        resolved = resolved.replaceFirst(REGEX_STRING, Matcher.quoteReplacement(value));
      }
      return resolved;
    }
docs: Actual recursive lookup replacement.
  
  @param base the string to resolve
  @param seen strings already seen during this lookup, used to prevent unbound recursion
  @return the resolved string