View Javadoc

1   package org.sourceforge.jemm.client;
2   
3   import java.lang.reflect.Constructor;
4   import java.util.HashMap;
5   import java.util.Map;
6   import java.util.Map.Entry;
7   
8   import org.sourceforge.jemm.JEMMInternalException;
9   import org.sourceforge.jemm.database.ClassId;
10  import org.sourceforge.jemm.database.ClassInfo;
11  import org.sourceforge.jemm.database.ClientId;
12  import org.sourceforge.jemm.database.FieldInfo;
13  import org.sourceforge.jemm.database.FieldType;
14  import org.sourceforge.jemm.database.GetObjectResp;
15  import org.sourceforge.jemm.database.ObjectState;
16  import org.sourceforge.jemm.database.ObjectSyncData;
17  import org.sourceforge.jemm.database.ObjectSyncResp;
18  import org.sourceforge.jemm.lifecycle.MethodListener;
19  import org.sourceforge.jemm.lifecycle.ShadowTypeObject;
20  import org.sourceforge.jemm.lifecycle.ShadowTypeObjectImpl;
21  import org.sourceforge.jemm.lifecycle.ShadowUserObject;
22  import org.sourceforge.jemm.lifecycle.ShadowUserObjectImpl;
23  import org.sourceforge.jemm.types.ID;
24  import org.sourceforge.jemm.util.JEMMObject;
25  import org.sourceforge.jemm.util.JEMMType;
26  
27  /**
28   * A Factory that converts and sets fields onto 
29   * @author Paul Keeble
30   *
31   */
32  public class JEMMObjectFieldMapper {
33  	public static final ClientId DEFAULT_CLIENTID= new ClientId("CLIENT");
34  	
35  	MethodListener listener;
36  	TypeRequestHandler typeRequestHandler;
37  	
38  	public JEMMObjectFieldMapper(MethodListener listener,TypeRequestHandler typeRequestHandler) {
39  		this.listener = listener;
40  		this.typeRequestHandler = typeRequestHandler;
41  	}
42  	
43  	/**
44  	 * Creates a new JEMMObject from the response along with introduced Tracked IDs.
45  	 * 
46  	 * @param resp The object response
47  	 * @param ci The class information for the object to be created
48  	 * @return The newly created JEMMObject
49  	 */
50  	public JEMMObject create(GetObjectResp resp,ClassInfo ci) {
51  		if(ci.isType)
52  			return createTypeObject(resp,resp.getClassId(),ci);
53  		else
54  			return createUserObject(resp,ci);
55  	}
56  	
57  	private JEMMObject createTypeObject(GetObjectResp resp, ClassId classId,ClassInfo ci) {
58  		try {
59  			Class<?> clazz = Class.forName(ci.className);
60  			Constructor<?> constructor =clazz.getDeclaredConstructor(new Class[]{ShadowTypeObject.class});
61  			constructor.setAccessible(true);
62  			ShadowTypeObjectImpl so = new ShadowTypeObjectImpl(null,resp.jemmId,classId,typeRequestHandler);
63  			JEMMType obj = (JEMMType)constructor.newInstance(so);
64  			so.setObject(obj);
65  			mapFields(resp.fieldValues,obj);
66  			return obj;
67  		} catch (Exception e) {
68  			throw new JEMMInternalException("Unable to construct object of type " + ci.className,e);
69  		} 
70  	}
71  
72  	private JEMMObject createUserObject(GetObjectResp resp, ClassInfo ci) {
73  		try {
74  			Class<?> clazz = Class.forName(ci.className);
75  			Constructor<?> constructor =clazz.getDeclaredConstructor(new Class[]{ShadowUserObject.class});
76  			ShadowUserObjectImpl so = new ShadowUserObjectImpl(listener,resp.jemmId,resp.clientVersion);
77  			JEMMObject obj = (JEMMObject)constructor.newInstance(so);
78  			so.setUserObject(obj);
79  			
80  			mapFields(resp.fieldValues,obj);
81  			return obj;
82  		} catch (Exception e) {
83  			throw new JEMMInternalException("Unable to construct object",e);
84  		} 
85  	}
86  
87  	/**
88  	 * Gets the Synchronisation data from a JEMMObject.
89  	 * 
90  	 * @param jo
91  	 * @return
92  	 */
93  	public ObjectSyncData getSyncData(JEMMObject jo) {
94  		ObjectAccessor oa = new ObjectAccessor(jo,null);
95  		Entity e = new Entity(jo);
96  		
97  		Map<FieldInfo,Object> fields = oa.getAllFieldsMap();
98  		ObjectSyncData data = new ObjectSyncData(e.getID(),e.getVersion(),fields);
99  		
100 		return data;
101 	}
102 	
103 	/**
104 	 * Updates the object with new meta and FieldData from the response.
105 	 * 
106 	 * Updates all primitive values. Updates and uninitialised Object fields with
107 	 * the new ID.
108 	 * 
109 	 * Returns any 
110 	 * @param jo
111 	 * @param response
112 	 */
113 	public Map<FieldInfo,ID> syncResponseUpdateObject(JEMMObject jo,ObjectSyncResp response) {
114 		Entity e = new Entity(jo);
115 		e.setVersion(response.getNewVersionNo());
116 		try {
117 			mapFields(response.getUpdatedFields(),jo);
118 			return null;
119 		} catch (ClassNotFoundException e1) {
120 			throw new JEMMInternalException("Unable to update object",e1);
121 		}
122 	}
123 	
124 	/**
125 	 * Updates all the primitive values and uninitialised fields on a JEMMObject.
126 	 * 
127 	 * @param jo
128 	 * @param state
129 	 */
130 	public void refreshPrimitiveState(JEMMObject jo, ObjectState state) {
131 		Entity e = new Entity(jo);
132 		e.setVersion(state.clientVersion);
133 		try {
134 			Map<FieldInfo,Object> primitiveFields = getPrimitiveFields(state.fieldValues);
135 			mapFields(primitiveFields,jo);
136 			Map<FieldKey,ID> unitialisedObjectFields = new ObjectAccessor(jo,null).getUninitialisedObjectFields();
137 			
138 			Map<FieldInfo,Object> uninitFieldState = getUninitialisedFields(unitialisedObjectFields,state.fieldValues);
139 			mapFields(uninitFieldState,jo);
140 		} catch (ClassNotFoundException e1) {
141 			throw new JEMMInternalException("Unable to refresh object",e1);
142 		}
143 	}
144 	
145 	Map<FieldInfo,Object> getPrimitiveFields(Map<FieldInfo,Object> origFields)  {
146 		Map<FieldInfo, Object> result = new HashMap<FieldInfo, Object>();
147 		
148 		for(Entry<FieldInfo,Object> fInfo : origFields.entrySet()) {
149 			if(FieldType.isPrimitive(fInfo.getKey().fieldType)) {
150 				result.put(fInfo.getKey(), fInfo.getValue());
151 			}
152 		}
153 		
154 		return result;
155 	}
156 	
157 	Map<FieldInfo,Object> getUninitialisedFields(Map<FieldKey,ID> uninitialisedFields, Map<FieldInfo,Object> state) {
158 		Map<FieldInfo,Object> result = new HashMap<FieldInfo,Object>();
159 		
160 		for(FieldKey fKey : uninitialisedFields.keySet()) {
161 			FieldInfo fi = new FieldInfo(fKey.getName(),fKey.getClazz(),FieldType.OBJECT);
162 			if(!state.containsKey(fi))
163 				throw new JEMMInternalException("State missing field:" + fKey);
164 			result.put(fi, state.get(fi));
165 		}
166 		return result;
167 	}
168 	
169 	
170 	private void mapFields(Map<FieldInfo,Object> origFields, JEMMObject obj) throws ClassNotFoundException {
171 		ObjectAccessor oa = new ObjectAccessor(obj,null);
172 		
173 		for(Entry<FieldInfo,Object> fInfo : origFields.entrySet()) {
174 			FieldInfo key = fInfo.getKey();
175 			Object value = fInfo.getValue();
176 			Class<?> declaringClass = Class.forName(key.className);
177 			oa.setField(declaringClass, key.fieldName, value);
178 		}
179 	}
180 }