View Javadoc

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