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.List;
22 import java.util.Map;
23 import java.util.WeakHashMap;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27 import org.codehaus.plexus.interpolation.util.StringUtils;
28
29
30
31
32
33
34
35
36 public class RegexBasedInterpolator implements Interpolator {
37
38 private String startRegex;
39
40 private String endRegex;
41
42 private Map existingAnswers = new HashMap();
43
44 private List<ValueSource> valueSources = new ArrayList<ValueSource>();
45
46 private List<InterpolationPostProcessor> postProcessors = new ArrayList<InterpolationPostProcessor>();
47
48 private boolean reusePatterns = false;
49
50 private boolean cacheAnswers = false;
51
52 public static final String DEFAULT_REGEXP = "\\$\\{(.+?)\\}";
53
54
55
56
57
58 private Map<String, Pattern> compiledPatterns = new WeakHashMap<String, Pattern>();
59
60
61
62
63
64
65
66 public RegexBasedInterpolator() {
67 compiledPatterns.put(DEFAULT_REGEXP, Pattern.compile(DEFAULT_REGEXP));
68 }
69
70
71
72
73
74 public RegexBasedInterpolator(boolean reusePatterns) {
75 this();
76 this.reusePatterns = reusePatterns;
77 }
78
79
80
81
82
83
84
85
86
87
88
89 public RegexBasedInterpolator(String startRegex, String endRegex) {
90 this();
91 this.startRegex = startRegex;
92 this.endRegex = endRegex;
93 }
94
95
96
97
98
99
100 public RegexBasedInterpolator(List valueSources) {
101 this();
102 this.valueSources.addAll(valueSources);
103 }
104
105
106
107
108
109
110
111
112
113 public RegexBasedInterpolator(String startRegex, String endRegex, List valueSources) {
114 this();
115 this.startRegex = startRegex;
116 this.endRegex = endRegex;
117 this.valueSources.addAll(valueSources);
118 }
119
120
121
122
123 public void addValueSource(ValueSource valueSource) {
124 valueSources.add(valueSource);
125 }
126
127
128
129
130 public void removeValuesSource(ValueSource valueSource) {
131 valueSources.remove(valueSource);
132 }
133
134
135
136
137 public void addPostProcessor(InterpolationPostProcessor postProcessor) {
138 postProcessors.add(postProcessor);
139 }
140
141
142
143
144 public void removePostProcessor(InterpolationPostProcessor postProcessor) {
145 postProcessors.remove(postProcessor);
146 }
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 public String interpolate(String input, String thisPrefixPattern, RecursionInterceptor recursionInterceptor)
165 throws InterpolationException {
166 if (input == null) {
167
168 return "";
169 }
170 if (recursionInterceptor == null) {
171 recursionInterceptor = new SimpleRecursionInterceptor();
172 }
173
174 if (thisPrefixPattern != null && thisPrefixPattern.length() == 0) {
175 thisPrefixPattern = null;
176 }
177
178 int realExprGroup = 2;
179 Pattern expressionPattern;
180 final String expressionDelimiterStart;
181 final String expressionDelimiterEnd;
182 if (startRegex != null || endRegex != null) {
183 if (thisPrefixPattern == null) {
184 expressionPattern = getPattern(startRegex + endRegex);
185 realExprGroup = 1;
186 } else {
187 expressionPattern = getPattern(startRegex + thisPrefixPattern + endRegex);
188 }
189 expressionDelimiterStart = startRegex;
190 expressionDelimiterEnd = endRegex;
191
192 } else {
193 expressionDelimiterStart = "${";
194 expressionDelimiterEnd = "}";
195 if (thisPrefixPattern != null) {
196 expressionPattern = getPattern("\\$\\{(" + thisPrefixPattern + ")?(.+?)\\}");
197 } else {
198 expressionPattern = getPattern(DEFAULT_REGEXP);
199 realExprGroup = 1;
200 }
201 }
202 try {
203 return interpolate(
204 input,
205 recursionInterceptor,
206 expressionPattern,
207 expressionDelimiterStart,
208 expressionDelimiterEnd,
209 realExprGroup);
210 } finally {
211 if (!cacheAnswers) {
212 clearAnswers();
213 }
214 }
215 }
216
217 private Pattern getPattern(String regExp) {
218 if (!reusePatterns) {
219 return Pattern.compile(regExp);
220 }
221
222 Pattern pattern;
223 synchronized (this) {
224 pattern = compiledPatterns.get(regExp);
225
226 if (pattern != null) {
227 return pattern;
228 }
229
230 pattern = Pattern.compile(regExp);
231 compiledPatterns.put(regExp, pattern);
232 }
233
234 return pattern;
235 }
236
237
238
239
240
241
242
243 private String interpolate(
244 String input,
245 RecursionInterceptor recursionInterceptor,
246 Pattern expressionPattern,
247 String expressionDelimiterStart,
248 String expressionDelimiterEnd,
249 int realExprGroup)
250 throws InterpolationException {
251 if (input == null) {
252
253 return "";
254 }
255 String result = input;
256
257 Matcher matcher = expressionPattern.matcher(result);
258
259 while (matcher.find()) {
260 String wholeExpr = matcher.group(0);
261 String realExpr = matcher.group(realExprGroup);
262
263 if (realExpr.startsWith(".")) {
264 realExpr = realExpr.substring(1);
265 }
266
267 if (recursionInterceptor.hasRecursiveExpression(realExpr)) {
268 throw new InterpolationCycleException(recursionInterceptor, realExpr, wholeExpr);
269 }
270
271 recursionInterceptor.expressionResolutionStarted(realExpr);
272 try {
273 Object value = existingAnswers.get(realExpr);
274 for (ValueSource vs : valueSources) {
275 if (value != null) break;
276
277 value = vs.getValue(realExpr, expressionDelimiterStart, expressionDelimiterEnd);
278 }
279
280 if (value != null) {
281 value = interpolate(
282 String.valueOf(value),
283 recursionInterceptor,
284 expressionPattern,
285 expressionDelimiterStart,
286 expressionDelimiterEnd,
287 realExprGroup);
288
289 if (postProcessors != null && !postProcessors.isEmpty()) {
290 for (InterpolationPostProcessor postProcessor : postProcessors) {
291 Object newVal = postProcessor.execute(realExpr, value);
292 if (newVal != null) {
293 value = newVal;
294 break;
295 }
296 }
297 }
298
299
300
301
302 result = StringUtils.replace(result, wholeExpr, String.valueOf(value));
303
304 matcher.reset(result);
305 }
306 } finally {
307 recursionInterceptor.expressionResolutionFinished(realExpr);
308 }
309 }
310
311 return result;
312 }
313
314
315
316
317
318
319
320
321
322
323 public List getFeedback() {
324 List messages = new ArrayList();
325 for (Object valueSource : valueSources) {
326 ValueSource vs = (ValueSource) valueSource;
327 List feedback = vs.getFeedback();
328 if (feedback != null && !feedback.isEmpty()) {
329 messages.addAll(feedback);
330 }
331 }
332
333 return messages;
334 }
335
336
337
338
339 public void clearFeedback() {
340 for (Object valueSource : valueSources) {
341 ValueSource vs = (ValueSource) valueSource;
342 vs.clearFeedback();
343 }
344 }
345
346
347
348
349
350
351
352
353
354
355
356
357 public String interpolate(String input, String thisPrefixPattern) throws InterpolationException {
358 return interpolate(input, thisPrefixPattern, null);
359 }
360
361
362
363
364
365
366
367
368
369
370
371 public String interpolate(String input) throws InterpolationException {
372 return interpolate(input, null, null);
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388 public String interpolate(String input, RecursionInterceptor recursionInterceptor) throws InterpolationException {
389 return interpolate(input, null, recursionInterceptor);
390 }
391
392 public boolean isReusePatterns() {
393 return reusePatterns;
394 }
395
396 public void setReusePatterns(boolean reusePatterns) {
397 this.reusePatterns = reusePatterns;
398 }
399
400 public boolean isCacheAnswers() {
401 return cacheAnswers;
402 }
403
404 public void setCacheAnswers(boolean cacheAnswers) {
405 this.cacheAnswers = cacheAnswers;
406 }
407
408 public void clearAnswers() {
409 existingAnswers.clear();
410 }
411 }