001    package com.khubla.pragmatach.plugin.mongodb.serializer;
002    
003    import java.lang.reflect.Field;
004    import java.lang.reflect.ParameterizedType;
005    import java.lang.reflect.Type;
006    import java.util.HashSet;
007    import java.util.Iterator;
008    import java.util.Set;
009    
010    import javax.persistence.Entity;
011    
012    import org.apache.commons.beanutils.PropertyUtils;
013    
014    import com.khubla.pragmatach.framework.api.PragmatachException;
015    import com.khubla.pragmatach.plugin.mongodb.MongoDBObjectPersister;
016    import com.khubla.pragmatach.plugin.mongodb.util.ClassTypeUtils;
017    import com.mongodb.BasicDBObject;
018    import com.mongodb.DBObject;
019    
020    /**
021     * @author tom
022     */
023    public class SetFieldSerializer implements FieldSerializer {
024       /**
025        * type utils
026        */
027       private final ClassTypeUtils classTypeUtils;
028       /**
029        * the type
030        */
031       private final Class<?> typeClazz;
032    
033       /**
034        * ctor
035        */
036       public SetFieldSerializer(Class<?> typeClazz) {
037          this.typeClazz = typeClazz;
038          classTypeUtils = new ClassTypeUtils(this.typeClazz);
039       }
040    
041       @SuppressWarnings({ "rawtypes", "unchecked" })
042       @Override
043       public void deserializeField(Object object, Field field, DBObject dbObject) throws PragmatachException {
044          try {
045             if (null != dbObject) {
046                /*
047                 * eager load?
048                 */
049                if (ClassTypeUtils.isEagerLoad(field)) {
050                   /*
051                    * create the set
052                    */
053                   final HashSet set = new HashSet();
054                   /*
055                    * get the contained type of the set
056                    */
057                   final Class<?> containedType = getContainedType(field);
058                   if (null != containedType.getAnnotation(Entity.class)) {
059                      /*
060                       * persister for the contained type
061                       */
062                      final MongoDBObjectPersister mongoDBObjectPersister = new MongoDBObjectPersister(containedType);
063                      /*
064                       * get the set
065                       */
066                      final DBObject setObject = (DBObject) dbObject.get(field.getName());
067                      if (null != setObject) {
068                         /*
069                          * walk the ids
070                          */
071                         int i = 0;
072                         String id = (String) setObject.get(Integer.toString(i));
073                         while (null != id) {
074                            /*
075                             * get the object for the id
076                             */
077                            final DBObject containedObjectJSON = mongoDBObjectPersister.find(id);
078                            /*
079                             * sanity check
080                             */
081                            if (null != containedObjectJSON) {
082                               final Object containedObject = mongoDBObjectPersister.load(containedObjectJSON);
083                               set.add(containedObject);
084                            }
085                            /*
086                             * next one
087                             */
088                            id = (String) setObject.get(Integer.toString(++i));
089                         }
090                      }
091                      /*
092                       * set the field
093                       */
094                      PropertyUtils.setProperty(object, field.getName(), set);
095                   } else {
096                      throw new Exception("Type '" + containedType.getName() + "' is not an @Entity");
097                   }
098                }
099             }
100          } catch (final Exception e) {
101             throw new PragmatachException("Exception in deserializeField", e);
102          }
103       }
104    
105       /**
106        * get the interior type of the set
107        */
108       private Class<?> getContainedType(Field field) throws PragmatachException {
109          final Type type = field.getGenericType();
110          final ParameterizedType parameterizedType = (ParameterizedType) type;
111          return (Class<?>) parameterizedType.getActualTypeArguments()[0];
112       }
113    
114       /**
115        * the strategy here is that we store the id's in the parent object, and then use DAOs to persist each contained object.
116        */
117       @Override
118       public void serializeField(BasicDBObject parentDBObject, Object object, Field field) throws PragmatachException {
119          try {
120             /*
121              * check if cascade
122              */
123             if (ClassTypeUtils.isCascadeSave(field)) {
124                /*
125                 * get the set
126                 */
127                final Set<?> set = (Set<?>) PropertyUtils.getProperty(object, field.getName());
128                if (null != set) {
129                   /*
130                    * get the contained type of the set
131                    */
132                   final Class<?> containedType = getContainedType(field);
133                   /*
134                    * the object for the set id's
135                    */
136                   final BasicDBObject dbObject = new BasicDBObject();
137                   /*
138                    * walk the set
139                    */
140                   int i = 0;
141                   final Iterator<?> iter = set.iterator();
142                   while (iter.hasNext()) {
143                      final Object o = iter.next();
144                      /*
145                       * save the object
146                       */
147                      final MongoDBObjectPersister mongoDBObjectPersister = new MongoDBObjectPersister(containedType);
148                      mongoDBObjectPersister.save(o);
149                      /*
150                       * store the id
151                       */
152                      final String id = classTypeUtils.getId(o);
153                      dbObject.append(Integer.toString(i++), id);
154                   }
155                   /*
156                    * add the id's to the parent
157                    */
158                   parentDBObject.append(field.getName(), dbObject);
159                }
160             }
161          } catch (final Exception e) {
162             throw new PragmatachException("Exception in serializeField", e);
163          }
164       }
165    }