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 public static void populatePropertyExpressionsFromGraph(UifDictionaryBean expressionConfigurable, boolean buildRefreshGraphs) {
54 if (expressionConfigurable == null || expressionConfigurable.getExpressionGraph() == null) {
55 return;
56 }
57
58
59
60 Map<String, Map<String, String>> refreshExpressionGraphs = new HashMap<String, Map<String, String>>();
61
62 Map<String, String> expressionGraph = expressionConfigurable.getExpressionGraph();
63 for (Map.Entry<String, String> expressionEntry : expressionGraph.entrySet()) {
64 String propertyName = expressionEntry.getKey();
65 String expression = expressionEntry.getValue();
66
67
68 UifDictionaryBean configurableWithExpression = expressionConfigurable;
69
70
71 String adjustedPropertyName = propertyName;
72 if (StringUtils.contains(propertyName, ".")) {
73 String configurablePath = StringUtils.substringBeforeLast(propertyName, ".");
74 adjustedPropertyName = StringUtils.substringAfterLast(propertyName, ".");
75
76 Object nestedObject = ObjectPropertyUtils.getPropertyValue(expressionConfigurable, configurablePath);
77 if ((nestedObject == null) || !(nestedObject instanceof UifDictionaryBean)) {
78 throw new RiceRuntimeException(
79 "Object for which expression is configured on is null or does not implement UifDictionaryBean: '"
80 + configurablePath
81 + "'");
82 }
83
84
85 configurableWithExpression = (UifDictionaryBean) nestedObject;
86
87
88 if (buildRefreshGraphs) {
89 String currentPath = "";
90
91 String[] configurablePathNames = StringUtils.split(configurablePath, ".");
92 for (String configurablePathName : configurablePathNames) {
93 if (StringUtils.isNotBlank(currentPath)) {
94 currentPath += ".";
95 }
96 currentPath += configurablePathName;
97
98 Map<String, String> graphExpressions = null;
99 if (refreshExpressionGraphs.containsKey(currentPath)) {
100 graphExpressions = refreshExpressionGraphs.get(currentPath);
101 } else {
102 graphExpressions = new HashMap<String, String>();
103 refreshExpressionGraphs.put(currentPath, graphExpressions);
104 }
105
106
107 String configurablePropertyName = StringUtils.substringAfter(propertyName, currentPath + ".");
108 graphExpressions.put(configurablePropertyName, expression);
109 }
110 }
111 }
112
113 configurableWithExpression.getPropertyExpressions().put(adjustedPropertyName, expression);
114 }
115
116
117 if (buildRefreshGraphs) {
118 for (String configurablePath : refreshExpressionGraphs.keySet()) {
119 Object nestedObject = ObjectPropertyUtils.getPropertyValue(expressionConfigurable, configurablePath);
120
121 if ((nestedObject != null) && (nestedObject instanceof UifDictionaryBean)) {
122 ((UifDictionaryBean) nestedObject).setRefreshExpressionGraph(refreshExpressionGraphs.get(
123 configurablePath));
124 }
125 }
126
127
128 expressionConfigurable.setRefreshExpressionGraph(expressionGraph);
129 }
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 public static String parseExpression(String exp, List<String> controlNames) {
151
152 exp = exp.trim();
153 if (exp.startsWith("@{")) {
154 exp = StringUtils.removeStart(exp, "@{");
155 if (exp.endsWith("}")) {
156 exp = StringUtils.removeEnd(exp, "}");
157 }
158 }
159
160 exp = StringUtils.replace(exp, "!=", " != ");
161 exp = StringUtils.replace(exp, "==", " == ");
162 exp = StringUtils.replace(exp, ">", " > ");
163 exp = StringUtils.replace(exp, "<", " < ");
164 exp = StringUtils.replace(exp, "<=", " <= ");
165 exp = StringUtils.replace(exp, ">=", " >= ");
166
167 String conditionJs = exp;
168 String stack = "";
169
170 boolean expectingSingleQuote = false;
171 boolean ignoreNext = false;
172 for (int i = 0; i < exp.length(); i++) {
173 char c = exp.charAt(i);
174 if (!expectingSingleQuote && !ignoreNext && (c == '(' || c == ' ' || c == ')')) {
175 evaluateCurrentStack(stack.trim(), controlNames);
176
177 stack = "";
178 continue;
179 } else if (!ignoreNext && c == '\'') {
180 stack = stack + c;
181 expectingSingleQuote = !expectingSingleQuote;
182 } else if (c == '\\') {
183 stack = stack + c;
184 ignoreNext = !ignoreNext;
185 } else {
186 stack = stack + c;
187 ignoreNext = false;
188 }
189 }
190
191 if (StringUtils.isNotEmpty(stack)) {
192 evaluateCurrentStack(stack.trim(), controlNames);
193 }
194
195 conditionJs = conditionJs.replaceAll("\\s(?i:ne)\\s", " != ").replaceAll("\\s(?i:eq)\\s", " == ").replaceAll(
196 "\\s(?i:gt)\\s", " > ").replaceAll("\\s(?i:lt)\\s", " < ").replaceAll("\\s(?i:lte)\\s", " <= ")
197 .replaceAll("\\s(?i:gte)\\s", " >= ").replaceAll("\\s(?i:and)\\s", " && ").replaceAll("\\s(?i:or)\\s",
198 " || ").replaceAll("\\s(?i:not)\\s", " != ").replaceAll("\\s(?i:null)\\s?", " '' ").replaceAll(
199 "\\s?(?i:#empty)\\((.*?)\\)", "isValueEmpty($1)").replaceAll("\\s?(?i:#listContains)\\((.*?)\\)",
200 "listContains($1)").replaceAll("\\s?(?i:#emptyList)\\((.*?)\\)", "emptyList($1)");
201
202 if (conditionJs.contains("matches")) {
203 conditionJs = conditionJs.replaceAll("\\s+(?i:matches)\\s+'.*'", ".match(/" + "$0" + "/) != null ");
204 conditionJs = conditionJs.replaceAll("\\(/\\s+(?i:matches)\\s+'", "(/");
205 conditionJs = conditionJs.replaceAll("'\\s*/\\)", "/)");
206 }
207
208 List<String> removeControlNames = new ArrayList<String>();
209
210 for (String propertyName : controlNames) {
211
212 if(propertyName.trim().startsWith("{") && propertyName.trim().endsWith("}")){
213 String array = propertyName.trim().replace('{', '[');
214 array = array.replace('}', ']');
215 conditionJs = conditionJs.replace(propertyName, array);
216 removeControlNames.add(propertyName);
217 continue;
218 }
219
220 conditionJs = conditionJs.replace(propertyName, "coerceValue(\"" + propertyName + "\")");
221 }
222
223 controlNames.removeAll(removeControlNames);
224
225 return conditionJs;
226 }
227
228
229
230
231
232
233
234
235 public static void evaluateCurrentStack(String stack, List<String> controlNames) {
236 if (StringUtils.isNotBlank(stack)) {
237 if (!(stack.equals("==")
238 || stack.equals("!=")
239 || stack.equals(">")
240 || stack.equals("<")
241 || stack.equals(">=")
242 || stack.equals("<=")
243 || stack.equalsIgnoreCase("ne")
244 || stack.equalsIgnoreCase("eq")
245 || stack.equalsIgnoreCase("gt")
246 || stack.equalsIgnoreCase("lt")
247 || stack.equalsIgnoreCase("lte")
248 || stack.equalsIgnoreCase("gte")
249 || stack.equalsIgnoreCase("matches")
250 || stack.equalsIgnoreCase("null")
251 || stack.equalsIgnoreCase("false")
252 || stack.equalsIgnoreCase("true")
253 || stack.equalsIgnoreCase("and")
254 || stack.equalsIgnoreCase("or")
255 || stack.contains("#empty")
256 || stack.contains("#emptyList")
257 || stack.contains("#listContains")
258 || stack.startsWith("'")
259 || stack.endsWith("'"))) {
260
261 boolean isNumber = false;
262 if ((StringUtils.isNumeric(stack.substring(0, 1)) || stack.substring(0, 1).equals("-"))) {
263 try {
264 Double.parseDouble(stack);
265 isNumber = true;
266 } catch (NumberFormatException e) {
267 isNumber = false;
268 }
269 }
270
271 if (!(isNumber)) {
272
273 if(StringUtils.endsWith(stack, ",")){
274 stack = StringUtils.removeEnd(stack, ",").trim();
275 }
276
277 if (!controlNames.contains(stack)) {
278 controlNames.add(stack);
279 }
280 }
281 }
282 }
283 }
284
285 }