1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration2.interpol;
18
19 import java.util.ArrayList;
20 import java.util.Objects;
21
22 import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
23 import org.apache.commons.configuration2.io.ConfigurationLogger;
24 import org.apache.commons.jexl2.Expression;
25 import org.apache.commons.jexl2.JexlContext;
26 import org.apache.commons.jexl2.JexlEngine;
27 import org.apache.commons.jexl2.MapContext;
28 import org.apache.commons.lang3.ClassUtils;
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.commons.text.StringSubstitutor;
31 import org.apache.commons.text.lookup.StringLookup;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class ExprLookup implements Lookup {
66
67 private static final String CLASS = "Class:";
68
69
70 private static final String DEFAULT_PREFIX = "$[";
71
72
73 private static final String DEFAULT_SUFFIX = "]";
74
75
76 private ConfigurationInterpolator interpolator;
77
78
79 private StringSubstitutor substitutor;
80
81
82 private ConfigurationLogger logger;
83
84
85 private final JexlEngine engine = new JexlEngine();
86
87
88 private Variables variables;
89
90
91 private String prefixMatcher = DEFAULT_PREFIX;
92
93
94 private String suffixMatcher = DEFAULT_SUFFIX;
95
96
97
98
99 public ExprLookup() {
100 }
101
102
103
104
105
106
107 public ExprLookup(final Variables list) {
108 setVariables(list);
109 }
110
111
112
113
114
115
116
117
118 public ExprLookup(final Variables list, final String prefix, final String suffix) {
119 this(list);
120 setVariablePrefixMatcher(prefix);
121 setVariableSuffixMatcher(suffix);
122 }
123
124
125
126
127
128
129
130 public void setVariablePrefixMatcher(final String prefix) {
131 prefixMatcher = prefix;
132 }
133
134
135
136
137
138
139
140 public void setVariableSuffixMatcher(final String suffix) {
141 suffixMatcher = suffix;
142 }
143
144
145
146
147
148
149 public void setVariables(final Variables list) {
150 variables = new Variables(list);
151 }
152
153
154
155
156
157
158
159 public Variables getVariables() {
160 return new Variables(variables);
161 }
162
163
164
165
166
167
168
169 public ConfigurationLogger getLogger() {
170 return logger;
171 }
172
173
174
175
176
177
178
179 public void setLogger(final ConfigurationLogger logger) {
180 this.logger = logger;
181 }
182
183
184
185
186
187
188
189 public ConfigurationInterpolator getInterpolator() {
190 return interpolator;
191 }
192
193
194
195
196
197
198
199 public void setInterpolator(final ConfigurationInterpolator interpolator) {
200 this.interpolator = interpolator;
201 installSubstitutor(interpolator);
202 }
203
204
205
206
207
208
209
210 @Override
211 public String lookup(final String var) {
212 if (substitutor == null) {
213 return var;
214 }
215
216 String result = substitutor.replace(var);
217 try {
218 final Expression exp = engine.createExpression(result);
219 final Object exprResult = exp.evaluate(createContext());
220 result = exprResult != null ? String.valueOf(exprResult) : null;
221 } catch (final Exception e) {
222 final ConfigurationLogger l = getLogger();
223 if (l != null) {
224 l.debug("Error encountered evaluating " + result + ": " + e);
225 }
226 }
227
228 return result;
229 }
230
231
232
233
234
235
236
237 private void installSubstitutor(final ConfigurationInterpolator ip) {
238 if (ip == null) {
239 substitutor = null;
240 } else {
241 final StringLookup variableResolver = key -> Objects.toString(ip.resolve(key), null);
242 substitutor = new StringSubstitutor(variableResolver, prefixMatcher, suffixMatcher, StringSubstitutor.DEFAULT_ESCAPE);
243 }
244 }
245
246
247
248
249
250
251 private JexlContext createContext() {
252 final JexlContext ctx = new MapContext();
253 initializeContext(ctx);
254 return ctx;
255 }
256
257
258
259
260
261
262 private void initializeContext(final JexlContext ctx) {
263 variables.forEach(var -> ctx.set(var.getName(), var.getValue()));
264 }
265
266
267
268
269 public static class Variables extends ArrayList<Variable> {
270
271
272
273 private static final long serialVersionUID = 20111205L;
274
275
276
277
278 public Variables() {
279 }
280
281
282
283
284
285
286 public Variables(final Variables vars) {
287 super(vars);
288 }
289
290 public Variable getVariable() {
291 return !isEmpty() ? get(size() - 1) : null;
292 }
293
294 }
295
296
297
298
299 public static class Variable {
300
301 private String key;
302
303
304 private Object value;
305
306 public Variable() {
307 }
308
309 public Variable(final String name, final Object value) {
310 setName(name);
311 setValue(value);
312 }
313
314 public String getName() {
315 return key;
316 }
317
318 public void setName(final String name) {
319 this.key = name;
320 }
321
322 public Object getValue() {
323 return value;
324 }
325
326 public void setValue(final Object value) throws ConfigurationRuntimeException {
327 try {
328 if (!(value instanceof String)) {
329 this.value = value;
330 return;
331 }
332 final String val = (String) value;
333 final String name = StringUtils.removeStartIgnoreCase(val, CLASS);
334 final Class<?> clazz = ClassUtils.getClass(name);
335 if (name.length() == val.length()) {
336 this.value = clazz.getConstructor().newInstance();
337 } else {
338 this.value = clazz;
339 }
340 } catch (final Exception e) {
341 throw new ConfigurationRuntimeException("Unable to create " + value, e);
342 }
343
344 }
345 }
346 }