1 package cz.cuni.amis.pogamut.base.communication.worldview.impl;
2
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.Map;
7 import java.util.Queue;
8 import java.util.concurrent.ConcurrentLinkedQueue;
9 import java.util.logging.Level;
10
11 import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
12 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEvent;
13 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
14 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObject;
15 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
16 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
17 import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectId;
18 import cz.cuni.amis.pogamut.base.component.IComponent;
19 import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
20 import cz.cuni.amis.pogamut.base.component.controller.ComponentControlHelper;
21 import cz.cuni.amis.pogamut.base.component.controller.ComponentController;
22 import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
23 import cz.cuni.amis.pogamut.base.component.controller.IComponentControlHelper;
24 import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
25 import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
26 import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
27 import cz.cuni.amis.utils.ClassUtils;
28 import cz.cuni.amis.utils.exception.PogamutException;
29 import cz.cuni.amis.utils.listener.IListener;
30 import cz.cuni.amis.utils.listener.Listeners;
31 import cz.cuni.amis.utils.listener.ListenersMap;
32 import cz.cuni.amis.utils.maps.HashMapMap;
33 import cz.cuni.amis.utils.maps.LazyMap;
34 import cz.cuni.amis.utils.token.Token;
35 import cz.cuni.amis.utils.token.Tokens;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 @AgentScoped
69 @SuppressWarnings("unchecked")
70 public abstract class AbstractWorldView implements IWorldView {
71
72 public static final Token COMPONENT_ID = Tokens.get("WorldView");
73
74
75
76
77
78 private static class ListenerNotifier<T> implements Listeners.ListenerNotifier<IListener> {
79
80
81
82
83 private T event = null;
84
85 @Override
86 public T getEvent() {
87 return event;
88 }
89
90 public void setEvent(T event) {
91 this.event = event;
92 }
93
94
95
96
97 @Override
98 public void notify(IListener listener) {
99 listener.notify(event);
100 }
101
102 }
103
104
105
106
107 private ListenerNotifier notifier = new ListenerNotifier();
108
109
110
111
112
113
114
115
116
117
118 private HashMapMap<Class, WorldObjectId, IWorldObject> worldObjects =
119 new HashMapMap<Class, WorldObjectId, IWorldObject>();
120
121
122
123
124 private Map<Class, Map<WorldObjectId, IWorldObject>> syncWorldObjects =
125 Collections.synchronizedMap(worldObjects);
126
127
128
129
130 private Map<WorldObjectId, IWorldObject> knownObjects =
131 Collections.synchronizedMap(new HashMap<WorldObjectId, IWorldObject>());
132
133
134
135
136
137
138 private ListenersMap<Class> eventListeners = new ListenersMap<Class>();
139
140
141
142
143
144
145 private ListenersMap<Class> objectsListeners = new ListenersMap<Class>();
146
147
148
149
150
151
152
153
154 private Map<Class, ListenersMap<Class>> objectEventListeners =
155 Collections.synchronizedMap(
156 new LazyMap<Class, ListenersMap<Class>>(){
157
158 @Override
159 protected ListenersMap<Class> create(Class key) {
160 ListenersMap<Class> listeners = new ListenersMap<Class>();
161 listeners.setLog(log, "LevelC-" + key.getSimpleName());
162 return listeners;
163 }
164 }
165 );
166
167
168
169
170
171
172 private ListenersMap<WorldObjectId> specificObjectListeners = new ListenersMap<WorldObjectId>();
173
174
175
176
177
178
179
180
181 private Map<WorldObjectId, ListenersMap<Class>> specificObjectEventListeners =
182 Collections.synchronizedMap(
183 new LazyMap<WorldObjectId, ListenersMap<Class>>() {
184
185 @Override
186 protected ListenersMap<Class> create(WorldObjectId key) {
187 ListenersMap<Class> listeners = new ListenersMap<Class>();
188 listeners.setLog(log, "LevelE-" + key.getStringId());
189 return listeners;
190 }
191 }
192 );
193
194
195
196
197
198
199
200 private boolean raiseEventProcessing = false;
201
202
203
204
205
206
207 private Queue<IWorldEvent> raiseEventsList = new ConcurrentLinkedQueue<IWorldEvent>();
208
209 protected LogCategory log;
210
211 protected IComponentBus eventBus;
212
213 protected ComponentController<IComponent> controller;
214
215 public AbstractWorldView(ComponentDependencies dependencies, IComponentBus bus, IAgentLogger logger) {
216 this.log = logger.getCategory(getComponentId().getToken());
217 this.eventBus = bus;
218 this.controller = new ComponentController(this, control, this.eventBus, this.log, dependencies);
219
220 this.eventListeners.setLog(log, "LevelA");
221 this.objectsListeners.setLog(log, "LevelB");
222 this.specificObjectListeners.setLog(log, "LevelD");
223 }
224
225
226
227
228
229
230
231 protected IComponentControlHelper control = new ComponentControlHelper() {
232
233 @Override
234 public void startPaused() {
235 AbstractWorldView.this.start(true);
236 }
237
238 @Override
239 public void start() throws PogamutException {
240 AbstractWorldView.this.start(false);
241 }
242
243 @Override
244 public void prePause() throws PogamutException {
245 AbstractWorldView.this.prePause();
246 }
247
248 @Override
249 public void pause() throws PogamutException {
250 AbstractWorldView.this.pause();
251 }
252
253 @Override
254 public void resume() throws PogamutException {
255 AbstractWorldView.this.resume();
256 }
257
258 @Override
259 public void preStop() throws PogamutException {
260 AbstractWorldView.this.preStop();
261 }
262
263 @Override
264 public void stop() throws PogamutException {
265 AbstractWorldView.this.stop();
266 }
267
268 @Override
269 public void kill() {
270 AbstractWorldView.this.kill();
271 }
272
273 @Override
274 public void reset() {
275 AbstractWorldView.this.reset();
276 }
277
278 };
279
280
281
282
283
284
285 protected void cleanUp() {
286 synchronized(worldObjects) {
287 worldObjects.clear();
288 }
289 synchronized(knownObjects) {
290 knownObjects.clear();
291 }
292 synchronized(raiseEventsList) {
293 raiseEventsList.clear();
294 }
295 }
296
297
298
299
300
301
302 protected void start(boolean startPaused) {
303 cleanUp();
304 }
305
306
307
308
309
310
311 protected void prePause() {
312 }
313
314
315
316
317
318
319 protected void pause() {
320 }
321
322
323
324
325
326
327 protected void resume() {
328 }
329
330
331
332
333
334
335 protected void preStop() {
336 }
337
338
339
340
341
342
343 protected void stop() {
344 cleanUp();
345 }
346
347
348
349
350
351
352 protected void kill() {
353 cleanUp();
354 }
355
356
357
358
359
360
361 protected void reset() {
362 cleanUp();
363 }
364
365 protected boolean isRunning() {
366 return controller.isRunning();
367 }
368
369 protected boolean isPaused() {
370 return controller.isPaused();
371 }
372
373 @Override
374 public Token getComponentId() {
375 return COMPONENT_ID;
376 }
377
378 public LogCategory getLog() {
379 return log;
380 }
381
382
383
384
385
386
387
388 @Override
389 public IComponentBus getEventBus() {
390 return eventBus;
391 }
392
393
394
395
396
397
398
399 @Override
400 public void addEventListener(Class<?> event, IWorldEventListener<?> listener) {
401 eventListeners.add(event, listener);
402 }
403
404 @Override
405 public void addObjectListener(Class<?> objectClass, IWorldObjectEventListener<?, ?> listener) {
406 objectsListeners.add(objectClass, listener);
407 }
408
409 @Override
410 public void addObjectListener(Class<?> objectClass, Class<?> eventClass, IWorldObjectEventListener<?,?> listener) {
411 ListenersMap<Class> listeners = objectEventListeners.get(eventClass);
412 listeners.add(objectClass, listener);
413 }
414
415 @Override
416 public void addObjectListener(WorldObjectId objectId, IWorldObjectEventListener<?, ?> listener) {
417 specificObjectListeners.add(objectId, listener);
418 }
419
420 @Override
421 public void addObjectListener(WorldObjectId objectId, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
422 ListenersMap<Class> listeners = specificObjectEventListeners.get(objectId);
423 listeners.add(eventClass, listener);
424 }
425
426 @Override
427 public boolean isListening(Class<?> eventClass, IWorldEventListener<?> listener) {
428 return eventListeners.isListening(eventClass, listener);
429 }
430
431 @Override
432 public boolean isListening(Class<?> objectClass, IWorldObjectEventListener<?, ?> listener) {
433 return objectsListeners.isListening(listener);
434 }
435
436
437 @Override
438 public boolean isListening(Class<?> objectClass, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
439 if (objectEventListeners.containsKey(objectClass)) {
440 return objectEventListeners.get(eventClass).isListening(objectClass, listener);
441 } else {
442 return false;
443 }
444 }
445
446 @Override
447 public boolean isListening(WorldObjectId objectId, IWorldObjectEventListener<?, ?> listener) {
448 return specificObjectListeners.isListening(objectId, listener);
449 }
450
451 @Override
452 public boolean isListening(WorldObjectId objectId, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
453 if (specificObjectEventListeners.containsKey(objectId)) {
454 return specificObjectEventListeners.get(objectId).isListening(eventClass, listener);
455 } else {
456 return false;
457 }
458
459 }
460
461 @Override
462 public boolean isListening(IWorldEventListener<?> listener) {
463 if (eventListeners.isListening(listener) ||
464 specificObjectListeners.isListening(listener)) {
465 return true;
466 }
467 synchronized(objectEventListeners) {
468 for (ListenersMap<Class> listeners : objectEventListeners.values()) {
469 if (listeners.isListening(listener)) return true;
470 }
471 }
472 synchronized(specificObjectEventListeners) {
473 for (ListenersMap<Class> listeners : specificObjectEventListeners.values()) {
474 if (listeners.isListening(listener)) return true;
475 }
476 }
477 return false;
478 }
479
480 @Override
481 public void removeEventListener(Class<?> eventClass, IWorldEventListener<?> listener) {
482 eventListeners.remove(eventClass, listener);
483 }
484
485 @Override
486 public void removeObjectListener(Class<?> objectClass, IWorldObjectEventListener<?, ?> listener) {
487 objectsListeners.remove(objectClass, listener);
488 }
489
490 @Override
491 public void removeObjectListener(Class<?> objectClass, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
492 if (objectEventListeners.containsKey(eventClass)) {
493 objectEventListeners.get(eventClass).remove(objectClass, listener);
494 }
495 }
496
497 @Override
498 public void removeObjectListener(WorldObjectId objectId, IWorldObjectEventListener<?, ?> listener) {
499 specificObjectListeners.remove(objectId, listener);
500 }
501
502 @Override
503 public void removeObjectListener(WorldObjectId objectId, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
504 if (specificObjectEventListeners.containsKey(objectId)) {
505 specificObjectEventListeners.get(objectId).remove(eventClass, listener);
506 }
507 }
508
509
510 @Override
511 public void removeListener(IWorldEventListener<?> listener) {
512 eventListeners.remove(listener);
513 synchronized(objectEventListeners) {
514 for (ListenersMap<Class> listeners : objectEventListeners.values()) {
515 listeners.remove(listener);
516 }
517 }
518 specificObjectListeners.remove(listener);
519 specificObjectEventListeners.remove(listener);
520 }
521
522
523
524
525
526
527
528 @Override
529 public Map<Class, Map<WorldObjectId, IWorldObject>> getAll() {
530 return syncWorldObjects;
531 }
532
533 @Override
534 public <T extends IWorldObject> Map<WorldObjectId, T> getAll(Class<T> type) {
535 return (Map<WorldObjectId, T>) syncWorldObjects.get(type);
536 }
537
538 @Override
539 public <T extends IWorldObject> T getSingle(Class<T> cls) {
540 Collection<T> col = getAll(cls).values();
541 if(col.size() > 1) throw new IllegalArgumentException("There must be at most one object of given class (" + cls.getName() + ") to use this method. But there were more instances (" + col.size() + ").");
542 if(col.size() < 1) return null;
543 synchronized(col) {
544 return col.iterator().next();
545 }
546 }
547
548 @Override
549 public IWorldObject get(WorldObjectId objectId) {
550 return knownObjects.get(objectId);
551 }
552
553 @Override
554 public <T extends IWorldObject> T get(WorldObjectId id, Class<T> clazz) {
555 IWorldObject obj = get(id);
556 if(obj == null){
557 return null;
558 }
559 else if(clazz.isAssignableFrom(obj.getClass())){
560 return (T)obj;
561 } else {
562 throw new ClassCastException("Object with id " + id + " is not of class " + clazz);
563 }
564 }
565
566
567
568 @Override
569 public Map<WorldObjectId, IWorldObject> get() {
570 return knownObjects;
571 }
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587 protected synchronized void addWorldObject(IWorldObject worldObject) {
588 knownObjects.put(worldObject.getId(), worldObject);
589 for (Class cls : ClassUtils.getSubclasses(worldObject.getClass())) {
590 syncWorldObjects.get(cls).put(worldObject.getId(), worldObject);
591 }
592 }
593
594
595
596
597
598
599
600
601
602
603 protected synchronized void removeWorldObject(IWorldObject worldObject) {
604 knownObjects.remove(worldObject.getId());
605 for (Class<?> cls : ClassUtils.getSubclasses(worldObject.getClass())) {
606 syncWorldObjects.get(cls).remove(worldObject.getId());
607 }
608 }
609
610
611
612
613
614
615
616
617
618
619
620
621 protected synchronized void raiseEvent(IWorldEvent event) {
622
623
624
625 if (raiseEventProcessing) {
626
627
628
629 raiseEventsList.add(event);
630 return;
631 } else {
632
633 raiseEventProcessing = true;
634 }
635
636
637 innerRaiseEvent(event);
638
639
640 while(raiseEventsList.size() != 0) {
641
642 innerRaiseEvent(raiseEventsList.poll());
643 }
644
645 raiseEventProcessing = false;
646 }
647
648
649
650
651
652
653
654
655
656
657
658 private void notifyLevelAListeners(IWorldEvent event) {
659 Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
660 notifier.setEvent(event);
661 for (Class eventClass : eventClasses) {
662 eventListeners.notify(eventClass, notifier);
663 }
664 }
665
666
667
668
669
670 private void notifyLevelBListeners(IWorldObjectEvent event) {
671 IWorldObject object = event.getObject();
672 Collection<Class> objectClasses = ClassUtils.getSubclasses(object.getClass());
673 notifier.setEvent(event);
674 for (Class objectClass : objectClasses) {
675 objectsListeners.notify(objectClass, notifier);
676 }
677 }
678
679
680
681
682
683
684 private void notifyLevelCListeners(IWorldObjectEvent event) {
685 Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
686 Collection<Class> objectClasses = ClassUtils.getSubclasses(event.getObject().getClass());
687 notifier.setEvent(event);
688 for (Class eventClass : eventClasses) {
689 ListenersMap<Class> listeners = objectEventListeners.get(eventClass);
690 if (listeners == null) continue;
691 if (!listeners.hasListeners()) continue;
692 for (Class objectClass : objectClasses) {
693 listeners.notify(objectClass, notifier);
694 }
695 }
696 }
697
698
699
700
701
702 private void notifyLevelDListeners(IWorldObjectEvent event) {
703 notifier.setEvent(event);
704 specificObjectListeners.notify(event.getId(), notifier);
705 }
706
707
708
709
710
711 private void notifyLevelEListeners(IWorldObjectEvent event) {
712 notifier.setEvent(event);
713 WorldObjectId objectId = event.getId();
714 ListenersMap<Class> listeners = specificObjectEventListeners.get(objectId);
715 if (listeners.hasListeners()) {
716 Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
717 notifier.setEvent(event);
718 for (Class eventClass : eventClasses) {
719 listeners.notify(eventClass, notifier);
720 }
721 }
722 }
723
724
725
726
727
728
729
730
731 private void innerRaiseEvent(IWorldEvent event) {
732 if (log.isLoggable(Level.FINEST)) log.finest("notifying " + event);
733 notifyLevelAListeners(event);
734 if (event instanceof IWorldObjectEvent) {
735
736 IWorldObjectEvent objectEvent = (IWorldObjectEvent)event;
737 notifyLevelBListeners(objectEvent);
738 notifyLevelCListeners(objectEvent);
739 notifyLevelDListeners(objectEvent);
740 notifyLevelEListeners(objectEvent);
741 }
742 }
743
744 @Override
745 public String toString() {
746 if (this == null) return "AbstractWorldView-instantiating";
747 return getClass().getSimpleName();
748 }
749
750 }