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.exception.ComponentNotRunningException;
15  import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
16  import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
17  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
18  import cz.cuni.amis.pogamut.base3d.ILockableVisionWorldView;
19  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BeginMessage;
20  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
21  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
22  
23  import java.util.logging.Level;
24  
25  /**
26   * Lockable word view.
27   * <p><p>
28   * Contains GameBots2004 correct locking of the worldview.
29   * <p><p>
30   * All messages are processed always in batches (all messages between EndMessages are one batch) meaning that the world view is always 
31   * correct!
32   * <p><p>
33   * When worldview is lock()ed it postpones the events until unlock()ed, which is triggering
34   * raising all events that came from the lock().
35   * <p><p>
36   * The world view is unlocked from the beginning.
37   * <p><p>
38   * All those locking mechanisms start working when the first BEGIN message comes. 
39   * 
40   * @author Jimmy
41   */
42  @AgentScoped
43  public class UT2004LockableWorldView extends UT2004WorldView implements ILockableVisionWorldView {
44  	
45  	public static final String WORLDVIEW_DEPENDENCY = "UT2004LockableWorldViewDependency";
46  	
47  	/**
48  	 * Here we store batches that are complete (ends with the EndMessage).
49  	 */
50  	private Queue<List<IWorldChangeEvent>> batches = new LinkedList<List<IWorldChangeEvent>>();
51  	
52  	/**
53  	 * Here we store new events that are coming from the Mediator.
54  	 */
55  	private List<IWorldChangeEvent> currentBatch = new ArrayList<IWorldChangeEvent>();
56  	
57  	/**
58  	 * Whether the world view is locked.
59  	 */
60  	private boolean locked = false;
61  	
62  	/**
63  	 * First BEG message 
64  	 */
65  	private boolean beginCame = false;
66  	
67  	/**
68  	 * Synchronization mutex for this class.
69  	 */
70  	private final Object objectMutex = new Object();
71  	
72      @Inject
73      public UT2004LockableWorldView(@Named(WORLDVIEW_DEPENDENCY) ComponentDependencies dependencies, IMediator mediator, IComponentBus bus, IAgentLogger log) {
74          super(dependencies, mediator, bus, log);
75      }
76  	
77  	/**
78  	 * When the world view is locked - no batches are processes until unlocked.
79  	 */
80  	public void lock() throws ComponentNotRunningException {
81  		if (!isRunning()) throw new ComponentNotRunningException(controller.getState().getFlag(), this);
82  		synchronized(objectMutex) {
83  			if (isLocked()) return;
84  			locked = true;
85  			if (log.isLoggable(Level.FINER)) log.finer("World view locked.");
86  		}
87  	}
88  	
89  	/**
90  	 * Unlocks the world view - triggers processing of all events till the last EndMessage that
91  	 * came between lock() / unlock() calls.
92  	 */
93  	public void unlock() throws ComponentNotRunningException {
94  		synchronized(objectMutex) {
95  			if (!isLocked()) return;
96  			if (log.isLoggable(Level.FINER)) log.finer("World view is being unlocked.");
97  			locked = false;
98  			for (List<IWorldChangeEvent> batch : batches) {
99  				processBatch(batch);
100 			}
101 			batches.clear();			
102 			if (log.isLoggable(Level.FINER)) log.finer("World view unlocked.");
103 		}
104 	}
105 	
106 	public boolean isLocked() {
107 		return locked;
108 	}
109 	
110 	public boolean hasBatchesToProcess() {
111 		return !batches.isEmpty();
112 	}	
113 	
114 	/**
115 	 * Does super.notifyEvent(event) for each event in the batch. 
116 	 * <p><p>
117 	 * <b>Unsync!</b>
118 	 * @param batch
119 	 */
120 	private void processBatch(List<IWorldChangeEvent> batch) {
121 		for (IWorldChangeEvent event : batch) {
122 			super.notify(event);
123 		}		
124 	}
125 	
126 	/**
127 	 * Implements locking logic.
128 	 */
129     @Override
130 	public void notify(IWorldChangeEvent event) {
131     	
132     	
133     	if (!isRunning()) throw new ComponentNotRunningException(controller.getState().getFlag(), this);
134 		synchronized(objectMutex) {
135 			if (!beginCame) {
136 				if (event instanceof BeginMessage) {
137 					beginCame = true;
138 				} else {
139 					super.notify(event);
140 					return;
141 				}
142 			}
143 			if (isLocked()) {
144 				if (event instanceof EndMessage) {
145 					currentBatch.add(event);
146 					batches.add(currentBatch);
147 					currentBatch = new ArrayList<IWorldChangeEvent>(currentBatch.size()+20);
148 				} else {
149 					currentBatch.add(event);				
150 				}
151 			} else {
152 				if (event instanceof EndMessage) {
153 					currentBatch.add(event);
154 					processBatch(currentBatch);
155 					currentBatch.clear();
156 				} else {
157 					currentBatch.add(event);
158 				}
159 			}
160 		}
161 	}
162 
163 
164 }