1 package cz.cuni.amis.pogamut.ut2004.communication.messages.custom;
2
3 import java.lang.reflect.Field;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
11 import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
12 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.SendControlMessage;
13 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ControlMessage;
14 import cz.cuni.amis.utils.ClassUtils;
15 import cz.cuni.amis.utils.Tuple2;
16 import cz.cuni.amis.utils.Tuple3;
17
18
19
20
21
22
23
24
25
26
27 public class SendControlMessageMapper {
28
29 public static interface SendControlMessageSetter<T> {
30 public void set(SendControlMessage msg, T value);
31 }
32
33 @SuppressWarnings("unchecked")
34 public static final SendControlMessageSetter<Integer>[] setterIntegers =
35 new SendControlMessageSetter[] {
36
37 null,
38
39 new SendControlMessageSetter<Integer>() {
40 @Override
41 public void set(SendControlMessage msg, Integer value) {
42 msg.setPI1(value);
43 }
44 },
45
46 new SendControlMessageSetter<Integer>() {
47 @Override
48 public void set(SendControlMessage msg, Integer value) {
49 msg.setPI2(value);
50 }
51 },
52
53 new SendControlMessageSetter<Integer>() {
54 @Override
55 public void set(SendControlMessage msg, Integer value) {
56 msg.setPI3(value);
57 }
58 },
59 };
60
61 @SuppressWarnings("unchecked")
62 public static final SendControlMessageSetter<Double>[] setterDoubles =
63 new SendControlMessageSetter[] {
64
65 null,
66
67 new SendControlMessageSetter<Double>() {
68 @Override
69 public void set(SendControlMessage msg, Double value) {
70 msg.setPF1(value);
71 }
72 },
73
74 new SendControlMessageSetter<Double>() {
75 @Override
76 public void set(SendControlMessage msg, Double value) {
77 msg.setPF2(value);
78 }
79 },
80
81 new SendControlMessageSetter<Double>() {
82 @Override
83 public void set(SendControlMessage msg, Double value) {
84 msg.setPF3(value);
85 }
86 },
87 };
88
89 @SuppressWarnings("unchecked")
90 public static final SendControlMessageSetter<Double>[] setterStrings =
91 new SendControlMessageSetter[] {
92
93 null,
94
95 new SendControlMessageSetter<String>() {
96 @Override
97 public void set(SendControlMessage msg, String value) {
98 msg.setPS1(value);
99 }
100 },
101
102 new SendControlMessageSetter<String>() {
103 @Override
104 public void set(SendControlMessage msg, String value) {
105 msg.setPS2(value);
106 }
107 },
108
109 new SendControlMessageSetter<String>() {
110 @Override
111 public void set(SendControlMessage msg, String value) {
112 msg.setPS3(value);
113 }
114 },
115 };
116
117 @SuppressWarnings("unchecked")
118 public static final SendControlMessageSetter<Double>[] setterBooleans =
119 new SendControlMessageSetter[] {
120
121 null,
122
123 new SendControlMessageSetter<Boolean>() {
124 @Override
125 public void set(SendControlMessage msg, Boolean value) {
126 msg.setPB1(value);
127 }
128 },
129
130 new SendControlMessageSetter<Boolean>() {
131 @Override
132 public void set(SendControlMessage msg, Boolean value) {
133 msg.setPB2(value);
134 }
135 },
136
137 new SendControlMessageSetter<Boolean>() {
138 @Override
139 public void set(SendControlMessage msg, Boolean value) {
140 msg.setPB3(value);
141 }
142 },
143 };
144
145 private Class<? extends ICustomControlMessage> descriptor;
146
147 private String type;
148
149 private List<Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper>> fields = new ArrayList<Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper>>();
150
151 public SendControlMessageMapper(Class<? extends ICustomControlMessage> customControlMessageClass) {
152 Map<Integer, Field> integers = new HashMap<Integer, Field>();
153 Map<Integer, Field> doubles = new HashMap<Integer, Field>();
154 Map<Integer, Field> strings = new HashMap<Integer, Field>();
155 Map<Integer, Field> booleans = new HashMap<Integer, Field>();
156
157 this.descriptor = customControlMessageClass;
158
159 if (!customControlMessageClass.isAnnotationPresent(ControlMessageType.class)) {
160 throw new RuntimeException("Cannot create SendControlMessageSerializer for " + customControlMessageClass + " as it is not annotated with ControlMessageType!");
161 }
162 this.type = customControlMessageClass.getAnnotation(ControlMessageType.class).type();
163
164 Collection<Class> classes = ClassUtils.getSubclasses(customControlMessageClass);
165 for (Class cls : classes) {
166
167 if (cls.isAnnotation()) continue;
168 if (cls.isInterface()) continue;
169
170 for (Field field : cls.getDeclaredFields()) {
171
172 if (!field.isAnnotationPresent(ControlMessageField.class)) continue;
173
174 ControlMessageField info = field.getAnnotation(ControlMessageField.class);
175
176 if (info.index() < 0 || info.index() > 3) {
177 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " contains annotation ControlMessageParam(index=" + info.index() + "), unsupported. 1 <= index <= 3.");
178 }
179
180 Map<Integer, Field> map;
181
182 if (field.getType() == Integer.class) {
183 map = integers;
184 } else
185 if (field.getType() == Double.class) {
186 map = doubles;
187 } else
188 if (field.getType() == String.class) {
189 map = strings;
190 } else
191 if (field.getType() == Boolean.class) {
192 map = booleans;
193 } else
194 if (field.getType() == UnrealId.class) {
195 map = strings;
196 } else
197 if (field.getType() == Location.class) {
198 map = strings;
199 } else {
200 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " is of invalid type " + field.getType() + ", only Integer, Double, String, Boolean, UnrealId, Location is supported.");
201 }
202
203 if (map.containsKey(info.index())) {
204 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " is referencing index " + info.index() + " that has already been defined/taken by field " + map.get(info.index()).getName() + ".");
205 }
206
207 map.put(info.index(), field);
208
209 if (field.getType() == Integer.class) {
210 if (info.index() >= setterIntegers.length) {
211 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " has unexpected index " + info.index() + " for ControlMessage Integer field, I do not have SendControlMessageSetter for that!");
212 }
213 fields.add(
214 new Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper>(
215 field,
216 setterIntegers[info.index()],
217 ControlMessageTypeMapper.DIRECT_MAPPER
218 )
219 );
220 } else
221 if (field.getType() == Double.class) {
222 if (info.index() >= setterDoubles.length) {
223 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " has unexpected index " + info.index() + " for ControlMessage Double field, I do not have SendControlMessageSetter for that!");
224 }
225 fields.add(
226 new Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper>(
227 field,
228 setterDoubles[info.index()],
229 ControlMessageTypeMapper.DIRECT_MAPPER
230 )
231 );
232 } else
233 if (field.getType() == String.class) {
234 if (info.index() >= setterStrings.length) {
235 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " has unexpected index " + info.index() + " for ControlMessage String field, I do not have SendControlMessageSetter for that!");
236 }
237 fields.add(
238 new Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper>(
239 field,
240 setterStrings[info.index()],
241 ControlMessageTypeMapper.DIRECT_MAPPER
242 )
243 );
244 } else
245 if (field.getType() == Boolean.class) {
246 if (info.index() >= setterBooleans.length) {
247 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " has unexpected index " + info.index() + " for ControlMessage Boolean field, I do not have SendControlMessageSetter for that!");
248 }
249 fields.add(
250 new Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper>(
251 field,
252 setterBooleans[info.index()],
253 ControlMessageTypeMapper.DIRECT_MAPPER
254 )
255 );
256 } else
257 if (field.getType() == UnrealId.class) {
258 if (info.index() >= setterStrings.length) {
259 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " has unexpected index " + info.index() + " for ControlMessage String field, I do not have SendControlMessageSetter for that!");
260 }
261 fields.add(
262 new Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper>(
263 field,
264 setterStrings[info.index()],
265 ControlMessageTypeMapper.UNREAL_ID_2_STRING_MAPPER
266 )
267 );
268 } else
269 if (field.getType() == Location.class) {
270 if (info.index() >= setterStrings.length) {
271 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " has unexpected index " + info.index() + " for ControlMessage String field, I do not have SendControlMessageSetter for that!");
272 }
273 fields.add(
274 new Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper>(
275 field,
276 setterStrings[info.index()],
277 ControlMessageTypeMapper.LOCATION_2_STRING_MAPPER
278 )
279 );
280 } else {
281 throw new RuntimeException("Cannot create SendControlMessageDeserializer for " + customControlMessageClass + " as field " + field.getDeclaringClass() + "." + field.getName() + " is of invalid type " + field.getType() + ", only Integer, Double, String, Boolean, UnrealId, Location is supported.");
282 }
283 }
284 }
285 }
286
287 public Class<? extends ICustomControlMessage> getDescriptor() {
288 return descriptor;
289 }
290
291 public String getType() {
292 return type;
293 }
294
295 public SendControlMessage serialize(ICustomControlMessage message) {
296 SendControlMessage result = new SendControlMessage();
297
298 for (Tuple3<Field, SendControlMessageSetter, ControlMessageTypeMapper> field : fields) {
299 Object baseValue;
300 try {
301 field.getFirst().setAccessible(true);
302 baseValue = field.getFirst().get(message);
303 } catch (Exception e) {
304 throw new RuntimeException("Failed to get " + descriptor + "." + field.getFirst().getName() + " value." , e);
305 }
306 Object value = field.getThird().map(baseValue);
307 field.getSecond().set(result, value);
308 }
309
310 result.setType(type);
311 return result;
312 }
313
314 }