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 }