public static String substituteTemplateVariables(String s, Collection<? extends TemplateVariable> variables, boolean escape) throws Exception {
    Map<String, String> lookup = new HashMap<>();
    for (TemplateVariable v : variables) {
      lookup.put(v.getName(), v.getValue());
    }
    StringBuilder sb = new StringBuilder();
    Matcher m = PLACEHOLDER_PATTERN.matcher(s);
    while (m.find()) {
      String name = m.group(1);
      String replacement = lookup.get(name);
      if (replacement == null) {
        throw new Exception((String.format("Template variable '%s' is undefined", name)));
      }
      // TODO: add proper escape|unescape property to template variables
      if (escape && !name.equals(GenericRepository.SERVER_URL)) {
        m.appendReplacement(sb, URLEncoder.encode(replacement, StandardCharsets.UTF_8));
      }
      else {
        m.appendReplacement(sb, replacement);
      }
    }
    return m.appendTail(sb).toString();
  }
public static String substituteTemplateVariables(String s, Collection<? extends TemplateVariable> variables, boolean escape)