View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.communication.worldview;
2   
3   import java.util.ArrayList;
4   import java.util.LinkedList;
5   import java.util.List;
6   import java.util.Queue;
7   
8   import com.google.inject.Inject;
9   import com.google.inject.name.Named;
10  
11  import cz.cuni.amis.pogamut.base.communication.mediator.IMediator;
12  import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldChangeEvent;
13  import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
14  import cz.cuni.amis.pogamut.base.component.bus.event.BusAwareCountDownLatch;
15  import cz.cuni.amis.pogamut.base.component.bus.exception.ComponentNotRunningException;
16  import cz.cuni.amis.pogamut.base.component.bus.exception.ComponentPausedException;
17  import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
18  import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
19  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
20  import cz.cuni.amis.pogamut.base3d.ILockableVisionWorldView;
21  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BeginMessage;
22  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
23  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
24  import cz.cuni.amis.utils.exception.PogamutInterruptedException;
25  import java.util.logging.Level;
26  
27  /**
28   * Lockable word view.
29   * <p>
30   * <p>
31   * Contains GameBots2004 correct locking of the worldview.
32   * <p>
33   * <p>
34   * All messages are processed always in batches (all messages between
35   * EndMessages are one batch) meaning that the world view is always correct!
36   * <p>
37   * <p>
38   * When worldview is lock()ed it postpones the events until unlock()ed, which is
39   * triggering raising all events that came from the lock().
40   * <p>
41   * <p>
42   * <b>lock() method here blocks</b> until the END message of the batch is hit,
43   * then the world view is considered to be fully locked and let the lock()
44   * continue. You may use it to create correct sync bot. (just lock() the world
45   * view before your logic and unlock() the world view after the logic finishes)
46   * <p>
47   * <p>
48   * The world view is unlocked from the beginning.
49   * <p>
50   * <p>
51   * The locking mechanism starts to work with the first BeginMessage. (To let all
52   * other events to be processed automatically during the handshake.)
53   * 
54   * @author Jimmy
55   *         <p>
56   *         <p>
57   * 
58   * 
59   * @author Jimmy
60   * @see UT2004LockableWorldView
61   */
62  @AgentScoped
63  public class UT2004SyncLockableWorldView extends UT2004WorldView
64  		implements ILockableVisionWorldView {
65  
66  	public static final String WORLDVIEW_DEPENDENCY = "UT2004SyncLockableWorldViewDependency";
67  
68  	/**
69  	 * Here we store batches that are complete (ends with the EndMessage).
70  	 */
71  	private Queue<List<IWorldChangeEvent>> batches = new LinkedList<List<IWorldChangeEvent>>();
72  
73  	/**
74  	 * Here we store new events that are coming from the Mediator.
75  	 */
76  	private List<IWorldChangeEvent> currentBatch = new ArrayList<IWorldChangeEvent>();
77  
78  	/**
79  	 * Whether the world view is locked.
80  	 */
81  	private boolean locked = false;
82  
83  	/**
84  	 * First the world view will become locked, when the next END message is
85  	 * received, it will raise this flag meaning the lock() succeeded (the
86  	 * lockLatch has been raised) and we have to buffer all new messages.
87  	 */
88  	private boolean inLock = false;
89  
90  	/**
91  	 * First BEG message
92  	 */
93  	private boolean beginCame = false;
94  
95  	/**
96  	 * Synchronization mutex for this class.
97  	 */
98  	private final Object objectMutex = new Object();
99  
100 	/**
101 	 * lock() waits on this latch to continue...
102 	 */
103 	private BusAwareCountDownLatch lockLatch;
104 
105 	/**
106 	 * Whether the stop() method has been called.
107 	 */
108 	private boolean stopRequested = false;
109 	
110 	/**
111 	 * Whether the pause() method has been called.
112 	 */
113 	private boolean pauseRequested = false;
114 
115 	@Inject
116 	public UT2004SyncLockableWorldView(
117 			@Named(WORLDVIEW_DEPENDENCY) ComponentDependencies dependencies,
118 			IMediator mediator,
119 			IComponentBus bus, IAgentLogger log) {
120 		super(dependencies, mediator, bus, log);		
121 	}
122 
123 	/**
124 	 * When the world view is locked - no batches are processes until unlocked.
125 	 * 
126 	 * @throws PogamutInterruptedException
127 	 */
128 	public void lock() throws PogamutInterruptedException, ComponentNotRunningException {
129 		if (isPaused()) throw new ComponentPausedException(controller.getState().getFlag(), this);
130 		if (!isRunning()) throw new ComponentNotRunningException(controller.getState().getFlag(), this);
131 		synchronized (objectMutex) {
132 			if (isLocked())
133 				return;
134 			locked = true;
135 			if (log.isLoggable(Level.FINER)) log.finer("World view is being locked.");
136 		}
137 		if (isPaused()) {
138 			if (log.isLoggable(Level.FINER)) log.finer("World view paused, unlocking.");
139 			locked = false;
140 			throw new ComponentPausedException(controller.getState().getFlag(), this);
141 		}
142 		if (!isRunning()) {
143 			if (log.isLoggable(Level.FINER)) log.finer("World view not running, unlocking.");
144 			locked = false;
145 			throw new ComponentNotRunningException(controller.getState().getFlag(), this);
146 		}
147 		lockLatch.await();
148 		if (log.isLoggable(Level.FINER)) log.finer("World view locked.");
149 		if (pauseRequested) { 
150 			throw new ComponentPausedException("Component pause requested.", this);
151 		}
152 		if (stopRequested) {
153 			throw new ComponentNotRunningException("Component stop requested.", this);
154 		}
155 	}
156 
157 	/**
158 	 * Unlocks the world view - triggers processing of all events till the last
159 	 * EndMessage that came between lock() / unlock() calls.
160 	 */
161 	public void unlock() throws ComponentNotRunningException {
162 		synchronized (objectMutex) {
163 			if (!isLocked())
164 				return;
165 			locked = false;
166 			if (log.isLoggable(Level.FINER)) log.finer("World view is being unlocked.");
167 			inLock = false;
168 			processBatches();
169 			if (log.isLoggable(Level.FINER)) log.finer("World view unlocked.");
170 			// reinitialize the lock latch so the next lock() blocks as well
171 			lockLatch = new BusAwareCountDownLatch(1, eventBus, this);
172 		}
173 	}
174 
175 	public boolean isLocked() {
176 		return locked;
177 	}
178 
179 	public boolean isInLock() {
180 		return inLock;
181 	}
182 
183 	/**
184 	 * Process all messages that are stored inside the batches and clears them.
185 	 * <p><p>
186 	 * <b>Unsync!</b>
187 	 */
188 	private void processBatches() {
189 		// process old batches
190 		for (List<IWorldChangeEvent> batch : batches) {
191 			processBatch(batch);
192 		}
193 		batches.clear();
194 		// process current opened batch
195 		processBatch(currentBatch);
196 	}
197 
198 	/**
199 	 * Does super.notifyEvent(event) for each event in the batch.
200 	 * <p>
201 	 * <p>
202 	 * <b>Unsync!</b>
203 	 * 
204 	 * @param batch
205 	 */
206 	private void processBatch(List<IWorldChangeEvent> batch) {
207 		for (IWorldChangeEvent event : batch) {
208 			super.notify(event);
209 		}
210 		batch.clear();
211 	}
212 
213 	/**
214 	 * Implements locking logic.
215 	 */
216 	@Override
217 	public void notify(IWorldChangeEvent event) {
218 
219             /* Guys if you have to log something that will cause performance problems - comment it before commiting, thanks.
220 		if ( event instanceof Player )
221 		{
222 			System.out.println("PLAYER EVENT : " + event.toString());
223 		}
224 		if ( event instanceof BeginMessage )
225 		{
226 			System.out.println("Begin message : " + event.toString());
227 		}
228             */
229 		synchronized (objectMutex) {
230 			if (!beginCame) {
231 				if (event instanceof BeginMessage) {
232 					beginCame = true;
233 				} else {
234 					super.notify(event);
235 					return;
236 				}
237 			}
238 			if (isLocked()) {
239 				if (isInLock()) {
240 					// we're IN LOCK - logic is running, do not process any new
241 					// message
242 					if (event instanceof EndMessage) {
243 						currentBatch.add(event);
244 						batches.add(currentBatch);
245 						currentBatch = new ArrayList<IWorldChangeEvent>(
246 								currentBatch.size() + 10);
247 					} else {
248 						currentBatch.add(event);
249 					}
250 				} else {
251 					// we're waiting for the next EndMessage
252 					if (event instanceof EndMessage) {
253 						// EndMessage came! Notify...
254 						super.notify(event);
255 						// ... raise the latch and let the logic continue!
256 						if (log.isLoggable(Level.FINER)) log.finer("World view in-locked state, raising the lock() latch.");
257 						lockLatch.countDown();
258 						inLock = true;
259 					} else {
260 						// not an EndMessage, process as usual
261 						super.notify(event);
262 					}
263 				}
264 			} else {
265 				super.notify(event);
266 			}
267 		}
268 	}
269 	
270 	@Override
271 	protected void start(boolean startPaused) {
272 		super.start(startPaused);
273 		lockLatch = new BusAwareCountDownLatch(1, eventBus, this);
274 		stopRequested = false;
275 		pauseRequested = false;
276 	}
277 
278 	@Override
279 	protected void preStop() {
280 		super.preStop();
281 		synchronized (objectMutex) {
282 			stopRequested = true;
283 			lockLatch.countDown();
284 		}
285 	}
286 	
287 	@Override
288 	protected void prePause() {
289 		super.preStop();
290 		synchronized (objectMutex) {
291 			pauseRequested = true;
292 			lockLatch.countDown();
293 		}
294 	}
295 	
296 	@Override
297 	protected void resume() {
298 		super.resume();
299 		synchronized(objectMutex) {
300 			lockLatch.countDown();
301 			lockLatch = new BusAwareCountDownLatch(1, eventBus, this);
302 			pauseRequested = false;
303 		}
304 	}
305 	
306 	@Override
307 	protected void stop() {
308 		super.stop();
309 		synchronized (objectMutex) {
310 			stopRequested = true;
311 			lockLatch.countDown();
312 		}
313 	}
314 
315 }