1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.util;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.kuali.rice.core.api.exception.RiceRuntimeException;
22 import org.kuali.rice.krad.datadictionary.uif.UifDictionaryBean;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29
30
31
32
33
34 public class ExpressionUtils {
35 private static final Log LOG = LogFactory.getLog(ExpressionUtils.class);
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public static void populatePropertyExpressionsFromGraph(UifDictionaryBean expressionConfigurable) {
59 if (expressionConfigurable == null || expressionConfigurable.getExpressionGraph() == null) {
60 return;
61 }
62
63
64
65 Map<String, Map<String, String>> refreshExpressionGraphs = new HashMap<String, Map<String, String>>();
66
67 Map<String, String> expressionGraph = expressionConfigurable.getExpressionGraph();
68 for (Map.Entry<String, String> expressionEntry : expressionGraph.entrySet()) {
69 String propertyName = expressionEntry.getKey();
70 String expression = expressionEntry.getValue();
71
72
73 UifDictionaryBean configurableWithExpression = expressionConfigurable;
74
75
76 String adjustedPropertyName = propertyName;
77 if (StringUtils.contains(propertyName, ".")) {
78 String configurablePath = StringUtils.substringBeforeLast(propertyName, ".");
79 adjustedPropertyName = StringUtils.substringAfterLast(propertyName, ".");
80
81 Object nestedObject = ObjectPropertyUtils.getPropertyValue(expressionConfigurable, configurablePath);
82
83
84
85 if (nestedObject == null
86 && expressionConfigurable instanceof LifecycleElement
87 && ((LifecycleElement) expressionConfigurable).skipLifecycle()) {
88 continue;
89 }
90
91 if ((nestedObject == null) || !(nestedObject instanceof UifDictionaryBean)) {
92 throw new RiceRuntimeException("Object for which expression is configured on is null or does not "
93 + "implement UifDictionaryBean: '"
94 + configurablePath
95 + "' on class "
96 + expressionConfigurable.getClass().getName()
97 + " while evaluating "
98 + "expression for "
99 + propertyName);
100 }
101
102
103 configurableWithExpression = (UifDictionaryBean) nestedObject;
104 }
105
106 configurableWithExpression.getPropertyExpressions().put(adjustedPropertyName, expression);
107 }
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 public static String parseExpression(String exp, List<String> controlNames) {
129
130 exp = exp.trim();
131 if (exp.startsWith("@{")) {
132 exp = StringUtils.removeStart(exp, "@{");
133 if (exp.endsWith("}")) {
134 exp = StringUtils.removeEnd(exp, "}");
135 }
136 }
137
138 exp = StringUtils.replace(exp, "!=", " != ");
139 exp = StringUtils.replace(exp, "==", " == ");
140 exp = StringUtils.replace(exp, ">", " > ");
141 exp = StringUtils.replace(exp, "<", " < ");
142 exp = StringUtils.replace(exp, "<=", " <= ");
143 exp = StringUtils.replace(exp, ">=", " >= ");
144
145 String conditionJs = exp;
146 String stack = "";
147
148 boolean expectingSingleQuote = false;
149 boolean ignoreNext = false;
150 for (int i = 0; i < exp.length(); i++) {
151 char c = exp.charAt(i);
152 if (!expectingSingleQuote && !ignoreNext && (c == '(' || c == ' ' || c == ')')) {
153 evaluateCurrentStack(stack.trim(), controlNames);
154
155 stack = "";
156 continue;
157 } else if (!ignoreNext && c == '\'') {
158 stack = stack + c;
159 expectingSingleQuote = !expectingSingleQuote;
160 } else if (c == '\\') {
161 stack = stack + c;
162 ignoreNext = !ignoreNext;
163 } else {
164 stack = stack + c;
165 ignoreNext = false;
166 }
167 }
168
169 if (StringUtils.isNotEmpty(stack)) {
170 evaluateCurrentStack(stack.trim(), controlNames);
171 }
172
173 conditionJs = conditionJs.replaceAll("\\s(?i:ne)\\s", " != ").replaceAll("\\s(?i:eq)\\s", " == ").replaceAll(
174 "\\s(?i:gt)\\s", " > ").replaceAll("\\s(?i:lt)\\s", " < ").replaceAll("\\s(?i:lte)\\s", " <= ")
175 .replaceAll("\\s(?i:gte)\\s", " >= ").replaceAll("\\s(?i:and)\\s", " && ").replaceAll("\\s(?i:or)\\s",
176 " || ").replaceAll("\\s(?i:not)\\s", " != ").replaceAll("\\s(?i:null)\\s?", " '' ").replaceAll(
177 "\\s?(?i:#empty)\\((.*?)\\)", "isValueEmpty($1)").replaceAll(
178 "\\s?(?i:#listContains)\\((.*?)\\)", "listContains($1)").replaceAll(
179 "\\s?(?i:#emptyList)\\((.*?)\\)", "emptyList($1)");
180
181 if (conditionJs.contains("matches")) {
182 conditionJs = conditionJs.replaceAll("\\s+(?i:matches)\\s+'.*'", ".match(/" + "$0" + "/) != null ");
183 conditionJs = conditionJs.replaceAll("\\(/\\s+(?i:matches)\\s+'", "(/");
184 conditionJs = conditionJs.replaceAll("'\\s*/\\)", "/)");
185 }
186
187 List<String> removeControlNames = new ArrayList<String>();
188 List<String> addControlNames = new ArrayList<String>();
189
190 for (String propertyName : controlNames) {
191
192 if (propertyName.trim().startsWith("{") && propertyName.trim().endsWith("}")) {
193 String array = propertyName.trim().replace('{', '[');
194 array = array.replace('}', ']');
195 conditionJs = conditionJs.replace(propertyName, array);
196 removeControlNames.add(propertyName);
197 continue;
198 }
199
200
201 if (propertyName.startsWith("!")) {
202 String actualPropertyName = StringUtils.removeStart(propertyName, "!");
203 conditionJs = conditionJs.replace(propertyName, "!coerceValue(\"" + actualPropertyName + "\")");
204 removeControlNames.add(propertyName);
205 addControlNames.add(actualPropertyName);
206 } else {
207 conditionJs = conditionJs.replace(propertyName, "coerceValue(\"" + propertyName + "\")");
208 }
209 }
210
211 controlNames.removeAll(removeControlNames);
212 controlNames.addAll(addControlNames);
213
214 return conditionJs;
215 }
216
217
218
219
220
221
222
223
224 public static void evaluateCurrentStack(String stack, List<String> controlNames) {
225 if (StringUtils.isNotBlank(stack)) {
226 if (!(stack.equals("==")
227 || stack.equals("!=")
228 || stack.equals(">")
229 || stack.equals("<")
230 || stack.equals(">=")
231 || stack.equals("<=")
232 || stack.equalsIgnoreCase("ne")
233 || stack.equalsIgnoreCase("eq")
234 || stack.equalsIgnoreCase("gt")
235 || stack.equalsIgnoreCase("lt")
236 || stack.equalsIgnoreCase("lte")
237 || stack.equalsIgnoreCase("gte")
238 || stack.equalsIgnoreCase("matches")
239 || stack.equalsIgnoreCase("null")
240 || stack.equalsIgnoreCase("false")
241 || stack.equalsIgnoreCase("true")
242 || stack.equalsIgnoreCase("and")
243 || stack.equalsIgnoreCase("or")
244 || stack.contains("#empty")
245 || stack.equals("!")
246 || stack.contains("#emptyList")
247 || stack.contains("#listContains")
248 || stack.startsWith("'")
249 || stack.endsWith("'"))) {
250
251 boolean isNumber = false;
252 if ((StringUtils.isNumeric(stack.substring(0, 1)) || stack.substring(0, 1).equals("-"))) {
253 try {
254 Double.parseDouble(stack);
255 isNumber = true;
256 } catch (NumberFormatException e) {
257 isNumber = false;
258 }
259 }
260
261 if (!(isNumber)) {
262
263 if (StringUtils.endsWith(stack, ",")) {
264 stack = StringUtils.removeEnd(stack, ",").trim();
265 }
266
267 if (!controlNames.contains(stack)) {
268 controlNames.add(stack);
269 }
270 }
271 }
272 }
273 }
274
275 }