1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.service.impl;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.krad.datadictionary.uif.UifDictionaryBean;
20 import org.kuali.rice.krad.uif.UifConstants;
21 import org.kuali.rice.krad.uif.component.BindingInfo;
22 import org.kuali.rice.krad.uif.component.Component;
23 import org.kuali.rice.krad.uif.component.KeepExpression;
24 import org.kuali.rice.krad.uif.component.PropertyReplacer;
25 import org.kuali.rice.krad.uif.container.CollectionGroup;
26 import org.kuali.rice.krad.uif.field.DataField;
27 import org.kuali.rice.krad.uif.layout.LayoutManager;
28 import org.kuali.rice.krad.uif.service.ExpressionEvaluatorService;
29 import org.kuali.rice.krad.uif.util.CloneUtils;
30 import org.kuali.rice.krad.uif.util.ExpressionFunctions;
31 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
32 import org.kuali.rice.krad.uif.view.View;
33 import org.springframework.expression.Expression;
34 import org.springframework.expression.ExpressionParser;
35 import org.springframework.expression.common.TemplateParserContext;
36 import org.springframework.expression.spel.standard.SpelExpressionParser;
37 import org.springframework.expression.spel.support.StandardEvaluationContext;
38
39 import java.util.Collection;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Map.Entry;
43
44
45
46
47
48
49 public class ExpressionEvaluatorServiceImpl implements ExpressionEvaluatorService {
50 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
51 ExpressionEvaluatorServiceImpl.class);
52
53
54
55
56
57
58 public void evaluateExpressionsOnConfigurable(View view, UifDictionaryBean expressionConfigurable,
59 Object contextObject, Map<String, Object> evaluationParameters) {
60 if ((expressionConfigurable instanceof Component) || (expressionConfigurable instanceof LayoutManager)) {
61 evaluatePropertyReplacers(view, expressionConfigurable, contextObject, evaluationParameters);
62 }
63 evaluatePropertyExpressions(view, expressionConfigurable, contextObject, evaluationParameters);
64 }
65
66
67
68
69
70 public String evaluateExpressionTemplate(Object contextObject, Map<String, Object> evaluationParameters,
71 String expressionTemplate) {
72 StandardEvaluationContext context = new StandardEvaluationContext(contextObject);
73 context.setVariables(evaluationParameters);
74 addCustomFunctions(context);
75
76 ExpressionParser parser = new SpelExpressionParser();
77
78 String result = null;
79 try {
80 Expression expression = null;
81 if (StringUtils.contains(expressionTemplate, UifConstants.EL_PLACEHOLDER_PREFIX)) {
82 expression = parser.parseExpression(expressionTemplate, new TemplateParserContext(
83 UifConstants.EL_PLACEHOLDER_PREFIX, UifConstants.EL_PLACEHOLDER_SUFFIX));
84 } else {
85 expression = parser.parseExpression(expressionTemplate);
86 }
87
88 result = expression.getValue(context, String.class);
89 } catch (Exception e) {
90 LOG.error("Exception evaluating expression: " + expressionTemplate);
91 throw new RuntimeException("Exception evaluating expression: " + expressionTemplate, e);
92 }
93
94 return result;
95 }
96
97
98
99
100
101
102 public void evaluatePropertyExpression(View view, Object contextObject, Map<String, Object> evaluationParameters,
103 UifDictionaryBean expressionConfigurable, String propertyName, boolean removeExpression) {
104
105 Map<String, String> propertyExpressions = expressionConfigurable.getPropertyExpressions();
106 if ((propertyExpressions == null) || !propertyExpressions.containsKey(propertyName)) {
107 return;
108 }
109
110 String expression = propertyExpressions.get(propertyName);
111
112
113 if (CloneUtils.fieldHasAnnotation(expressionConfigurable.getClass(), propertyName, KeepExpression.class)) {
114
115 ObjectPropertyUtils.setPropertyValue(expressionConfigurable, propertyName, expression);
116 return;
117 }
118
119 Object propertyValue = null;
120
121
122 String adjustedExpression = replaceBindingPrefixes(view, expressionConfigurable, expression);
123
124
125 if (StringUtils.startsWith(adjustedExpression, UifConstants.EL_PLACEHOLDER_PREFIX) && StringUtils.endsWith(
126 adjustedExpression, UifConstants.EL_PLACEHOLDER_SUFFIX) && (StringUtils.countMatches(adjustedExpression,
127 UifConstants.EL_PLACEHOLDER_PREFIX) == 1)) {
128 propertyValue = evaluateExpression(contextObject, evaluationParameters, adjustedExpression);
129 } else {
130
131 propertyValue = evaluateExpressionTemplate(contextObject, evaluationParameters, adjustedExpression);
132 }
133
134
135
136 if (StringUtils.endsWith(propertyName, ExpressionEvaluatorService.EMBEDDED_PROPERTY_NAME_ADD_INDICATOR)) {
137 StringUtils.removeEnd(propertyName, ExpressionEvaluatorService.EMBEDDED_PROPERTY_NAME_ADD_INDICATOR);
138
139 Collection collectionValue = ObjectPropertyUtils.getPropertyValue(expressionConfigurable, propertyName);
140 if (collectionValue == null) {
141 throw new RuntimeException("Property name: "
142 + propertyName
143 + " with collection type was not initialized. Cannot add expression result");
144 }
145 collectionValue.add(propertyValue);
146 } else {
147 ObjectPropertyUtils.setPropertyValue(expressionConfigurable, propertyName, propertyValue);
148 }
149
150 if (removeExpression) {
151 propertyExpressions.remove(propertyName);
152 }
153 }
154
155
156
157
158 public boolean containsElPlaceholder(String value) {
159 boolean containsElPlaceholder = false;
160
161 if (StringUtils.isNotBlank(value)) {
162 String elPlaceholder = StringUtils.substringBetween(value, UifConstants.EL_PLACEHOLDER_PREFIX,
163 UifConstants.EL_PLACEHOLDER_SUFFIX);
164 if (StringUtils.isNotBlank(elPlaceholder)) {
165 containsElPlaceholder = true;
166 }
167 }
168
169 return containsElPlaceholder;
170 }
171
172
173
174
175
176 public String replaceBindingPrefixes(View view, Object object, String expression) {
177 String adjustedExpression = StringUtils.replace(expression, UifConstants.NO_BIND_ADJUST_PREFIX, "");
178
179
180 if (object instanceof DataField) {
181
182
183 BindingInfo bindingInfo = ((DataField) object).getBindingInfo();
184 String fieldPath = bindingInfo.getBindingPath();
185
186
187 fieldPath = StringUtils.removeEnd(fieldPath, "." + bindingInfo.getBindingName());
188 adjustedExpression = StringUtils.replace(adjustedExpression, UifConstants.FIELD_PATH_BIND_ADJUST_PREFIX,
189 fieldPath + ".");
190 } else {
191 adjustedExpression = StringUtils.replace(adjustedExpression, UifConstants.FIELD_PATH_BIND_ADJUST_PREFIX,
192 "");
193 }
194
195
196 if (StringUtils.isNotBlank(view.getDefaultBindingObjectPath())) {
197 adjustedExpression = StringUtils.replace(adjustedExpression, UifConstants.DEFAULT_PATH_BIND_ADJUST_PREFIX,
198 view.getDefaultBindingObjectPath() + ".");
199
200 } else {
201 adjustedExpression = StringUtils.replace(adjustedExpression, UifConstants.DEFAULT_PATH_BIND_ADJUST_PREFIX,
202 "");
203 }
204
205
206 if (adjustedExpression.contains(UifConstants.LINE_PATH_BIND_ADJUST_PREFIX) && (object instanceof Component)) {
207 String linePath = getLinePathPrefixValue((Component) object);
208
209 adjustedExpression = StringUtils.replace(adjustedExpression, UifConstants.LINE_PATH_BIND_ADJUST_PREFIX,
210 linePath + ".");
211 }
212
213
214 if (adjustedExpression.contains(UifConstants.NODE_PATH_BIND_ADJUST_PREFIX) && (object instanceof Component)) {
215 String nodePath = "";
216
217 Map<String, Object> context = ((Component) object).getContext();
218 if (context.containsKey(UifConstants.ContextVariableNames.NODE_PATH)) {
219 nodePath = (String) context.get(UifConstants.ContextVariableNames.NODE_PATH);
220 }
221
222 adjustedExpression = StringUtils.replace(adjustedExpression, UifConstants.NODE_PATH_BIND_ADJUST_PREFIX,
223 nodePath + ".");
224 }
225
226 return adjustedExpression;
227 }
228
229
230
231
232
233 public Object evaluateExpression(Object contextObject, Map<String, Object> evaluationParameters,
234 String expressionStr) {
235 StandardEvaluationContext context = new StandardEvaluationContext(contextObject);
236 context.setVariables(evaluationParameters);
237 addCustomFunctions(context);
238
239
240 if (StringUtils.startsWith(expressionStr, UifConstants.EL_PLACEHOLDER_PREFIX) && StringUtils.endsWith(
241 expressionStr, UifConstants.EL_PLACEHOLDER_SUFFIX)) {
242 expressionStr = StringUtils.removeStart(expressionStr, UifConstants.EL_PLACEHOLDER_PREFIX);
243 expressionStr = StringUtils.removeEnd(expressionStr, UifConstants.EL_PLACEHOLDER_SUFFIX);
244 }
245
246 ExpressionParser parser = new SpelExpressionParser();
247 Object result = null;
248 try {
249 Expression expression = parser.parseExpression(expressionStr);
250
251 result = expression.getValue(context);
252 } catch (Exception e) {
253 LOG.error("Exception evaluating expression: " + expressionStr);
254 throw new RuntimeException("Exception evaluating expression: " + expressionStr, e);
255 }
256
257 return result;
258 }
259
260
261
262
263
264
265 protected void addCustomFunctions(StandardEvaluationContext context) {
266 try {
267
268 context.registerFunction("isAssignableFrom", ExpressionFunctions.class.getDeclaredMethod("isAssignableFrom",
269 new Class[]{Class.class, Class.class}));
270 context.registerFunction("empty", ExpressionFunctions.class.getDeclaredMethod("empty",
271 new Class[]{Object.class}));
272 context.registerFunction("emptyList", ExpressionFunctions.class.getDeclaredMethod("emptyList",
273 new Class[]{List.class}));
274 context.registerFunction("listContains", ExpressionFunctions.class.getDeclaredMethod("listContains",
275 new Class[]{List.class, Object[].class}));
276 context.registerFunction("getName", ExpressionFunctions.class.getDeclaredMethod("getName",
277 new Class[]{Class.class}));
278 context.registerFunction("getParm", ExpressionFunctions.class.getDeclaredMethod("getParm",
279 new Class[]{String.class, String.class, String.class}));
280 context.registerFunction("getParmInd", ExpressionFunctions.class.getDeclaredMethod("getParmInd",
281 new Class[]{String.class, String.class, String.class}));
282 context.registerFunction("hasPerm", ExpressionFunctions.class.getDeclaredMethod("hasPerm",
283 new Class[]{String.class, String.class}));
284 context.registerFunction("hasPermDtls", ExpressionFunctions.class.getDeclaredMethod("hasPermDtls",
285 new Class[]{String.class, String.class, Map.class, Map.class}));
286 context.registerFunction("hasPermTmpl", ExpressionFunctions.class.getDeclaredMethod("hasPermTmpl",
287 new Class[]{String.class, String.class, Map.class, Map.class}));
288 context.registerFunction("sequence", ExpressionFunctions.class.getDeclaredMethod("sequence",
289 new Class[]{String.class}));
290 } catch (NoSuchMethodException e) {
291 LOG.error("Custom function for el expressions not found: " + e.getMessage());
292 throw new RuntimeException("Custom function for el expressions not found: " + e.getMessage(), e);
293 }
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307
308 protected void evaluatePropertyReplacers(View view, UifDictionaryBean expressionConfigurable, Object contextObject,
309 Map<String, Object> evaluationParameters) {
310 List<PropertyReplacer> replacers = null;
311 if (Component.class.isAssignableFrom(expressionConfigurable.getClass())) {
312 replacers = ((Component) expressionConfigurable).getPropertyReplacers();
313 } else if (LayoutManager.class.isAssignableFrom(expressionConfigurable.getClass())) {
314 replacers = ((LayoutManager) expressionConfigurable).getPropertyReplacers();
315 }
316
317 for (PropertyReplacer propertyReplacer : replacers) {
318 String expression = propertyReplacer.getCondition();
319 String adjustedExpression = replaceBindingPrefixes(view, expressionConfigurable, expression);
320
321 String conditionEvaluation = evaluateExpressionTemplate(contextObject, evaluationParameters,
322 adjustedExpression);
323 boolean conditionSuccess = Boolean.parseBoolean(conditionEvaluation);
324 if (conditionSuccess) {
325 ObjectPropertyUtils.setPropertyValue(expressionConfigurable, propertyReplacer.getPropertyName(),
326 propertyReplacer.getReplacement());
327 }
328 }
329 }
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346 protected void evaluatePropertyExpressions(View view, UifDictionaryBean expressionConfigurable,
347 Object contextObject, Map<String, Object> evaluationParameters) {
348 Map<String, String> propertyExpressions = expressionConfigurable.getPropertyExpressions();
349 for (String propertyName : propertyExpressions.keySet()) {
350 evaluatePropertyExpression(view, contextObject, evaluationParameters, expressionConfigurable, propertyName,
351 false);
352 }
353 }
354
355
356
357
358
359
360
361
362
363 protected static String getLinePathPrefixValue(Component component) {
364 String linePath = "";
365
366 CollectionGroup collectionGroup = (CollectionGroup) (component.getContext().get(
367 UifConstants.ContextVariableNames.COLLECTION_GROUP));
368 if (collectionGroup == null) {
369 LOG.warn("collection group not found for " + component + "," + component.getId() + ", " + component
370 .getComponentTypeName());
371 return linePath;
372 }
373
374 Object indexObj = component.getContext().get(UifConstants.ContextVariableNames.INDEX);
375 if (indexObj != null) {
376 int index = (Integer) indexObj;
377 boolean addLine = false;
378 Object addLineObj = component.getContext().get(UifConstants.ContextVariableNames.IS_ADD_LINE);
379
380 if (addLineObj != null) {
381 addLine = (Boolean) addLineObj;
382 }
383
384 if (addLine) {
385 linePath = collectionGroup.getAddLineBindingInfo().getBindingPath();
386 } else {
387 linePath = collectionGroup.getBindingInfo().getBindingPath() + "[" + index + "]";
388 }
389 }
390
391 return linePath;
392 }
393
394 }