VariableReplacer.java

  1. /*
  2.  *    Copyright 2010-2023 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       https://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.migration;

  17. import java.util.Arrays;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Objects;
  22. import java.util.stream.Collectors;

  23. /**
  24.  * @author Clinton Begin
  25.  */
  26. public class VariableReplacer {

  27.   private static final String OPEN_TOKEN = "${";
  28.   private static final String CLOSE_TOKEN = "}";
  29.   private final List<Map<? extends Object, ? extends Object>> variablesList;

  30.   public VariableReplacer(Map<? extends Object, ? extends Object> variablesList) {
  31.     this(Arrays.asList(variablesList));
  32.   }

  33.   public VariableReplacer(List<Map<? extends Object, ? extends Object>> variablesList) {
  34.     this.variablesList = variablesList == null ? Collections.emptyList()
  35.         : variablesList.stream().filter(Objects::nonNull).collect(Collectors.toList());
  36.   }

  37.   public String replace(String text) {
  38.     if (text == null || text.isEmpty()) {
  39.       return "";
  40.     }
  41.     // search open token
  42.     int start = text.indexOf(OPEN_TOKEN);
  43.     if (start == -1) {
  44.       return text;
  45.     }
  46.     char[] src = text.toCharArray();
  47.     int offset = 0;
  48.     final StringBuilder builder = new StringBuilder();
  49.     StringBuilder expression = null;
  50.     while (start > -1) {
  51.       if (start > 0 && src[start - 1] == '\\') {
  52.         // this open token is escaped. remove the backslash and continue.
  53.         builder.append(src, offset, start - offset - 1).append(OPEN_TOKEN);
  54.         offset = start + OPEN_TOKEN.length();
  55.       } else {
  56.         // found open token. let's search close token.
  57.         if (expression == null) {
  58.           expression = new StringBuilder();
  59.         } else {
  60.           expression.setLength(0);
  61.         }
  62.         builder.append(src, offset, start - offset);
  63.         offset = start + OPEN_TOKEN.length();
  64.         int end = text.indexOf(CLOSE_TOKEN, offset);
  65.         while (end > -1) {
  66.           if (end <= offset || src[end - 1] != '\\') {
  67.             expression.append(src, offset, end - offset);
  68.             break;
  69.           }
  70.           // this close token is escaped. remove the backslash and continue.
  71.           expression.append(src, offset, end - offset - 1).append(CLOSE_TOKEN);
  72.           offset = end + CLOSE_TOKEN.length();
  73.           end = text.indexOf(CLOSE_TOKEN, offset);
  74.         }
  75.         if (end == -1) {
  76.           // close token was not found.
  77.           builder.append(src, start, src.length - start);
  78.           offset = src.length;
  79.         } else {
  80.           appendWithReplace(builder, expression.toString());
  81.           offset = end + CLOSE_TOKEN.length();
  82.         }
  83.       }
  84.       start = text.indexOf(OPEN_TOKEN, offset);
  85.     }
  86.     if (offset < src.length) {
  87.       builder.append(src, offset, src.length - offset);
  88.     }
  89.     return builder.toString();
  90.   }

  91.   private StringBuilder appendWithReplace(StringBuilder builder, String key) {
  92.     String value = null;
  93.     for (Map<? extends Object, ? extends Object> variables : variablesList) {
  94.       value = (String) variables.get(key);
  95.       if (value != null) {
  96.         builder.append(value);
  97.         break;
  98.       }
  99.     }
  100.     if (value == null) {
  101.       builder.append(OPEN_TOKEN).append(key).append(CLOSE_TOKEN);
  102.     }
  103.     return builder;
  104.   }
  105. }