1 package cz.cuni.amis.pogamut.ut2004multi.communication.module;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Set;
9
10 import cz.cuni.amis.pogamut.base.agent.IAgentId;
11 import cz.cuni.amis.pogamut.base.agent.utils.runner.impl.MultipleAgentRunner;
12 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObject;
13 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
14 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
15 import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectId;
16 import cz.cuni.amis.pogamut.base3d.worldview.IVisionWorldView;
17 import cz.cuni.amis.pogamut.multi.communication.worldview.object.ICompositeWorldObject;
18 import cz.cuni.amis.pogamut.multi.communication.worldview.object.ILocalWorldObject;
19 import cz.cuni.amis.pogamut.multi.communication.worldview.object.ISharedProperty;
20 import cz.cuni.amis.pogamut.multi.communication.worldview.object.ISharedWorldObject;
21 import cz.cuni.amis.pogamut.multi.communication.worldview.object.IStaticWorldObject;
22 import cz.cuni.amis.pogamut.multi.communication.worldview.property.PropertyId;
23 import cz.cuni.amis.pogamut.multi.utils.timekey.TimeKey;
24 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.UT2004CompositeObjectCreator;
25 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.UT2004SharedObjectCreator;
26 import cz.cuni.amis.utils.concurrency.AtomicLongList;
27 import cz.cuni.amis.utils.exception.PogamutException;
28 import cz.cuni.amis.utils.maps.HashMapMap;
29 import cz.cuni.amis.utils.maps.SyncHashMap;
30 import cz.cuni.amis.utils.maps.WeakHashTriMap;
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public class SharedKnowledgeDatabase {
45
46
47
48
49 protected static Map<Integer, SharedKnowledgeDatabase> instances = new HashMap<Integer, SharedKnowledgeDatabase>();
50
51
52
53
54
55
56 public static SharedKnowledgeDatabase get( int team )
57 {
58 synchronized(instances) {
59 SharedKnowledgeDatabase instance = instances.get(team);
60 if ( instance == null )
61 {
62 instance = new SharedKnowledgeDatabase(team);
63 instances.put(team, instance);
64 };
65 return instance;
66 }
67 }
68
69
70
71
72
73
74
75
76 protected SyncHashMap<IAgentId, Integer> registeredAgents = new SyncHashMap<IAgentId, Integer>();
77
78
79
80
81 protected int team;
82
83
84
85
86 protected AtomicLongList agentLockTimes = new AtomicLongList(10, 10);
87
88
89
90
91
92 protected Map<IAgentId, IVisionWorldView> agentWorldViews = new HashMap<IAgentId, IVisionWorldView>();
93
94
95
96
97 protected Map<IAgentId, Set<IWorldObjectEventListener>> listeners = new HashMap<IAgentId, Set<IWorldObjectEventListener>>();
98
99
100
101
102 protected WeakHashTriMap<TimeKey, WorldObjectId, PropertyId, ISharedProperty> sharedProperties = new WeakHashTriMap<TimeKey, WorldObjectId, PropertyId, ISharedProperty>();
103
104
105
106
107 protected HashMapMap< WorldObjectId, PropertyId, ISharedProperty> currSharedProperties = new HashMapMap< WorldObjectId, PropertyId, ISharedProperty>();
108
109
110
111
112 protected Map<WorldObjectId, Long> lastUpdateTime = new HashMap<WorldObjectId, Long>();
113
114
115
116
117 protected HashMap<TimeKey,Set<IAgentId>> heldKeys = new HashMap<TimeKey,Set<IAgentId>>();
118
119
120
121
122 protected Map<IAgentId, TimeKey> currentTimeKeys = new HashMap<IAgentId, TimeKey>();
123
124
125
126
127 protected Set<Class> registeredClasses = new HashSet<Class>();
128
129 protected SharedKnowledgeDatabase( int team )
130 {
131 this.team = team;
132 }
133
134
135
136
137
138
139
140
141
142
143 protected void addTimeLock(TimeKey timeKey, IAgentId id)
144 {
145 Set<IAgentId> agentLocks = heldKeys.get(timeKey);
146 if ( agentLocks == null )
147 {
148 agentLocks = new HashSet<IAgentId>();
149 heldKeys.put(timeKey, agentLocks);
150 }
151
152 for ( TimeKey t : heldKeys.keySet() )
153 {
154 if ( t.getTime() >= timeKey.getTime())
155 {
156 heldKeys.get(t).add(id);
157 }
158 }
159 }
160
161
162
163
164
165
166 protected void removeTimeLock( TimeKey timeKey, IAgentId id)
167 {
168 synchronized (heldKeys)
169 {
170 Set<IAgentId> agentLocks = heldKeys.get(timeKey);
171 agentLocks.remove(id);
172 if ( agentLocks.isEmpty() )
173 {
174 heldKeys.remove(timeKey);
175 }
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 public void addAgent( IAgentId id, IVisionWorldView agentWorldView, int team)
196 {
197 if (team != this.team)
198 {
199 throw new PogamutException("Trying to add an agent of different team than the one registered with this sharedKnowledgeDatabase.", this);
200 }
201
202 if ( registeredAgents.get(id) != null) {
203 return;
204 }
205
206 registeredAgents.getWriteLock().lock();
207 try {
208 int unusedNumber = getUnusedAgentNumber();
209 registeredAgents.getMap().put(id, unusedNumber);
210 } finally {
211 registeredAgents.getWriteLock().unlock();
212 }
213 }
214
215
216
217
218
219 private int getUnusedAgentNumber() {
220 List<Boolean> used = new ArrayList<Boolean>(registeredAgents.size()+1);
221 for (Integer agentNumber : registeredAgents.getMap().values()) {
222 used.set(agentNumber, true);
223 }
224 for (int i = 0; i < used.size(); ++i) {
225 if (used.get(i) == null || !used.get(i)) {
226 return i;
227 }
228 }
229
230 throw new RuntimeException("registeredAgents corrupted!");
231 }
232
233
234
235
236
237
238
239 public void addObjectClass(Class c)
240 {
241 synchronized (registeredClasses)
242 {
243 registeredClasses.add(c);
244
245 for ( IAgentId id : registeredAgents.getMap().keySet())
246 {
247 addClassListener(agentWorldViews.get(id),c, id);
248 }
249 }
250 }
251
252
253
254
255
256
257 public boolean removeObjectClass(Class c)
258 {
259 synchronized (registeredClasses)
260 {
261 return registeredClasses.remove(c);
262 }
263 }
264
265
266
267
268
269
270
271
272 public boolean removeAgent( IAgentId id)
273 {
274 synchronized (registeredAgents)
275 {
276
277 if ( !registeredAgents.getMap().containsKey(id) )
278 {
279 return false;
280 }
281 IVisionWorldView wv = agentWorldViews.get(id);
282 Set<IWorldObjectEventListener> listenerSet = listeners.get(id);
283 if ( listenerSet != null)
284 {
285 for (IWorldObjectEventListener listener : listenerSet )
286 {
287 wv.removeListener(listener);
288 }
289 }
290 agentWorldViews.remove(id);
291 registeredAgents.remove(id);
292 listeners.remove(id);
293 return true;
294 }
295 }
296
297
298
299
300
301
302
303 public IWorldObject getObject(WorldObjectId id, IAgentId agentId)
304 {
305 synchronized (sharedProperties)
306 {
307 ICompositeWorldObject agentObject = (ICompositeWorldObject)agentWorldViews.get(agentId).get(id);
308 if (agentObject == null)
309 {
310 return null;
311 }
312 ILocalWorldObject localPart = agentObject.getLocal();
313 IStaticWorldObject staticPart = agentObject.getStatic();
314 Map<PropertyId, ISharedProperty> properties = agentObject.getShared().getProperties();
315 TimeKey timeKey = TimeKey.get(localPart.getSimTime());
316 for ( PropertyId pId : currSharedProperties.get(id).keySet() )
317 {
318 ISharedProperty p = sharedProperties.get(timeKey, id, pId);
319 if ( p == null )
320 {
321 p = currSharedProperties.get(id, pId);
322 }
323 properties.put(p.getPropertyId(), p);
324 }
325 Class msgClass = localPart.getCompositeClass();
326
327 ISharedWorldObject sharedPart = UT2004SharedObjectCreator.create( msgClass , id , properties.values());
328 return UT2004CompositeObjectCreator.createObject(localPart, sharedPart, staticPart);
329 }
330 }
331
332
333
334
335
336
337
338
339
340
341
342 protected void addClassListener(IVisionWorldView wv, Class c, IAgentId agentId)
343 {
344 synchronized (listeners)
345 {
346 IWorldObjectEventListener listener =
347 new AgentSpecificObjectEventListener<IWorldObject, IWorldObjectEvent<IWorldObject>>(agentId) {
348 @Override
349 public void notify(IWorldObjectEvent<IWorldObject> event)
350 {
351 SharedKnowledgeDatabase.this.processObjEvent(event, this.agentId);
352 };
353 };
354
355 wv.addObjectListener(c, listener);
356
357 Set<IWorldObjectEventListener> listenerSet = listeners.get(agentId);
358 if ( listenerSet == null )
359 {
360 listenerSet = new HashSet<IWorldObjectEventListener>();
361 listeners.put(agentId, listenerSet);
362 };
363 listenerSet.add(listener);
364 }
365 }
366
367
368
369
370
371
372 protected void processObjEvent(IWorldObjectEvent<IWorldObject> event, IAgentId agentId)
373 {
374
375 TimeKey currentTime = currentTimeKeys.get(agentId);
376 if ( currentTime != null )
377 {
378 if ( currentTime.getTime() < event.getSimTime())
379 {
380 TimeKey newTimeKey = TimeKey.get(event.getSimTime());
381
382 this.removeTimeLock(currentTime, agentId);
383 currentTimeKeys.put(agentId, newTimeKey);
384 this.addTimeLock(newTimeKey, agentId);
385 }
386 }
387 else
388 {
389 TimeKey newTimeKey = TimeKey.get(event.getSimTime());
390 currentTimeKeys.put(agentId, newTimeKey);
391 this.addTimeLock(newTimeKey, agentId);
392 }
393
394 WorldObjectId id = event.getId();
395
396 ISharedWorldObject sharedObj = ((ICompositeWorldObject)event.getObject()).getShared();
397
398 long lastUpdateTime = -1;
399 if ( this.lastUpdateTime.containsKey(id) )
400 {
401 lastUpdateTime = this.lastUpdateTime.get(id);
402 }
403
404
405 if ( sharedObj.getSimTime() >= lastUpdateTime )
406 {
407 synchronized (sharedProperties)
408 {
409
410
411 for ( ISharedProperty p : sharedObj.getProperties().values())
412 {
413 if ( p.getValue() != null )
414 {
415 PropertyId propertyId = p.getPropertyId();
416 ISharedProperty old = currSharedProperties.get(id, propertyId);
417 for ( TimeKey key : heldKeys.keySet() )
418 {
419 if ( sharedProperties.get(key, id, propertyId) == null )
420 {
421 sharedProperties.put(key,id, propertyId, p);
422 }
423 }
424 }
425 }
426 }
427 }
428 }
429 }