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.uif.UifDictionaryBean;
22 import org.kuali.rice.krad.uif.UifConstants;
23 import org.kuali.rice.krad.uif.UifPropertyPaths;
24 import org.kuali.rice.krad.uif.service.ExpressionEvaluatorService;
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.BeanDefinitionRegistry;
34 import org.springframework.beans.factory.support.ManagedArray;
35 import org.springframework.beans.factory.support.ManagedList;
36 import org.springframework.beans.factory.support.ManagedMap;
37 import org.springframework.beans.factory.support.ManagedSet;
38
39 import java.util.HashMap;
40 import java.util.HashSet;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Set;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class UifBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
67 private static final Log LOG = LogFactory.getLog(UifBeanFactoryPostProcessor.class);
68
69
70
71
72
73
74
75 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
76 Set<String> processedBeanNames = new HashSet<String>();
77
78 LOG.info("Beginning post processing of bean factory for UIF expressions");
79
80 String[] beanNames = beanFactory.getBeanDefinitionNames();
81 for (int i = 0; i < beanNames.length; i++) {
82 String beanName = beanNames[i];
83 BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
84
85 processBeanDefinition(beanName, beanDefinition, beanFactory, processedBeanNames);
86 }
87
88 LOG.info("Finished post processing of bean factory for UIF expressions");
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 protected void processBeanDefinition(String beanName, BeanDefinition beanDefinition,
106 ConfigurableListableBeanFactory beanFactory, Set<String> processedBeanNames) {
107 Class<?> beanClass = getBeanClass(beanDefinition, beanFactory);
108 if ((beanClass == null) || !UifDictionaryBean.class.isAssignableFrom(beanClass) || processedBeanNames.contains(
109 beanName)) {
110 return;
111 }
112
113
114 ManagedMap<String, String> expressionGraph = new ManagedMap<String, String>();
115 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
116 if (pvs.contains(UifPropertyPaths.EXPRESSION_GRAPH)) {
117 expressionGraph = (ManagedMap<String, String>) pvs.getPropertyValue(UifPropertyPaths.EXPRESSION_GRAPH)
118 .getValue();
119 if (expressionGraph == null) {
120 expressionGraph = new ManagedMap<String, String>();
121 }
122 }
123
124 expressionGraph.setMergeEnabled(false);
125 processNestedBeanDefinition(beanName, beanDefinition, "", expressionGraph, beanFactory, processedBeanNames);
126
127
128 pvs = beanDefinition.getPropertyValues();
129 pvs.addPropertyValue(UifPropertyPaths.EXPRESSION_GRAPH, expressionGraph);
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143 protected void processNestedBeanDefinition(String beanName, BeanDefinition beanDefinition,
144 String nestedPropertyName, Map<String, String> expressionGraph,
145 ConfigurableListableBeanFactory beanFactory, Set<String> processedBeanNames) {
146 Class<?> beanClass = getBeanClass(beanDefinition, beanFactory);
147 if ((beanClass == null) || !UifDictionaryBean.class.isAssignableFrom(beanClass) || processedBeanNames.contains(
148 beanName)) {
149 return;
150 }
151
152 LOG.debug("Processing bean name '" + beanName + "'");
153
154 Map<String, String> parentExpressionGraph = getExpressionGraphFromParent(beanDefinition.getParentName(),
155 beanFactory, processedBeanNames);
156
157
158 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
159 PropertyValue[] pvArray = pvs.getPropertyValues();
160 for (PropertyValue pv : pvArray) {
161 if (pv.getName().equals(UifPropertyPaths.EXPRESSION_GRAPH)) {
162 continue;
163 }
164
165 String propertyPath = pv.getName();
166 if (StringUtils.isNotBlank(nestedPropertyName)) {
167 propertyPath = nestedPropertyName + "." + propertyPath;
168 }
169
170
171 if (expressionGraph.containsKey(propertyPath)) {
172 expressionGraph.remove(propertyPath);
173 }
174
175 if (hasExpression(pv.getValue())) {
176
177 String strValue = getStringValue(pv.getValue());
178 expressionGraph.put(propertyPath, strValue);
179
180
181 pvs.removePropertyValue(pv.getName());
182 } else {
183
184 Object newValue = processPropertyValue(propertyPath, pv.getName(), pv.getValue(), beanDefinition,
185 parentExpressionGraph, expressionGraph, beanFactory, processedBeanNames);
186
187 pvs.removePropertyValue(pv.getName());
188 pvs.addPropertyValue(pv.getName(), newValue);
189 }
190
191
192 if (parentExpressionGraph.containsKey(pv.getName())) {
193 parentExpressionGraph.remove(pv.getName());
194 }
195 }
196
197
198 if (StringUtils.isNotBlank(nestedPropertyName)) {
199 pvs.addPropertyValue(UifPropertyPaths.EXPRESSION_GRAPH, null);
200 }
201
202
203 for (Map.Entry<String, String> parentExpression : parentExpressionGraph.entrySet()) {
204 String expressionPath = parentExpression.getKey();
205 if (StringUtils.isNotBlank(nestedPropertyName)) {
206 expressionPath = nestedPropertyName + "." + expressionPath;
207 }
208 expressionGraph.put(expressionPath, parentExpression.getValue());
209 }
210
211
212
213 if (StringUtils.isNotBlank(beanName) && !StringUtils.contains(beanName, "$") && !StringUtils.contains(beanName,
214 "#") && !beanFactory.containsBean(beanName)) {
215 ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(beanName, beanDefinition);
216 }
217
218 if (StringUtils.isNotBlank(beanName)) {
219 processedBeanNames.add(beanName);
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> getExpressionGraphFromParent(String parentBeanName,
260 ConfigurableListableBeanFactory beanFactory, Set<String> processedBeanNames) {
261 Map<String, String> expressionGraph = new HashMap<String, String>();
262 if (StringUtils.isBlank(parentBeanName) || !beanFactory.containsBeanDefinition(parentBeanName)) {
263 return expressionGraph;
264 }
265
266 BeanDefinition beanDefinition = beanFactory.getBeanDefinition(parentBeanName);
267 if (!processedBeanNames.contains(parentBeanName)) {
268 processBeanDefinition(parentBeanName, beanDefinition, beanFactory, processedBeanNames);
269 }
270
271 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
272 PropertyValue propertyExpressionsPV = pvs.getPropertyValue(UifPropertyPaths.EXPRESSION_GRAPH);
273 if (propertyExpressionsPV != null) {
274 Object value = propertyExpressionsPV.getValue();
275 if ((value != null) && (value instanceof ManagedMap)) {
276 expressionGraph.putAll((ManagedMap) value);
277 }
278 }
279
280 return expressionGraph;
281 }
282
283
284
285
286
287
288
289
290 protected boolean hasExpression(Object propertyValue) {
291 if (propertyValue != null) {
292
293 String strValue = getStringValue(propertyValue);
294 if (strValue != null) {
295 String elPlaceholder = StringUtils.substringBetween(strValue, UifConstants.EL_PLACEHOLDER_PREFIX,
296 UifConstants.EL_PLACEHOLDER_SUFFIX);
297 if (StringUtils.isNotBlank(elPlaceholder)) {
298 return true;
299 }
300 }
301 }
302
303 return false;
304 }
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321 protected Object processPropertyValue(String nestedPropertyName, String propertyName, Object propertyValue,
322 BeanDefinition beanDefinition, Map<String, String> parentExpressionGraph,
323 Map<String, String> expressionGraph, ConfigurableListableBeanFactory beanFactory,
324 Set<String> processedBeanNames) {
325 boolean clearExpressionsForNull = false;
326 if (propertyValue instanceof TypedStringValue) {
327 TypedStringValue typedStringValue = (TypedStringValue) propertyValue;
328
329 String value = typedStringValue.getValue();
330 if (value == null) {
331 clearExpressionsForNull = true;
332 }
333 } else if (propertyValue == null) {
334 clearExpressionsForNull = true;
335 }
336
337
338 if (clearExpressionsForNull) {
339 removeExpressionsByPrefix(nestedPropertyName, expressionGraph);
340 removeExpressionsByPrefix(propertyName, parentExpressionGraph);
341
342 return propertyValue;
343 }
344
345
346 if ((propertyValue instanceof BeanDefinition) || (propertyValue instanceof BeanDefinitionHolder)) {
347 String beanName = null;
348 BeanDefinition beanDefinitionValue;
349 if (propertyValue instanceof BeanDefinition) {
350 beanDefinitionValue = (BeanDefinition) propertyValue;
351 } else {
352 beanDefinitionValue = ((BeanDefinitionHolder) propertyValue).getBeanDefinition();
353 beanName = ((BeanDefinitionHolder) propertyValue).getBeanName();
354 }
355
356
357 removeExpressionsByPrefix(nestedPropertyName, expressionGraph);
358 removeExpressionsByPrefix(propertyName, parentExpressionGraph);
359
360 processNestedBeanDefinition(beanName, beanDefinitionValue, nestedPropertyName, expressionGraph, beanFactory,
361 processedBeanNames);
362
363 return propertyValue;
364 }
365
366
367 if (propertyValue instanceof Object[]) {
368 visitArray(nestedPropertyName, parentExpressionGraph, expressionGraph, (Object[]) propertyValue, beanFactory,
369 processedBeanNames);
370 } else if (propertyValue instanceof List) {
371 visitList(nestedPropertyName, propertyName, beanDefinition, parentExpressionGraph, expressionGraph,
372 (List) propertyValue, beanFactory, processedBeanNames);
373 } else if (propertyValue instanceof Set) {
374 visitSet(nestedPropertyName, parentExpressionGraph, expressionGraph, (Set) propertyValue, beanFactory,
375 processedBeanNames);
376 } else if (propertyValue instanceof Map) {
377 visitMap(nestedPropertyName, parentExpressionGraph, expressionGraph, (Map) propertyValue, beanFactory,
378 processedBeanNames);
379 }
380
381
382 return propertyValue;
383 }
384
385
386
387
388
389
390
391 protected void removeExpressionsByPrefix(String propertyNamePrefix, Map<String, String> expressionGraph) {
392 Map<String, String> adjustedExpressionGraph = new HashMap<String, String>();
393 for (String propertyName : expressionGraph.keySet()) {
394 if (!propertyName.startsWith(propertyNamePrefix + ".")) {
395 adjustedExpressionGraph.put(propertyName, expressionGraph.get(propertyName));
396 }
397 }
398
399 expressionGraph.clear();
400 expressionGraph.putAll(adjustedExpressionGraph);
401 }
402
403
404
405
406
407
408
409 protected String getStringValue(Object value) {
410 if (value instanceof TypedStringValue) {
411 TypedStringValue typedStringValue = (TypedStringValue) value;
412 return typedStringValue.getValue();
413 } else if (value instanceof String) {
414 return (String) value;
415 }
416
417 return null;
418 }
419
420 @SuppressWarnings("unchecked")
421 protected void visitArray(String propertyName, Map<String, String> parentExpressionGraph,
422 Map<String, String> expressionGraph, Object array, ConfigurableListableBeanFactory beanFactory,
423 Set<String> processedBeanNames) {
424 Object newArray = null;
425 Object[] arrayVal = null;
426
427 boolean isMergeEnabled = false;
428 if (array instanceof ManagedArray) {
429 isMergeEnabled = ((ManagedArray) array).isMergeEnabled();
430 arrayVal = (Object[]) ((ManagedArray) array).getSource();
431
432 newArray = new ManagedArray(((ManagedArray) array).getElementTypeName(), arrayVal.length);
433 ((ManagedArray) newArray).setMergeEnabled(isMergeEnabled);
434 } else {
435 arrayVal = (Object[]) array;
436 newArray = new Object[arrayVal.length];
437 }
438
439 for (int i = 0; i < arrayVal.length; i++) {
440 Object elem = arrayVal[i];
441 String elemPropertyName = propertyName + "[" + i + "]";
442
443 if (hasExpression(elem)) {
444 String strValue = getStringValue(elem);
445 expressionGraph.put(elemPropertyName, strValue);
446 arrayVal[i] = null;
447 } else {
448
449 if ((elem instanceof BeanDefinition) || (elem instanceof BeanDefinitionHolder)) {
450 String beanName = null;
451 BeanDefinition beanDefinition;
452 if (elem instanceof BeanDefinition) {
453 beanDefinition = (BeanDefinition) elem;
454 } else {
455 beanDefinition = ((BeanDefinitionHolder) elem).getBeanDefinition();
456 beanName = ((BeanDefinitionHolder) elem).getBeanName();
457 }
458
459 processBeanDefinition(beanName, beanDefinition, beanFactory, processedBeanNames);
460 }
461
462 arrayVal[i] = elem;
463 }
464
465 if (isMergeEnabled && parentExpressionGraph.containsKey(elemPropertyName)) {
466 parentExpressionGraph.remove(elemPropertyName);
467 }
468 }
469
470
471 if (!isMergeEnabled) {
472
473 Map<String, String> adjustedParentExpressionGraph = new HashMap<String, String>();
474 for (Map.Entry<String, String> parentExpression : parentExpressionGraph.entrySet()) {
475 if (!parentExpression.getKey().startsWith(propertyName + "[")) {
476 adjustedParentExpressionGraph.put(parentExpression.getKey(), parentExpression.getValue());
477 }
478 }
479
480 parentExpressionGraph.clear();
481 parentExpressionGraph.putAll(adjustedParentExpressionGraph);
482 }
483
484 if (array instanceof ManagedArray) {
485 ((ManagedArray) array).setSource(newArray);
486 } else {
487 array = newArray;
488 }
489 }
490
491 @SuppressWarnings("unchecked")
492 protected void visitList(String nestedPropertyName, String propertyName, BeanDefinition beanDefinition,
493 Map<String, String> parentExpressionGraph, Map<String, String> expressionGraph, List listVal,
494 ConfigurableListableBeanFactory beanFactory, Set<String> processedBeanNames) {
495 boolean isMergeEnabled = false;
496 if (listVal instanceof ManagedList) {
497 isMergeEnabled = ((ManagedList) listVal).isMergeEnabled();
498 }
499
500 ManagedList newList = new ManagedList();
501 newList.setMergeEnabled(isMergeEnabled);
502
503
504
505 int parentListSize = 0;
506 if (isMergeEnabled && StringUtils.isNotBlank(beanDefinition.getParentName())) {
507 BeanDefinition parentBeanDefinition = beanFactory.getMergedBeanDefinition(beanDefinition.getParentName());
508 PropertyValue parentListPropertyValue = parentBeanDefinition.getPropertyValues().getPropertyValue(
509 propertyName);
510 if (parentListPropertyValue != null) {
511 List parentList = (List) parentListPropertyValue.getValue();
512 parentListSize = parentList.size();
513 }
514 }
515
516 for (int i = 0; i < listVal.size(); i++) {
517 Object elem = listVal.get(i);
518
519 int elementPosition = i + parentListSize;
520 String elemPropertyName = nestedPropertyName + "[" + elementPosition + "]";
521
522 if (hasExpression(elem)) {
523 String strValue = getStringValue(elem);
524
525 expressionGraph.put(elemPropertyName, strValue);
526 newList.add(i, null);
527 } else {
528
529 if ((elem instanceof BeanDefinition) || (elem instanceof BeanDefinitionHolder)) {
530 String beanName = null;
531 BeanDefinition beanDefinitionValue;
532 if (elem instanceof BeanDefinition) {
533 beanDefinitionValue = (BeanDefinition) elem;
534 } else {
535 beanDefinitionValue = ((BeanDefinitionHolder) elem).getBeanDefinition();
536 beanName = ((BeanDefinitionHolder) elem).getBeanName();
537 }
538
539 processBeanDefinition(beanName, beanDefinitionValue, beanFactory, processedBeanNames);
540 }
541
542 newList.add(i, elem);
543 }
544 }
545
546
547 if (!isMergeEnabled) {
548
549 Map<String, String> adjustedParentExpressionGraph = new HashMap<String, String>();
550 for (Map.Entry<String, String> parentExpression : parentExpressionGraph.entrySet()) {
551 if (!parentExpression.getKey().startsWith(nestedPropertyName + "[")) {
552 adjustedParentExpressionGraph.put(parentExpression.getKey(), parentExpression.getValue());
553 }
554 }
555
556 parentExpressionGraph.clear();
557 parentExpressionGraph.putAll(adjustedParentExpressionGraph);
558 }
559
560 listVal.clear();
561 listVal.addAll(newList);
562 }
563
564 @SuppressWarnings("unchecked")
565 protected void visitSet(String propertyName, Map<String, String> parentPropertyExpressions,
566 Map<String, String> propertyExpressions, Set setVal, ConfigurableListableBeanFactory beanFactory,
567 Set<String> processedBeanNames) {
568 boolean isMergeEnabled = false;
569 if (setVal instanceof ManagedSet) {
570 isMergeEnabled = ((ManagedSet) setVal).isMergeEnabled();
571 }
572
573 ManagedSet newSet = new ManagedSet();
574 newSet.setMergeEnabled(isMergeEnabled);
575
576 for (Object elem : setVal) {
577 if (hasExpression(elem)) {
578 String strValue = getStringValue(elem);
579 propertyExpressions.put(propertyName + ExpressionEvaluatorService.EMBEDDED_PROPERTY_NAME_ADD_INDICATOR,
580 strValue);
581 } else {
582
583 if ((elem instanceof BeanDefinition) || (elem instanceof BeanDefinitionHolder)) {
584 String beanName = null;
585 BeanDefinition beanDefinition;
586 if (elem instanceof BeanDefinition) {
587 beanDefinition = (BeanDefinition) elem;
588 } else {
589 beanDefinition = ((BeanDefinitionHolder) elem).getBeanDefinition();
590 beanName = ((BeanDefinitionHolder) elem).getBeanName();
591 }
592
593 processBeanDefinition(beanName, beanDefinition, beanFactory, processedBeanNames);
594 }
595
596 newSet.add(elem);
597 }
598 }
599
600
601 if (!isMergeEnabled) {
602
603 Map<String, String> adjustedParentExpressions = new HashMap<String, String>();
604 for (Map.Entry<String, String> parentExpression : parentPropertyExpressions.entrySet()) {
605 if (!parentExpression.getKey().startsWith(
606 propertyName + ExpressionEvaluatorService.EMBEDDED_PROPERTY_NAME_ADD_INDICATOR)) {
607 adjustedParentExpressions.put(parentExpression.getKey(), parentExpression.getValue());
608 }
609 }
610
611 parentPropertyExpressions.clear();
612 parentPropertyExpressions.putAll(adjustedParentExpressions);
613 }
614
615 setVal.clear();
616 setVal.addAll(newSet);
617 }
618
619 @SuppressWarnings("unchecked")
620 protected void visitMap(String propertyName, Map<String, String> parentExpressionGraph,
621 Map<String, String> expressionGraph, Map<?, ?> mapVal, ConfigurableListableBeanFactory beanFactory,
622 Set<String> processedBeanNames) {
623 boolean isMergeEnabled = false;
624 if (mapVal instanceof ManagedMap) {
625 isMergeEnabled = ((ManagedMap) mapVal).isMergeEnabled();
626 }
627
628 ManagedMap newMap = new ManagedMap();
629 newMap.setMergeEnabled(isMergeEnabled);
630
631 for (Map.Entry entry : mapVal.entrySet()) {
632 Object key = entry.getKey();
633 Object val = entry.getValue();
634
635 String keyStr = getStringValue(key);
636 String elemPropertyName = propertyName + "['" + keyStr + "']";
637
638 if (hasExpression(val)) {
639 String strValue = getStringValue(val);
640 expressionGraph.put(elemPropertyName, strValue);
641 } else {
642
643 if ((val instanceof BeanDefinition) || (val instanceof BeanDefinitionHolder)) {
644 String beanName = null;
645 BeanDefinition beanDefinition;
646 if (val instanceof BeanDefinition) {
647 beanDefinition = (BeanDefinition) val;
648 } else {
649 beanDefinition = ((BeanDefinitionHolder) val).getBeanDefinition();
650 beanName = ((BeanDefinitionHolder) val).getBeanName();
651 }
652
653 processBeanDefinition(beanName, beanDefinition, beanFactory, processedBeanNames);
654 }
655
656 newMap.put(key, val);
657 }
658
659 if (isMergeEnabled && parentExpressionGraph.containsKey(elemPropertyName)) {
660 parentExpressionGraph.remove(elemPropertyName);
661 }
662 }
663
664 if (!isMergeEnabled) {
665
666 Map<String, String> adjustedParentExpressionGraph = new HashMap<String, String>();
667 for (Map.Entry<String, String> parentExpression : parentExpressionGraph.entrySet()) {
668 if (!parentExpression.getKey().startsWith(propertyName + "[")) {
669 adjustedParentExpressionGraph.put(parentExpression.getKey(), parentExpression.getValue());
670 }
671 }
672
673 parentExpressionGraph.clear();
674 parentExpressionGraph.putAll(adjustedParentExpressionGraph);
675 }
676
677 mapVal.clear();
678 mapVal.putAll(newMap);
679 }
680 }