1 package cz.cuni.amis.pogamut.multi.communication.worldview.impl;
2
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.LinkedList;
7 import java.util.Map;
8 import java.util.Queue;
9 import java.util.Set;
10 import java.util.concurrent.ConcurrentLinkedQueue;
11 import java.util.logging.Level;
12 import java.util.logging.Logger;
13
14 import cz.cuni.amis.pogamut.base.agent.IAgentId;
15 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEvent;
16 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
17 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObject;
18 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
19 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
20 import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectId;
21 import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
22 import cz.cuni.amis.pogamut.base.component.controller.ISharedComponentControlHelper;
23 import cz.cuni.amis.pogamut.base.component.controller.ISharedComponentController;
24 import cz.cuni.amis.pogamut.base.component.controller.SharedComponentControlHelper;
25 import cz.cuni.amis.pogamut.base.component.controller.SharedComponentController;
26 import cz.cuni.amis.pogamut.base.component.lifecyclebus.ILifecycleBus;
27 import cz.cuni.amis.pogamut.multi.agent.ITeamId;
28 import cz.cuni.amis.pogamut.multi.agent.impl.TeamedAgentId;
29 import cz.cuni.amis.pogamut.multi.communication.worldview.ILocalWorldView;
30 import cz.cuni.amis.pogamut.multi.communication.worldview.ISharedWorldView;
31 import cz.cuni.amis.pogamut.multi.communication.worldview.object.ISharedProperty;
32 import cz.cuni.amis.pogamut.multi.communication.worldview.object.ISharedWorldObject;
33 import cz.cuni.amis.pogamut.multi.communication.worldview.object.IStaticWorldObject;
34 import cz.cuni.amis.pogamut.multi.communication.worldview.property.PropertyId;
35 import cz.cuni.amis.pogamut.multi.utils.timekey.TimeKey;
36 import cz.cuni.amis.pogamut.multi.utils.timekey.TimeKeyManager;
37 import cz.cuni.amis.utils.ClassUtils;
38 import cz.cuni.amis.utils.exception.PogamutException;
39 import cz.cuni.amis.utils.listener.IListener;
40 import cz.cuni.amis.utils.listener.Listeners;
41 import cz.cuni.amis.utils.listener.ListenersMap;
42 import cz.cuni.amis.utils.maps.HashTriMap;
43 import cz.cuni.amis.utils.maps.LazyMap;
44 import cz.cuni.amis.utils.maps.WeakHashQuadMap;
45 import cz.cuni.amis.utils.maps.WeakHashTriMap;
46 import cz.cuni.amis.utils.token.Token;
47 import cz.cuni.amis.utils.token.Tokens;
48
49 @SuppressWarnings("unchecked")
50 public abstract class AbstractSharedWorldView implements ISharedWorldView {
51
52 public static final Token COMPONENT_ID = Tokens.get("AbstractSharedWorldView");
53
54
55
56
57 protected HashMap<TeamedAgentId, ILocalWorldView> localWorldViews = new HashMap<TeamedAgentId, ILocalWorldView>();
58
59
60
61
62 protected WeakHashQuadMap<TimeKey, ITeamId, WorldObjectId, PropertyId, ISharedProperty> sharedProperties =
63 new WeakHashQuadMap<TimeKey, ITeamId, WorldObjectId, PropertyId, ISharedProperty>(8,8,32,8);
64
65
66
67
68 protected Map<TimeKey, Map<ITeamId, Map<WorldObjectId, Map<PropertyId, ISharedProperty>>>> syncSharedProperties =
69 Collections.synchronizedMap( sharedProperties );
70
71
72
73
74 protected HashTriMap<ITeamId, WorldObjectId, PropertyId, ISharedProperty> currentSharedProperties =
75 new HashTriMap<ITeamId, WorldObjectId, PropertyId, ISharedProperty>(8,32,8);
76
77
78
79
80 protected Map<ITeamId, Map<WorldObjectId, Map<PropertyId, ISharedProperty>>> syncCurrentSharedProperties =
81 Collections.synchronizedMap( currentSharedProperties );
82
83
84
85
86 protected Map<WorldObjectId, IStaticWorldObject> staticWorldObjects =
87 Collections.synchronizedMap( new HashMap<WorldObjectId, IStaticWorldObject>(32) );
88
89
90
91
92 protected WeakHashTriMap<TimeKey, ITeamId, WorldObjectId, ISharedWorldObject> sharedWorldObjects =
93 new WeakHashTriMap<TimeKey, ITeamId, WorldObjectId, ISharedWorldObject>(8,8,32);
94
95
96
97
98 protected Map<TimeKey, Map<ITeamId, Map<WorldObjectId, ISharedWorldObject>>> syncSharedWorldObjects =
99 Collections.synchronizedMap( sharedWorldObjects );
100
101 protected HashMap<WorldObjectId, Class> idClassMap = new HashMap<WorldObjectId, Class>();
102
103 protected Map<WorldObjectId, Class> syncIdClassMap = Collections.synchronizedMap( idClassMap );
104
105
106
107
108
109
110
111
112
113
114
115 @Override
116 public void registerLocalWorldView( ILocalWorldView localWV, ILifecycleBus bus) {
117 this.localWorldViews.put( (TeamedAgentId)localWV.getAgentId(), localWV);
118 this.addComponentBus( localWV.getAgentId(), bus, new ComponentDependencies() );
119 }
120
121
122
123
124
125
126 protected ISharedProperty getSharedProperty(PropertyId id, ITeamId teamId, TimeKey time) {
127 ISharedProperty result = syncSharedProperties.get(time).get(teamId).get(id.getWorldObjectId()).get(id);
128 if ( result != null )
129 {
130 return result;
131 }
132 return currentSharedProperties.get(teamId, id.getWorldObjectId(), id);
133 }
134
135
136
137
138
139
140
141
142 protected Collection<ISharedProperty> getSharedProperties(WorldObjectId objectId, ITeamId teamId, TimeKey time)
143 {
144 LinkedList<ISharedProperty> lst = new LinkedList<ISharedProperty>();
145 Set<PropertyId> set = syncCurrentSharedProperties.get(teamId).get(objectId).keySet();
146 for ( PropertyId propId : set)
147 {
148 lst.add( getSharedProperty(propId, teamId, time) );
149 }
150 return lst;
151 }
152
153
154
155
156
157
158
159
160
161
162
163 protected abstract ISharedWorldObject createSharedObject(Class msgClass, WorldObjectId id, ITeamId teamId, TimeKey time);
164
165 @Override
166 public ISharedWorldObject getShared(ITeamId teamId, WorldObjectId objectId, TimeKey time) {
167 ISharedWorldObject value = sharedWorldObjects.get(time, teamId, objectId);
168
169 if ( value != null )
170 {
171 return value;
172 }
173
174 Class msgClass = syncIdClassMap.get(objectId);
175 value = createSharedObject(msgClass, objectId, teamId, time);
176 if (value == null) {
177 throw new PogamutException("SharedObject for objectId=" + objectId + ", teamId = " + teamId + ", time = " + time + ", could not have been created, createSharedObject(objectId, teamId, time) returned null!", this);
178 }
179 sharedWorldObjects.put(time, teamId, objectId, value);
180 return value;
181 }
182
183 @Override
184 public IStaticWorldObject getStatic(WorldObjectId id) {
185 return staticWorldObjects.get(id);
186 }
187
188
189
190
191
192
193 protected void addStaticWorldObject(IStaticWorldObject object) {
194 synchronized(this.staticWorldObjects) {
195 this.staticWorldObjects.put(object.getId(), object);
196 }
197 }
198
199 protected void removeStaticWorldObject(WorldObjectId id) {
200 synchronized(this.staticWorldObjects) {
201 this.staticWorldObjects.remove(id);
202 }
203 }
204
205 protected void removeStaticWorldObject(IStaticWorldObject object) {
206 synchronized(this.staticWorldObjects) {
207 this.staticWorldObjects.remove(object.getId());
208 }
209 }
210
211
212
213
214
215
216 protected void addSharedProperty(ISharedProperty property, ITeamId teamId) {
217 synchronized(syncCurrentSharedProperties) {
218 syncCurrentSharedProperties.get(teamId).get(property.getObjectId()).put(property.getPropertyId(),property);
219 }
220 }
221
222
223
224
225
226 protected void addSharedProperty(ISharedProperty property) {
227 synchronized(syncCurrentSharedProperties) {
228 for ( ITeamId team : syncCurrentSharedProperties.keySet() ) {
229 this.addSharedProperty(property, team);
230 }
231 }
232 }
233
234 protected void removeSharedProperty(ISharedProperty property, ITeamId teamId) {
235 if (teamId == null) {
236 removeSharedProperty(property);
237 return;
238 }
239 synchronized(syncCurrentSharedProperties) {
240 this.syncCurrentSharedProperties.get(teamId).get(property.getObjectId()).remove(property.getPropertyId());
241 }
242 }
243
244 protected void removeSharedProperty(ISharedProperty property) {
245 synchronized(syncCurrentSharedProperties) {
246 for (ITeamId team : syncCurrentSharedProperties.keySet()) {
247 this.removeSharedProperty(property, team);
248 }
249 }
250 }
251
252
253
254
255
256 protected void addSharedWorldObject(ISharedWorldObject object) {
257 synchronized(syncCurrentSharedProperties) {
258 for ( ISharedProperty property : object.getProperties().values() ) {
259 addSharedProperty( property );
260 }
261 }
262 }
263
264
265
266
267
268
269
270
271 protected void addOldSharedProperty(ISharedProperty property, ITeamId teamId, long eventTime) {
272 for (Long t : TimeKeyManager.get().getHeldKeys())
273 {
274 if (t < eventTime)
275 {
276 TimeKey timeKey = TimeKey.get(t);
277 Map<PropertyId, ISharedProperty> props = sharedProperties.get(timeKey, teamId, property.getObjectId());
278 synchronized(props)
279 {
280 ISharedProperty old = props.get(property.getPropertyId());
281 if ( old == null)
282 {
283
284 props.put(property.getPropertyId(), property);
285 }
286 }
287 }
288 }
289 }
290
291
292
293
294 private static class ListenerNotifier<T> implements Listeners.ListenerNotifier<IListener> {
295
296
297
298
299 private T event = null;
300
301 @Override
302 public T getEvent() {
303 return event;
304 }
305
306 public void setEvent(T event) {
307 this.event = event;
308 }
309
310
311
312
313 @Override
314 public void notify(IListener listener) {
315 listener.notify(event);
316 }
317
318 }
319
320
321
322
323 private ListenerNotifier notifier = new ListenerNotifier();
324
325
326
327
328
329
330
331 private ListenersMap<Class> eventListeners = new ListenersMap<Class>();
332
333
334
335
336
337
338 private ListenersMap<Class> objectsListeners = new ListenersMap<Class>();
339
340
341
342
343
344
345
346
347 private Map<Class, ListenersMap<Class>> objectEventListeners =
348 Collections.synchronizedMap(
349 new LazyMap<Class, ListenersMap<Class>>(){
350
351 @Override
352 protected ListenersMap<Class> create(Class key) {
353 return new ListenersMap<Class>();
354 }
355 }
356 );
357
358
359
360
361
362
363 private ListenersMap<WorldObjectId> specificObjectListeners = new ListenersMap<WorldObjectId>();
364
365
366
367
368
369
370
371
372 private Map<WorldObjectId, ListenersMap<Class>> specificObjectEventListeners =
373 Collections.synchronizedMap(
374 new LazyMap<WorldObjectId, ListenersMap<Class>>() {
375
376 @Override
377 protected ListenersMap<Class> create(WorldObjectId key) {
378 return new ListenersMap<Class>();
379 }
380 }
381 );
382
383
384
385
386
387
388
389 private boolean raiseEventProcessing = false;
390
391
392
393
394
395
396 private Queue<IWorldEvent> raiseEventsList = new ConcurrentLinkedQueue<IWorldEvent>();
397
398 protected Logger log;
399
400 protected ISharedComponentController<ISharedWorldView> controller;
401
402 public AbstractSharedWorldView( Logger logger) {
403 this.log = logger;
404 this.controller = new SharedComponentController<ISharedWorldView>(this, control, logger);
405
406 this.eventListeners.setLog(log, "LevelA");
407 this.objectsListeners.setLog(log, "LevelB");
408 this.specificObjectListeners.setLog(log, "LevelD");
409 }
410
411
412
413
414
415
416
417 @Override
418 public void addComponentBus(IAgentId agentId, ILifecycleBus bus,
419 ComponentDependencies dependencies) {
420 this.controller.addComponentBus(agentId, bus, dependencies);
421
422 }
423
424 @Override
425 public void removeComponentBus(IAgentId agentId, ILifecycleBus bus) {
426 this.controller.removeComponentBus(agentId, bus);
427 }
428
429
430
431 protected ISharedComponentControlHelper control = new SharedComponentControlHelper() {
432
433 @Override
434 public void start() throws PogamutException {
435 AbstractSharedWorldView.this.start();
436 }
437
438 @Override
439 public void prePause() throws PogamutException {
440 AbstractSharedWorldView.this.prePause();
441 }
442
443 @Override
444 public void pause() throws PogamutException {
445 AbstractSharedWorldView.this.pause();
446 }
447
448 @Override
449 public void resume() throws PogamutException {
450 AbstractSharedWorldView.this.resume();
451 }
452
453 @Override
454 public void preStop() throws PogamutException {
455 AbstractSharedWorldView.this.preStop();
456 }
457
458 @Override
459 public void stop() throws PogamutException {
460 AbstractSharedWorldView.this.stop();
461 }
462
463 @Override
464 public void kill() {
465 AbstractSharedWorldView.this.kill();
466 }
467
468 @Override
469 public void reset() {
470 AbstractSharedWorldView.this.reset();
471 }
472
473 };
474
475
476
477
478
479
480 protected void cleanUp() {
481
482 synchronized( this.sharedProperties ) {
483 sharedProperties.clear();
484 }
485 synchronized(this.staticWorldObjects) {
486 staticWorldObjects.clear();
487 }
488 synchronized(this.sharedWorldObjects)
489 {
490 sharedWorldObjects.clear();
491 }
492 synchronized(raiseEventsList) {
493 raiseEventsList.clear();
494 }
495 }
496
497
498
499
500
501
502 protected void start() {
503 cleanUp();
504 }
505
506
507
508
509
510
511 protected void prePause() {
512 }
513
514
515
516
517
518
519 protected void pause() {
520 }
521
522
523
524
525
526
527 protected void resume() {
528 }
529
530
531
532
533
534
535 protected void preStop() {
536 }
537
538
539
540
541
542
543 protected void stop() {
544 cleanUp();
545 }
546
547
548
549
550
551
552 protected void kill() {
553 cleanUp();
554 }
555
556
557
558
559
560
561 protected void reset() {
562 cleanUp();
563 }
564
565 protected boolean isRunning() {
566 return controller.isRunning();
567 }
568
569 protected boolean isPaused() {
570 return controller.isPaused();
571 }
572
573 @Override
574 public Token getComponentId() {
575 return COMPONENT_ID;
576 }
577
578
579
580
581
582 @Override
583 public void addEventListener(Class<?> event, IWorldEventListener<?> listener) {
584 eventListeners.add(event, listener);
585 }
586
587 @Override
588 public void addObjectListener(Class<?> objectClass, IWorldObjectEventListener<?, ?> listener) {
589 objectsListeners.add(objectClass, listener);
590 }
591
592 @Override
593 public void addObjectListener(Class<?> objectClass, Class<?> eventClass, IWorldObjectEventListener<?,?> listener) {
594 ListenersMap<Class> listeners = objectEventListeners.get(eventClass);
595 listeners.add(objectClass, listener);
596 }
597
598 @Override
599 public void addObjectListener(WorldObjectId objectId, IWorldObjectEventListener<?, ?> listener) {
600 specificObjectListeners.add(objectId, listener);
601 }
602
603 @Override
604 public void addObjectListener(WorldObjectId objectId, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
605 ListenersMap<Class> listeners = specificObjectEventListeners.get(objectId);
606 listeners.add(eventClass, listener);
607 }
608
609 @Override
610 public boolean isListening(Class<?> eventClass, IWorldEventListener<?> listener) {
611 return eventListeners.isListening(eventClass, listener);
612 }
613
614 @Override
615 public boolean isListening(Class<?> objectClass, IWorldObjectEventListener<?, ?> listener) {
616 return objectsListeners.isListening(listener);
617 }
618
619
620 @Override
621 public boolean isListening(Class<?> objectClass, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
622 if (objectEventListeners.containsKey(objectClass)) {
623 return objectEventListeners.get(eventClass).isListening(objectClass, listener);
624 } else {
625 return false;
626 }
627 }
628
629 @Override
630 public boolean isListening(WorldObjectId objectId, IWorldObjectEventListener<?, ?> listener) {
631 return specificObjectListeners.isListening(objectId, listener);
632 }
633
634 @Override
635 public boolean isListening(WorldObjectId objectId, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
636 if (specificObjectEventListeners.containsKey(objectId)) {
637 return specificObjectEventListeners.get(objectId).isListening(eventClass, listener);
638 } else {
639 return false;
640 }
641
642 }
643
644 @Override
645 public boolean isListening(IWorldEventListener<?> listener) {
646 if (eventListeners.isListening(listener) ||
647 specificObjectListeners.isListening(listener)) {
648 return true;
649 }
650 synchronized(objectEventListeners) {
651 for (ListenersMap<Class> listeners : objectEventListeners.values()) {
652 if (listeners.isListening(listener)) return true;
653 }
654 }
655 synchronized(specificObjectEventListeners) {
656 for (ListenersMap<Class> listeners : specificObjectEventListeners.values()) {
657 if (listeners.isListening(listener)) return true;
658 }
659 }
660 return false;
661 }
662
663 @Override
664 public void removeEventListener(Class<?> eventClass, IWorldEventListener<?> listener) {
665 eventListeners.remove(eventClass, listener);
666 }
667
668 @Override
669 public void removeObjectListener(Class<?> objectClass, IWorldObjectEventListener<?, ?> listener) {
670 objectsListeners.remove(objectClass, listener);
671 }
672
673 @Override
674 public void removeObjectListener(Class<?> objectClass, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
675 if (objectEventListeners.containsKey(eventClass)) {
676 objectEventListeners.get(eventClass).remove(objectClass, listener);
677 }
678 }
679
680 @Override
681 public void removeObjectListener(WorldObjectId objectId, IWorldObjectEventListener<?, ?> listener) {
682 specificObjectListeners.remove(objectId, listener);
683 }
684
685 @Override
686 public void removeObjectListener(WorldObjectId objectId, Class<?> eventClass, IWorldObjectEventListener<?, ?> listener) {
687 if (specificObjectEventListeners.containsKey(objectId)) {
688 specificObjectEventListeners.get(objectId).remove(eventClass, listener);
689 }
690 }
691
692
693 @Override
694 public void removeListener(IWorldEventListener<?> listener) {
695 eventListeners.remove(listener);
696 synchronized(objectEventListeners) {
697 for (ListenersMap<Class> listeners : objectEventListeners.values()) {
698 listeners.remove(listener);
699 }
700 }
701 specificObjectListeners.remove(listener);
702 specificObjectEventListeners.remove(listener);
703 }
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719 protected synchronized void raiseEvent(IWorldEvent event) {
720
721
722
723 if (raiseEventProcessing) {
724
725
726
727 raiseEventsList.add(event);
728 return;
729 } else {
730
731 raiseEventProcessing = true;
732 }
733
734
735 innerRaiseEvent(event);
736
737
738 while(raiseEventsList.size() != 0) {
739
740 innerRaiseEvent(raiseEventsList.poll());
741 }
742
743 raiseEventProcessing = false;
744 }
745
746
747
748
749
750
751
752
753
754
755
756 private void notifyLevelAListeners(IWorldEvent event) {
757 Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
758 notifier.setEvent(event);
759 for (Class eventClass : eventClasses) {
760 eventListeners.notify(eventClass, notifier);
761 }
762 }
763
764
765
766
767
768 private void notifyLevelBListeners(IWorldObjectEvent event) {
769 IWorldObject object = event.getObject();
770 Collection<Class> objectClasses = ClassUtils.getSubclasses(object.getClass());
771 notifier.setEvent(event);
772 for (Class objectClass : objectClasses) {
773 objectsListeners.notify(objectClass, notifier);
774 }
775 }
776
777
778
779
780
781
782 private void notifyLevelCListeners(IWorldObjectEvent event) {
783 Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
784 Collection<Class> objectClasses = ClassUtils.getSubclasses(event.getObject().getClass());
785 notifier.setEvent(event);
786 for (Class eventClass : eventClasses) {
787 ListenersMap<Class> listeners = objectEventListeners.get(eventClass);
788 if (listeners == null) continue;
789 if (!listeners.hasListeners()) continue;
790 for (Class objectClass : objectClasses) {
791 listeners.notify(objectClass, notifier);
792 }
793 }
794 }
795
796
797
798
799
800 private void notifyLevelDListeners(IWorldObjectEvent event) {
801 notifier.setEvent(event);
802 specificObjectListeners.notify(event.getId(), notifier);
803 }
804
805
806
807
808
809 private void notifyLevelEListeners(IWorldObjectEvent event) {
810 notifier.setEvent(event);
811 WorldObjectId objectId = event.getId();
812 ListenersMap<Class> listeners = specificObjectEventListeners.get(objectId);
813 if (listeners.hasListeners()) {
814 Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
815 notifier.setEvent(event);
816 for (Class eventClass : eventClasses) {
817 listeners.notify(eventClass, notifier);
818 }
819 }
820 }
821
822
823
824
825
826
827
828
829 private void innerRaiseEvent(IWorldEvent event) {
830 if (log.isLoggable(Level.FINEST)) log.finest("notifying " + event);
831 notifyLevelAListeners(event);
832 if (event instanceof IWorldObjectEvent) {
833
834 IWorldObjectEvent objectEvent = (IWorldObjectEvent)event;
835 notifyLevelBListeners(objectEvent);
836 notifyLevelCListeners(objectEvent);
837 notifyLevelDListeners(objectEvent);
838 notifyLevelEListeners(objectEvent);
839 }
840 }
841 }