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