1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.common.util.property;
17
18 import java.util.HashMap;
19 import java.util.Map;
20 import java.util.Set;
21
22 import org.apache.commons.lang3.StringUtils;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public class EscapingPropertyPlaceholderHelper extends org.springframework.util.PropertyPlaceholderHelper {
42
43 private static final Logger logger = LoggerFactory.getLogger(EscapingPropertyPlaceholderHelper.class);
44 private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<String, String>(4);
45
46 static {
47 wellKnownSimplePrefixes.put("}", "{");
48 wellKnownSimplePrefixes.put("]", "[");
49 wellKnownSimplePrefixes.put(")", "(");
50 }
51
52 String placeholderPrefix;
53 String placeholderSuffix;
54 String valueSeparator;
55 boolean ignoreUnresolvablePlaceholders;
56 String simplePrefix;
57 String escapeString = Constants.DEFAULT_ESCAPE_STRING;
58 String skipString;
59
60 public EscapingPropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {
61 this(placeholderPrefix, placeholderSuffix, Constants.DEFAULT_VALUE_SEPARATOR, Constants.DEFAULT_ESCAPE_STRING, Constants.DEFAULT_IGNORE_UNRESOLVABLE_PLACEHOLDERS);
62 }
63
64 public EscapingPropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, String valueSeparator, String escapeString, boolean ignoreUnresolvablePlaceholders) {
65 super(placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders);
66 this.placeholderPrefix = placeholderPrefix;
67 this.placeholderSuffix = placeholderSuffix;
68 this.valueSeparator = valueSeparator;
69 this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;
70 String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix);
71 if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {
72 this.simplePrefix = simplePrefixForSuffix;
73 } else {
74 this.simplePrefix = this.placeholderPrefix;
75 }
76 this.escapeString = StringUtils.trimToNull(escapeString);
77 if (this.escapeString != null) {
78 this.skipString = this.escapeString + this.placeholderPrefix;
79 }
80 }
81
82
83 protected int getStartIndex(String s, String prefix, String skipString, int fromIndex) {
84 if (skipString == null) {
85 return StringUtils.indexOf(s, prefix, fromIndex);
86 }
87 int pos = StringUtils.indexOf(s, skipString, fromIndex);
88 int len = StringUtils.length(s);
89 fromIndex = getNewFromIndex(fromIndex, pos, skipString);
90 while (pos != -1 && fromIndex < len) {
91 pos = StringUtils.indexOf(s, skipString, fromIndex);
92 fromIndex = getNewFromIndex(fromIndex, pos, skipString);
93 }
94 if (fromIndex >= len) {
95 return -1;
96 } else {
97 return StringUtils.indexOf(s, prefix, fromIndex);
98 }
99 }
100
101
102 protected int getNewFromIndex(int fromIndex, int pos, String s) {
103 return pos == -1 ? fromIndex : pos + s.length();
104 }
105
106 @Override
107 protected String parseStringValue(String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
108 StringBuilder buf = new StringBuilder(strVal);
109
110
111
112 int startIndex = getStartIndex(strVal, placeholderPrefix, skipString, 0);
113 while (startIndex != -1) {
114 int endIndex = findPlaceholderEndIndex(buf, startIndex);
115 if (endIndex != -1) {
116 String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex);
117 String originalPlaceholder = placeholder;
118 if (!visitedPlaceholders.add(originalPlaceholder)) {
119 throw new IllegalArgumentException("Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
120 }
121
122 placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
123
124 String propVal = placeholderResolver.resolvePlaceholder(placeholder);
125 if (propVal == null && this.valueSeparator != null) {
126 int separatorIndex = placeholder.indexOf(this.valueSeparator);
127 if (separatorIndex != -1) {
128 String actualPlaceholder = placeholder.substring(0, separatorIndex);
129 String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
130 propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
131 if (propVal == null) {
132
133
134 propVal = parseStringValue(defaultValue, placeholderResolver, visitedPlaceholders);
135 }
136 }
137 }
138 if (propVal != null) {
139
140
141 propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
142 buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
143 if (logger.isTraceEnabled()) {
144 logger.trace("Resolved placeholder '" + placeholder + "'");
145 }
146
147
148 int fromIndex = startIndex + propVal.length();
149 startIndex = getStartIndex(buf.toString(), placeholderPrefix, skipString, fromIndex);
150 } else if (this.ignoreUnresolvablePlaceholders) {
151
152
153
154 int fromIndex = endIndex + placeholderSuffix.length();
155 startIndex = getStartIndex(buf.toString(), placeholderPrefix, skipString, fromIndex);
156 } else {
157 throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'" + " in string value \"" + strVal + "\"");
158 }
159 visitedPlaceholders.remove(originalPlaceholder);
160 } else {
161 startIndex = -1;
162 }
163 }
164
165 String s = buf.toString();
166 if (skipString != null) {
167
168 return StringUtils.replace(s, skipString, placeholderPrefix);
169 } else {
170 return s;
171 }
172 }
173
174 private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
175 int index = startIndex + this.placeholderPrefix.length();
176 int withinNestedPlaceholder = 0;
177 while (index < buf.length()) {
178 if (org.springframework.util.StringUtils.substringMatch(buf, index, this.placeholderSuffix)) {
179 if (withinNestedPlaceholder > 0) {
180 withinNestedPlaceholder--;
181 index = index + this.placeholderSuffix.length();
182 } else {
183 return index;
184 }
185 } else if (org.springframework.util.StringUtils.substringMatch(buf, index, this.simplePrefix)) {
186 withinNestedPlaceholder++;
187 index = index + this.simplePrefix.length();
188 } else {
189 index++;
190 }
191 }
192 return -1;
193 }
194
195 public String getPlaceholderPrefix() {
196 return placeholderPrefix;
197 }
198
199 public String getPlaceholderSuffix() {
200 return placeholderSuffix;
201 }
202
203 public String getValueSeparator() {
204 return valueSeparator;
205 }
206
207 public boolean isIgnoreUnresolvablePlaceholders() {
208 return ignoreUnresolvablePlaceholders;
209 }
210
211 public String getSimplePrefix() {
212 return simplePrefix;
213 }
214
215 public String getEscapeString() {
216 return escapeString;
217 }
218
219 public String getSkipString() {
220 return skipString;
221 }
222
223 }