1 package cz.cuni.amis.pogamut.usar2004.agent.module.master;
2
3 import cz.cuni.amis.pogamut.usar2004.agent.module.datatypes.MessageDescriptor;
4 import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
5 import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
6 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
7 import cz.cuni.amis.pogamut.usar2004.agent.USAR2004Bot;
8 import cz.cuni.amis.pogamut.usar2004.agent.module.datatypes.SensorType;
9 import cz.cuni.amis.pogamut.usar2004.agent.module.datatypes.SensorsContainerQueued;
10 import cz.cuni.amis.pogamut.usar2004.agent.module.sensor.SuperSensor;
11 import cz.cuni.amis.pogamut.usar2004.communication.messages.usarinfomessages.SensorMessage;
12 import java.util.HashMap;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Queue;
16
17 /**
18 * Master module for gathering every sensor message server sends. They are saved
19 * respectively by their type and than name. There is a listener for SEN
20 * messages that updates data in SensorContainerQueued. Note that this is
21 * equvalent with SensorMasterModule. The difference is that the Queued version
22 * does not throw out records until it is requiered to do so. It lines them up
23 * to lists. This is needed when we want the best quality readings and regular
24 * ticks are not enough to keep up with the speed of sensor messages being
25 * recieved.
26 *
27 * @author vejmanm
28 */
29 public class SensorMasterModuleQueued extends SensorModule<USAR2004Bot>
30 {
31 protected SensorMessageListener sensorListener;
32 protected static SensorMasterModuleQueued singleton = null;
33 //DataStructure representing the list of all availible SensorTypes, each is listed by its name.
34 protected SensorsContainerQueued sensorModules;
35
36 /**
37 * Private ctor
38 *
39 * @param bot USAR2004Bot variable for creating instance of each new record
40 * in sensorModules(due to inheritance)
41 */
42 public SensorMasterModuleQueued(USAR2004Bot bot)
43 {
44 super(bot);
45 sensorModules = new SensorsContainerQueued();
46 sensorListener = new SensorMessageListener(worldView);
47 }
48
49 /**
50 * Method for obtaining the singleton.
51 *
52 * @param bot USAR2004Bot parameter for creation of the singleton instance
53 * when called for the first time.
54 * @return Returns singleton instance.
55 */
56 public static SensorMasterModuleQueued getModuleInstance(USAR2004Bot bot)
57 {
58 if(singleton == null)
59 {
60 singleton = new SensorMasterModuleQueued(bot);
61 }
62 return singleton;
63 }
64
65 /**
66 * Collection of sensor data check.
67 *
68 * @return Returns false if either sensor collection is empty or null;
69 */
70 public Boolean isReady()
71 {
72 return (sensorModules != null && !sensorModules.isEmpty());
73 }
74
75 /**
76 * Gets sensor message representatives from local hashmap. Returns null if
77 * none matches or this hash map is empty.
78 *
79 * @param type String representing the type of sensor to return.
80 * @return Returns List of specified type of Sensor module.
81 */
82 public List<SuperSensor> getSensorsByType(String type)
83 {
84 if(type == null)
85 {
86 return null;
87 }
88 return sensorModules.getSensorsByType(type.toLowerCase());
89 }
90
91 /**
92 * Iterates through local hashmap values and seeks match. Returns null if
93 * this hash map is empty. Note, that if <B>type</B> = UNKNOWN_SENSOR it
94 * returns all unknown sensors.
95 *
96 * @param type SensorType representing the type of sensor to return.
97 * @return Returns List of all sensors that suit input SensorType.
98 */
99 public List<SuperSensor> getSensorsBySensorType(SensorType type)
100 {
101 return sensorModules.getSensorsBySensorType(type);
102 }
103
104 /**
105 * Returns value based on the sensor module element count. If sensorModule
106 * of specified <B>type</B> has more than zero elements, it returns true.
107 *
108 * @param type SensorType representing the type of sensor.
109 * @return Returns true if sensor data of specified <B>type</B> is
110 * availible.
111 */
112 public boolean isSensorReady(SensorType type)
113 {
114 return sensorModules.isReady(type);
115 }
116
117 /**
118 * Adds every object that can be casted to initial class to the output list.
119 * Note that if You feed this method with SuperClass it will return all
120 * available submodules.
121 *
122 * @param c Class representing the type of which the return list should be
123 * @return Returns a list of eligible objects, that can be casted to Class c
124 */
125 public List<SuperSensor> getSensorsByClass(Class c)
126 {
127 return sensorModules.getSensorsByClass(c);
128 }
129
130 /**
131 * Gets sensor message representatives from local hashmap specified by type
132 * and by name. Returns null if none matches or this hash map is empty or
133 * either type or name is null.
134 *
135 * @param type String representing the type of sensor to return.
136 * @param name String representing the name of sensor to return.
137 * @return Returns List of specified type of Sensor module.
138 */
139 public SuperSensor getSensorByTypeName(String type, String name)
140 {
141 if(type == null || name == null)
142 {
143 return null;
144 }
145 return (SuperSensor) sensorModules.getSensorByTypeName(type.toLowerCase(), name.toLowerCase());
146 }
147
148 /**
149 * For each type of sensor it adds all individuals to the returnee List as a
150 * couple (Type, Name)
151 *
152 * @return returns Map of couples (Type/Name) of non empty sensor
153 * representatives.
154 */
155 public List<MessageDescriptor> getNonEmptyDescripton()
156 {
157 return sensorModules.getNonEmptyDescription();
158 }
159
160 /**
161 * Asks SensorType enum if it knows SensorType represented by string
162 * <B>type</B>. If it does, it also contains Class reference. This reference
163 * is then instantiated and returned. If it does not, it returns instance of
164 * base class SuperSensor which is represented by SensorType.UNKNOWN_SENSOR.
165 *
166 * @param type String representing possible valid SensorType.
167 * @return Returns Class instance relevant to input String.
168 */
169 protected SuperSensor createNewSensor(SensorMessage message)
170 {
171 return ModuleInstanceProvider.getSensorInstanceByType(message.getType());
172 }
173
174 /**
175 * Returns a flag that indicates if sensorUpdate was successful.
176 *
177 * @param message new SensorMessage object.
178 * @return Return false if this message type with this name does not exist
179 * yet.
180 */
181 protected boolean updateSensorCollection(SensorMessage message)
182 {
183 if(!sensorModules.containsKey(message.getType().toLowerCase()))
184 {
185 return false;
186 }
187 if(sensorModules.get(message.getType().toLowerCase()).isEmpty())
188 {
189 return false;
190 }
191 if(!sensorModules.get(message.getType().toLowerCase()).containsKey(message.getName().toLowerCase()))
192 {
193 return false;
194 }
195 SuperSensor newSensor = createNewSensor(message);
196 newSensor.updateMessage(message);//fill the object
197 sensorModules.get(message.getType().toLowerCase()).get(message.getName().toLowerCase()).add(newSensor);
198 return true;
199 }
200
201 /**
202 * Updates previous State on genuine Sensor or creates a new Record.
203 *
204 * @param message This ought to be SensorMessage caught by listener.
205 */
206 protected void fileMessage(SensorMessage message)
207 {
208 if(updateSensorCollection(message))
209 {
210 return;
211 }
212 if(!sensorModules.containsKey(message.getType().toLowerCase()))
213 {
214 sensorModules.put(message.getType().toLowerCase(), new HashMap<String, Queue<SuperSensor>>());
215 }
216 if(sensorModules.get(message.getType().toLowerCase()).isEmpty() || !sensorModules.get(message.getType().toLowerCase()).containsKey(message.getName().toLowerCase()))
217 {
218 String type = message.getType().toLowerCase();
219 String name = message.getName().toLowerCase();
220 sensorModules.get(type).put(name, new LinkedList<SuperSensor>());
221
222 SuperSensor newSensor = createNewSensor(message);
223 if(newSensor == null)
224 {
225 System.out.println("This sensor is not supported! " + message.getName());
226 return;
227 }
228 newSensor.updateMessage(message);//fill the object
229 sensorModules.get(type).get(name).add(newSensor);
230 }
231 }
232
233 @Override
234 protected void cleanUp()
235 {
236 super.cleanUp();
237 sensorListener = null;
238 sensorModules = null;
239 singleton = null;
240 }
241
242 private class SensorMessageListener implements IWorldEventListener<SensorMessage>
243 {
244 @Override
245 public void notify(SensorMessage event)
246 {
247 fileMessage(event);
248 }
249
250 public SensorMessageListener(IWorldView worldView)
251 {
252 worldView.addEventListener(SensorMessage.class, this);
253 }
254 }
255 }