Coverage Report - org.kuali.rice.krad.lookup.LookupUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
LookupUtils
0%
0/107
0%
0/72
4.571
 
 1  
 /*
 2  
  * Copyright 2007 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 1.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/ecl1.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.lookup;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.apache.ojb.broker.query.Criteria;
 20  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 21  
 import org.kuali.rice.core.api.encryption.EncryptionService;
 22  
 import org.kuali.rice.core.api.search.SearchOperator;
 23  
 import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
 24  
 import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
 25  
 import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
 26  
 import org.kuali.rice.krad.datadictionary.exception.UnknownBusinessClassAttributeException;
 27  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 28  
 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
 29  
 import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils;
 30  
 import org.kuali.rice.krad.util.KRADConstants;
 31  
 import org.kuali.rice.krad.util.KRADPropertyConstants;
 32  
 import org.kuali.rice.krad.util.ObjectUtils;
 33  
 
 34  
 import java.sql.Date;
 35  
 import java.sql.Timestamp;
 36  
 import java.text.ParseException;
 37  
 import java.util.ArrayList;
 38  
 import java.util.Calendar;
 39  
 import java.util.HashMap;
 40  
 import java.util.HashSet;
 41  
 import java.util.List;
 42  
 import java.util.Map;
 43  
 import java.util.Set;
 44  
 import java.util.StringTokenizer;
 45  
 
 46  
 /**
 47  
  * Provides static utility methods for use within the lookup framework
 48  
  *
 49  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 50  
  */
 51  0
 public class LookupUtils {
 52  
 
 53  
     /**
 54  
      * Uses the DataDictionary to determine whether to force uppercase the value, and if it should, then it does the
 55  
      * uppercase, and returns the upper-cased value.
 56  
      *
 57  
      * @param dataObjectClass Parent DO class that the fieldName is a member of.
 58  
      * @param fieldName Name of the field to be forced to uppercase.
 59  
      * @param fieldValue Value of the field that may be uppercased.
 60  
      * @return The correctly uppercased fieldValue if it should be uppercased, otherwise fieldValue is returned
 61  
      *         unchanged.
 62  
      */
 63  
     public static String forceUppercase(Class<?> dataObjectClass, String fieldName, String fieldValue) {
 64  
         // short-circuit to exit if there isnt enough information to do the forceUppercase
 65  0
         if (StringUtils.isBlank(fieldValue)) {
 66  0
             return fieldValue;
 67  
         }
 68  
 
 69  
         // parameter validation
 70  0
         if (dataObjectClass == null) {
 71  0
             throw new IllegalArgumentException("Parameter dataObjectClass passed in with null value.");
 72  
         }
 73  
 
 74  0
         if (StringUtils.isBlank(fieldName)) {
 75  0
             throw new IllegalArgumentException("Parameter fieldName passed in with empty value.");
 76  
         }
 77  
 
 78  0
         if (!KRADServiceLocatorWeb.getDataDictionaryService().isAttributeDefined(dataObjectClass, fieldName)
 79  
                 .booleanValue()) {
 80  0
             return fieldValue;
 81  
         }
 82  
 
 83  0
         boolean forceUpperCase = false;
 84  
         try {
 85  0
             forceUpperCase = KRADServiceLocatorWeb.getDataDictionaryService()
 86  
                     .getAttributeForceUppercase(dataObjectClass, fieldName).booleanValue();
 87  0
         } catch (UnknownBusinessClassAttributeException ubae) {
 88  
             // do nothing, don't alter the fieldValue
 89  0
         }
 90  0
         if (forceUpperCase && !fieldValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
 91  0
             return fieldValue.toUpperCase();
 92  
         }
 93  
 
 94  0
         return fieldValue;
 95  
     }
 96  
 
 97  
     /**
 98  
      * Uses the DataDictionary to determine whether to force uppercase the values, and if it should, then it does the
 99  
      * uppercase, and returns the upper-cased Map of fieldname/fieldValue pairs.
 100  
      *
 101  
      * @param dataObjectClass Parent DO class that the fieldName is a member of.
 102  
      * @param fieldValues A Map<String,String> where the key is the fieldName and the value is the fieldValue.
 103  
      * @return The same Map is returned, with the appropriate values uppercased (if any).
 104  
      */
 105  
     public static Map<String, String> forceUppercase(Class<?> dataObjectClass, Map<String, String> fieldValues) {
 106  0
         if (dataObjectClass == null) {
 107  0
             throw new IllegalArgumentException("Parameter boClass passed in with null value.");
 108  
         }
 109  
 
 110  0
         if (fieldValues == null) {
 111  0
             throw new IllegalArgumentException("Parameter fieldValues passed in with null value.");
 112  
         }
 113  
 
 114  0
         for (String fieldName : fieldValues.keySet()) {
 115  0
             fieldValues.put(fieldName, forceUppercase(dataObjectClass, fieldName, (String) fieldValues.get(fieldName)));
 116  
         }
 117  
 
 118  0
         return fieldValues;
 119  
     }
 120  
 
 121  
     /**
 122  
      * Parses and returns the lookup result set limit, checking first for the limit
 123  
      * for the class being looked up, and then the global application limit if there isn't a limit
 124  
      * specific to this data object class
 125  
      *
 126  
      * @param dataObjectClass - class to get limit for
 127  
      */
 128  
     public static Integer getSearchResultsLimit(Class dataObjectClass) {
 129  0
         Integer limit = KRADServiceLocatorWeb.getViewDictionaryService().getResultSetLimitForLookup(dataObjectClass);
 130  0
         if (limit == null) {
 131  0
             limit = getApplicationSearchResultsLimit();
 132  
         }
 133  
 
 134  0
         return limit;
 135  
     }
 136  
 
 137  
     /**
 138  
      * Retrieves the default application search limit configured through
 139  
      * a system parameter
 140  
      */
 141  
     public static Integer getApplicationSearchResultsLimit() {
 142  0
         String limitString = CoreFrameworkServiceLocator.getParameterService()
 143  
                 .getParameterValueAsString(KRADConstants.KRAD_NAMESPACE,
 144  
                         KRADConstants.DetailTypes.LOOKUP_PARM_DETAIL_TYPE,
 145  
                         KRADConstants.SystemGroupParameterNames.LOOKUP_RESULTS_LIMIT);
 146  0
         if (limitString != null) {
 147  0
             return Integer.valueOf(limitString);
 148  
         }
 149  
 
 150  0
         return null;
 151  
     }
 152  
 
 153  
     /**
 154  
      * This method applies the search results limit to the search criteria for this BO
 155  
      *
 156  
      * @param businessObjectClass BO class to search on / get limit for
 157  
      * @param criteria search criteria
 158  
      * @param platform database platform
 159  
      */
 160  
     public static void applySearchResultsLimit(Class businessObjectClass, Criteria criteria,
 161  
             DatabasePlatform platform) {
 162  0
         Integer limit = getSearchResultsLimit(businessObjectClass);
 163  0
         if (limit != null) {
 164  0
             platform.applyLimit(limit, criteria);
 165  
         }
 166  0
     }
 167  
 
 168  
     /**
 169  
      * Applies the search results limit to the search criteria for this BO (JPA)
 170  
      *
 171  
      * @param businessObjectClass BO class to search on / get limit for
 172  
      * @param criteria search criteria
 173  
      */
 174  
     public static void applySearchResultsLimit(Class businessObjectClass,
 175  
             org.kuali.rice.core.framework.persistence.jpa.criteria.Criteria criteria) {
 176  0
         Integer limit = getSearchResultsLimit(businessObjectClass);
 177  0
         if (limit != null) {
 178  0
             criteria.setSearchLimit(limit);
 179  
         }
 180  0
     }
 181  
 
 182  
     /**
 183  
      * Determines what Timestamp should be used for active queries on effective dated records. Determination made as
 184  
      * follows:
 185  
      *
 186  
      * <ul>
 187  
      * <li>Use activeAsOfDate value from search values Map if value is not empty</li>
 188  
      * <li>If search value given, try to convert to sql date, if conversion fails, try to convert to Timestamp</li>
 189  
      * <li>If search value empty, use current Date</li>
 190  
      * <li>If Timestamp value not given, create Timestamp from given Date setting the time as 1 second before midnight
 191  
      * </ul>
 192  
      *
 193  
      * @param searchValues - Map containing search key/value pairs
 194  
      * @return Timestamp to be used for active criteria
 195  
      */
 196  
     public static Timestamp getActiveDateTimestampForCriteria(Map searchValues) {
 197  0
         Date activeDate = CoreApiServiceLocator.getDateTimeService().getCurrentSqlDate();
 198  0
         Timestamp activeTimestamp = null;
 199  0
         if (searchValues.containsKey(KRADPropertyConstants.ACTIVE_AS_OF_DATE)) {
 200  0
             String activeAsOfDate = (String) searchValues.get(KRADPropertyConstants.ACTIVE_AS_OF_DATE);
 201  0
             if (StringUtils.isNotBlank(activeAsOfDate)) {
 202  
                 try {
 203  0
                     activeDate = CoreApiServiceLocator.getDateTimeService()
 204  
                             .convertToSqlDate(ObjectUtils.clean(activeAsOfDate));
 205  0
                 } catch (ParseException e) {
 206  
                     // try to parse as timestamp
 207  
                     try {
 208  0
                         activeTimestamp = CoreApiServiceLocator.getDateTimeService()
 209  
                                 .convertToSqlTimestamp(ObjectUtils.clean(activeAsOfDate));
 210  0
                     } catch (ParseException e1) {
 211  0
                         throw new RuntimeException("Unable to convert date: " + ObjectUtils.clean(activeAsOfDate));
 212  0
                     }
 213  0
                 }
 214  
             }
 215  
         }
 216  
 
 217  
         // if timestamp not given set to 1 second before midnight on the given date
 218  0
         if (activeTimestamp == null) {
 219  0
             Calendar cal = Calendar.getInstance();
 220  0
             cal.setTime(activeDate);
 221  0
             cal.set(Calendar.HOUR, cal.getMaximum(Calendar.HOUR));
 222  0
             cal.set(Calendar.MINUTE, cal.getMaximum(Calendar.MINUTE));
 223  0
             cal.set(Calendar.SECOND, cal.getMaximum(Calendar.SECOND));
 224  
 
 225  0
             activeTimestamp = new Timestamp(cal.getTime().getTime());
 226  
         }
 227  
 
 228  0
         return activeTimestamp;
 229  
     }
 230  
 
 231  
     /**
 232  
      * Changes from/to dates into the range operators the lookupable dao expects ("..",">" etc) this method modifies
 233  
      * the
 234  
      * passed in map and returns a list containing only the modified fields
 235  
      *
 236  
      * @param searchCriteria - map of criteria currently set for which the date criteria will be adjusted
 237  
      */
 238  
     public static Map<String, String> preprocessDateFields(Map<String, String> searchCriteria) {
 239  0
         Map<String, String> fieldsToUpdate = new HashMap<String, String>();
 240  0
         Set<String> fieldsForLookup = searchCriteria.keySet();
 241  0
         for (String propName : fieldsForLookup) {
 242  0
             if (propName.startsWith(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX)) {
 243  0
                 String from_DateValue = searchCriteria.get(propName);
 244  0
                 String dateFieldName =
 245  
                         StringUtils.remove(propName, KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX);
 246  0
                 String to_DateValue = searchCriteria.get(dateFieldName);
 247  0
                 String newPropValue = to_DateValue;// maybe clean above with
 248  
                 // ObjectUtils.clean(propertyValue)
 249  0
                 if (StringUtils.isNotEmpty(from_DateValue) && StringUtils.isNotEmpty(to_DateValue)) {
 250  0
                     newPropValue = from_DateValue + SearchOperator.BETWEEN + to_DateValue;
 251  0
                 } else if (StringUtils.isNotEmpty(from_DateValue) && StringUtils.isEmpty(to_DateValue)) {
 252  0
                     newPropValue = SearchOperator.GREATER_THAN_EQUAL.op() + from_DateValue;
 253  0
                 } else if (StringUtils.isNotEmpty(to_DateValue) && StringUtils.isEmpty(from_DateValue)) {
 254  0
                     newPropValue = SearchOperator.LESS_THAN_EQUAL.op() + to_DateValue;
 255  
                 } // could optionally continue on else here
 256  
 
 257  0
                 fieldsToUpdate.put(dateFieldName, newPropValue);
 258  0
             }
 259  
         }
 260  
 
 261  
         // update lookup values from found date values to update
 262  0
         Set<String> keysToUpdate = fieldsToUpdate.keySet();
 263  0
         for (String updateKey : keysToUpdate) {
 264  0
             searchCriteria.put(updateKey, fieldsToUpdate.get(updateKey));
 265  
         }
 266  
 
 267  0
         return fieldsToUpdate;
 268  
     }
 269  
 
 270  
     /**
 271  
      * Checks whether any of the fieldValues being passed refer to a property within an ExternalizableBusinessObject.
 272  
      */
 273  
     public static boolean hasExternalBusinessObjectProperty(Class<?> boClass,
 274  
             Map<String, String> fieldValues) throws IllegalAccessException, InstantiationException {
 275  0
         Object sampleBo = boClass.newInstance();
 276  0
         for (String key : fieldValues.keySet()) {
 277  0
             if (isExternalBusinessObjectProperty(sampleBo, key)) {
 278  0
                 return true;
 279  
             }
 280  
         }
 281  
 
 282  0
         return false;
 283  
     }
 284  
 
 285  
     /**
 286  
      * Check whether the given property represents a property within an EBO starting with the sampleBo object given.
 287  
      * This is used to determine if a criteria needs to be applied to the EBO first,
 288  
      * before sending to the normal lookup DAO.
 289  
      */
 290  
     public static boolean isExternalBusinessObjectProperty(Object sampleBo, String propertyName) {
 291  0
         if (propertyName.indexOf(".") > 0 && !StringUtils.contains(propertyName, "add.")) {
 292  0
             Class<?> propertyClass =
 293  
                     ObjectPropertyUtils.getPropertyType(sampleBo, StringUtils.substringBeforeLast(propertyName, "."));
 294  0
             if (propertyClass != null) {
 295  0
                 return ExternalizableBusinessObjectUtils.isExternalizableBusinessObjectInterface(propertyClass);
 296  
             }
 297  
         }
 298  
 
 299  0
         return false;
 300  
     }
 301  
 
 302  
     /**
 303  
      * Returns a map stripped of any properties which refer to ExternalizableBusinessObjects. These values may not be
 304  
      * passed into the lookup service, since the objects they refer to are not in the
 305  
      * local database.
 306  
      */
 307  
     public static Map<String, String> removeExternalizableBusinessObjectFieldValues(Class<?> boClass,
 308  
             Map<String, String> fieldValues) throws IllegalAccessException, InstantiationException {
 309  0
         Map<String, String> eboFieldValues = new HashMap<String, String>();
 310  0
         Object sampleBo = boClass.newInstance();
 311  0
         for (String key : fieldValues.keySet()) {
 312  0
             if (!isExternalBusinessObjectProperty(sampleBo, key)) {
 313  0
                 eboFieldValues.put(key, fieldValues.get(key));
 314  
             }
 315  
         }
 316  
 
 317  0
         return eboFieldValues;
 318  
     }
 319  
 
 320  
     /**
 321  
      * Return the EBO fieldValue entries explicitly for the given eboPropertyName. (I.e., any properties with the given
 322  
      * property name as a prefix.
 323  
      */
 324  
     public static Map<String, String> getExternalizableBusinessObjectFieldValues(String eboPropertyName,
 325  
             Map<String, String> fieldValues) {
 326  0
         Map<String, String> eboFieldValues = new HashMap<String, String>();
 327  0
         for (String key : fieldValues.keySet()) {
 328  0
             if (key.startsWith(eboPropertyName + ".")) {
 329  0
                 eboFieldValues.put(StringUtils.substringAfterLast(key, "."), fieldValues.get(key));
 330  
             }
 331  
         }
 332  
 
 333  0
         return eboFieldValues;
 334  
     }
 335  
 
 336  
     /**
 337  
      * Get the complete list of all properties referenced in the fieldValues that are ExternalizableBusinessObjects.
 338  
      *
 339  
      * This is a list of the EBO object references themselves, not of the properties within them.
 340  
      */
 341  
     public static List<String> getExternalizableBusinessObjectProperties(Class<?> boClass,
 342  
             Map<String, String> fieldValues) throws IllegalAccessException, InstantiationException {
 343  0
         Set<String> eboPropertyNames = new HashSet<String>();
 344  
 
 345  0
         Object sampleBo = boClass.newInstance();
 346  0
         for (String key : fieldValues.keySet()) {
 347  0
             if (isExternalBusinessObjectProperty(sampleBo, key)) {
 348  0
                 eboPropertyNames.add(StringUtils.substringBeforeLast(key, "."));
 349  
             }
 350  
         }
 351  
 
 352  0
         return new ArrayList<String>(eboPropertyNames);
 353  
     }
 354  
 
 355  
     /**
 356  
      * Given an property on the main BO class, return the defined type of the ExternalizableBusinessObject. This will
 357  
      * be used by other code to determine the correct module service to call for the lookup.
 358  
      *
 359  
      * @param boClass
 360  
      * @param propertyName
 361  
      * @return
 362  
      */
 363  
     public static Class<? extends ExternalizableBusinessObject> getExternalizableBusinessObjectClass(Class<?> boClass,
 364  
             String propertyName) throws IllegalAccessException, InstantiationException {
 365  0
         return (Class<? extends ExternalizableBusinessObject>) ObjectPropertyUtils
 366  
                 .getPropertyType(boClass.newInstance(), StringUtils.substringBeforeLast(propertyName, "."));
 367  
     }
 368  
 
 369  
 }