1 package org.kuali.student.common.assembly.transform;
2
3 import java.beans.BeanInfo;
4 import java.beans.Introspector;
5 import java.beans.PropertyDescriptor;
6 import java.lang.reflect.Field;
7 import java.lang.reflect.ParameterizedType;
8 import java.lang.reflect.Type;
9 import java.sql.Time;
10 import java.sql.Timestamp;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Date;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Set;
21
22 import org.apache.log4j.Logger;
23 import org.kuali.student.common.assembly.data.Data;
24 import org.kuali.student.common.assembly.data.Data.DataType;
25 import org.kuali.student.common.assembly.data.Data.DataValue;
26 import org.kuali.student.common.assembly.data.Data.Key;
27 import org.kuali.student.common.assembly.data.Data.Property;
28 import org.kuali.student.common.assembly.data.Data.StringKey;
29 import org.kuali.student.common.assembly.data.Metadata;
30
31
32 public class DefaultDataBeanMapper implements DataBeanMapper {
33 public static DataBeanMapper INSTANCE = new DefaultDataBeanMapper();
34 final Logger LOG = Logger.getLogger(DefaultDataBeanMapper.class);
35
36
37
38
39 public Data convertFromBean(Object value, Metadata metadata) throws Exception{
40 Data result = new Data();
41
42 if (value != null) {
43 BeanInfo info = Introspector.getBeanInfo(value.getClass());
44 PropertyDescriptor[] properties = info.getPropertyDescriptors();
45
46 for (PropertyDescriptor pd : properties) {
47 String propKey = pd.getName();
48 Object propValue = pd.getReadMethod().invoke(value, (Object[]) null);
49
50 if ("attributes".equals(propKey)){
51 setDataAttributes(result, propValue, metadata);
52 } else {
53 setDataValue(result, propKey, propValue, metadata);
54 }
55 }
56 }
57
58 return result;
59 }
60
61
62
63
64
65
66 public Object convertFromData(Data data, Class<?> clazz, Metadata metadata) throws Exception{
67 Object result = null;
68
69 result = clazz.newInstance();
70 BeanInfo info = Introspector.getBeanInfo(result.getClass());
71 PropertyDescriptor[] properties = info.getPropertyDescriptors();
72
73 PropertyDescriptor attrProperty = null;
74
75 Set<Key> staticProperties = new HashSet<Key>();
76 for (PropertyDescriptor pd : properties) {
77 if ("attributes".equals(pd.getName())){
78
79 attrProperty = pd;
80 } else {
81 StringKey propKey = new StringKey(pd.getName());
82 Object propValue = data.get(propKey);
83
84
85 if (propValue instanceof Data){
86 clazz.getFields();
87 if(metadata!=null){
88 if(DataType.LIST.equals(metadata.getDataType())){
89 propValue = convertNestedData((Data)propValue, clazz.getDeclaredField(propKey.toString()),metadata.getProperties().get("*"));
90 }else{
91 propValue = convertNestedData((Data)propValue, clazz.getDeclaredField(propKey.toString()),metadata.getProperties().get(propKey.toString()));
92 }
93 }
94 else{
95 propValue = convertNestedData((Data)propValue, clazz.getDeclaredField(propKey.toString()),null);
96 }
97 }else if(metadata!=null&&propValue==null){
98 Metadata fieldMetadata = metadata.getProperties().get(propKey.toString());
99 if(fieldMetadata != null && fieldMetadata.getDefaultValue() != null){
100 propValue = fieldMetadata.getDefaultValue().get();
101 }
102 }
103
104
105 if(pd.getWriteMethod() != null & propValue != null){
106 if(!(propValue instanceof List) && pd.getPropertyType().isAssignableFrom(List.class)){
107 ArrayList<Object> list = new ArrayList<Object>(1);
108 list.add(propValue);
109 pd.getWriteMethod().invoke(result, list);
110 }else{
111 pd.getWriteMethod().invoke(result, new Object[] {propValue});
112 }
113 }
114
115
116 staticProperties.add(propKey);
117 }
118 }
119
120
121
122 Set<Key> keySet = data.keySet();
123 if (keySet != null && attrProperty != null){
124 Map<String,String> attributes = new HashMap<String,String>();
125 for (Key k : keySet) {
126 String keyString = k.toString();
127
128 if(metadata==null){
129 if (!staticProperties.contains(k) && data.get(k) != null && !keyString.startsWith("_run")){
130 attributes.put((String)k.get(),data.get(k).toString());
131 }
132 }
133 else {
134 if ((! staticProperties.contains(k)) &&
135 (null != data.get(k)) &&
136 (! keyString.startsWith("_run")) &&
137 (null != metadata.getProperties().get(keyString)) &&
138 (metadata.getProperties().get(keyString).isDynamic()))
139 {
140 if (data.get(k) instanceof Data){
141 attributes.put((String) k.get(), convertDataValueToStringValue((Data)data.get(k)));
142 } else {
143 attributes.put((String) k.get(), data.get(k).toString());
144 }
145 }
146 }
147 }
148 if (attrProperty.getWriteMethod() != null) {
149 attrProperty.getWriteMethod().invoke(result, new Object[] {attributes});
150 }
151 }
152
153 return result;
154 }
155
156
157
158
159
160
161
162
163
164
165
166 protected Object convertNestedData(Data data, Field propField, Metadata metadata) throws Exception{
167 Object result = null;
168
169 Class<?> propClass = propField.getType();
170 if ("java.util.List".equals(propClass.getName())){
171
172 ParameterizedType propType = (ParameterizedType)propField.getGenericType();
173 Type itemType = propType.getActualTypeArguments()[0];
174
175
176 List<Object> resultList = new ArrayList<Object>();
177 for(Iterator<Property> listIter = data.realPropertyIterator(); listIter.hasNext();){
178 Property listItem = listIter.next();
179 Object listItemValue = listItem.getValue();
180 if (listItemValue instanceof Data ){
181 Data listItemData = (Data)listItemValue;
182 Boolean isDeleted = listItemData.query("_runtimeData/deleted");
183 if (isDeleted == null || !isDeleted){
184 if(metadata!=null){
185 listItemValue = convertFromData((Data)listItemValue, (Class<?>)itemType, metadata.getProperties().get("*"));
186 }else{
187 listItemValue = convertFromData((Data)listItemValue, (Class<?>)itemType, null);
188 }
189 resultList.add(listItemValue);
190 }
191 } else {
192 resultList.add(listItemValue);
193 }
194 }
195
196 result = resultList;
197 } else {
198 result = convertFromData(data, propClass,metadata);
199 }
200
201 return result;
202 }
203
204
205
206
207
208
209
210
211 protected void setDataValue(Data data, String propertyKey, Object value, Metadata metadata) throws Exception{
212 if (isPropertyValid(value)){
213 if (value instanceof Boolean){
214 data.set(propertyKey, (Boolean)value);
215 } else if (value instanceof Date){
216 data.set(propertyKey, (Date)value);
217 } else if (value instanceof Integer){
218 data.set(propertyKey, (Integer)value);
219 } else if (value instanceof Double){
220 data.set(propertyKey, (Double)value);
221 } else if (value instanceof Float){
222 data.set(propertyKey, (Float)value);
223 } else if (value instanceof Long) {
224 data.set(propertyKey, (Long)value);
225 } else if (value instanceof Short){
226 data.set(propertyKey, (Short)value);
227 } else if (value instanceof String){
228 data.set(propertyKey, (String)value);
229 } else if (value instanceof Timestamp){
230 data.set(propertyKey, (Timestamp)value);
231 } else if (value instanceof Time){
232 data.set(propertyKey, (Time)value);
233 } else if (value instanceof Collection){
234
235 data.set(propertyKey, getCollectionData(value, null));
236 } else {
237
238 Data dataValue = convertFromBean(value, null);
239 data.set(propertyKey, dataValue);
240 }
241 }
242
243 }
244
245
246
247
248
249
250
251 protected void setDataAttributes(Data data, Object value, Metadata metadata) {
252 @SuppressWarnings("unchecked")
253 Map<String, String> attributes = (Map<String, String>)value;
254
255 for (Entry<String, String> entry:attributes.entrySet()){
256 Metadata fieldMetadata = null;
257 if (metadata != null) {
258 fieldMetadata = metadata.getProperties().get(entry.getKey());
259 } else {
260
261 LOG.warn("Metadata was null while processing property " + entry.getKey());
262 }
263 if (fieldMetadata != null && DataType.LIST.equals(fieldMetadata.getDataType())){
264 data.set(entry.getKey(), convertStringToDataValue(entry.getValue()));
265 } else if ("false".equals(entry.getValue())||"true".equals(entry.getValue())){
266 data.set(entry.getKey(), Boolean.valueOf(entry.getValue()));
267 }else{
268 data.set(entry.getKey(), entry.getValue());
269 }
270 }
271 }
272
273
274
275
276
277
278
279 protected Data convertStringToDataValue(String stringValue) {
280 Data data = null;
281
282 if (stringValue != null){
283 data = new Data();
284 String[] stringValues = stringValue.split(",");
285 for (String value:stringValues){
286 data.add(value);
287 }
288 }
289
290 return data;
291 }
292
293
294
295
296
297
298
299 protected String convertDataValueToStringValue(Data data) {
300 StringBuffer sbValue = new StringBuffer();
301
302 Iterator<Property> propertyIterator = data.realPropertyIterator();
303 while(propertyIterator.hasNext()){
304 Property property = propertyIterator.next();
305 String propertyValue = property.getValue();
306 sbValue.append(",");
307 sbValue.append(propertyValue);
308 }
309
310 if (sbValue.toString().isEmpty()){
311 return "";
312 } else {
313 return sbValue.toString().substring(1);
314 }
315 }
316
317
318
319
320
321
322
323 protected void setDataListValue(Data data, Object value, Metadata metadata) throws Exception{
324 if (isPropertyValid(value)){
325 if (value instanceof Boolean){
326 data.add((Boolean)value);
327 } else if (value instanceof Date){
328 data.add((Date)value);
329 } else if (value instanceof Integer){
330 data.add((Integer)value);
331 } else if (value instanceof Double){
332 data.add((Double)value);
333 } else if (value instanceof Float){
334 data.add((Float)value);
335 } else if (value instanceof Long) {
336 data.add((Long)value);
337 } else if (value instanceof Short){
338 data.add((Short)value);
339 } else if (value instanceof String){
340 data.add((String)value);
341 } else if (value instanceof Timestamp){
342 data.add((Timestamp)value);
343 } else if (value instanceof Time){
344 data.add((Time)value);
345 } else if (value instanceof Collection){
346
347 data.add(getCollectionData(value, null));
348 } else {
349
350 Data dataValue = convertFromBean(value, null);
351 data.add(dataValue);
352 }
353 }
354 }
355
356
357
358
359
360
361
362
363 protected Data getCollectionData(Object value, Metadata metadata) throws Exception{
364 Data result = new Data();
365
366 if (value instanceof List){
367 List<?> valueList = (List<?>)value;
368 for (int i=0;i<valueList.size();i++){
369 Object itemValue = valueList.get(i);
370 setDataListValue(result, itemValue, metadata);
371 }
372 } else {
373 Collection<?> valueCollection = (Collection<?>)value;
374 for (Object o:valueCollection){
375 setDataListValue(result, o, metadata);
376 }
377 }
378
379 return result;
380 }
381
382 protected boolean isPropertyValid(Object value){
383 boolean isValid = false;
384
385 if (value != null){
386 Class<?> clazz = value.getClass();
387 isValid = !(clazz.isArray() || clazz.isAnnotation() || value instanceof Class);
388 }
389
390 return isValid;
391 }
392 }