1 package org.codehaus.plexus.interpolation;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 public class StringSearchInterpolator implements Interpolator {
27
28 private Map<String, Object> existingAnswers = new HashMap<String, Object>();
29
30 private List<ValueSource> valueSources = new ArrayList<ValueSource>();
31
32 private List<InterpolationPostProcessor> postProcessors = new ArrayList<InterpolationPostProcessor>();
33
34 private boolean cacheAnswers = false;
35
36 public static final String DEFAULT_START_EXPR = "${";
37
38 public static final String DEFAULT_END_EXPR = "}";
39
40 private String startExpr;
41
42 private String endExpr;
43
44 private String escapeString;
45
46 public StringSearchInterpolator() {
47 this.startExpr = DEFAULT_START_EXPR;
48 this.endExpr = DEFAULT_END_EXPR;
49 }
50
51 public StringSearchInterpolator(String startExpr, String endExpr) {
52 this.startExpr = startExpr;
53 this.endExpr = endExpr;
54 }
55
56
57
58
59 public void addValueSource(ValueSource valueSource) {
60 valueSources.add(valueSource);
61 }
62
63
64
65
66 public void removeValuesSource(ValueSource valueSource) {
67 valueSources.remove(valueSource);
68 }
69
70
71
72
73 public void addPostProcessor(InterpolationPostProcessor postProcessor) {
74 postProcessors.add(postProcessor);
75 }
76
77
78
79
80 public void removePostProcessor(InterpolationPostProcessor postProcessor) {
81 postProcessors.remove(postProcessor);
82 }
83
84 public String interpolate(String input, String thisPrefixPattern) throws InterpolationException {
85 return interpolate(input, new SimpleRecursionInterceptor());
86 }
87
88 public String interpolate(String input, String thisPrefixPattern, RecursionInterceptor recursionInterceptor)
89 throws InterpolationException {
90 return interpolate(input, recursionInterceptor);
91 }
92
93 public String interpolate(String input) throws InterpolationException {
94 return interpolate(input, new SimpleRecursionInterceptor());
95 }
96
97
98
99
100
101
102
103 public String interpolate(String input, RecursionInterceptor recursionInterceptor) throws InterpolationException {
104 try {
105 return interpolate(input, recursionInterceptor, new HashSet<String>());
106 } finally {
107 if (!cacheAnswers) {
108 existingAnswers.clear();
109 }
110 }
111 }
112
113 private String interpolate(String input, RecursionInterceptor recursionInterceptor, Set<String> unresolvable)
114 throws InterpolationException {
115 if (input == null) {
116
117 return "";
118 }
119
120 int startIdx;
121 int endIdx = -1;
122 if ((startIdx = input.indexOf(startExpr, endIdx + 1)) > -1) {
123 StringBuilder result = new StringBuilder(input.length() * 2);
124 do {
125 result.append(input, endIdx + 1, startIdx);
126
127 endIdx = input.indexOf(endExpr, startIdx + 1);
128 if (endIdx < 0) {
129 break;
130 }
131
132 final String wholeExpr = input.substring(startIdx, endIdx + endExpr.length());
133 String realExpr = wholeExpr.substring(startExpr.length(), wholeExpr.length() - endExpr.length());
134
135 if (startIdx >= 0 && escapeString != null && escapeString.length() > 0) {
136 int startEscapeIdx = startIdx == 0 ? 0 : startIdx - escapeString.length();
137 if (startEscapeIdx >= 0) {
138 String escape = input.substring(startEscapeIdx, startIdx);
139 if (escapeString.equals(escape)) {
140 result.append(wholeExpr);
141 result.replace(startEscapeIdx, startEscapeIdx + escapeString.length(), "");
142 continue;
143 }
144 }
145 }
146
147 boolean resolved = false;
148 if (!unresolvable.contains(wholeExpr)) {
149 if (realExpr.startsWith(".")) {
150 realExpr = realExpr.substring(1);
151 }
152
153 if (recursionInterceptor.hasRecursiveExpression(realExpr)) {
154 throw new InterpolationCycleException(recursionInterceptor, realExpr, wholeExpr);
155 }
156
157 recursionInterceptor.expressionResolutionStarted(realExpr);
158 try {
159 Object value = getExistingAnswer(realExpr);
160 Object bestAnswer = null;
161
162 for (ValueSource valueSource : valueSources) {
163 if (value != null) {
164 break;
165 }
166 value = valueSource.getValue(realExpr, startExpr, endExpr);
167
168 if (value != null && value.toString().contains(wholeExpr)) {
169 bestAnswer = value;
170 value = null;
171 }
172 }
173
174
175
176
177 if (value == null && bestAnswer != null) {
178 throw new InterpolationCycleException(recursionInterceptor, realExpr, wholeExpr);
179 }
180
181 if (value != null) {
182 value = interpolate(String.valueOf(value), recursionInterceptor, unresolvable);
183
184 if (postProcessors != null && !postProcessors.isEmpty()) {
185 for (InterpolationPostProcessor postProcessor : postProcessors) {
186 Object newVal = postProcessor.execute(realExpr, value);
187 if (newVal != null) {
188 value = newVal;
189 break;
190 }
191 }
192 }
193
194
195
196
197
198 result.append(String.valueOf(value));
199 resolved = true;
200
201 if (cacheAnswers) {
202 existingAnswers.put(realExpr, value);
203 }
204 } else {
205 unresolvable.add(wholeExpr);
206 }
207 } finally {
208 recursionInterceptor.expressionResolutionFinished(realExpr);
209 }
210 }
211
212 if (!resolved) {
213 result.append(wholeExpr);
214 }
215
216 if (endIdx > -1) {
217 endIdx += endExpr.length() - 1;
218 }
219 } while ((startIdx = input.indexOf(startExpr, endIdx + 1)) > -1);
220
221 if (endIdx == -1 && startIdx > -1) {
222 result.append(input, startIdx, input.length());
223 } else if (endIdx < input.length()) {
224 result.append(input, endIdx + 1, input.length());
225 }
226
227 return result.toString();
228 } else {
229 return input;
230 }
231 }
232
233
234
235
236
237
238
239
240
241
242 public List getFeedback() {
243 List<?> messages = new ArrayList();
244 for (ValueSource vs : valueSources) {
245 List feedback = vs.getFeedback();
246 if (feedback != null && !feedback.isEmpty()) {
247 messages.addAll(feedback);
248 }
249 }
250
251 return messages;
252 }
253
254
255
256
257 public void clearFeedback() {
258 for (ValueSource vs : valueSources) {
259 vs.clearFeedback();
260 }
261 }
262
263 public boolean isCacheAnswers() {
264 return cacheAnswers;
265 }
266
267 public void setCacheAnswers(boolean cacheAnswers) {
268 this.cacheAnswers = cacheAnswers;
269 }
270
271 public void clearAnswers() {
272 existingAnswers.clear();
273 }
274
275 public String getEscapeString() {
276 return escapeString;
277 }
278
279 public void setEscapeString(String escapeString) {
280 this.escapeString = escapeString;
281 }
282
283
284
285
286
287
288 protected Object getExistingAnswer(String key) {
289 return existingAnswers.get(key);
290 }
291 }