protected String parseResolvablePropString(String unparsedString, PropertyResolver resolver,
      Set<String> visitedReplaceableStrings) {
    StringBuilder buf = new StringBuilder(unparsedString);
    int prefixIndex = buf.indexOf(propertyPrefix);

    while (prefixIndex != -1) {
      int suffixIndex = findSuffixIndex(buf, prefixIndex + propertyPrefix.length());
      if (suffixIndex != -1) {
        String replaceableString =
            buf.substring(prefixIndex + propertyPrefix.length(), suffixIndex);
        // Check for circular references
        if (!visitedReplaceableStrings.add(replaceableString)) {
          logger.info(
              "Some still unresolved string {} was replaced by resolver, leading to circular references.",
              replaceableString);
          throw new IllegalArgumentException("Some still unresolved string " + replaceableString
              + " was replaced by resolver, leading to circular references.");
        }
        /* Find the replacement using given <code>resolver</code> */
        replaceableString =
            parseResolvablePropString(replaceableString, resolver, visitedReplaceableStrings);
        String replacement = resolver.resolveReplaceString(replaceableString);

        if (replacement != null) {
          /*
           * put replacement in <code>unparsedString</code> and call
           * <code>parseResolvablePropString</code> recursively to find more unparsedStrings in the
           * replaced value of given unparsedString.
           */
          replacement = parseResolvablePropString(replacement, resolver, visitedReplaceableStrings);
          buf.replace(prefixIndex, suffixIndex + propertySuffix.length(), replacement);
          prefixIndex = buf.indexOf(propertyPrefix, prefixIndex + replacement.length());
        } else if (resolver.isIgnoreUnresolvedProperties()) {
          /* Look for more replaceable strings in given <code>unparsedString</code>. */
          prefixIndex = buf.indexOf(propertyPrefix, suffixIndex + propertySuffix.length());
        } else {
          throw new IllegalArgumentException(
              "No replacement found for property : " + replaceableString);
        }
        // Before iterating again remove replaceable string from visitedReplaceableStrings as it can
        // appear again.
        visitedReplaceableStrings.remove(replaceableString);
      } else {
        prefixIndex = -1;
      }
    }

    return buf.toString();
  }
Parses the given string which are supposed to be like ${} for system and/or Gemfire properties
to be replaced. This will return property.name from ${property.name}.
geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheXmlPropertyResolverHelper.java