View Javadoc

1   /**
2    * Copyright 2005-2011 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.coreservice.framework.CoreFrameworkServiceLocator;
20  import org.kuali.rice.core.api.CoreApiServiceLocator;
21  import org.kuali.rice.core.api.encryption.EncryptionService;
22  import org.kuali.rice.core.api.util.type.KualiDecimal;
23  import org.kuali.rice.coreservice.framework.parameter.ParameterConstants;
24  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
25  import org.kuali.rice.core.web.format.BooleanFormatter;
26  import org.kuali.rice.krad.UserSession;
27  import org.kuali.rice.krad.service.KRADServiceLocator;
28  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
29  import org.kuali.rice.krad.service.KualiModuleService;
30  import org.kuali.rice.krad.service.ModuleService;
31  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
32  
33  import javax.servlet.ServletRequest;
34  import javax.servlet.http.HttpServletRequest;
35  import java.lang.reflect.Constructor;
36  import java.security.GeneralSecurityException;
37  import java.text.NumberFormat;
38  import java.util.ArrayList;
39  import java.util.Arrays;
40  import java.util.Collection;
41  import java.util.HashMap;
42  import java.util.Iterator;
43  import java.util.List;
44  import java.util.Map;
45  import java.util.regex.Pattern;
46  
47  /**
48   * Miscellaneous Utility Methods
49   *
50   * @author Kuali Rice Team (rice.collab@kuali.org)
51   */
52  public final class KRADUtils {
53      private static KualiModuleService kualiModuleService;
54  
55      private KRADUtils() {
56          throw new UnsupportedOperationException("do not call");
57      }
58  
59      public final static String getBusinessTitleForClass(Class<? extends Object> clazz) {
60          if (clazz == null) {
61              throw new IllegalArgumentException(
62                      "The getBusinessTitleForClass method of KRADUtils requires a non-null class");
63          }
64          String className = clazz.getSimpleName();
65  
66          StringBuffer label = new StringBuffer(className.substring(0, 1));
67          for (int i = 1; i < className.length(); i++) {
68              if (Character.isLowerCase(className.charAt(i))) {
69                  label.append(className.charAt(i));
70              } else {
71                  label.append(" ").append(className.charAt(i));
72              }
73          }
74          return label.toString().trim();
75      }
76  
77      /**
78       * Picks off the filename from the full path. Takes care of different OS seperators.
79       */
80      public final static List<String> getFileNameFromPath(List<String> fullFileNames) {
81          List<String> fileNameList = new ArrayList<String>();
82  
83          for (String fullFileName : fullFileNames) {
84              if (StringUtils.contains(fullFileName, "/")) {
85                  fileNameList.add(StringUtils.substringAfterLast(fullFileName, "/"));
86              } else {
87                  fileNameList.add(StringUtils.substringAfterLast(fullFileName, "\\"));
88              }
89          }
90  
91          return fileNameList;
92      }
93  
94      private static final KualiDecimal ONE_HUNDRED = new KualiDecimal("100.00");
95  
96      /**
97       * Convert the given monney amount into an interger string. Since the return string cannot have decimal point,
98       * multiplies the
99       * amount by 100 so the decimal places are not lost, for example, 320.15 is converted into 32015.
100      *
101      * @return an integer string of the given money amount through multiplicating by 100 and removing the fraction
102      *         portion.
103      */
104     public final static String convertDecimalIntoInteger(KualiDecimal decimalNumber) {
105         KualiDecimal decimalAmount = decimalNumber.multiply(ONE_HUNDRED);
106         NumberFormat formatter = NumberFormat.getIntegerInstance();
107         String formattedAmount = formatter.format(decimalAmount);
108 
109         return StringUtils.replace(formattedAmount, ",", "");
110     }
111 
112     public static Integer getIntegerValue(String numberStr) {
113         Integer numberInt = null;
114         try {
115             numberInt = new Integer(numberStr);
116         } catch (NumberFormatException nfe) {
117             Double numberDbl = new Double(numberStr);
118             numberInt = new Integer(numberDbl.intValue());
119         }
120         return numberInt;
121     }
122 
123     public static Object createObject(Class<?> clazz, Class<?>[] argumentClasses, Object[] argumentValues) {
124         if (clazz == null)
125             return null;
126         try {
127             Constructor<?> constructor = clazz.getConstructor(argumentClasses);
128             return constructor.newInstance(argumentValues);
129         } catch (Exception e) {
130             return null;
131         }
132     }
133 
134     public static String joinWithQuotes(List<String> list) {
135         if (list == null || list.size() == 0)
136             return "";
137 
138         return KRADConstants.SINGLE_QUOTE +
139                 StringUtils.join(list.iterator(), KRADConstants.SINGLE_QUOTE + "," + KRADConstants.SINGLE_QUOTE) +
140                 KRADConstants.SINGLE_QUOTE;
141     }
142 
143     private static KualiModuleService getKualiModuleService() {
144         if (kualiModuleService == null) {
145             kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService();
146         }
147         return kualiModuleService;
148     }
149 
150     /**
151      * TODO this method will probably need to be exposed in a public KRADUtils class as it is used
152      * by several different modules.  That will have to wait until ModuleService and KualiModuleService are moved
153      * to core though.
154      */
155     public static String getNamespaceCode(Class<? extends Object> clazz) {
156         ModuleService moduleService = getKualiModuleService().getResponsibleModuleService(clazz);
157         if (moduleService == null) {
158             return KRADConstants.DEFAULT_NAMESPACE;
159         }
160         return moduleService.getModuleConfiguration().getNamespaceCode();
161     }
162 
163     public static Map<String, String> getNamespaceAndComponentSimpleName(Class<? extends Object> clazz) {
164         Map<String, String> map = new HashMap<String, String>();
165         map.put(KRADConstants.NAMESPACE_CODE, getNamespaceCode(clazz));
166         map.put(KRADConstants.COMPONENT_NAME, getComponentSimpleName(clazz));
167         return map;
168     }
169 
170     public static Map<String, String> getNamespaceAndComponentFullName(Class<? extends Object> clazz) {
171         Map<String, String> map = new HashMap<String, String>();
172         map.put(KRADConstants.NAMESPACE_CODE, getNamespaceCode(clazz));
173         map.put(KRADConstants.COMPONENT_NAME, getComponentFullName(clazz));
174         return map;
175     }
176 
177     public static Map<String, String> getNamespaceAndActionClass(Class<? extends Object> clazz) {
178         Map<String, String> map = new HashMap<String, String>();
179         map.put(KRADConstants.NAMESPACE_CODE, getNamespaceCode(clazz));
180         map.put(KRADConstants.ACTION_CLASS, clazz.getName());
181         return map;
182     }
183 
184     private static String getComponentSimpleName(Class<? extends Object> clazz) {
185         return clazz.getSimpleName();
186     }
187 
188     private static String getComponentFullName(Class<? extends Object> clazz) {
189         return clazz.getName();
190     }
191 
192     /**
193      * Parses a string that is in map format (commas separating map entries, colon separates
194      * map key/value) to a new map instance
195      *
196      * @param parameter - string parameter to parse
197      * @return Map<String, String> instance populated from string parameter
198      */
199     public static Map<String, String> convertStringParameterToMap(String parameter) {
200         Map<String, String> map = new HashMap<String, String>();
201 
202         if (StringUtils.isNotBlank(parameter)) {
203             if (StringUtils.contains(parameter, ",")) {
204                 String[] fieldConversions = StringUtils.split(parameter, ",");
205 
206                 for (int i = 0; i < fieldConversions.length; i++) {
207                     String fieldConversionStr = fieldConversions[i];
208                     if (StringUtils.isNotBlank(fieldConversionStr)) {
209                         if (StringUtils.contains(fieldConversionStr, ":")) {
210                             String[] fieldConversion = StringUtils.split(fieldConversionStr, ":");
211                             map.put(fieldConversion[0], fieldConversion[1]);
212                         } else {
213                             map.put(fieldConversionStr, fieldConversionStr);
214                         }
215                     }
216                 }
217             } else if (StringUtils.contains(parameter, ":")) {
218                 String[] fieldConversion = StringUtils.split(parameter, ":");
219                 map.put(fieldConversion[0], fieldConversion[1]);
220             } else {
221                 map.put(parameter, parameter);
222             }
223         }
224 
225         return map;
226     }
227 
228     /**
229      * Parses a string that is in list format (commas separating list entries) to a new List instance
230      *
231      * @param parameter - string parameter to parse
232      * @return List<String> instance populated from string parameter
233      */
234     public static List<String> convertStringParameterToList(String parameter) {
235         List<String> list = new ArrayList<String>();
236 
237         if (StringUtils.isNotBlank(parameter)) {
238             if (StringUtils.contains(parameter, ",")) {
239                 String[] parameters = StringUtils.split(parameter, ",");
240                 List arraysList = Arrays.asList(parameters);
241                 list.addAll(arraysList);
242             } else {
243                 list.add(parameter);
244             }
245         }
246 
247         return list;
248     }
249 
250     /**
251      * Translates characters in the given string like brackets that will cause
252      * problems with binding to characters that do not affect the binding
253      *
254      * @param key - string to translate
255      * @return String translated string
256      */
257     public static String translateToMapSafeKey(String key) {
258         String safeKey = key;
259 
260         safeKey = StringUtils.replace(safeKey, "[", "_");
261         safeKey = StringUtils.replace(safeKey, "]", "_");
262 
263         return safeKey;
264     }
265 
266     /**
267      * Builds a string from the given map by joining each entry with a comma and
268      * each key/value pair with a colon
269      *
270      * @param map - map instance to build string for
271      * @return String of map entries
272      */
273     public static String buildMapParameterString(Map<String, String> map) {
274         String parameterString = "";
275 
276         for (Map.Entry<String, String> entry : map.entrySet()) {
277             if (StringUtils.isNotBlank(parameterString)) {
278                 parameterString += ",";
279             }
280 
281             parameterString += entry.getKey() + ":" + entry.getValue();
282         }
283 
284         return parameterString;
285     }
286 
287     /**
288      * Parses the given string into a Map by splitting on the comma to get the
289      * map entries and within each entry splitting by colon to get the key/value
290      * pairs
291      *
292      * @param parameterString - string to parse into map
293      * @return Map<String, String> map from string
294      */
295     public static Map<String, String> getMapFromParameterString(String parameterString) {
296         Map<String, String> map = new HashMap<String, String>();
297 
298         String[] entries = parameterString.split(",");
299         for (int i = 0; i < entries.length; i++) {
300             String[] keyValue = entries[i].split(":");
301             if (keyValue.length != 2) {
302                 throw new RuntimeException("malformed field conversion pair: " + Arrays.toString(keyValue));
303             }
304 
305             map.put(keyValue[0], keyValue[1]);
306         }
307 
308         return map;
309     }
310 
311     /**
312      * Retrieves value for the given parameter name in the request and attempts to convert to a Boolean using
313      * the <code>BooleanFormatter</code>
314      *
315      * @param request - servlet request containing parameters
316      * @param parameterName - name of parameter to retrieve value for
317      * @return Boolean set to value of parameter, or null if parameter was not found in request
318      */
319     public static Boolean getRequestParameterAsBoolean(ServletRequest request, String parameterName) {
320         Boolean parameterValue = null;
321 
322         String parameterValueStr = request.getParameter(parameterName);
323         if (StringUtils.isNotBlank(parameterValueStr)) {
324             parameterValue = (Boolean) new BooleanFormatter().convertFromPresentationFormat(parameterValueStr);
325         }
326 
327         return parameterValue;
328     }
329 
330     /**
331      * Translates the given Map of String keys and String array values to a Map
332      * of String key and values. If the String array contains more than one
333      * value, the single string is built by joining the values with the vertical
334      * bar character
335      *
336      * @param requestParameters - Map of request parameters to translate
337      * @return Map<String, String> translated Map
338      */
339     public static Map<String, String> translateRequestParameterMap(Map<String, String[]> requestParameters) {
340         Map<String, String> parameters = new HashMap<String, String>();
341 
342         for (Map.Entry<String, String[]> parameter : requestParameters.entrySet()) {
343             String parameterValue = "";
344             if (parameter.getValue().length > 1) {
345                 parameterValue = StringUtils.join(parameter.getValue(), "|");
346             } else {
347                 parameterValue = parameter.getValue()[0];
348             }
349             parameters.put(parameter.getKey(), parameterValue);
350         }
351 
352         return parameters;
353     }
354 
355     /**
356      * Retrieves parameter values from the request that match the requested
357      * names. In addition, based on the object class an authorization check is
358      * performed to determine if the values are secure and should be decrypted.
359      * If true, the value is decrypted before returning
360      *
361      * @param parameterNames - names of the parameters whose values should be retrieved
362      * from the request
363      * @param parentObjectClass - object class that contains the parameter names as properties
364      * and should be consulted for security checks
365      * @param requestParameters - all request parameters to pull from
366      * @return Map<String, String> populated with parameter name/value pairs
367      *         pulled from the request
368      */
369     public static Map<String, String> getParametersFromRequest(List<String> parameterNames, Class<?> parentObjectClass,
370             Map<String, String> requestParameters) {
371         Map<String, String> parameterValues = new HashMap<String, String>();
372 
373         for (Iterator<String> iter = parameterNames.iterator(); iter.hasNext(); ) {
374             String keyPropertyName = iter.next();
375 
376             if (requestParameters.get(keyPropertyName) != null) {
377                 String keyValue = requestParameters.get(keyPropertyName);
378 
379                 // Check if this element was encrypted, if it was decrypt it
380                 if (KRADServiceLocatorWeb.getDataObjectAuthorizationService()
381                         .attributeValueNeedsToBeEncryptedOnFormsAndLinks(parentObjectClass, keyPropertyName)) {
382                     try {
383                         keyValue = StringUtils.removeEnd(keyValue, EncryptionService.ENCRYPTION_POST_PREFIX);
384                         keyValue = CoreApiServiceLocator.getEncryptionService().decrypt(keyValue);
385                     } catch (GeneralSecurityException e) {
386                         throw new RuntimeException(e);
387                     }
388                 }
389 
390                 parameterValues.put(keyPropertyName, keyValue);
391             }
392         }
393 
394         return parameterValues;
395     }
396 
397     /**
398      * Builds a Map containing a key/value pair for each property given in the property names list, general
399      * security is checked to determine if the value needs to be encrypted along with applying formatting to
400      * the value
401      *
402      * @param propertyNames - list of property names to get key/value pairs for
403      * @param dataObject - object instance containing the properties for which the values will be pulled
404      * @return Map<String, String> containing entry for each property name with the property name as the map key
405      *         and the property value as the value
406      */
407     public static Map<String, String> getPropertyKeyValuesFromDataObject(List<String> propertyNames,
408             Object dataObject) {
409         Map<String, String> propertyKeyValues = new HashMap<String, String>();
410 
411         if (dataObject == null) {
412             return propertyKeyValues;
413         }
414 
415         // iterate through properties and add a map entry for each
416         for (String propertyName : propertyNames) {
417             Object propertyValue = ObjectPropertyUtils.getPropertyValue(dataObject, propertyName);
418             if (propertyValue == null) {
419                 propertyValue = StringUtils.EMPTY;
420             }
421 
422             if (KRADServiceLocatorWeb.getDataObjectAuthorizationService()
423                     .attributeValueNeedsToBeEncryptedOnFormsAndLinks(dataObject.getClass(), propertyName)) {
424                 try {
425                     propertyValue = CoreApiServiceLocator.getEncryptionService().encrypt(propertyValue) +
426                             EncryptionService.ENCRYPTION_POST_PREFIX;
427                 } catch (GeneralSecurityException e) {
428                     throw new RuntimeException("Exception while trying to encrypt value for key/value map.", e);
429                 }
430             }
431 
432             // TODO: need to apply formatting to return value once util class is ready
433             propertyKeyValues.put(propertyName, propertyValue.toString());
434         }
435 
436         return propertyKeyValues;
437     }
438 
439     public static boolean containsSensitiveDataPatternMatch(String fieldValue) {
440         if (StringUtils.isBlank(fieldValue)) {
441             return false;
442         }
443         ParameterService parameterService = CoreFrameworkServiceLocator.getParameterService();
444         Collection<String> sensitiveDataPatterns = parameterService
445                 .getParameterValuesAsString(KRADConstants.KRAD_NAMESPACE, ParameterConstants.ALL_COMPONENT,
446                         KRADConstants.SystemGroupParameterNames.SENSITIVE_DATA_PATTERNS);
447         for (String pattern : sensitiveDataPatterns) {
448             if (Pattern.compile(pattern).matcher(fieldValue).find()) {
449                 return true;
450             }
451         }
452         return false;
453     }
454 
455     /**
456      * Gets the UserSession object from the HttpServletRequest object's
457      * associated session.
458      *
459      * <p>
460      * In some cases (different threads) the UserSession cannot be retrieved
461      * from GlobalVariables but can still be accessed via the session object
462      * </p>
463      */
464     public static final UserSession getUserSessionFromRequest(HttpServletRequest request) {
465         return (UserSession) request.getSession().getAttribute(KRADConstants.USER_SESSION_KEY);
466     }
467 
468     /**
469      * @return whether the deploy environment is production
470      */
471     public static boolean isProductionEnvironment() {
472         return KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
473                 KRADConstants.PROD_ENVIRONMENT_CODE_KEY)
474                 .equalsIgnoreCase(KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
475                         KRADConstants.ENVIRONMENT_KEY));
476     }
477 
478 }