1 package cz.cuni.amis.pogamut.usar2004.agent.module.master;
2
3 import cz.cuni.amis.pogamut.base.agent.module.SensomotoricModule;
4 import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
5 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
6 import cz.cuni.amis.pogamut.usar2004.agent.USAR2004Bot;
7 import cz.cuni.amis.pogamut.usar2004.agent.module.configuration.SuperConfiguration;
8 import cz.cuni.amis.pogamut.usar2004.agent.module.datatypes.MessageDescriptor;
9 import cz.cuni.amis.pogamut.usar2004.agent.module.datatypes.ConfigContainer;
10 import cz.cuni.amis.pogamut.usar2004.agent.module.datatypes.ConfigType;
11 import cz.cuni.amis.pogamut.usar2004.communication.messages.usarcommands.GetConf;
12 import cz.cuni.amis.pogamut.usar2004.communication.messages.usarinfomessages.ConfigurationMessage;
13 import java.util.HashMap;
14 import java.util.List;
15
16 /**
17 * ConfigurationMasterModule provides methods for querying messages to server
18 * and methods for reading answers to those queries. Please note, that You have
19 * to produce suitable query before reading any data. Query methods: starts with
20 * query* Module methods: starts with get* Data at each module updates every
21 * time You call query method again.
22 *
23 * @author vejmanm
24 */
25 public class ConfigMasterModule extends SensomotoricModule<USAR2004Bot>
26 {
27 //Quest: Some ConfigTypes such as "Robot" are theoretically useless as long as we wont happen to INIT more than one bot within one USAR2004Bot. So..Do we need List for one Item then?
28 //Quest: Should unite With GeoMasterModule, cause its just copy/paste thing going on here...
29 protected ConfigurationMessageListener confListener;
30 protected static ConfigMasterModule singleton = null;
31 //DataStructure representing the list of all availible SensorTypes, each is listed by name.
32 protected ConfigContainer configModules;
33
34 /**
35 * Private ctor
36 *
37 * @param bot USAR2004Bot variable for creating instance of each new record
38 * in configModules(due to inheritance)
39 */
40 private ConfigMasterModule(USAR2004Bot bot)
41 {
42 super(bot);
43 configModules = new ConfigContainer();
44 confListener = new ConfigurationMessageListener(worldView);
45 }
46
47 /**
48 * Method for obtaining the singleton.
49 *
50 * @param bot USAR2004Bot parameter for creation of the singleton instance
51 * when called for the first time.
52 * @return Returns singleton instance.
53 */
54 public static ConfigMasterModule getModuleInstance(USAR2004Bot bot)
55 {
56 if(singleton == null)
57 {
58 singleton = new ConfigMasterModule(bot);
59 }
60 return singleton;
61 }
62
63 /**
64 * Collection of sensor data check.
65 *
66 * @return Returns false if either sensor collection is empty or null;
67 */
68 public Boolean isReady()
69 {
70 return (configModules != null && !configModules.isEmpty());
71 }
72
73 /**
74 * Adds every object that can be casted to initial class to the output list.
75 * Note that if You feed this method with SuperClass it will return all
76 * available submodules.
77 *
78 * @param c Class representing the type of which the return list should be
79 * @return Returns a list of eligible objects, that can be casted to Class c
80 */
81 public List<SuperConfiguration> getConfigurationsByClass(Class clazz)
82 {
83 return configModules.getConfigurationsByClass(clazz);
84 }
85
86 /**
87 *
88 * @param type String representing the type of Configuration to return
89 * @return Returns List of specified type of Configuration module.
90 */
91 public List<SuperConfiguration> getConfigurationsByType(String type)
92 {
93 if(type == null)
94 {
95 return null;
96 }
97 return configModules.getConfigurationsByType(type.toLowerCase());
98 }
99
100 /**
101 * Note, that if <B>type</B> = UNKNOWN it returns all unknown
102 * Configurations.
103 *
104 * @param type ConfigurationType representing the type of Configuration to
105 * return
106 * @return Returns List of all Configurations that suit input
107 * ConfigurationType.
108 */
109 public List<SuperConfiguration> getConfigurationsByConfigType(ConfigType type)
110 {
111 return configModules.getConfigurationsByConfigType(type);
112 }
113
114 /**
115 * Gets configuration message representatives from local hashmap specified
116 * by type and by name. Returns null if none matches or this hash map is
117 * empty.
118 *
119 * @param type String representing the type of configuration to return.
120 * @param name String representing the name of configuration to return.
121 * @return Returns List of specified type of Configuration representative.
122 */
123 public SuperConfiguration getConfigurationByTypeName(String type, String name)
124 {
125 if(type == null || name == null)
126 {
127 return null;
128 }
129 return configModules.getConfigurationByTypeName(type.toLowerCase(), name.toLowerCase());//name can be null, but we cant put null to lowerCase!
130 }
131
132 /**
133 * For each type of Configuration it adds all individuals to the returnee
134 * List as a couple (Type, Name)
135 *
136 * @return returns Map of couples (Type/Name) of non empty Configurations
137 */
138 public List<MessageDescriptor> getNonEmptyDescription()
139 {
140 return configModules.getNonEmptyDescription();
141 }
142
143 /**
144 * Sends GETCONF message with specified type. If the type is genuine, this
145 * module will acquire Configuration data of all sensors/effecters specified
146 * by <B>type</B>.
147 *
148 * @param type type of Configuration data we want to know about. For example
149 * : Sonar, MisPkg, Robot, Effecter, etc..
150 */
151 public void queryConfigurationByType(String type)
152 {
153 queryConfigurationByTypeName(type, null);
154 }
155
156 /**
157 * Sends GETCONF message with specified type and name. This module then
158 * ought to acquire data from server matching requirements.
159 *
160 * @param type type of Configuration data we want to know about. For example
161 * : Sonar, MisPkg, Robot, Effecter, etc..
162 * @param name of sensor/effecter. Can be omitted.
163 */
164 public void queryConfigurationByTypeName(String type, String name)
165 {
166 this.act.act(new GetConf(type, name));
167 }
168
169 /**
170 * Asks ConfigType enum if it knows ConfigType represented by string
171 * <B>type</B>. If it does, it also contains Class reference. This reference
172 * is then instantiated and returned. If it does not, it returns instance of
173 * base class SuperConfiguration which is represented by ConfigType.SENSOR.
174 *
175 * @param type String representing possible valid ConfigType.
176 * @return Returns Class instance relevant to input String.
177 */
178 protected SuperConfiguration createNewSensor(ConfigurationMessage message)
179 {
180 return ModuleInstanceProvider.getConfigInstanceByType(message.getType());
181 }
182
183 /**
184 * Returns a flag that indicates if sensorUpdate was successful.
185 *
186 * @param message
187 * @return Return false if this message type with this name does not exist
188 * yet.
189 */
190 protected boolean updateSensorCollection(ConfigurationMessage message)
191 {
192 if(!configModules.containsKey(message.getType().toLowerCase()))
193 {
194 return false;
195 }
196 if(configModules.get(message.getType().toLowerCase()).isEmpty())
197 {
198 return false;
199 }
200 if(!configModules.get(message.getType().toLowerCase()).containsKey(message.getName().toLowerCase()))
201 {
202 return false;
203 }
204 //sensorModules.get(message.getType().toLowerCase()).get(message.getName().toLowerCase()).updateMessage(message);
205 return true;
206 }
207
208 /**
209 * Updates previous State on genuine Sensor or creates a new Record.
210 *
211 * @param message This ought to be SensorMessage caught by listener.
212 */
213 protected void fileMessage(ConfigurationMessage message)
214 {
215 if(updateSensorCollection(message))
216 {
217 return;
218 }
219 if(!configModules.containsKey(message.getType().toLowerCase()))
220 {
221 configModules.put(message.getType().toLowerCase(), new HashMap<String, SuperConfiguration>());
222 }
223 if(configModules.get(message.getType().toLowerCase()).isEmpty() || !configModules.get(message.getType().toLowerCase()).containsKey(message.getName().toLowerCase()))
224 {
225 SuperConfiguration newSensor = createNewSensor(message);
226 if(newSensor == null)
227 {
228 System.out.println("This Configuration message is not supported! " + message.getName());
229 return;
230 }
231 String type = message.getType().toLowerCase();
232 String name = message.getName().toLowerCase();
233 newSensor.updateMessage(message);//fill the object
234 configModules.get(type).put(name, newSensor);
235 }
236 }
237
238 @Override
239 protected void cleanUp()
240 {
241 super.cleanUp();
242 confListener = null;
243 configModules = null;
244 singleton = null;
245 }
246
247 private class ConfigurationMessageListener implements IWorldEventListener<ConfigurationMessage>
248 {
249 @Override
250 public void notify(ConfigurationMessage event)
251 {
252 fileMessage(event);
253 }
254
255 public ConfigurationMessageListener(IWorldView worldView)
256 {
257 worldView.addEventListener(ConfigurationMessage.class, this);
258 }
259 }
260 }