code: private String substituteVars(String expr) {
      if (expr == null) {
        return null;
      }
      String eval = expr;
      for (int s = 0; s < MAX_SUBST; s++) {
        final int[] varBounds = findSubVariable(eval);
        if (varBounds[SUB_START_IDX] == -1) {
          return eval;
        }
        final String var = eval.substring(varBounds[SUB_START_IDX],
            varBounds[SUB_END_IDX]);
        String val = null;
        try {
          val = System.getProperty(var);
        } catch(SecurityException se) {
          LOG.warn("Unexpected SecurityException in Configuration", se);
        }
        if (val == null) {
          val = getRaw(var);
        }
        if (val == null) {
          return eval; // return literal ${var}: var is unbound
        }
        final int dollar = varBounds[SUB_START_IDX] - "${".length();
        final int afterRightBrace = varBounds[SUB_END_IDX] + "}".length();
        // substitute
        eval = eval.substring(0, dollar)
               + val
               + eval.substring(afterRightBrace);
      }
      throw new IllegalStateException("Variable substitution depth too large: "
                                      + MAX_SUBST + " " + expr);
    }
docs: Attempts to repeatedly expand the value {@code expr} by replacing the
  left-most substring of the form "${var}" in the following precedence order
  <ol>
  <li>by the value of the Java system property "var" if defined</li>
  <li>by the value of the configuration key "var" if defined</li>
  </ol>
  
  If var is unbounded the current state of expansion "prefix${var}suffix" is
  returned.
  
  @param expr the literal value of a config key
  @return null if expr is null, otherwise the value resulting from expanding
  expr using the algorithm above.
  @throws IllegalArgumentException when more than
  {@link Configuration#MAX_SUBST} replacements are required