001/** 002 * Copyright 2005-2018 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.datadictionary; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.exception.RiceRuntimeException; 020import org.kuali.rice.core.api.util.KeyValue; 021import org.kuali.rice.krad.messages.Message; 022import org.kuali.rice.krad.messages.MessageService; 023import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 024import org.kuali.rice.krad.uif.UifConstants; 025import org.kuali.rice.krad.uif.component.DataBinding; 026import org.kuali.rice.krad.uif.element.Action; 027import org.kuali.rice.krad.uif.field.ActionField; 028import org.kuali.rice.krad.util.KRADConstants; 029import org.kuali.rice.krad.util.KRADPropertyConstants; 030import org.springframework.beans.MutablePropertyValues; 031import org.springframework.beans.PropertyValue; 032import org.springframework.beans.factory.config.BeanDefinition; 033import org.springframework.beans.factory.config.BeanDefinitionHolder; 034import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 035import org.springframework.beans.factory.config.ListFactoryBean; 036 037import java.text.MessageFormat; 038import java.util.Collection; 039import java.util.List; 040import java.util.Map; 041import java.util.Set; 042import java.util.Stack; 043 044/** 045 * Dictionary bean processor that retrieves external messages for bean definitions and alters the bean 046 * definitions to use the external text 047 * 048 * @author Kuali Rice Team (rice.collab@kuali.org) 049 */ 050public class MessageBeanProcessor extends DictionaryBeanProcessorBase { 051 052 private ConfigurableListableBeanFactory beanFactory; 053 private DataDictionary dataDictionary; 054 055 public MessageBeanProcessor(DataDictionary dataDictionary, ConfigurableListableBeanFactory beanFactory) { 056 this.dataDictionary = dataDictionary; 057 this.beanFactory = beanFactory; 058 } 059 060 /** 061 * @see DictionaryBeanProcessor#processRootBeanDefinition(java.lang.String, 062 * org.springframework.beans.factory.config.BeanDefinition) 063 */ 064 public void processRootBeanDefinition(String beanName, BeanDefinition beanDefinition) { 065 processBeanMessages(beanName, beanDefinition, null); 066 } 067 068 /** 069 * {@inheritDoc} 070 */ 071 @Override 072 public void processNestedBeanDefinition(String beanName, BeanDefinition beanDefinition, String propertyName, 073 Stack<BeanDefinitionHolder> nestedBeanStack) { 074 processBeanMessages(beanName, beanDefinition, nestedBeanStack); 075 } 076 077 /** 078 * {@inheritDoc} 079 */ 080 @Override 081 public String processStringPropertyValue(String propertyName, String propertyValue, 082 Stack<BeanDefinitionHolder> nestedBeanStack) { 083 return processMessagePlaceholders(propertyValue, nestedBeanStack); 084 } 085 086 /** 087 * {@inheritDoc} 088 */ 089 @Override 090 public void processCollectionBeanDefinition(String beanName, BeanDefinition beanDefinition, String propertyName, 091 Stack<BeanDefinitionHolder> nestedBeanStack) { 092 processBeanMessages(beanName, beanDefinition, nestedBeanStack); 093 } 094 095 /** 096 * {@inheritDoc} 097 */ 098 @Override 099 public String processArrayStringPropertyValue(String propertyName, Object[] propertyValue, String elementValue, 100 int elementIndex, Stack<BeanDefinitionHolder> nestedBeanStack) { 101 return processMessagePlaceholders(elementValue, nestedBeanStack); 102 } 103 104 /** 105 * {@inheritDoc} 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 * {@inheritDoc} 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 * {@inheritDoc} 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 * Retrieves external messages whose namespace and component matches the bean definition and applies 133 * the message text to the bean property values 134 * 135 * @param beanName name of the bean to process 136 * @param beanDefinition bean definition to process 137 * @param nestedBeanStack stack of beans that contain the given bean, used for finding a namespace 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 // check if there is a parent bean in the factory using the standard suffix, if so we will skip this 155 // bean as messages will be picked up by that parent bean definition. Note this is not for all parents, 156 // just where the convention has been setup for extension (ex. 'bean' and 'bean-parentName') 157 String extensionParentBeanName = beanName + KRADConstants.DICTIONARY_BEAN_PARENT_SUFFIX; 158 if (beanFactory.containsBean(extensionParentBeanName)) { 159 return; 160 } 161 } 162 163 // if a namespace and component was found retrieve all messages associated with them 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 * Applies the text for a given message to the associated bean definition property 174 * 175 * @param message message instance to apply 176 * @param beanDefinition bean definition the message should be applied to 177 * @param beanClass class for the bean definition 178 */ 179 protected void applyMessageToBean(Message message, BeanDefinition beanDefinition, Class<?> beanClass) { 180 String key = message.getKey().trim(); 181 182 // if message doesn't start with path indicator, it will be an explicit key that is matched when 183 // iterating over the property values, so we will just return in that case 184 if (!key.startsWith(KRADConstants.MESSAGE_KEY_PATH_INDICATOR)) { 185 return; 186 } 187 188 // if here dealing with a path key, strip off indicator and then process as a property path 189 key = StringUtils.stripStart(key, KRADConstants.MESSAGE_KEY_PATH_INDICATOR); 190 191 // list factory beans just have the one list property (with no name) 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 * Applies the given message text to the property within the given bean definition 208 * 209 * <p> 210 * The message text is applied to the bean definiton based on the property path. The path could be nested 211 * in which case the property values of the bean definition are traversed to find the nested bean definition 212 * that should hold the property value. The path could also represent a nested list bean. In this case a 213 * helper method is called to find the correct list bean to apply the message to 214 * </p> 215 * 216 * @param message message containing the text to apply 217 * @param beanDefinition bean definition containing the property 218 * @param propertyPath path to property within the bean definition the message should be applied to 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 * Applies a message to a nested list bean definition 256 * 257 * <p> 258 * Here the property path first gives an identifier value (such as property name) to use for finding 259 * the bean definition with the list the message should apply to. Any part of the path after the identifier 260 * value is treated like a nested property path 261 * </p> 262 * 263 * @param message message instance that contains the text to apply 264 * @param listPropertyValue property value list that should contain the bean definition the message 265 * will be applied to 266 * @param propertyPath path to the bean definition the message should apply to 267 */ 268 protected void applyMessageToNestedListBean(Message message, List<?> listPropertyValue, String propertyPath) { 269 // property path must be nested, with first part giving the list bean identifier value 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 // iterate through list and find beans that match the given identifier 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 * Determines whether the given bean definition is a matched based on the given identifier value 304 * 305 * <p> 306 * Based on the class for the bean definition an identifier property name is used, the corresponding value 307 * from the bean definition is then retrieved and compared to the given value to determine whether the 308 * bean definition is a match 309 * </p> 310 * 311 * @param matchListIdentifierPropertyValue property value to match bean definitions on 312 * @param beanDefinition bean definition to determine the match for 313 * @return boolean true if the bean definition is a match, false if not 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 * Attempts to find a property value for the given property name within the bean definition, if the property 342 * does not exist in the bean and there is a parent, the parent is checked for containing the property. This 343 * continues until a property value is found or all the parents have been traversed 344 * 345 * @param beanDefinition bean definition to find property value in 346 * @param propertyName name of the property to find the value for 347 * @return String value for property in the bean definition or null if the property was not found 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 * Checks a string property value for a message placeholder and if found the message is retrieved and updated 371 * in the property value 372 * 373 * @param propertyValue string value to process for message placeholders 374 * @param nestedBeanStack stack of bean definitions that contain the property, used to determine the namespace 375 * and component for the message retrieval 376 * @return String new value for the property (possibly modified from an external message) 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 // first check for a replacement message key 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 // get any default specified value (given after the message key) 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 // set the new property value to the message text (if found), or the default value if a message was not found 399 // note the message text could be an empty string, in which case it will override the default 400 String messageText = getMessageTextForKey(messageKeyStr, nestedBeanStack); 401 if (messageText != null) { 402 // if default value set then we need to merge any expressions 403 if (StringUtils.isNotBlank(defaultPropertyValue)) { 404 newPropertyValue = getMergedMessageText(messageText, defaultPropertyValue); 405 } else { 406 newPropertyValue = messageText; 407 } 408 } else { 409 newPropertyValue = defaultPropertyValue; 410 } 411 } 412 // now check for message keys within an expression 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 * Retrieves the test associated with the message give by the message key string 431 * 432 * @param messageKeyStr key string for the message, can contain just the key, or also the component and/or 433 * namespace. If component or namespace not given it is determined from the bean stack 434 * @param nestedBeanStack bean stack that contains the property for which the message applies 435 * @return String test associated with the message 436 */ 437 protected String getMessageTextForKey(String messageKeyStr, Stack<BeanDefinitionHolder> nestedBeanStack) { 438 String namespace = null; 439 String componentCode = null; 440 String key = null; 441 442 // check for specification of namespace and component 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 * Applies the given message text to the bean definition with the given property name, if a current 485 * value exists for the property name the value is checked for expressions which are then merged with 486 * the message 487 * 488 * @param propertyName - name of the property to set on the bean definition 489 * @param messageText - message text that will be the property value 490 * @param beanDefinition - bean definition to set property on 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 * Prepares the message text that will replace the property value checking for any expression placeholders 511 * 512 * <p> 513 * The message text may contain placeholders (using brace delimiters) for expression placement. It is 514 * expected when these placeholders are given the property value contains the expressions (using the 515 * expression placeholders) that will be inserted into the message text 516 * </p> 517 * 518 * @param messageText - raw text of the message 519 * @param propertyValue - current value for the property 520 * @return String the message text with expressions inserted (if any expressions were found) 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 // add expression placeholders back on 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 // escape single quotes for message format process 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 * Walks up the stack of bean definitions until a namespace is found and returns that namespace 552 * 553 * @param nestedBeanStack stack of bean definitions to find namespace for 554 * @return String namespace found in stack or null if one was not found 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 * Retrieves the namespace associated with the bean definition 574 * 575 * @param beanName name of the bean to find namespace for 576 * @param beanDefinition bean definition to find namespace for 577 * @return String namespace for bean or null if a namespace was not found 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 // if not on bean definition, get from associated module in the dictionary 588 namespace = dataDictionary.getNamespaceForBeanDefinition(beanName); 589 } 590 591 return namespace; 592 } 593 594 /** 595 * Retrieves the component code associated with the bean definition 596 * 597 * @param beanName name of the bean to find component code for 598 * @param beanDefinition bean definition to find component code for 599 * @return String component code for bean or null if a component code was not found 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 * Returns instance of the Message Service 624 * 625 * @return MessageService isntanc 626 */ 627 protected MessageService getMessageService() { 628 return KRADServiceLocatorWeb.getMessageService(); 629 } 630}