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 if (startRegex != null || endRegex != null) {
181 if (thisPrefixPattern == null) {
182 expressionPattern = getPattern(startRegex + endRegex);
183 realExprGroup = 1;
184 } else {
185 expressionPattern = getPattern(startRegex + thisPrefixPattern + endRegex);
186 }
187
188 } else if (thisPrefixPattern != null) {
189 expressionPattern = getPattern("\\$\\{(" + thisPrefixPattern + ")?(.+?)\\}");
190 } else {
191 expressionPattern = getPattern(DEFAULT_REGEXP);
192 realExprGroup = 1;
193 }
194
195 try {
196 return interpolate(input, recursionInterceptor, expressionPattern, realExprGroup);
197 } finally {
198 if (!cacheAnswers) {
199 clearAnswers();
200 }
201 }
202 }
203
204 private Pattern getPattern(String regExp) {
205 if (!reusePatterns) {
206 return Pattern.compile(regExp);
207 }
208
209 Pattern pattern;
210 synchronized (this) {
211 pattern = compiledPatterns.get(regExp);
212
213 if (pattern != null) {
214 return pattern;
215 }
216
217 pattern = Pattern.compile(regExp);
218 compiledPatterns.put(regExp, pattern);
219 }
220
221 return pattern;
222 }
223
224
225
226
227
228
229
230 private String interpolate(
231 String input, RecursionInterceptor recursionInterceptor, Pattern expressionPattern, int realExprGroup)
232 throws InterpolationException {
233 if (input == null) {
234
235 return "";
236 }
237 String result = input;
238
239 Matcher matcher = expressionPattern.matcher(result);
240
241 while (matcher.find()) {
242 String wholeExpr = matcher.group(0);
243 String realExpr = matcher.group(realExprGroup);
244
245 if (realExpr.startsWith(".")) {
246 realExpr = realExpr.substring(1);
247 }
248
249 if (recursionInterceptor.hasRecursiveExpression(realExpr)) {
250 throw new InterpolationCycleException(recursionInterceptor, realExpr, wholeExpr);
251 }
252
253 recursionInterceptor.expressionResolutionStarted(realExpr);
254 try {
255 Object value = existingAnswers.get(realExpr);
256 for (ValueSource vs : valueSources) {
257 if (value != null) break;
258
259 value = vs.getValue(realExpr);
260 }
261
262 if (value != null) {
263 value = interpolate(String.valueOf(value), recursionInterceptor, expressionPattern, realExprGroup);
264
265 if (postProcessors != null && !postProcessors.isEmpty()) {
266 for (InterpolationPostProcessor postProcessor : postProcessors) {
267 Object newVal = postProcessor.execute(realExpr, value);
268 if (newVal != null) {
269 value = newVal;
270 break;
271 }
272 }
273 }
274
275
276
277
278 result = StringUtils.replace(result, wholeExpr, String.valueOf(value));
279
280 matcher.reset(result);
281 }
282 } finally {
283 recursionInterceptor.expressionResolutionFinished(realExpr);
284 }
285 }
286
287 return result;
288 }
289
290
291
292
293
294
295
296
297
298
299 public List getFeedback() {
300 List messages = new ArrayList();
301 for (Object valueSource : valueSources) {
302 ValueSource vs = (ValueSource) valueSource;
303 List feedback = vs.getFeedback();
304 if (feedback != null && !feedback.isEmpty()) {
305 messages.addAll(feedback);
306 }
307 }
308
309 return messages;
310 }
311
312
313
314
315 public void clearFeedback() {
316 for (Object valueSource : valueSources) {
317 ValueSource vs = (ValueSource) valueSource;
318 vs.clearFeedback();
319 }
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333 public String interpolate(String input, String thisPrefixPattern) throws InterpolationException {
334 return interpolate(input, thisPrefixPattern, null);
335 }
336
337
338
339
340
341
342
343
344
345
346
347 public String interpolate(String input) throws InterpolationException {
348 return interpolate(input, null, null);
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364 public String interpolate(String input, RecursionInterceptor recursionInterceptor) throws InterpolationException {
365 return interpolate(input, null, recursionInterceptor);
366 }
367
368 public boolean isReusePatterns() {
369 return reusePatterns;
370 }
371
372 public void setReusePatterns(boolean reusePatterns) {
373 this.reusePatterns = reusePatterns;
374 }
375
376 public boolean isCacheAnswers() {
377 return cacheAnswers;
378 }
379
380 public void setCacheAnswers(boolean cacheAnswers) {
381 this.cacheAnswers = cacheAnswers;
382 }
383
384 public void clearAnswers() {
385 existingAnswers.clear();
386 }
387 }