code: protected String substitute(String expression) throws AbstractTracer.Exception {
      Pattern compiledPattern = Pattern.compile("\\$\\{[a-zA-Z0-9.]+\\}");
      Matcher matcher = compiledPattern.matcher(expression);
      int pos = 0;
      StringBuilder stringBuilder = new StringBuilder();
      boolean flag;
  
      do {
        flag = false;
  
        while (matcher.find()) {
          stringBuilder.append(expression.substring(pos, matcher.start()));
          String propertyKey = expression.substring(matcher.start() + 2, matcher.end() - 1);
          if (System.getProperties().containsKey(propertyKey)) {
            String propertyValue = System.getProperty(propertyKey);
            stringBuilder.append(propertyValue);
            pos = matcher.end();
            flag = true;
          }
          else {
            throw new AbstractTracer.Exception("Unknown property key.");
          }
        }
  
        stringBuilder.append(expression.substring(pos));
        expression = stringBuilder.toString();
  
        if (flag) {
          stringBuilder = new StringBuilder();
          matcher.reset(expression);
          pos = 0;
        }
      } while (flag);
  
      return expression;
    }
docs: Replaces the given argument by repeatedly substituting all expressions of the form ${property-key} with the
  corresponding property value.
  
  @param expression the to be replaced expression
  @return the replaced expression
  @throws de.christofreichardt.diagnosis.AbstractTracer.Exception indicates problems during the replacement