001 package org.kuali.student.r2.common.assembler; 002 003 import org.kuali.student.r2.common.dto.AttributeInfo; 004 import org.kuali.student.r2.common.entity.AttributeOwner; 005 import org.kuali.student.r2.common.entity.BaseAttributeEntity; 006 import org.kuali.student.r2.common.infc.Attribute; 007 import org.kuali.student.r2.common.infc.HasAttributes; 008 import org.kuali.student.r2.common.util.date.DateFormatters; 009 010 import java.text.ParseException; 011 import java.util.ArrayList; 012 import java.util.Date; 013 import java.util.HashMap; 014 import java.util.HashSet; 015 import java.util.List; 016 import java.util.Map; 017 import java.util.Set; 018 019 /** 020 * Utility class containing utility methods to aide in DTO & Entity transformations 021 */ 022 public class TransformUtility { 023 024 025 /** 026 * 027 * This merges DTO attributes into Entity attributes and returns the orphaned attributes to delete 028 * 029 * @param attributeClass The attribute entity class for the attributes on the entity owner 030 * @param dto The dto to copy attributes from 031 * @param owner The owner entity of the attributes. 032 * 033 * @return The orphaned attributes to delete. 034 */ 035 public static <A extends BaseAttributeEntity<O>, O extends AttributeOwner<A>> List<Object> 036 mergeToEntityAttributes(Class<A> attributeClass, HasAttributes dto, O owner) { 037 038 039 // Existing Attributes 040 Map<String, A> existingAttributes = new HashMap<String, A>(); 041 Map<String, Attribute> dtoAttributes = new HashMap<String, Attribute>(); 042 043 // Find all the old attributes and add to existing attributes map 044 if(owner.getAttributes()!=null){ 045 for (A attribute : owner.getAttributes()) { 046 existingAttributes.put(attribute.getKey(), attribute); 047 } 048 } 049 050 for (Attribute attribute : dto.getAttributes()) { 051 dtoAttributes.put(attribute.getKey(), attribute); 052 } 053 054 //Clear out the attributes 055 Set<A> attributes = new HashSet<A>(); 056 057 //Update anything that exists, or create a new attribute if it doesn't 058 for (Map.Entry<String, Attribute> entry : dtoAttributes.entrySet()) { 059 Attribute attributeInfo = entry.getValue(); 060 A attribute; 061 if (existingAttributes.containsKey(attributeInfo.getKey())) { 062 attribute = existingAttributes.remove(attributeInfo.getKey()); 063 }else{ 064 try{ 065 attribute = attributeClass.newInstance(); 066 }catch(Exception e){ 067 throw new RuntimeException("Error copying attributes.",e); 068 } 069 070 attribute.setOwner(owner); 071 attribute.setKey(attributeInfo.getKey()); 072 } 073 attribute.setValue(attributeInfo.getValue()); 074 attributes.add(attribute); 075 } 076 owner.setAttributes(attributes); 077 078 //Remove the orphaned attributes 079 List<Object> orphansToDelete = new ArrayList<Object>(); 080 orphansToDelete.addAll(existingAttributes.values()); 081 082 return orphansToDelete; 083 } 084 085 086 /** 087 * Converts attributes from an entity to list of AttributeInfo objects for a DTO 088 * 089 * @param owner The entity containing the attributes 090 * @return list of attributeInfo object 091 */ 092 public static <A extends BaseAttributeEntity<O>, O extends AttributeOwner<A>> List<AttributeInfo> toAttributeInfoList(AttributeOwner<A> owner){ 093 List<AttributeInfo> attributes = new ArrayList<AttributeInfo>(); 094 if (null != owner.getAttributes()){ 095 for (A attr : owner.getAttributes()) { 096 AttributeInfo attrInfo = attr.toDto(); 097 attributes.add(attrInfo); 098 } 099 } 100 101 return attributes; 102 } 103 // ====================================================================================================== 104 // Pick a format that is human readable. Year-month-day is kinda neutral way to represent a date 105 // so that it isn't the US month-day-year, nor other places day-month-year. The advantage of using this over 106 // a more agnostic UTC representation (i.e., milliseconds since Jan 1, 1970) is that 107 // Used in the two methods below for KSDateFormatter 108 public static final String DYNAMIC_ATTRIBUTE_DATE_FORMAT = "yyyy MMM d HH:mm:ss zzz"; 109 110 /** 111 * dateTime refers to a date where hours/minutes/seconds are important in addition to the month day year 112 * This is used to convert to and from a dynamic attribute which requires a string format. 113 * @param date A date object to convert 114 * @return The string version to save it as a dynamic attribute 115 */ 116 public static String dateTimeToDynamicAttributeString(Date date) { 117 if (date == null) { 118 return null; 119 } 120 121 String formattedDate = DateFormatters.DYNAMIC_ATTRIBUTE_DATE_FORMATTER.format(date); 122 return formattedDate; 123 } 124 125 /** 126 * Takes a dynamic attribute representing 127 * @param formattedDateStr 128 * @return 129 * @throws ParseException 130 */ 131 public static Date dynamicAttributeStringToDateTime(String formattedDateStr) throws ParseException { 132 if (formattedDateStr == null) { 133 return null; 134 } 135 136 Date date = DateFormatters.DYNAMIC_ATTRIBUTE_DATE_FORMATTER.parse(formattedDateStr); 137 return date; 138 } 139 // ------------------------ For Dynamic Attributes --------------------------------- 140 private static Map<Class, DynAttrConverter<? extends Object>> dynAttrConverterMap = 141 new HashMap<Class, DynAttrConverter<? extends Object>>(); 142 143 private static DynAttrConverter<Date> dateDynAttrConverter = null; 144 private static DynAttrConverter<Date> _getDateDynamicAttributeConverter() { 145 if (dateDynAttrConverter == null) { 146 dateDynAttrConverter = new DynAttrConverter<Date>() { 147 @Override 148 public String convertNativeValueToString(Date date) { 149 return dateTimeToDynamicAttributeString(date); 150 } 151 152 @Override 153 public Date convertStringValueToNative(String formattedDateStr) { 154 try { 155 return dynamicAttributeStringToDateTime(formattedDateStr); 156 } catch (Exception e) { 157 e.printStackTrace(); 158 return null; 159 } 160 } 161 }; 162 } 163 return dateDynAttrConverter; 164 } 165 166 private static DynAttrConverter<Integer> intDynAttrConverter = null; 167 private static DynAttrConverter<Integer> _getIntegerDynamicAttributeConverter() { 168 if (intDynAttrConverter == null) { 169 intDynAttrConverter = new DynAttrConverter<Integer>() { 170 @Override 171 public String convertNativeValueToString(Integer val) { 172 if (val == null) { 173 return null; 174 } 175 176 return val.toString(); 177 } 178 179 @Override 180 public Integer convertStringValueToNative(String intStr) { 181 if (intStr == null) { 182 return null; 183 } 184 try { 185 Integer intVal = Integer.parseInt(intStr); 186 return intVal; 187 } catch (Exception e) { 188 return null; 189 } 190 } 191 }; 192 } 193 return intDynAttrConverter; 194 } 195 static { 196 dynAttrConverterMap.put(Date.class, _getDateDynamicAttributeConverter()); 197 dynAttrConverterMap.put(Integer.class, _getIntegerDynamicAttributeConverter()); 198 } 199 200 public static DynAttrConverter<? extends Object> getConverterByClass(Class clazz) { 201 return dynAttrConverterMap.get(clazz); 202 } 203 } 204