View Javadoc
1   /**
2    * Copyright (C) 2008-2010 Matt Gumbley, DevZendo.org <http://devzendo.org>;
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    *         http://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  
17  /**
18   * 
19   */
20  package org.devzendo.xplp;
21  
22  import java.util.HashSet;
23  import java.util.Properties;
24  import java.util.regex.Matcher;
25  import java.util.regex.Pattern;
26  
27  /**
28   * Interpolation of name=value pairs from a
29   * Properties object into a String, using Ant-style references
30   * to names - e.g ${name}.
31   * @author matt
32   *
33   */
34  public final class PropertiesInterpolator {
35      private final Properties mProps;
36      private final Matcher variableReferenceMatcher = 
37          Pattern.compile("^(.*?)\\$\\{([^}]+?)\\}(.*?)$", Pattern.DOTALL).matcher("");
38      private final HashSet<String>  verbatimVariables = new HashSet<>();
39  
40      /**
41       * Create an interpolator, given a set of properties to
42       * interpolate inside incoming string data.
43       * @param props the name=value pairs.
44       * 
45       */
46      public PropertiesInterpolator(final Properties props) {
47          mProps = props;
48      }
49  
50      /**
51       * Replace any ${names} with their ${values}, except in # lines
52       * @param input the input string, can be null
53       * @return the output, null iff input == null
54       */
55      public String interpolate(final String input) {
56          //System.out.println("Interpolating '" + input + "'");
57          if (input == null || input.length() == 0) {
58              return input;
59          }
60          if (input.matches("^\\s*#.*$")) {
61              return input;
62          }
63          String s = input;
64          final StringBuilder sb = new StringBuilder();
65          while (true) {
66              variableReferenceMatcher.reset(s);
67  //            System.out.println("Finding variables in '" + s + "'");
68              if (variableReferenceMatcher.find()) {
69  //                System.out.println("Found variable");
70                  final String before = variableReferenceMatcher.group(1);
71                  final String variableName = variableReferenceMatcher.group(2);
72                  final String after = variableReferenceMatcher.group(3);
73  //                System.out.println("Variable '" + variableName + "'");
74                  if (verbatimVariables.contains(variableName)) {
75  //                    System.out.println("Verbatim variable '" + variableName + "'");
76                      sb.append(before);
77                      sb.append("${");
78                      sb.append(variableName);
79                      sb.append("}");
80                  } else {
81                      if (mProps.containsKey(variableName)) {
82                          final String variableValue = mProps.getProperty(variableName);
83  //                        System.out.println("Replacement is '" + variableValue + "'");
84                          sb.append(before);
85                          sb.append(variableValue);
86                      } else {
87                          //System.out.println("Got no value for variable");
88                          throw new IllegalStateException("The name '" + variableName + "' is not defined");
89                      }
90                  }
91                  s = after;
92              } else {
93  //                System.out.println("No more variables");
94                  sb.append(s);
95                  break;
96              }
97          }
98  //        System.out.println("Output is '" + sb.toString() + "'");
99          return sb.toString();
100     }
101 
102     /**
103      * Mark ${verbatimVariable} as a variable name that should not be interpolated
104      * @param verbatimVariable a variable not to be interpolated; should be passed through as ${verbatimVariable}
105      */
106     public void doNotInterpolate(final String verbatimVariable) {
107         verbatimVariables.add(verbatimVariable);
108     }
109 }