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