View Javadoc

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   * Reads definition of {@link ICustomControlMessage} implementation interpreting {@link ControlMessageType}, {@link ControlMessageField} and {@link ControlMessageSimType}.
20   * and provides {@link ControlMessageMapper#serialize(ControlMessage)} method for auto-mapping of {@link ControlMessage} onto {@link SendControlMessage} commands.
21   * 
22   * @author Jimmy
23   *
24   * @param <T>
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  			// 0
37  			null,
38  			// 1
39  			new SendControlMessageSetter<Integer>() {
40  				@Override
41  				public void set(SendControlMessage msg, Integer value) {
42  					msg.setPI1(value);
43  				}
44  			},
45  			// 2
46  			new SendControlMessageSetter<Integer>() {
47  				@Override
48  				public void set(SendControlMessage msg, Integer value) {
49  					msg.setPI2(value);
50  				}
51  			},
52  			// 3
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  			// 0
65  			null,
66  			// 1
67  			new SendControlMessageSetter<Double>() {
68  				@Override
69  				public void set(SendControlMessage msg, Double value) {
70  					msg.setPF1(value);
71  				}
72  			},
73  			// 2
74  			new SendControlMessageSetter<Double>() {
75  				@Override
76  				public void set(SendControlMessage msg, Double value) {
77  					msg.setPF2(value);
78  				}
79  			},
80  			// 3
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  			// 0
93  			null,
94  			// 1
95  			new SendControlMessageSetter<String>() {
96  				@Override
97  				public void set(SendControlMessage msg, String value) {
98  					msg.setPS1(value);
99  				}
100 			},
101 			// 2
102 			new SendControlMessageSetter<String>() {
103 				@Override
104 				public void set(SendControlMessage msg, String value) {
105 					msg.setPS2(value);
106 				}
107 			},
108 			// 3
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 			// 0
121 			null,
122 			// 1
123 			new SendControlMessageSetter<Boolean>() {
124 				@Override
125 				public void set(SendControlMessage msg, Boolean value) {
126 					msg.setPB1(value);
127 				}
128 			},
129 			// 2
130 			new SendControlMessageSetter<Boolean>() {
131 				@Override
132 				public void set(SendControlMessage msg, Boolean value) {
133 					msg.setPB2(value);
134 				}
135 			},
136 			// 3
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 			// SANITY-CHECKS
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 }