001    package org.kuali.student.common.assembly.transform;
002    
003    import java.util.ArrayList;
004    import java.util.HashMap;
005    import java.util.List;
006    import java.util.Map;
007    
008    import org.apache.log4j.Logger;
009    import org.kuali.student.common.assembly.data.Data;
010    import org.kuali.student.common.assembly.data.Metadata;
011    import org.kuali.student.common.assembly.dictionary.MetadataServiceImpl;
012    import org.kuali.student.common.dto.DtoConstants;
013    
014    public class TransformationManager {
015            final Logger LOG = Logger.getLogger(TransformationManager.class);
016    
017            private MetadataServiceImpl metadataService;
018            private DataBeanMapper mapper = new DefaultDataBeanMapper();
019            private List<TransformFilter> filterList = new ArrayList<TransformFilter>();
020    
021        private static ThreadLocal<Metadata> metadataCache = new ThreadLocal<Metadata>();
022    
023            /**
024             * This is an outbound transform request which will convert incoming DTO objects
025             * to a Data map and apply outbound filter operation to both the data object
026             * and the converted DTO object.
027             *
028             * @param value
029             * @return
030             * @throws Exception
031             */
032            public Data transform(Object value) throws Exception{
033                    applyOutboundFilters(value.getClass().getName(), value, new HashMap<String,Object>());
034                    Data dataValue = mapper.convertFromBean(value);
035                    applyOutboundFilters(value.getClass().getName(), dataValue, new HashMap<String,Object>());
036    
037                    return dataValue;
038            }
039    
040            public Data transform(Object value, Map<String,Object> filterProperties) throws Exception{
041                    applyOutboundFilters(value.getClass().getName(), value, filterProperties);
042                    Data dataValue = mapper.convertFromBean(value);
043                    applyOutboundFilters(value.getClass().getName(), dataValue, filterProperties);
044    
045                    return dataValue;
046            }
047    
048    
049            /**
050             * This is an inbound transform request which will convert incoming Data objects
051             * to the corresponding DTO object and apply inbound filter operations to both the data object
052             * and the converted DTO object.
053             *
054             * @param value The incoming Data value to transform to DTO object
055             * @param clazz The DTO object class represented by the Data value
056             * @return The converted DTO with both inbound Data and DTO filters applied.
057             */
058            public Object transform(Data value, Class<?> clazz) throws Exception{
059                    Metadata metadata = null;
060                    metadata = (metadata != null ? metadata:getMetadata(clazz.getName(), new HashMap<String,Object>()));
061                    applyInboundFilters(clazz.getName(), value, new HashMap<String,Object>(),metadata);
062                    Object dtoValue = mapper.convertFromData(value, clazz,metadata);
063                    applyInboundFilters(clazz.getName(), dtoValue, new HashMap<String,Object>(),metadata);
064    
065                    return dtoValue;
066            }
067    
068            /**
069             * This is an inbound transform request which will convert incoming Data objects
070             * to the corresponding DTO object and apply inbound filters to both the data object
071             * and the converted DTO object.
072             *
073             * @param value The incoming Data value to transform to DTO object
074             * @param clazz The DTO object class represented by the Data value
075             * @param filterProperties properties that can be consumed by the filters
076             * @return The converted DTO with both inbound Data and DTO filters applied.
077             */
078            public Object transform(Data value, Class<?> clazz, Map<String,Object> filterProperties) throws Exception{
079                    Metadata metadata = null;
080                    metadata = (metadata != null ? metadata:getMetadata(clazz.getName(), filterProperties));
081            metadataCache.set(metadata);
082                    applyInboundFilters(clazz.getName(), value, filterProperties,metadata);
083                    Object dtoValue = mapper.convertFromData(value, clazz,metadata);
084                    applyInboundFilters(clazz.getName(), dtoValue, filterProperties,metadata);
085                    return dtoValue;
086            }
087    
088            /**
089             * This method applies all inbound filters known to his transformation manager.
090             *
091             * @param dtoName The name of the dto represented by a Data value, for Dto values,
092             *  this can simply be the name of the dto class
093             * @param value The dto or data object to apply filters to
094             * @throws Exception
095             */
096            public void applyInboundFilters(String dtoName, Object value, Map<String,Object> properties, Metadata metadata) throws Exception{
097                    for (TransformFilter filter:filterList){
098                            if (filter.getType().isInstance(value)){
099                                    if (filter instanceof AbstractDataFilter) {
100                                            ((AbstractDataFilter)filter).applyInboundDataFilter((Data)value, metadata, properties);
101                                    } else {
102                                            ((AbstractDTOFilter)filter).applyInboundDtoFilter(value, properties);
103                                    }
104                                    LOG.info(filter.getClass().getName() + ": Filter Applied");
105                            }
106                    }
107            }
108    
109            /**
110             * This method applies all outbound filters known to his transformation manager.
111             *
112             * @param dtoName The name of the dto represented by a Data value, for Dto values,
113             *  this can simply be the name of the dto class
114             * @param value The dto or data object to apply filters to
115             * @throws Exception
116             */
117            public void applyOutboundFilters(String dtoName, Object value, Map<String,Object> properties) throws Exception{
118                    Metadata metadata = metadataCache.get();
119    
120                    for (TransformFilter filter:filterList){
121                            if (filter.getType().isInstance(value)){
122                                    if (filter instanceof AbstractDataFilter) {
123                                            metadata = (metadata != null ? metadata:getMetadata(dtoName, properties));
124                                            ((AbstractDataFilter)filter).applyOutboundDataFilter((Data)value, metadata, properties);
125                                    } else {
126                                            ((AbstractDTOFilter)filter).applyOutboundDtoFilter(value, properties);
127                                    }
128                                    LOG.info(filter.getClass().getName() + ": Filter Applied");
129                            }
130                    }
131            }
132    
133            public Metadata getMetadata(String dtoName, Map<String,Object> filterProperties){
134                    String state = (String)filterProperties.get(DtoConstants.DTO_STATE);
135                    String nextState = (String)filterProperties.get(DtoConstants.DTO_NEXT_STATE);
136    
137                    Metadata metadata = metadataService.getMetadata(dtoName, null, state, nextState);
138    
139                    applyMetadataFilters(dtoName, metadata, filterProperties);
140                    return metadata;
141            }
142    
143            public void applyMetadataFilters(String dtoName, Metadata metadata, Map<String, Object> filterProperties){
144                    for (TransformFilter filter:filterList){
145                            if (filter instanceof MetadataFilter){
146                                    ((MetadataFilter) filter).applyMetadataFilter(dtoName, metadata, filterProperties);
147                            }
148                    }
149            }
150    
151            public Metadata getUnfilteredMetadata(String dtoName){
152                    Metadata metadata = metadataService.getMetadata(dtoName);
153                    return metadata;
154            }
155    
156            public void setMetadataService(MetadataServiceImpl metadataService) {
157                    this.metadataService = metadataService;
158            }
159    
160            public void addFilter(TransformFilter filter){
161                    filterList.add(filter);
162            }
163    
164            public void setFilters(List<TransformFilter> filters){
165                    filterList.addAll(filters);
166            }
167            
168            public void removeFilter(TransformFilter filter){
169                    filterList.remove(filter);
170            }
171    }