1 package cz.cuni.amis.pogamut.base.communication.worldview.object;
2
3 import java.util.Map;
4 import java.util.concurrent.ExecutionException;
5 import java.util.concurrent.Future;
6 import java.util.concurrent.TimeUnit;
7
8 import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
9 import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectDestroyedEvent;
10 import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectFirstEncounteredEvent;
11 import cz.cuni.amis.pogamut.base.component.bus.event.BusAwareCountDownLatch;
12 import cz.cuni.amis.utils.exception.PogamutException;
13
14
15
16
17
18
19 public class WorldObjectFuture<T extends IWorldObject> implements Future<T> {
20
21 public static class WorldObjectFutureException extends PogamutException {
22
23 public WorldObjectFutureException(String message, Object origin) {
24 super(message, origin);
25 }
26
27 }
28
29 private final IWorldView worldView;
30 private final Class<T> objectClass;
31
32 private T worldObject = null;
33 private BusAwareCountDownLatch latch;
34 private IWorldObjectListener<T> listener = null;
35 private boolean cancelled = false;
36
37
38
39
40
41
42
43 @SuppressWarnings("unchecked")
44 public WorldObjectFuture(final IWorldView worldView, final Class<T> objectClass) {
45 this.worldView = worldView;
46 this.objectClass = objectClass;
47 Map<WorldObjectId, T> objects = worldView.getAll(objectClass);
48 switch (objects.size()) {
49 case 0:
50 latch = new BusAwareCountDownLatch(1, worldView.getEventBus(), worldView);
51 worldView.addObjectListener(
52 objectClass,
53 IWorldObjectEvent.class,
54 listener = new IWorldObjectListener<T>() {
55 @Override
56 public void notify(IWorldObjectEvent<T> event) {
57 if (event instanceof WorldObjectDestroyedEvent) return;
58 worldObject = event.getObject();
59 worldView.removeObjectListener(objectClass, IWorldObjectEvent.class, this);
60 customObjectEncounteredHook(worldObject);
61 latch.countDown();
62 }
63 }
64 );
65 objects = worldView.getAll(objectClass);
66 switch (objects.size()) {
67 case 0:
68 break;
69 case 1:
70 worldView.removeObjectListener(objectClass, IWorldObjectEvent.class, listener);
71 worldObject = objects.values().iterator().next();
72 latch.countDown();
73 break;
74 case 2:
75 if (worldObject != null) return;
76 worldView.removeObjectListener(objectClass, IWorldObjectEvent.class, listener);
77 latch.countDown();
78 throw new WorldObjectFutureException("There are already " + objects.size() + " objects in world view of class " + objectClass.getSimpleName() + ".", this);
79 }
80 break;
81 case 1:
82 latch = new BusAwareCountDownLatch(0, worldView.getEventBus(), worldView);
83 worldObject = objects.values().iterator().next();
84 customObjectEncounteredHook(worldObject);
85 break;
86 default:
87 throw new WorldObjectFutureException("There are already " + objects.size() + " objects in world view of class " + objectClass.getSimpleName() + ".", this);
88 }
89 }
90
91
92
93
94
95
96
97
98 @SuppressWarnings("unchecked")
99 public WorldObjectFuture(final IWorldView worldView, final String id, final Class<T> objectClass) {
100 this.worldView = worldView;
101 this.objectClass = objectClass;
102
103 IWorldObject o = worldView.get(WorldObjectId.get(id));
104 if (o != null) {
105 this.worldObject = (T) o;
106 latch = new BusAwareCountDownLatch(0, worldView.getEventBus(), worldView);
107 } else {
108 latch = new BusAwareCountDownLatch(1, worldView.getEventBus(), worldView);
109 worldView.addObjectListener(
110 objectClass,
111 IWorldObjectEvent.class,
112 listener = new IWorldObjectListener<T>() {
113
114 @Override
115 public void notify(IWorldObjectEvent<T> event) {
116 if (event instanceof WorldObjectDestroyedEvent) return;
117 if (event.getObject().getId().getStringId().equals(id)) {
118 worldObject = event.getObject();
119 worldView.removeObjectListener(objectClass, IWorldObjectEvent.class, this);
120 latch.countDown();
121 customObjectEncounteredHook(worldObject);
122 }
123 }
124 }
125 );
126
127 o = worldView.get(WorldObjectId.get(id));
128 if (o != null) {
129 worldView.removeObjectListener(objectClass, WorldObjectFirstEncounteredEvent.class, listener);
130 latch.countDown();
131 }
132 }
133 }
134
135
136
137
138
139 protected void customObjectEncounteredHook(T obj) {
140 }
141
142 @Override
143 public synchronized boolean cancel(boolean mayInterruptIfRunning) {
144 if (latch != null) latch.countDown();
145 cancelled = true;
146 worldView.removeObjectListener(objectClass, IWorldObjectEvent.class, listener);
147 return true;
148 }
149
150 @Override
151 public synchronized boolean isCancelled() {
152 return cancelled;
153 }
154
155 @Override
156 public boolean isDone() {
157 return worldObject != null;
158 }
159
160
161
162
163
164
165 @Override
166 public T get() {
167 latch.await();
168 return worldObject;
169 }
170
171 @Override
172 public T get(long timeout, TimeUnit unit) {
173 latch.await(timeout, unit);
174 return worldObject;
175 }
176 }