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