1 package cz.cuni.amis.pogamut.base3d.worldview.impl;
2
3 import java.util.ArrayList;
4 import java.util.LinkedList;
5 import java.util.List;
6 import java.util.Queue;
7 import java.util.concurrent.CountDownLatch;
8
9 import com.google.inject.Inject;
10 import com.google.inject.name.Named;
11
12 import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldChangeEvent;
13 import cz.cuni.amis.pogamut.base.communication.worldview.ILockableWorldView;
14 import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
15 import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
16 import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
17 import cz.cuni.amis.utils.exception.PogamutInterruptedException;
18 import java.util.logging.Level;
19
20 public abstract class SyncLockableBatchAwareWorldView extends BatchAwareWorldView implements ILockableWorldView {
21
22 public static final String WORLDVIEW_DEPENDENCY = "SyncLockableBatchAwareWorldView";
23
24
25
26
27 private Queue<List<IWorldChangeEvent>> batches = new LinkedList<List<IWorldChangeEvent>>();
28
29
30
31
32 private List<IWorldChangeEvent> currentBatch = new ArrayList<IWorldChangeEvent>();
33
34
35
36
37 private boolean locked = false;
38
39
40
41
42
43
44 private boolean inLock = false;
45
46
47
48
49 private boolean beginCame = false;
50
51
52
53
54 private final Object objectMutex = new Object();
55
56
57
58
59 private CountDownLatch lockLatch = new CountDownLatch(1);
60
61
62
63
64 private boolean stopRequested = false;
65
66 @Inject
67 public SyncLockableBatchAwareWorldView(@Named(WORLDVIEW_DEPENDENCY) ComponentDependencies dependencies, IComponentBus bus, IAgentLogger log) {
68 super(dependencies, bus, log);
69 }
70
71
72
73
74
75
76 public void lock() throws PogamutInterruptedException {
77 synchronized (objectMutex) {
78 if (isLocked())
79 return;
80 locked = true;
81 if (log.isLoggable(Level.FINER)) log.finer("World view locked.");
82 }
83 try {
84 lockLatch.await();
85 } catch (InterruptedException e) {
86 throw new PogamutInterruptedException(e.getMessage(), e, log, this);
87 }
88 if (stopRequested) {
89 throw new PogamutInterruptedException(
90 "lock() interrupted with the request to stop the work", log, this);
91 }
92 }
93
94
95
96
97
98 public void unlock() {
99 synchronized (objectMutex) {
100 if (!isLocked())
101 return;
102 if (log.isLoggable(Level.FINER)) log.finer("World view is being unlocked.");
103 locked = false;
104 inLock = false;
105 processBatches();
106 if (log.isLoggable(Level.FINER)) log.finer("World view unlocked.");
107
108 lockLatch = new CountDownLatch(1);
109 }
110 }
111
112 public boolean isLocked() {
113 return locked;
114 }
115
116 public boolean isInLock() {
117 return inLock;
118 }
119
120
121
122
123
124
125
126 private void processBatches() {
127
128 for (List<IWorldChangeEvent> batch : batches) {
129 processBatch(batch);
130 }
131 batches.clear();
132
133 processBatch(currentBatch);
134 }
135
136
137
138
139
140
141
142
143
144 private void processBatch(List<IWorldChangeEvent> batch) {
145 for (IWorldChangeEvent event : batch) {
146 super.notify(event);
147 }
148 batch.clear();
149 }
150
151
152
153
154 @Override
155 public void notify(IWorldChangeEvent event) {
156 synchronized (objectMutex) {
157 if (!beginCame) {
158 if (isBatchBeginEvent(event)) {
159 beginCame = true;
160 } else {
161 super.notify(event);
162 return;
163 }
164 }
165 if (isLocked()) {
166 if (isInLock()) {
167
168
169 if (isBatchEndEvent(event)) {
170 currentBatch.add(event);
171 batches.add(currentBatch);
172 currentBatch = new ArrayList<IWorldChangeEvent>(
173 currentBatch.size() + 10
174 );
175 } else {
176 currentBatch.add(event);
177 }
178 } else {
179
180 if (isBatchEndEvent(event)) {
181
182 super.notify(event);
183
184 if (log.isLoggable(Level.FINER)) log.finer("World view in-locked state, raising the lock() latch.");
185 lockLatch.countDown();
186 inLock = true;
187 } else {
188
189 super.notify(event);
190 }
191 }
192 } else {
193 super.notify(event);
194 }
195 }
196 }
197
198 @Override
199 public void stop() {
200 super.stop();
201 synchronized (objectMutex) {
202 stopRequested = true;
203 lockLatch.countDown();
204 }
205 }
206
207 }