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