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
29
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
45
46
47
48
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
89
90
91
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
105
106
107
108
109
110
111
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
126
127
128
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 }