View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.util;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.util.Truth;
20  import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
21  import org.kuali.rice.core.api.CoreApiServiceLocator;
22  import org.kuali.rice.core.api.encryption.EncryptionService;
23  import org.kuali.rice.core.api.util.type.KualiDecimal;
24  import org.kuali.rice.coreservice.framework.parameter.ParameterConstants;
25  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
26  import org.kuali.rice.core.web.format.BooleanFormatter;
27  import org.kuali.rice.krad.UserSession;
28  import org.kuali.rice.krad.messages.MessageService;
29  import org.kuali.rice.krad.service.KRADServiceLocator;
30  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
31  import org.kuali.rice.krad.service.KualiModuleService;
32  import org.kuali.rice.krad.service.ModuleService;
33  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
34  
35  import javax.servlet.ServletRequest;
36  import javax.servlet.http.HttpServletRequest;
37  import java.lang.reflect.Constructor;
38  import java.lang.reflect.Method;
39  import java.security.GeneralSecurityException;
40  import java.text.MessageFormat;
41  import java.text.NumberFormat;
42  import java.util.ArrayList;
43  import java.util.Arrays;
44  import java.util.Collection;
45  import java.util.HashMap;
46  import java.util.Iterator;
47  import java.util.List;
48  import java.util.Map;
49  import java.util.Properties;
50  import java.util.regex.Pattern;
51  
52  /**
53   * Miscellaneous Utility Methods
54   *
55   * @author Kuali Rice Team (rice.collab@kuali.org)
56   */
57  public final class KRADUtils {
58      private static KualiModuleService kualiModuleService;
59  
60      private static final KualiDecimal ONE_HUNDRED = new KualiDecimal("100.00");
61  
62      /**
63       * Prevent instantiation of the class.
64       */
65      private KRADUtils() {
66          throw new UnsupportedOperationException("do not call");
67      }
68  
69      /**
70       * Retrieve the title for a business object class
71       *
72       * <p>
73       * The title is a nicely formatted version of the simple class name.
74       * </p>
75       *
76       * @param clazz business object class
77       * @return title of the business object class
78       */
79      public final static String getBusinessTitleForClass(Class<? extends Object> clazz) {
80          if (clazz == null) {
81              throw new IllegalArgumentException(
82                      "The getBusinessTitleForClass method of KRADUtils requires a non-null class");
83          }
84          String className = clazz.getSimpleName();
85  
86          StringBuffer label = new StringBuffer(className.substring(0, 1));
87          for (int i = 1; i < className.length(); i++) {
88              if (Character.isLowerCase(className.charAt(i))) {
89                  label.append(className.charAt(i));
90              } else {
91                  label.append(" ").append(className.charAt(i));
92              }
93          }
94          return label.toString().trim();
95      }
96  
97      /**
98       * Picks off the filename from the full path
99       *
100      * <p>
101      * The different OS path separators are being taken into consideration.
102      * </p>
103      *
104      * @param fullFileNames file name with path
105      * @return file name
106      */
107     public final static List<String> getFileNameFromPath(List<String> fullFileNames) {
108         List<String> fileNameList = new ArrayList<String>();
109 
110         for (String fullFileName : fullFileNames) {
111             if (StringUtils.contains(fullFileName, "/")) {
112                 fileNameList.add(StringUtils.substringAfterLast(fullFileName, "/"));
113             } else {
114                 fileNameList.add(StringUtils.substringAfterLast(fullFileName, "\\"));
115             }
116         }
117 
118         return fileNameList;
119     }
120 
121     /**
122      * Convert the given money amount into an integer string.
123      *
124      * <p>
125      * Since the return string cannot have decimal point, multiplies the amount by 100 so the decimal places
126      * are not lost, for example, 320.15 is converted into 32015.
127      * </p>
128      *
129      * @param decimalNumber decimal number to be converted
130      * @return an integer string of the given money amount through multiplying by 100 and removing the fraction
131      *         portion.
132      */
133     public final static String convertDecimalIntoInteger(KualiDecimal decimalNumber) {
134         KualiDecimal decimalAmount = decimalNumber.multiply(ONE_HUNDRED);
135         NumberFormat formatter = NumberFormat.getIntegerInstance();
136         String formattedAmount = formatter.format(decimalAmount);
137 
138         return StringUtils.replace(formattedAmount, ",", "");
139     }
140 
141     /**
142      * Return the integer value of a string
143      *
144      * <p>
145      * If the string contains a decimal value everything after the decimal point is dropped.
146      * </p>
147      *
148      * @param numberStr string
149      * @return integer representation of the given string
150      */
151     public static Integer getIntegerValue(String numberStr) {
152         Integer numberInt = null;
153         try {
154             numberInt = new Integer(numberStr);
155         } catch (NumberFormatException nfe) {
156             Double numberDbl = new Double(numberStr);
157             numberInt = new Integer(numberDbl.intValue());
158         }
159         return numberInt;
160     }
161 
162     /**
163      * Attempt to coerce a String attribute value to the given propertyType.  If the transformation can't be made,
164      * either because the propertyType is null or because the transformation required exceeds this method's very small
165      * bag of tricks, then null is returned.
166      *
167      * @param propertyType the Class to coerce the attributeValue to
168      * @param attributeValue the String value to coerce
169      * @return an instance of the propertyType class, or null the transformation can't be made.
170      */
171     public static Object hydrateAttributeValue(Class<?> propertyType, String attributeValue) {
172         Object attributeValueObject = null;
173         if (propertyType != null && attributeValue != null) {
174             if (String.class.equals(propertyType)) {
175                 // it's already a String
176                 attributeValueObject = attributeValue;
177             } // KULRICE-6808: Kim Role Maintenance - Custom boolean role qualifier values are not being converted properly
178             else if (Boolean.class.equals(propertyType) || Boolean.TYPE.equals(propertyType)) {
179                 attributeValueObject = Truth.strToBooleanIgnoreCase(attributeValue);
180             } else {
181                 // try to create one with KRADUtils for other misc data types
182                 attributeValueObject = KRADUtils.createObject(propertyType, new Class[]{String.class},
183                         new Object[]{attributeValue});
184                 // if that didn't work, we'll get a null back
185             }
186         }
187         return attributeValueObject;
188     }
189 
190     public static Object createObject(Class<?> clazz, Class<?>[] argumentClasses, Object[] argumentValues) {
191         if (clazz == null) {
192             return null;
193         }
194         if (argumentClasses.length == 1 && argumentClasses[0] == String.class) {
195             if (argumentValues.length == 1 && argumentValues[0] != null) {
196                 if (clazz == String.class) {
197                     // this means we're trying to create a String from a String
198                     // don't new up Strings, it's a bad idea
199                     return argumentValues[0];
200                 } else {
201                     // maybe it's a type that supports valueOf?
202                     Method valueOfMethod = null;
203                     try {
204                         valueOfMethod = clazz.getMethod("valueOf", String.class);
205                     } catch (NoSuchMethodException e) {
206                         // ignored
207                     }
208                     if (valueOfMethod != null) {
209                         try {
210                             return valueOfMethod.invoke(null, argumentValues[0]);
211                         } catch (Exception e) {
212                             // ignored
213                         }
214                     }
215                 }
216             }
217         }
218         try {
219             Constructor<?> constructor = clazz.getConstructor(argumentClasses);
220             return constructor.newInstance(argumentValues);
221         } catch (Exception e) {
222             // ignored
223         }
224         return null;
225     }
226 
227     /**
228      * Creates a comma separated String representation of the given list.
229      *
230      * <p>
231      * For example 'a','b',c'.
232      * </p>
233      *
234      * @param list
235      * @return the joined String, empty if the list is null or has no elements
236      */
237     public static String joinWithQuotes(List<String> list) {
238         if (list == null || list.size() == 0) {
239             return "";
240         }
241 
242         return KRADConstants.SINGLE_QUOTE +
243                 StringUtils.join(list.iterator(), KRADConstants.SINGLE_QUOTE + "," + KRADConstants.SINGLE_QUOTE) +
244                 KRADConstants.SINGLE_QUOTE;
245     }
246 
247     private static KualiModuleService getKualiModuleService() {
248         if (kualiModuleService == null) {
249             kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService();
250         }
251         return kualiModuleService;
252     }
253 
254     /**
255      * TODO this method will probably need to be exposed in a public KRADUtils class as it is used
256      * by several different modules.  That will have to wait until ModuleService and KualiModuleService are moved
257      * to core though.
258      */
259     public static String getNamespaceCode(Class<? extends Object> clazz) {
260         ModuleService moduleService = getKualiModuleService().getResponsibleModuleService(clazz);
261         if (moduleService == null) {
262             return KRADConstants.DEFAULT_NAMESPACE;
263         }
264         return moduleService.getModuleConfiguration().getNamespaceCode();
265     }
266 
267     public static Map<String, String> getNamespaceAndComponentSimpleName(Class<? extends Object> clazz) {
268         Map<String, String> map = new HashMap<String, String>();
269         map.put(KRADConstants.NAMESPACE_CODE, getNamespaceCode(clazz));
270         map.put(KRADConstants.COMPONENT_NAME, getComponentSimpleName(clazz));
271         return map;
272     }
273 
274     public static Map<String, String> getNamespaceAndComponentFullName(Class<? extends Object> clazz) {
275         Map<String, String> map = new HashMap<String, String>();
276         map.put(KRADConstants.NAMESPACE_CODE, getNamespaceCode(clazz));
277         map.put(KRADConstants.COMPONENT_NAME, getComponentFullName(clazz));
278         return map;
279     }
280 
281     public static Map<String, String> getNamespaceAndActionClass(Class<? extends Object> clazz) {
282         Map<String, String> map = new HashMap<String, String>();
283         map.put(KRADConstants.NAMESPACE_CODE, getNamespaceCode(clazz));
284         map.put(KRADConstants.ACTION_CLASS, clazz.getName());
285         return map;
286     }
287 
288     private static String getComponentSimpleName(Class<? extends Object> clazz) {
289         return clazz.getSimpleName();
290     }
291 
292     private static String getComponentFullName(Class<? extends Object> clazz) {
293         return clazz.getName();
294     }
295 
296     /**
297      * Parses a string that is in map format (commas separating map entries, colon separates
298      * map key/value) to a new map instance
299      *
300      * @param parameter - string parameter to parse
301      * @return Map<String, String> instance populated from string parameter
302      */
303     public static Map<String, String> convertStringParameterToMap(String parameter) {
304         Map<String, String> map = new HashMap<String, String>();
305 
306         if (StringUtils.isNotBlank(parameter)) {
307             if (StringUtils.contains(parameter, ",")) {
308                 String[] fieldConversions = StringUtils.split(parameter, ",");
309 
310                 for (int i = 0; i < fieldConversions.length; i++) {
311                     String fieldConversionStr = fieldConversions[i];
312                     if (StringUtils.isNotBlank(fieldConversionStr)) {
313                         if (StringUtils.contains(fieldConversionStr, ":")) {
314                             String[] fieldConversion = StringUtils.split(fieldConversionStr, ":");
315                             map.put(fieldConversion[0], fieldConversion[1]);
316                         } else {
317                             map.put(fieldConversionStr, fieldConversionStr);
318                         }
319                     }
320                 }
321             } else if (StringUtils.contains(parameter, ":")) {
322                 String[] fieldConversion = StringUtils.split(parameter, ":");
323                 map.put(fieldConversion[0], fieldConversion[1]);
324             } else {
325                 map.put(parameter, parameter);
326             }
327         }
328 
329         return map;
330     }
331 
332     /**
333      * Parses a string that is in list format (commas separating list entries) to a new List instance
334      *
335      * @param parameter - string parameter to parse
336      * @return List<String> instance populated from string parameter
337      */
338     public static List<String> convertStringParameterToList(String parameter) {
339         List<String> list = new ArrayList<String>();
340 
341         if (StringUtils.isNotBlank(parameter)) {
342             if (StringUtils.contains(parameter, ",")) {
343                 String[] parameters = StringUtils.split(parameter, ",");
344                 List arraysList = Arrays.asList(parameters);
345                 list.addAll(arraysList);
346             } else {
347                 list.add(parameter);
348             }
349         }
350 
351         return list;
352     }
353 
354     /**
355      * Translates characters in the given string like brackets that will cause
356      * problems with binding to characters that do not affect the binding
357      *
358      * @param key - string to translate
359      * @return String translated string
360      */
361     public static String translateToMapSafeKey(String key) {
362         String safeKey = key;
363 
364         safeKey = StringUtils.replace(safeKey, "[", "_");
365         safeKey = StringUtils.replace(safeKey, "]", "_");
366 
367         return safeKey;
368     }
369 
370     /**
371      * Builds a string from the given map by joining each entry with a comma and
372      * each key/value pair with a colon
373      *
374      * @param map - map instance to build string for
375      * @return String of map entries
376      */
377     public static String buildMapParameterString(Map<String, String> map) {
378         String parameterString = "";
379 
380         for (Map.Entry<String, String> entry : map.entrySet()) {
381             if (StringUtils.isNotBlank(parameterString)) {
382                 parameterString += ",";
383             }
384 
385             parameterString += entry.getKey() + ":" + entry.getValue();
386         }
387 
388         return parameterString;
389     }
390 
391     /**
392      * Parses the given string into a Map by splitting on the comma to get the
393      * map entries and within each entry splitting by colon to get the key/value
394      * pairs
395      *
396      * @param parameterString - string to parse into map
397      * @return Map<String, String> map from string
398      */
399     public static Map<String, String> getMapFromParameterString(String parameterString) {
400         Map<String, String> map = new HashMap<String, String>();
401 
402         String[] entries = parameterString.split(",");
403         for (int i = 0; i < entries.length; i++) {
404             String[] keyValue = entries[i].split(":");
405             if (keyValue.length != 2) {
406                 throw new RuntimeException("malformed field conversion pair: " + Arrays.toString(keyValue));
407             }
408 
409             map.put(keyValue[0], keyValue[1]);
410         }
411 
412         return map;
413     }
414 
415     /**
416      * Retrieves value for the given parameter name in the request and attempts to convert to a Boolean using
417      * the <code>BooleanFormatter</code>
418      *
419      * @param request - servlet request containing parameters
420      * @param parameterName - name of parameter to retrieve value for
421      * @return Boolean set to value of parameter, or null if parameter was not found in request
422      */
423     public static Boolean getRequestParameterAsBoolean(ServletRequest request, String parameterName) {
424         Boolean parameterValue = null;
425 
426         String parameterValueStr = request.getParameter(parameterName);
427         if (StringUtils.isNotBlank(parameterValueStr)) {
428             parameterValue = (Boolean) new BooleanFormatter().convertFromPresentationFormat(parameterValueStr);
429         }
430 
431         return parameterValue;
432     }
433 
434     /**
435      * Translates the given Map of String keys and String array values to a Map
436      * of String key and values. If the String array contains more than one
437      * value, the single string is built by joining the values with the vertical
438      * bar character
439      *
440      * @param requestParameters - Map of request parameters to translate
441      * @return Map<String, String> translated Map
442      */
443     public static Map<String, String> translateRequestParameterMap(Map<String, String[]> requestParameters) {
444         Map<String, String> parameters = new HashMap<String, String>();
445 
446         for (Map.Entry<String, String[]> parameter : requestParameters.entrySet()) {
447             String parameterValue = "";
448             if (parameter.getValue().length > 1) {
449                 parameterValue = StringUtils.join(parameter.getValue(), "|");
450             } else {
451                 parameterValue = parameter.getValue()[0];
452             }
453             parameters.put(parameter.getKey(), parameterValue);
454         }
455 
456         return parameters;
457     }
458 
459     /**
460      * Retrieves parameter values from the request that match the requested
461      * names. In addition, based on the object class an authorization check is
462      * performed to determine if the values are secure and should be decrypted.
463      * If true, the value is decrypted before returning
464      *
465      * @param parameterNames - names of the parameters whose values should be retrieved
466      * from the request
467      * @param parentObjectClass - object class that contains the parameter names as properties
468      * and should be consulted for security checks
469      * @param requestParameters - all request parameters to pull from
470      * @return Map<String, String> populated with parameter name/value pairs
471      *         pulled from the request
472      */
473     public static Map<String, String> getParametersFromRequest(List<String> parameterNames, Class<?> parentObjectClass,
474             Map<String, String> requestParameters) {
475         Map<String, String> parameterValues = new HashMap<String, String>();
476 
477         for (Iterator<String> iter = parameterNames.iterator(); iter.hasNext(); ) {
478             String keyPropertyName = iter.next();
479 
480             if (requestParameters.get(keyPropertyName) != null) {
481                 String keyValue = requestParameters.get(keyPropertyName);
482 
483                 // Check if this element was encrypted, if it was decrypt it
484                 if (KRADServiceLocatorWeb.getDataObjectAuthorizationService()
485                         .attributeValueNeedsToBeEncryptedOnFormsAndLinks(parentObjectClass, keyPropertyName)) {
486                     try {
487                         keyValue = StringUtils.removeEnd(keyValue, EncryptionService.ENCRYPTION_POST_PREFIX);
488                         keyValue = CoreApiServiceLocator.getEncryptionService().decrypt(keyValue);
489                     } catch (GeneralSecurityException e) {
490                         throw new RuntimeException(e);
491                     }
492                 }
493 
494                 parameterValues.put(keyPropertyName, keyValue);
495             }
496         }
497 
498         return parameterValues;
499     }
500 
501     /**
502      * Builds a Map containing a key/value pair for each property given in the property names list, general
503      * security is checked to determine if the value needs to be encrypted along with applying formatting to
504      * the value
505      *
506      * @param propertyNames - list of property names to get key/value pairs for
507      * @param dataObject - object instance containing the properties for which the values will be pulled
508      * @return Map<String, String> containing entry for each property name with the property name as the map key
509      *         and the property value as the value
510      */
511     public static Map<String, String> getPropertyKeyValuesFromDataObject(List<String> propertyNames,
512             Object dataObject) {
513         Map<String, String> propertyKeyValues = new HashMap<String, String>();
514 
515         if (dataObject == null) {
516             return propertyKeyValues;
517         }
518 
519         // iterate through properties and add a map entry for each
520         for (String propertyName : propertyNames) {
521             Object propertyValue = ObjectPropertyUtils.getPropertyValue(dataObject, propertyName);
522             if (propertyValue == null) {
523                 propertyValue = StringUtils.EMPTY;
524             }
525 
526             if (KRADServiceLocatorWeb.getDataObjectAuthorizationService()
527                     .attributeValueNeedsToBeEncryptedOnFormsAndLinks(dataObject.getClass(), propertyName)) {
528                 try {
529                     if(CoreApiServiceLocator.getEncryptionService().isEnabled()) {
530                         propertyValue = CoreApiServiceLocator.getEncryptionService().encrypt(propertyValue) +
531                                 EncryptionService.ENCRYPTION_POST_PREFIX;
532                     }
533                 } catch (GeneralSecurityException e) {
534                     throw new RuntimeException("Exception while trying to encrypt value for key/value map.", e);
535                 }
536             }
537 
538             // TODO: need to apply formatting to return value once util class is ready
539             propertyKeyValues.put(propertyName, propertyValue.toString());
540         }
541 
542         return propertyKeyValues;
543     }
544 
545     /**
546      * Utility method to convert a Map to a Properties object
547      *
548      * @param parameters - map to convert
549      * @return Properties object containing all the map entries
550      */
551     public static Properties convertMapToProperties(Map<String, String> parameters) {
552         Properties properties = new Properties();
553 
554         if (parameters != null) {
555             for (Map.Entry<String, String> parameter : parameters.entrySet()) {
556                 properties.put(parameter.getKey(), parameter.getValue());
557             }
558         }
559 
560         return properties;
561     }
562 
563     /**
564      * Utility method to convert a Request Parameters Map to a Properties object
565      *
566      * <p>
567      * Multiple values for a parameter are joined together with comma delimiter
568      * </p>
569      *
570      * @param requestParameters - map to convert
571      * @return Properties object containing all the map entries
572      */
573     public static Properties convertRequestMapToProperties(Map<String, String[]> requestParameters) {
574         Properties properties = new Properties();
575 
576         if (requestParameters != null) {
577             for (Map.Entry<String, String[]> parameter : requestParameters.entrySet()) {
578                 String[] parameterValue = parameter.getValue();
579                 String parameterValueString = StringUtils.join(parameterValue, ",");
580 
581                 properties.put(parameter.getKey(), parameterValueString);
582             }
583         }
584 
585         return properties;
586     }
587 
588     /**
589      * Check if data might be sensitive
590      *
591      * <p>
592      * The sensitivity of the data is checked by matching it against the sensitive data patterns that are specified
593      * in the system parameter table.
594      * </p>
595      *
596      * @param fieldValue data to be checked for sensitivity
597      * @return true if the data matches the sensitive data pattern, false otherwise
598      */
599     public static boolean containsSensitiveDataPatternMatch(String fieldValue) {
600         if (StringUtils.isBlank(fieldValue)) {
601             return false;
602         }
603         ParameterService parameterService = CoreFrameworkServiceLocator.getParameterService();
604         Collection<String> sensitiveDataPatterns = parameterService.getParameterValuesAsString(
605                 KRADConstants.KNS_NAMESPACE, ParameterConstants.ALL_COMPONENT,
606                 KRADConstants.SystemGroupParameterNames.SENSITIVE_DATA_PATTERNS);
607         for (String pattern : sensitiveDataPatterns) {
608             if (Pattern.compile(pattern).matcher(fieldValue).find()) {
609                 return true;
610             }
611         }
612         return false;
613     }
614 
615     /**
616      * Gets the UserSession object from the HttpServletRequest object's
617      * associated session.
618      *
619      * <p>
620      * In some cases (different threads) the UserSession cannot be retrieved
621      * from GlobalVariables but can still be accessed via the session object
622      * </p>
623      */
624     public static final UserSession getUserSessionFromRequest(HttpServletRequest request) {
625         return (UserSession) request.getSession().getAttribute(KRADConstants.USER_SESSION_KEY);
626     }
627 
628     /**
629      * Check if current deployment is the production environment
630      *
631      * @return true if the deploy environment is production, false otherwise
632      */
633     public static boolean isProductionEnvironment() {
634         return KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
635                 KRADConstants.PROD_ENVIRONMENT_CODE_KEY).equalsIgnoreCase(
636                 KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
637                         KRADConstants.ENVIRONMENT_KEY));
638     }
639 
640     /**
641      * Gets the message associated with ErrorMessage object passed in, using message service.
642      * The prefix and suffix will be appended to the retrieved message if processPrefixSuffix is true and if those
643      * settings are set on the ErrorMessage passed in.
644      *
645      * @param errorMessage the ErrorMessage object containing the message key(s)
646      * @param processPrefixSuffix if true appends the prefix and suffix to the message if they exist on ErrorMessage
647      * @return the converted/retrieved message
648      */
649     public static String getMessageText(ErrorMessage errorMessage, boolean processPrefixSuffix) {
650         String message = "";
651         if (errorMessage != null && errorMessage.getErrorKey() != null) {
652             MessageService messageService = KRADServiceLocatorWeb.getMessageService();
653 
654             // find message by key
655             message = messageService.getMessageText(errorMessage.getNamespaceCode(), errorMessage.getComponentCode(),
656                     errorMessage.getErrorKey());
657             if (message == null) {
658                 message = "Intended message with key: " + errorMessage.getErrorKey() + " not found.";
659             }
660 
661             if (errorMessage.getMessageParameters() != null && StringUtils.isNotBlank(message)) {
662                 message = message.replace("'", "''");
663                 message = MessageFormat.format(message, (Object[]) errorMessage.getMessageParameters());
664             }
665 
666             // add prefix
667             if (StringUtils.isNotBlank(errorMessage.getMessagePrefixKey()) && processPrefixSuffix) {
668                 String prefix = messageService.getMessageText(errorMessage.getNamespaceCode(),
669                         errorMessage.getComponentCode(), errorMessage.getMessagePrefixKey());
670 
671                 if (errorMessage.getMessagePrefixParameters() != null && StringUtils.isNotBlank(prefix)) {
672                     prefix = prefix.replace("'", "''");
673                     prefix = MessageFormat.format(prefix, (Object[]) errorMessage.getMessagePrefixParameters());
674                 }
675 
676                 if (StringUtils.isNotBlank(prefix)) {
677                     message = prefix + " " + message;
678                 }
679             }
680 
681             // add suffix
682             if (StringUtils.isNotBlank(errorMessage.getMessageSuffixKey()) && processPrefixSuffix) {
683                 String suffix = messageService.getMessageText(errorMessage.getNamespaceCode(),
684                         errorMessage.getComponentCode(), errorMessage.getMessageSuffixKey());
685 
686                 if (errorMessage.getMessageSuffixParameters() != null && StringUtils.isNotBlank(suffix)) {
687                     suffix = suffix.replace("'", "''");
688                     suffix = MessageFormat.format(suffix, (Object[]) errorMessage.getMessageSuffixParameters());
689                 }
690 
691                 if (StringUtils.isNotBlank(suffix)) {
692                     message = message + " " + suffix;
693                 }
694             }
695         }
696 
697         return message;
698     }
699 }