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