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