gt:         catch (Exception e) {
context: /*
   * The Kuali Financial System, a comprehensive financial management system for higher education.
   * 
   * Copyright 2005-2014 The Kuali Foundation
   * 
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Affero General Public License as
   * published by the Free Software Foundation, either version 3 of the
   * License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Affero General Public License for more details.
   * 
   * You should have received a copy of the GNU Affero General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  package org.kuali.kfs.sys;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Properties;
  
  import org.apache.commons.beanutils.PropertyUtils;
  import org.apache.commons.lang.StringUtils;
  import org.kuali.kfs.sys.context.SpringContext;
  import org.kuali.rice.krad.bo.PersistableBusinessObject;
  import org.kuali.rice.krad.service.BusinessObjectService;
  import org.kuali.rice.krad.service.PersistenceService;
  import org.springframework.core.io.ClassPathResource;
  
  /**
   * provide with a set of utilities that can be used to prepare test data for unit testing. The core idea is to convert Java
   * properties into a list of specified business objects or search criteria.
   */
  public class TestDataPreparator {
      public static final String DEFAULT_FIELD_NAMES = "fieldNames";
      public static final String DEFAULT_DELIMINATOR = "deliminator";
  
      /**
       * load properties from the given class path resource. The class path is different than the absolute path. If a resource is
       * located at /project/test/org/kuali/kfs/util/message.properties, then its class path is org/kuali/kfs/util/message.properties,
       * which is the fully-qualified Java package name plus the resource name.
       * 
       * @param classPath the given class path of a resource
       * @return properties loaded from the given resource.
       */
      public static Properties loadPropertiesFromClassPath(String classPath) {
          Properties properties = new Properties();
          try {
              properties.load(TestDataPreparator.class.getClassLoader().getResourceAsStream(classPath));
          }
          catch (IOException e) {
              throw new RuntimeException("Invalid class path: " + classPath + e);
          }
  
          return properties;
      }
  
      /**
       * build a list of objects of type "clazz" from the test data provided by the given properties. The default fieldNames and
       * deliminator are used.
       * 
       * @param clazz the the specified object type
       * @param properties the given properties that contain the test data
       * @param propertyKeyPrefix the test data with the given key prefix can be used to construct the return objects
       * @param numberOfData the number of test data matching the search criteria
       * @return a list of objects of type "clazz" from the test data provided by the given properties
       */
      public static <T> List<T> buildTestDataList(Class<? extends T> clazz, Properties properties, String propertyKeyPrefix, int numberOfData) {
          String fieldNames = properties.getProperty(DEFAULT_FIELD_NAMES);
          String deliminator = properties.getProperty(DEFAULT_DELIMINATOR);
          return buildTestDataList(clazz, properties, propertyKeyPrefix, fieldNames, deliminator, numberOfData);
      }
  
      /**
       * build a list of objects of type "clazz" from the test data provided by the given properties
       * 
       * @param clazz the the specified object type
       * @param properties the given properties that contain the test data
       * @param propertyKeyPrefix the test data with the given key prefix can be used to construct the return objects
       * @param fieldNames the field names of the test data columns
       * @param deliminator the deliminator that is used to separate the field from each other
       * @param numberOfData the number of test data matching the search criteria
       * @return a list of objects of type "clazz" from the test data provided by the given properties
       */
      public static <T> List<T> buildTestDataList(Class<? extends T> clazz, Properties properties, String propertyKeyPrefix, String fieldNames, String deliminator, int numberOfData) {
          List<T> testDataList = new ArrayList<T>();
          for (int i = 1; i <= numberOfData; i++) {
              String propertyKey = propertyKeyPrefix + i;
              T testData = buildTestDataObject(clazz, properties, propertyKey, fieldNames, deliminator);
              testDataList.add(testData);
          }
          return testDataList;
      }
  
      /**
       * build an object of type "clazz" from the test data provided by the given properties
       * 
       * @param clazz the the specified object type
       * @param properties the given properties that contain the test data
       * @param propertyKey the test data with the given key
       * @param fieldNames the field names of the test data columns
       * @param deliminator the deliminator that is used to separate the field from each other
       * @return an object of type "clazz" from the test data provided by the given properties
       */
      public static <T> T buildTestDataObject(Class<? extends T> clazz, Properties properties, String propertyKey, String fieldNames, String deliminator) {
          T testData = null;
          try {
              testData = clazz.newInstance();
              ObjectUtil.populateBusinessObject(testData, properties, propertyKey, fieldNames, deliminator);
          }
          catch (Exception e) {
              e.printStackTrace();
          }
  
          return testData;
      }
  
      /**
       * build an object of type "clazz" from the test data provided by the given properties
       * 
       * @param clazz the the specified object type
       * @param properties the given properties that contain the test data
       * @param propertyKey the test data with the given key
       * @return an object of type "clazz" from the test data provided by the given properties
       */
      public static <T> T buildTestDataObject(Class<? extends T> clazz, Properties properties, String propertyKey) {
          String fieldNames = properties.getProperty(DEFAULT_FIELD_NAMES);
          String deliminator = properties.getProperty(DEFAULT_DELIMINATOR);
  
          T testData = null;
          try {
              testData = clazz.newInstance();
              ObjectUtil.populateBusinessObject(testData, properties, propertyKey, fieldNames, deliminator);
          }
          catch (Exception e) {
              e.printStackTrace();
          }
  
          return testData;
      }
  
      /**
       * build a list of objects of type "clazz" from the expected results provided by the given properties. The default fieldNames
       * and deliminator are used.
       * 
       * @param clazz the the specified object type. The instance of this type should be comparable through overriding Object.equals()
       * @param properties the given properties that contain the expected results
       * @param propertyKeyPrefix the expected results with the given key prefix can be used to construct the return objects
       * @param numberOfData the number of the expected results matching the search criteria
       * @return a list of objects of type "clazz" from the expected results provided by the given properties
       */
      public static <T> List<T> buildExpectedValueList(Class<? extends T> clazz, Properties properties, String propertyKeyPrefix, int numberOfData) {
          String fieldNames = properties.getProperty(DEFAULT_FIELD_NAMES);
          String deliminator = properties.getProperty(DEFAULT_DELIMINATOR);
          return buildExpectedValueList(clazz, properties, propertyKeyPrefix, fieldNames, deliminator, numberOfData);
      }
  
      /**
       * build a list of objects of type "clazz" from the expected results provided by the given properties
       * 
       * @param clazz the the specified object type. The instance of this type should be comparable through overriding Object.equals()
       * @param properties the given properties that contain the expected results
       * @param propertyKeyPrefix the expected results with the given key prefix can be used to construct the return objects
       * @param fieldNames the field names of the expected results columns
       * @param deliminator the deliminator that is used to separate the field from each other
       * @param numberOfData the number of the expected results matching the search criteria
       * @return a list of objects of type "clazz" from the expected results provided by the given properties
       */
      public static <T> List<T> buildExpectedValueList(Class<? extends T> clazz, Properties properties, String propertyKeyPrefix, String fieldNames, String deliminator, int numberOfData) {
          List<T> expectedDataList = new ArrayList<T>();
          for (int i = 1; i <= numberOfData; i++) {
              String propertyKey = propertyKeyPrefix + i;
              try {
                  T expectedData = TestDataPreparator.buildTestDataObject(clazz, properties, propertyKey, fieldNames, deliminator);
  
                  if (!expectedDataList.contains(expectedData)) {
                      expectedDataList.add(expectedData);
                  }
              }
              catch (Exception e) {
                  e.printStackTrace();
              }
          }
          return expectedDataList;
      }
  
      /**
       * build the cleanup criteria for "clazz" from the given properties. The default fieldNames and deliminator are used.
       * 
       * @param clazz the the specified object type.
       * @param properties the given properties that contain the cleanup criteria fields and values
       * @param propertyKey the given property whose value provides the cleanup criteria values
       * @return the cleanup criteria for "clazz" from the given properties
       */
      public static <T> Map<String, Object> buildCleanupCriteria(Class<? extends T> clazz, Properties properties, String propertyKey) {
          String fieldNames = properties.getProperty(DEFAULT_FIELD_NAMES);
          String deliminator = properties.getProperty(DEFAULT_DELIMINATOR);
          return buildCleanupCriteria(clazz, properties, propertyKey, fieldNames, deliminator);
      }
  
      /**
       * build the cleanup criteria for "clazz" from the given properties.
       * 
       * @param clazz the the specified object type.
       * @param properties the given properties that contain the cleanup criteria fields and values
       * @param propertyKey the given property whose value provides the cleanup criteria values
       * @param fieldNames the field names of the cleanup columns
       * @param deliminator the deliminator that is used to separate the field from each other
       * @return the cleanup criteria for "clazz" from the given properties
       */
      public static <T> Map<String, Object> buildCleanupCriteria(Class<? extends T> clazz, Properties properties, String propertyKey, String fieldNames, String deliminator) {
          T instanceOfClazz = TestDataPreparator.buildTestDataObject(clazz, properties, propertyKey, fieldNames, deliminator);
          return ObjectUtil.buildPropertyMap(instanceOfClazz, Arrays.asList(StringUtils.split(fieldNames, deliminator)));
      }
  
      /**
       * persist the given data object if it is not in the persistent store
       * 
       * @param dataObject the given data object
       * @return return the data object persisted into the data store
       */
      public static <T extends PersistableBusinessObject> T persistDataObject(T dataObject) {
          T existingDataObject = (T) getBusinessObjectService().retrieve(dataObject);
          if (existingDataObject == null) {
              getBusinessObjectService().save(dataObject);
              getPersistenceService().retrieveNonKeyFields(dataObject);
              return dataObject;
          }
          else {
              ObjectUtil.buildObject(existingDataObject, dataObject);
          }
  
          return existingDataObject;
      }
  
      /**
       * persist the given data object if it is not in the persistent store
       * 
       * @param dataObject the given data object
       * @return return the data object persisted into the data store
       */
      public static <T extends PersistableBusinessObject> void persistDataObject(List<T> dataObjects) {
          for (T dataObject : dataObjects) {
              persistDataObject(dataObject);
          }
      }
  
      /**
       * remove the existing data from the database so that they cannot affact the test results
       */
      public static <T extends PersistableBusinessObject> void doCleanUpWithoutReference(Class<T> clazz, Properties properties, String propertykey, String fieldNames, String deliminator) throws Exception {
          Map<String, Object> fieldValues = buildFieldValues(clazz, properties, propertykey, fieldNames, deliminator);
          getBusinessObjectService().deleteMatching(clazz, fieldValues);
      }
  
      /**
       * remove the existing data from the database so that they cannot affact the test results
       */
      public static <T extends PersistableBusinessObject> void doCleanUpWithReference(Class<T> clazz, Properties properties, String propertykey, String fieldNames, String deliminator) throws Exception {
          List<T> dataObjects = findMatching(clazz, properties, propertykey, fieldNames, deliminator);
  
          for (T object : dataObjects) {
              getBusinessObjectService().delete(object);
          }
      }
  
      /**
       * remove the existing data from the database so that they cannot affact the test results
       */
      public static <T extends PersistableBusinessObject> List<T> findMatching(Class<T> clazz, Properties properties, String propertykey, String fieldNames, String deliminator) throws Exception {
          Map<String, Object> fieldValues = buildFieldValues(clazz, properties, propertykey, fieldNames, deliminator);
          return (List<T>) getBusinessObjectService().findMatching(clazz, fieldValues);
      }
  
      /**
       * build the field name and value pairs from the given properties in the specified properties file
       */
      public static <T> Map<String, Object> buildFieldValues(Class<T> clazz, Properties properties, String propertykey, String fieldNames, String deliminator) throws Exception {
          T cleanup = clazz.newInstance();
          ObjectUtil.populateBusinessObject(cleanup, properties, propertykey, fieldNames, deliminator);
          return ObjectUtil.buildPropertyMap(cleanup, Arrays.asList(StringUtils.split(fieldNames, deliminator)));
      }
  
      /**
       * test if the given object is in the given collection. The given key fields can be used for the comparison.
       * 
       * @return true if the given object is in the given collection; otherwise, false
       */
      public static <T> boolean contains(List<T> collection, T object, List<String> keyFields) {
          for (T objectInCollection : collection) {
              boolean contains = ObjectUtil.equals(objectInCollection, object, keyFields);
  
              if (contains) {
                  return true;
              }
          }
  
          return false;
      }
  
      /**
       * test if the given two collections contain the exactly same elements. The given key fields can be used for the comparison.
       * 
       * @return true if the given two collections contain the exactly same elements; otherwise, false
       */
      public static <T> boolean hasSameElements(List<T> collection1, List<T> collection2, List<String> keyFields) {
          if (collection1 == collection2) {
              return true;
          }
  
          if (collection1 == null || collection2 == null) {
              return false;
          }
  
          if (collection1.size() != collection2.size()) {
              return false;
          }
  
          for (T object : collection2) {
              boolean contains = contains(collection1, object, keyFields);
              if (!contains) {
                  return false;
              }
          }
  
          return true;
      }
  
      /**
       * Generates transaction data for a business object from properties
       * 
       * @param businessObject the transction business object
       * @return the transction business object with data
       * @throws Exception thrown if an exception is encountered for any reason
       */
      public static <T> T buildTestDataObject(Class<? extends T> clazz, Properties properties) {
          T testData = null;
  
          try {
              testData = clazz.newInstance();
  
              Iterator propsIter = properties.keySet().iterator();
              while (propsIter.hasNext()) {
                  String propertyName = (String) propsIter.next();
                  String propertyValue = (String) properties.get(propertyName);
  
                  // if searchValue is empty and the key is not a valid property ignore
                  if (StringUtils.isBlank(propertyValue) || !(PropertyUtils.isWriteable(testData, propertyName))) {
                      continue;
                  }
  
                  String propertyType = PropertyUtils.getPropertyType(testData, propertyName).getSimpleName();
                  Object finalPropertyValue = ObjectUtil.valueOf(propertyType, propertyValue);
                  
                  if (finalPropertyValue != null) {
                      PropertyUtils.setProperty(testData, propertyName, finalPropertyValue);
                  }
              }
          }
  