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 = existingAnswers.get(realExpr);
160 Object bestAnswer = null;
161
162 for (ValueSource valueSource : valueSources) {
163 if (value != null) {
164 break;
165 }
166 value = valueSource.getValue(realExpr);
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 } else {
201 unresolvable.add(wholeExpr);
202 }
203 } finally {
204 recursionInterceptor.expressionResolutionFinished(realExpr);
205 }
206 }
207
208 if (!resolved) {
209 result.append(wholeExpr);
210 }
211
212 if (endIdx > -1) {
213 endIdx += endExpr.length() - 1;
214 }
215 } while ((startIdx = input.indexOf(startExpr, endIdx + 1)) > -1);
216
217 if (endIdx == -1 && startIdx > -1) {
218 result.append(input, startIdx, input.length());
219 } else if (endIdx < input.length()) {
220 result.append(input, endIdx + 1, input.length());
221 }
222
223 return result.toString();
224 } else {
225 return input;
226 }
227 }
228
229
230
231
232
233
234
235
236
237
238 public List getFeedback() {
239 List<?> messages = new ArrayList();
240 for (ValueSource vs : valueSources) {
241 List feedback = vs.getFeedback();
242 if (feedback != null && !feedback.isEmpty()) {
243 messages.addAll(feedback);
244 }
245 }
246
247 return messages;
248 }
249
250
251
252
253 public void clearFeedback() {
254 for (ValueSource vs : valueSources) {
255 vs.clearFeedback();
256 }
257 }
258
259 public boolean isCacheAnswers() {
260 return cacheAnswers;
261 }
262
263 public void setCacheAnswers(boolean cacheAnswers) {
264 this.cacheAnswers = cacheAnswers;
265 }
266
267 public void clearAnswers() {
268 existingAnswers.clear();
269 }
270
271 public String getEscapeString() {
272 return escapeString;
273 }
274
275 public void setEscapeString(String escapeString) {
276 this.escapeString = escapeString;
277 }
278 }