1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.datadictionary;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.exception.RiceRuntimeException;
20 import org.kuali.rice.core.api.util.KeyValue;
21 import org.kuali.rice.krad.messages.Message;
22 import org.kuali.rice.krad.messages.MessageService;
23 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
24 import org.kuali.rice.krad.uif.UifConstants;
25 import org.kuali.rice.krad.uif.component.DataBinding;
26 import org.kuali.rice.krad.uif.element.Action;
27 import org.kuali.rice.krad.uif.field.ActionField;
28 import org.kuali.rice.krad.util.KRADConstants;
29 import org.kuali.rice.krad.util.KRADPropertyConstants;
30 import org.springframework.beans.MutablePropertyValues;
31 import org.springframework.beans.PropertyValue;
32 import org.springframework.beans.factory.config.BeanDefinition;
33 import org.springframework.beans.factory.config.BeanDefinitionHolder;
34 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
35 import org.springframework.beans.factory.config.ListFactoryBean;
36
37 import java.text.MessageFormat;
38 import java.util.Collection;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.Stack;
43
44
45
46
47
48
49
50 public class MessageBeanProcessor extends DictionaryBeanProcessorBase {
51
52 private ConfigurableListableBeanFactory beanFactory;
53 private DataDictionary dataDictionary;
54
55 public MessageBeanProcessor(DataDictionary dataDictionary, ConfigurableListableBeanFactory beanFactory) {
56 this.dataDictionary = dataDictionary;
57 this.beanFactory = beanFactory;
58 }
59
60
61
62
63
64 public void processRootBeanDefinition(String beanName, BeanDefinition beanDefinition) {
65 processBeanMessages(beanName, beanDefinition, null);
66 }
67
68
69
70
71
72
73 public void processNestedBeanDefinition(String beanName, BeanDefinition beanDefinition, String propertyName,
74 Stack<BeanDefinitionHolder> nestedBeanStack) {
75 processBeanMessages(beanName, beanDefinition, nestedBeanStack);
76 }
77
78
79
80
81
82 public String processStringPropertyValue(String propertyName, String propertyValue,
83 Stack<BeanDefinitionHolder> nestedBeanStack) {
84 return processMessagePlaceholders(propertyValue, nestedBeanStack);
85 }
86
87
88
89
90
91
92 public void processCollectionBeanDefinition(String beanName, BeanDefinition beanDefinition, String propertyName,
93 Stack<BeanDefinitionHolder> nestedBeanStack) {
94 processBeanMessages(beanName, beanDefinition, nestedBeanStack);
95 }
96
97
98
99
100
101 public String processArrayStringPropertyValue(String propertyName, Object[] propertyValue, String elementValue,
102 int elementIndex, Stack<BeanDefinitionHolder> nestedBeanStack) {
103 return processMessagePlaceholders(elementValue, nestedBeanStack);
104 }
105
106
107
108
109
110 public String processListStringPropertyValue(String propertyName, List<?> propertyValue, String elementValue,
111 int elementIndex, Stack<BeanDefinitionHolder> nestedBeanStack) {
112 return processMessagePlaceholders(elementValue, nestedBeanStack);
113 }
114
115
116
117
118
119 public String processSetStringPropertyValue(String propertyName, Set<?> propertyValue, String elementValue,
120 Stack<BeanDefinitionHolder> nestedBeanStack) {
121 return processMessagePlaceholders(elementValue, nestedBeanStack);
122 }
123
124
125
126
127
128 public String processMapStringPropertyValue(String propertyName, Map<?, ?> propertyValue, String elementValue,
129 Object elementKey, Stack<BeanDefinitionHolder> nestedBeanStack) {
130 return processMessagePlaceholders(elementValue, nestedBeanStack);
131 }
132
133
134
135
136
137
138
139
140
141 protected void processBeanMessages(String beanName, BeanDefinition beanDefinition,
142 Stack<BeanDefinitionHolder> nestedBeanStack) {
143 Class<?> beanClass = getBeanClass(beanDefinition, beanFactory);
144 if ((beanClass == null) || !(DictionaryBean.class.isAssignableFrom(beanClass) || ListFactoryBean.class
145 .isAssignableFrom(beanClass))) {
146 return;
147 }
148
149 String namespace = getNamespaceForBean(beanName, beanDefinition);
150 if (StringUtils.isBlank(namespace)) {
151 namespace = getNamespaceForBeanInStack(nestedBeanStack);
152 }
153
154 String componentCode = getComponentForBean(beanName, beanDefinition);
155 if (StringUtils.equals(componentCode, beanName)) {
156
157
158
159 String extensionParentBeanName = beanName + KRADConstants.DICTIONARY_BEAN_PARENT_SUFFIX;
160 if (beanFactory.containsBean(extensionParentBeanName)) {
161 return;
162 }
163 }
164
165
166 if (StringUtils.isNotBlank(namespace) && StringUtils.isNotBlank(componentCode)) {
167 Collection<Message> beanMessages = getMessageService().getAllMessagesForComponent(namespace, componentCode);
168 for (Message beanMessage : beanMessages) {
169 applyMessageToBean(beanMessage, beanDefinition, beanClass);
170 }
171 }
172 }
173
174
175
176
177
178
179
180
181 protected void applyMessageToBean(Message message, BeanDefinition beanDefinition, Class<?> beanClass) {
182 String key = message.getKey().trim();
183
184
185
186 if (!key.startsWith(KRADConstants.MESSAGE_KEY_PATH_INDICATOR)) {
187 return;
188 }
189
190
191 key = StringUtils.stripStart(key, KRADConstants.MESSAGE_KEY_PATH_INDICATOR);
192
193
194 if (ListFactoryBean.class.isAssignableFrom(beanClass)) {
195 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
196
197 PropertyValue propertyValue = pvs.getPropertyValueList().get(0);
198 List<?> listValue = (List<?>) propertyValue.getValue();
199
200 applyMessageToNestedListBean(message, listValue, key);
201 } else if (StringUtils.contains(key, ".")) {
202 applyMessageToNestedBean(message, beanDefinition, key);
203 } else {
204 applyMessageTextToPropertyValue(key, message.getText(), beanDefinition);
205 }
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222 protected void applyMessageToNestedBean(Message message, BeanDefinition beanDefinition, String propertyPath) {
223 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
224
225 String beanPath = StringUtils.substringBefore(propertyPath, ".");
226 String nestedPropertyPath = StringUtils.substringAfter(propertyPath, ".");
227
228 boolean foundNestedBean = false;
229 while (StringUtils.isNotBlank(nestedPropertyPath)) {
230 if (pvs.contains(beanPath)) {
231 PropertyValue propertyValue = pvs.getPropertyValue(beanPath);
232
233 BeanDefinition propertyBeanDefinition = getPropertyValueBeanDefinition(propertyValue);
234 if (propertyBeanDefinition != null) {
235 applyMessageToNestedBean(message, propertyBeanDefinition, nestedPropertyPath);
236
237 foundNestedBean = true;
238 break;
239 } else if (propertyValue.getValue() instanceof List) {
240 applyMessageToNestedListBean(message, (List<?>) propertyValue.getValue(), nestedPropertyPath);
241
242 foundNestedBean = true;
243 break;
244 }
245 }
246
247 beanPath += "." + StringUtils.substringBefore(nestedPropertyPath, ".");
248 nestedPropertyPath = StringUtils.substringAfter(nestedPropertyPath, ".");
249 }
250
251 if (!foundNestedBean) {
252 applyMessageTextToPropertyValue(propertyPath, message.getText(), beanDefinition);
253 }
254 }
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270 protected void applyMessageToNestedListBean(Message message, List<?> listPropertyValue, String propertyPath) {
271
272 if (!StringUtils.contains(propertyPath, ".")) {
273 throw new RiceRuntimeException(
274 "Key for nested list bean must contain the identifer value followed by the path.");
275 }
276
277 String listIdentifierPropertyValue = StringUtils.substringBefore(propertyPath, ".");
278 String listBeanPropertyPath = StringUtils.substringAfter(propertyPath, ".");
279
280
281 for (int i = 0; i < listPropertyValue.size(); i++) {
282 Object elem = listPropertyValue.get(i);
283
284 if ((elem instanceof BeanDefinition) || (elem instanceof BeanDefinitionHolder)) {
285 BeanDefinition beanDefinition;
286 if (elem instanceof BeanDefinition) {
287 beanDefinition = (BeanDefinition) elem;
288 } else {
289 beanDefinition = ((BeanDefinitionHolder) elem).getBeanDefinition();
290 }
291
292 boolean isMatch = isBeanMessageMatch(listIdentifierPropertyValue, beanDefinition);
293 if (isMatch) {
294 if (StringUtils.contains(listBeanPropertyPath, ".")) {
295 applyMessageToNestedBean(message, beanDefinition, listBeanPropertyPath);
296 } else {
297 applyMessageTextToPropertyValue(listBeanPropertyPath, message.getText(), beanDefinition);
298 }
299 }
300 }
301 }
302 }
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317 protected boolean isBeanMessageMatch(String matchListIdentifierPropertyValue, BeanDefinition beanDefinition) {
318 boolean isMatch = false;
319
320 String listIdentifierPropertyName = null;
321
322 Class<?> beanClass = getBeanClass(beanDefinition, beanFactory);
323 if (DataBinding.class.isAssignableFrom(beanClass)) {
324 listIdentifierPropertyName = KRADPropertyConstants.PROPERTY_NAME;
325 } else if (Action.class.isAssignableFrom(beanClass) || ActionField.class.isAssignableFrom(beanClass)) {
326 listIdentifierPropertyName = KRADPropertyConstants.METHOD_TO_CALL;
327 } else if (KeyValue.class.isAssignableFrom(beanClass)) {
328 listIdentifierPropertyName = KRADPropertyConstants.KEY;
329 }
330
331 if (StringUtils.isNotBlank(listIdentifierPropertyName)) {
332 String listIdentifierPropertyValue = findPropertyValueInBeanDefinition(beanDefinition,
333 listIdentifierPropertyName);
334 if (listIdentifierPropertyValue != null) {
335 isMatch = StringUtils.equals(listIdentifierPropertyValue, matchListIdentifierPropertyValue);
336 }
337 }
338
339 return isMatch;
340 }
341
342
343
344
345
346
347
348
349
350
351 protected String findPropertyValueInBeanDefinition(BeanDefinition beanDefinition, String propertyName) {
352 String beanPropertyValue = null;
353
354 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
355 if (pvs.contains(propertyName)) {
356 PropertyValue propertyValue = pvs.getPropertyValue(propertyName);
357 if (propertyValue.getValue() != null) {
358 beanPropertyValue = propertyValue.getValue().toString();
359 }
360 } else {
361 if (StringUtils.isNotBlank(beanDefinition.getParentName())) {
362 BeanDefinition parentBeanDefinition = beanFactory.getBeanDefinition(beanDefinition.getParentName());
363
364 beanPropertyValue = findPropertyValueInBeanDefinition(parentBeanDefinition, propertyName);
365 }
366 }
367
368 return beanPropertyValue;
369 }
370
371
372
373
374
375
376
377
378
379
380 protected String processMessagePlaceholders(String propertyValue, Stack<BeanDefinitionHolder> nestedBeanStack) {
381 String trimmedPropertyValue = StringUtils.stripStart(propertyValue, " ");
382 if (StringUtils.isBlank(trimmedPropertyValue)) {
383 return propertyValue;
384 }
385
386 String newPropertyValue = propertyValue;
387
388
389 if (trimmedPropertyValue.startsWith(KRADConstants.MESSAGE_KEY_PLACEHOLDER_PREFIX) && StringUtils.contains(
390 trimmedPropertyValue, KRADConstants.MESSAGE_KEY_PLACEHOLDER_SUFFIX)) {
391 String messageKeyStr = StringUtils.substringBetween(trimmedPropertyValue,
392 KRADConstants.MESSAGE_KEY_PLACEHOLDER_PREFIX, KRADConstants.MESSAGE_KEY_PLACEHOLDER_SUFFIX);
393
394
395 String messageKeyWithPlaceholder = KRADConstants.MESSAGE_KEY_PLACEHOLDER_PREFIX + messageKeyStr +
396 KRADConstants.MESSAGE_KEY_PLACEHOLDER_SUFFIX;
397
398 String defaultPropertyValue = StringUtils.substringAfter(trimmedPropertyValue, messageKeyWithPlaceholder);
399
400
401
402 String messageText = getMessageTextForKey(messageKeyStr, nestedBeanStack);
403 if (messageText != null) {
404
405 if (StringUtils.isNotBlank(defaultPropertyValue)) {
406 newPropertyValue = getMergedMessageText(messageText, defaultPropertyValue);
407 } else {
408 newPropertyValue = messageText;
409 }
410 } else {
411 newPropertyValue = defaultPropertyValue;
412 }
413 }
414
415 else if (StringUtils.contains(trimmedPropertyValue, KRADConstants.EXPRESSION_MESSAGE_PLACEHOLDER_PREFIX)) {
416 String[] expressionMessageKeys = StringUtils.substringsBetween(newPropertyValue,
417 KRADConstants.EXPRESSION_MESSAGE_PLACEHOLDER_PREFIX,
418 KRADConstants.EXPRESSION_MESSAGE_PLACEHOLDER_SUFFIX);
419
420 for (String expressionMessageKey : expressionMessageKeys) {
421 String expressionMessageText = getMessageTextForKey(expressionMessageKey, nestedBeanStack);
422 newPropertyValue = StringUtils.replace(newPropertyValue,
423 KRADConstants.EXPRESSION_MESSAGE_PLACEHOLDER_PREFIX + expressionMessageKey +
424 KRADConstants.EXPRESSION_MESSAGE_PLACEHOLDER_SUFFIX, expressionMessageText);
425 }
426 }
427
428 return newPropertyValue;
429 }
430
431
432
433
434
435
436
437
438
439 protected String getMessageTextForKey(String messageKeyStr, Stack<BeanDefinitionHolder> nestedBeanStack) {
440 String namespace = null;
441 String componentCode = null;
442 String key = null;
443
444
445 if (StringUtils.contains(messageKeyStr, ":")) {
446 String[] messageParams = StringUtils.split(messageKeyStr, ":");
447
448 if (messageParams.length == 3) {
449 namespace = messageParams[0];
450 componentCode = messageParams[1];
451 key = messageParams[2];
452 } else if (messageParams.length == 2) {
453 componentCode = messageParams[0];
454 key = messageParams[1];
455 } else {
456 throw new RiceRuntimeException("Message key '" + messageKeyStr + "' has an invalid format");
457 }
458 } else {
459 key = messageKeyStr;
460 }
461
462 if (StringUtils.isBlank(namespace)) {
463 namespace = getNamespaceForBeanInStack(nestedBeanStack);
464 }
465
466 if (StringUtils.isBlank(componentCode)) {
467 for (int i = nestedBeanStack.size() - 1; i >= 0; i--) {
468 BeanDefinitionHolder definitionHolder = nestedBeanStack.get(i);
469 componentCode = getComponentForBean(definitionHolder.getBeanName(),
470 definitionHolder.getBeanDefinition());
471 if (StringUtils.isNotBlank(componentCode)) {
472 break;
473 }
474 }
475 }
476
477 String messageText = null;
478 if (StringUtils.isNotBlank(namespace) && StringUtils.isNotBlank(componentCode) && StringUtils.isNotBlank(key)) {
479 messageText = getMessageService().getMessageText(namespace, componentCode, key);
480 }
481
482 return messageText;
483 }
484
485
486
487
488
489
490
491
492
493
494 protected void applyMessageTextToPropertyValue(String propertyName, String messageText,
495 BeanDefinition beanDefinition) {
496 String newPropertyValue = messageText;
497
498 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
499 if (pvs.contains(propertyName)) {
500 PropertyValue propertyValue = pvs.getPropertyValue(propertyName);
501
502 String stringPropertyValue = getStringValue(propertyValue.getValue());
503 if (StringUtils.isNotBlank(stringPropertyValue)) {
504 newPropertyValue = getMergedMessageText(messageText, stringPropertyValue);
505 }
506 }
507
508 applyPropertyValueToBean(propertyName, newPropertyValue, pvs);
509 }
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524 protected String getMergedMessageText(String messageText, String propertyValue) {
525 String mergedText = messageText;
526
527 String[] expressions = StringUtils.substringsBetween(propertyValue, UifConstants.EL_PLACEHOLDER_PREFIX,
528 UifConstants.EL_PLACEHOLDER_SUFFIX);
529 if ((expressions != null) && expressions.length > 0) {
530
531 String[] messageParameters = new String[expressions.length];
532 for (int i = 0; i < expressions.length; i++) {
533 String expression = expressions[i];
534
535 expression = UifConstants.EL_PLACEHOLDER_PREFIX + expression + UifConstants.EL_PLACEHOLDER_SUFFIX;
536 messageParameters[i] = expression;
537 }
538
539
540 messageText = messageText.replace("'", "''");
541 try {
542 mergedText = MessageFormat.format(messageText, messageParameters);
543 } catch (IllegalArgumentException e) {
544 throw new RiceRuntimeException(
545 "Unable to merge expressions with message text. Expression count is: " + expressions.length, e);
546 }
547 }
548
549 return mergedText;
550 }
551
552
553
554
555
556
557
558 protected String getNamespaceForBeanInStack(Stack<BeanDefinitionHolder> nestedBeanStack) {
559 String namespace = null;
560
561 if (nestedBeanStack != null) {
562 for (int i = nestedBeanStack.size() - 1; i >= 0; i--) {
563 BeanDefinitionHolder definitionHolder = nestedBeanStack.get(i);
564 namespace = getNamespaceForBean(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
565 if (StringUtils.isNotBlank(namespace)) {
566 break;
567 }
568 }
569 }
570
571 return namespace;
572 }
573
574
575
576
577
578
579
580
581 protected String getNamespaceForBean(String beanName, BeanDefinition beanDefinition) {
582 String namespace = null;
583
584 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
585 if (pvs.contains(KRADPropertyConstants.NAMESPACE_CODE)) {
586 PropertyValue propertyValue = pvs.getPropertyValue(KRADPropertyConstants.NAMESPACE_CODE);
587 namespace = getStringValue(propertyValue.getValue());
588 } else if (StringUtils.isNotBlank(beanName) && !isGeneratedBeanName(beanName)) {
589
590 namespace = dataDictionary.getNamespaceForBeanDefinition(beanName);
591 }
592
593 return namespace;
594 }
595
596
597
598
599
600
601
602
603 protected String getComponentForBean(String beanName, BeanDefinition beanDefinition) {
604 String componentCode = null;
605
606 MutablePropertyValues pvs = beanDefinition.getPropertyValues();
607 if (pvs.contains(KRADPropertyConstants.COMPONENT_CODE)) {
608 PropertyValue propertyValue = pvs.getPropertyValue(KRADPropertyConstants.COMPONENT_CODE);
609
610 componentCode = getStringValue(propertyValue.getValue());
611 }
612
613 if ((componentCode == null) && StringUtils.isNotBlank(beanName) && !isGeneratedBeanName(beanName)) {
614 componentCode = beanName;
615 }
616
617 if (StringUtils.isNotBlank(componentCode)) {
618 componentCode = StringUtils.removeEnd(componentCode, KRADConstants.DICTIONARY_BEAN_PARENT_SUFFIX);
619 }
620
621 return componentCode;
622 }
623
624
625
626
627
628
629 protected MessageService getMessageService() {
630 return KRADServiceLocatorWeb.getMessageService();
631 }
632 }