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.krad.datadictionary.DataDictionary;
22 import org.kuali.rice.krad.uif.UifConstants;
23 import org.kuali.rice.krad.uif.UifPropertyPaths;
24 import org.kuali.rice.krad.uif.component.Configurable;
25 import org.springframework.beans.BeansException;
26 import org.springframework.beans.MutablePropertyValues;
27 import org.springframework.beans.PropertyValue;
28 import org.springframework.beans.factory.config.BeanDefinition;
29 import org.springframework.beans.factory.config.BeanDefinitionHolder;
30 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
31 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
32 import org.springframework.beans.factory.config.TypedStringValue;
33 import org.springframework.beans.factory.support.GenericBeanDefinition;
34 import org.springframework.beans.factory.support.ManagedList;
35 import org.springframework.beans.factory.support.ManagedMap;
36
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.LinkedHashMap;
41 import java.util.LinkedHashSet;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Set;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public class UifBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
61 private static final Log LOG = LogFactory.getLog(UifBeanFactoryPostProcessor.class);
62
63
64
65
66
67
68
69 @Override
70 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
71 Set<String> processedBeanNames = new HashSet<String>();
72
73 LOG.info("Beginning post processing of bean factory for UIF expressions");
74
75 String[] beanNames = beanFactory.getBeanDefinitionNames();
76 for (int i = 0; i < beanNames.length; i++) {
77 String beanName = beanNames[i];
78 BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
79
80 processBeanDefinition(beanName, beanDefinition, beanFactory, processedBeanNames);
81 }
82
83 LOG.info("Finished post processing of bean factory for UIF expressions");
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 protected void processBeanDefinition(String beanName, BeanDefinition beanDefinition,
100 ConfigurableListableBeanFactory beanFactory, Set<String> processedBeanNames) {
101 Class<?> beanClass = getBeanClass(beanDefinition, beanFactory);
102 if ((beanClass == null) || !Configurable.class.isAssignableFrom(beanClass)) {
103 return;
104 }
105
106 if (processedBeanNames.contains(beanName)) {
107 return;
108 }
109
110 LOG.debug("Processing bean name '" + beanName + "'");
111
112 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
113
114 if (pvs.getPropertyValue(UifPropertyPaths.PROPERTY_EXPRESSIONS) != null) {
115
116 return;
117 }
118
119 Map<String, String> propertyExpressions = new ManagedMap<String, String>();
120 Map<String, String> parentPropertyExpressions = getPropertyExpressionsFromParent(beanDefinition.getParentName(),
121 beanFactory, processedBeanNames);
122 boolean parentExpressionsExist = !parentPropertyExpressions.isEmpty();
123
124 PropertyValue[] pvArray = pvs.getPropertyValues();
125 for (PropertyValue pv : pvArray) {
126 if (hasExpression(pv.getValue())) {
127
128 String strValue = getStringValue(pv.getValue());
129 propertyExpressions.put(pv.getName(), strValue);
130
131
132 pvs.removePropertyValue(pv.getName());
133 } else {
134
135 Object newValue = processPropertyValue(pv.getName(), pv.getValue(), parentPropertyExpressions,
136 propertyExpressions, beanFactory, processedBeanNames);
137 pvs.removePropertyValue(pv.getName());
138 pvs.addPropertyValue(pv.getName(), newValue);
139 }
140
141
142 if (parentPropertyExpressions.containsKey(pv.getName())) {
143 parentPropertyExpressions.remove(pv.getName());
144 }
145
146
147 if (StringUtils.contains(pv.getName(), ".")) {
148
149 }
150 }
151
152 if (!propertyExpressions.isEmpty() || parentExpressionsExist) {
153
154 ManagedMap<String, String> mergedPropertyExpressions = new ManagedMap<String, String>();
155 mergedPropertyExpressions.setMergeEnabled(false);
156 mergedPropertyExpressions.putAll(parentPropertyExpressions);
157 mergedPropertyExpressions.putAll(propertyExpressions);
158
159 pvs.addPropertyValue(UifPropertyPaths.PROPERTY_EXPRESSIONS, mergedPropertyExpressions);
160 }
161
162 if (StringUtils.isNotBlank(beanName)) {
163 processedBeanNames.add(beanName);
164 }
165 }
166
167 protected void removeParentExpressionsOnNested(String propertyName, MutablePropertyValues pvs,
168 String parentBeanName, ConfigurableListableBeanFactory beanFactory) {
169 BeanDefinition parentBeanDefinition = beanFactory.getMergedBeanDefinition(parentBeanName);
170
171
172 MutablePropertyValues parentPvs = parentBeanDefinition.getPropertyValues();
173 PropertyValue[] pvArray = parentPvs.getPropertyValues();
174 for (PropertyValue pv : pvArray) {
175 boolean isNameMatch = false;
176 String nestedPropertyName = "";
177 if (propertyName.startsWith(pv.getName())) {
178 nestedPropertyName = StringUtils.removeStart(propertyName, pv.getName());
179 if (nestedPropertyName.startsWith(".")) {
180 nestedPropertyName = StringUtils.removeStart(nestedPropertyName, ".");
181 isNameMatch = true;
182 }
183 }
184
185
186 if (isNameMatch && ((pv.getValue() instanceof BeanDefinition) || (pv
187 .getValue() instanceof BeanDefinitionHolder))) {
188 BeanDefinition propertyBeanDefinition;
189 if (pv.getValue() instanceof BeanDefinition) {
190 propertyBeanDefinition = (BeanDefinition) pv.getValue();
191 } else {
192 propertyBeanDefinition = ((BeanDefinitionHolder) pv.getValue()).getBeanDefinition();
193 }
194
195 MutablePropertyValues nestedPvs = propertyBeanDefinition.getPropertyValues();
196 if (nestedPvs.contains(UifPropertyPaths.PROPERTY_EXPRESSIONS)) {
197 PropertyValue propertyExpressionsPV = nestedPvs.getPropertyValue(
198 UifPropertyPaths.PROPERTY_EXPRESSIONS);
199 if (propertyExpressionsPV != null) {
200 Object value = propertyExpressionsPV.getValue();
201 if ((value != null) && (value instanceof ManagedMap)) {
202 Map<String, String> nestedPropertyExpressions = (ManagedMap) value;
203 if (nestedPropertyExpressions.containsKey(nestedPropertyName)) {
204
205 ManagedMap<String, String> copiedPropertyExpressions = new ManagedMap<String, String>();
206 copiedPropertyExpressions.setMergeEnabled(false);
207 copiedPropertyExpressions.putAll(nestedPropertyExpressions);
208 copiedPropertyExpressions.remove(nestedPropertyName);
209
210 BeanDefinition copiedBeanDefinition = new GenericBeanDefinition(propertyBeanDefinition);
211 copiedBeanDefinition.getPropertyValues().add(UifPropertyPaths.PROPERTY_EXPRESSIONS,
212 copiedPropertyExpressions);
213
214 pvs.add(pv.getName(), copiedBeanDefinition);
215 }
216 }
217 }
218 }
219 }
220 }
221 }
222
223
224
225
226
227
228
229
230
231
232 protected Class<?> getBeanClass(BeanDefinition beanDefinition, ConfigurableListableBeanFactory beanFactory) {
233 if (StringUtils.isNotBlank(beanDefinition.getBeanClassName())) {
234 try {
235 return Class.forName(beanDefinition.getBeanClassName());
236 } catch (ClassNotFoundException e) {
237
238 return null;
239 }
240 } else if (StringUtils.isNotBlank(beanDefinition.getParentName())) {
241 BeanDefinition parentBeanDefinition = beanFactory.getBeanDefinition(beanDefinition.getParentName());
242 if (parentBeanDefinition != null) {
243 return getBeanClass(parentBeanDefinition, beanFactory);
244 }
245 }
246
247 return null;
248 }
249
250
251
252
253
254
255
256
257
258
259 protected Map<String, String> getPropertyExpressionsFromParent(String parentBeanName,
260 ConfigurableListableBeanFactory beanFactory, Set<String> processedBeanNames) {
261 Map<String, String> propertyExpressions = new HashMap<String, String>();
262 if (StringUtils.isBlank(parentBeanName) || !beanFactory.containsBeanDefinition(parentBeanName)) {
263 return propertyExpressions;
264 }
265
266 if (!processedBeanNames.contains(parentBeanName)) {
267 processBeanDefinition(parentBeanName, beanFactory.getBeanDefinition(parentBeanName), beanFactory,
268 processedBeanNames);
269 }
270
271 BeanDefinition beanDefinition = beanFactory.getBeanDefinition(parentBeanName);
272 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
273
274 PropertyValue propertyExpressionsPV = pvs.getPropertyValue(UifPropertyPaths.PROPERTY_EXPRESSIONS);
275 if (propertyExpressionsPV != null) {
276 Object value = propertyExpressionsPV.getValue();
277 if ((value != null) && (value instanceof ManagedMap)) {
278 propertyExpressions.putAll((ManagedMap) value);
279 }
280 }
281
282 return propertyExpressions;
283 }
284
285
286
287
288
289
290
291
292 protected boolean hasExpression(Object propertyValue) {
293 if (propertyValue != null) {
294
295 String strValue = getStringValue(propertyValue);
296 if (strValue != null) {
297 String elPlaceholder = StringUtils.substringBetween(strValue, UifConstants.EL_PLACEHOLDER_PREFIX,
298 UifConstants.EL_PLACEHOLDER_SUFFIX);
299 if (StringUtils.isNotBlank(elPlaceholder)) {
300 return true;
301 }
302 }
303 }
304
305 return false;
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321 protected Object processPropertyValue(String propertyName, Object propertyValue,
322 Map<String, String> parentPropertyExpressions, Map<String, String> propertyExpressions,
323 ConfigurableListableBeanFactory beanFactory, Set<String> processedBeanNames) {
324 if (propertyValue == null) {
325 return null;
326 }
327
328
329 if ((propertyValue instanceof BeanDefinition) || (propertyValue instanceof BeanDefinitionHolder)) {
330 BeanDefinition beanDefinition;
331 if (propertyValue instanceof BeanDefinition) {
332 beanDefinition = (BeanDefinition) propertyValue;
333 } else {
334 beanDefinition = ((BeanDefinitionHolder) propertyValue).getBeanDefinition();
335 }
336
337
338 removeExpressionsByPrefix(propertyName, parentPropertyExpressions);
339 processBeanDefinition(null, beanDefinition, beanFactory, processedBeanNames);
340
341 return propertyValue;
342 }
343
344
345 if (propertyValue instanceof Object[]) {
346 visitArray(propertyName, parentPropertyExpressions, propertyExpressions, (Object[]) propertyValue,
347 beanFactory, processedBeanNames);
348 } else if (propertyValue instanceof List) {
349 visitList(propertyName, parentPropertyExpressions, propertyExpressions, (List) propertyValue, beanFactory,
350 processedBeanNames);
351 } else if (propertyValue instanceof Set) {
352 visitSet(propertyName, parentPropertyExpressions, propertyExpressions, (Set) propertyValue, beanFactory,
353 processedBeanNames);
354 } else if (propertyValue instanceof Map) {
355 visitMap(propertyName, parentPropertyExpressions, propertyExpressions, (Map) propertyValue, beanFactory,
356 processedBeanNames);
357 }
358
359
360 return propertyValue;
361 }
362
363
364
365
366
367
368
369 protected void removeExpressionsByPrefix(String propertyNamePrefix, Map<String, String> propertyExpressions) {
370 Map<String, String> adjustedPropertyExpressions = new HashMap<String, String>();
371 for (String propertyName : propertyExpressions.keySet()) {
372 if (!propertyName.startsWith(propertyNamePrefix)) {
373 adjustedPropertyExpressions.put(propertyName, propertyExpressions.get(propertyName));
374 }
375 }
376
377 propertyExpressions.clear();
378 propertyExpressions.putAll(adjustedPropertyExpressions);
379 }
380
381
382
383
384
385
386
387 protected String getStringValue(Object value) {
388 if (value instanceof TypedStringValue) {
389 TypedStringValue typedStringValue = (TypedStringValue) value;
390 return typedStringValue.getValue();
391 } else if (value instanceof String) {
392 return (String) value;
393 }
394
395 return null;
396 }
397
398 @SuppressWarnings("unchecked")
399 protected void visitArray(String propertyName, Map<String, String> parentPropertyExpressions,
400 Map<String, String> propertyExpressions, Object[] arrayVal, ConfigurableListableBeanFactory beanFactory,
401 Set<String> processedBeanNames) {
402 for (int i = 0; i < arrayVal.length; i++) {
403 Object elem = arrayVal[i];
404 String elemPropertyName = propertyName + "[" + i + "]";
405
406 if (hasExpression(elem)) {
407 String strValue = getStringValue(elem);
408 propertyExpressions.put(elemPropertyName, strValue);
409 arrayVal[i] = null;
410 } else {
411 Object newElem = processPropertyValue(elemPropertyName, elem, parentPropertyExpressions,
412 propertyExpressions, beanFactory, processedBeanNames);
413 arrayVal[i] = newElem;
414 }
415
416 if (parentPropertyExpressions.containsKey(elemPropertyName)) {
417 parentPropertyExpressions.remove(elemPropertyName);
418 }
419 }
420 }
421
422 @SuppressWarnings("unchecked")
423 protected void visitList(String propertyName, Map<String, String> parentPropertyExpressions,
424 Map<String, String> propertyExpressions, List listVal, ConfigurableListableBeanFactory beanFactory,
425 Set<String> processedBeanNames) {
426 List newList = new ArrayList();
427
428 for (int i = 0; i < listVal.size(); i++) {
429 Object elem = listVal.get(i);
430 String elemPropertyName = propertyName + "[" + i + "]";
431
432 if (hasExpression(elem)) {
433 String strValue = getStringValue(elem);
434 propertyExpressions.put(elemPropertyName, strValue);
435 newList.add(i, null);
436 } else {
437 Object newElem = processPropertyValue(elemPropertyName, elem, parentPropertyExpressions,
438 propertyExpressions, beanFactory, processedBeanNames);
439 newList.add(i, newElem);
440 }
441
442 if (parentPropertyExpressions.containsKey(elemPropertyName)) {
443 parentPropertyExpressions.remove(elemPropertyName);
444 }
445 }
446
447
448 if (listVal instanceof ManagedList) {
449 boolean isMergeEnabled = ((ManagedList) listVal).isMergeEnabled();
450 if (!isMergeEnabled) {
451
452 Map<String, String> adjustedParentExpressions = new HashMap<String, String>();
453 for (Map.Entry<String, String> parentExpression : parentPropertyExpressions.entrySet()) {
454 if (!parentExpression.getKey().startsWith(propertyName + "[")) {
455 adjustedParentExpressions.put(parentExpression.getKey(), parentExpression.getValue());
456 }
457 }
458
459 parentPropertyExpressions.clear();
460 parentPropertyExpressions.putAll(adjustedParentExpressions);
461 }
462 }
463
464 listVal.clear();
465 listVal.addAll(newList);
466 }
467
468 @SuppressWarnings("unchecked")
469 protected void visitSet(String propertyName, Map<String, String> parentPropertyExpressions,
470 Map<String, String> propertyExpressions, Set setVal, ConfigurableListableBeanFactory beanFactory,
471 Set<String> processedBeanNames) {
472 Set newContent = new LinkedHashSet();
473
474
475 for (Object elem : setVal) {
476 Object newElem = processPropertyValue(propertyName, elem, parentPropertyExpressions, propertyExpressions,
477 beanFactory, processedBeanNames);
478 newContent.add(newElem);
479 }
480
481 setVal.clear();
482 setVal.addAll(newContent);
483 }
484
485 @SuppressWarnings("unchecked")
486 protected void visitMap(String propertyName, Map<String, String> parentPropertyExpressions,
487 Map<String, String> propertyExpressions, Map<?, ?> mapVal, ConfigurableListableBeanFactory beanFactory,
488 Set<String> processedBeanNames) {
489 Map newContent = new LinkedHashMap();
490
491 boolean isMergeEnabled = false;
492 if (mapVal instanceof ManagedMap) {
493 isMergeEnabled = ((ManagedMap) mapVal).isMergeEnabled();
494 }
495
496 for (Map.Entry entry : mapVal.entrySet()) {
497 Object key = entry.getKey();
498 Object val = entry.getValue();
499
500 String keyStr = getStringValue(key);
501 String elemPropertyName = propertyName + "['" + keyStr + "']";
502
503 if (hasExpression(val)) {
504 String strValue = getStringValue(val);
505 propertyExpressions.put(elemPropertyName, strValue);
506 newContent.put(key, null);
507 } else {
508 Object newElem = processPropertyValue(elemPropertyName, val, parentPropertyExpressions,
509 propertyExpressions, beanFactory, processedBeanNames);
510 newContent.put(key, newElem);
511 }
512
513 if (isMergeEnabled && parentPropertyExpressions.containsKey(elemPropertyName)) {
514 parentPropertyExpressions.remove(elemPropertyName);
515 }
516 }
517
518 if (!isMergeEnabled) {
519
520 Map<String, String> adjustedParentExpressions = new HashMap<String, String>();
521 for (Map.Entry<String, String> parentExpression : parentPropertyExpressions.entrySet()) {
522 if (!parentExpression.getKey().startsWith(propertyName + "[")) {
523 adjustedParentExpressions.put(parentExpression.getKey(), parentExpression.getValue());
524 }
525 }
526
527 parentPropertyExpressions.clear();
528 parentPropertyExpressions.putAll(adjustedParentExpressions);
529 }
530
531 mapVal.clear();
532 mapVal.putAll(newContent);
533 }
534 }