View Javadoc

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   
8   import com.google.inject.name.Named;
9   
10  import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldChangeEvent;
11  import cz.cuni.amis.pogamut.base.communication.worldview.ILockableWorldView;
12  import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
13  import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
14  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
15  import java.util.logging.Level;
16  
17  public abstract class LockableBatchAwareWorldView extends BatchAwareWorldView implements ILockableWorldView {
18  
19  	public static final String WORLDVIEW_DEPENDENCY = "LockableBatchAwareWorldView";
20  	
21  	/**
22  	 * Here we store batches that are complete (ends with the EndMessage).
23  	 */
24  	private Queue<List<IWorldChangeEvent>> batches = new LinkedList<List<IWorldChangeEvent>>();
25  	
26  	/**
27  	 * Here we store new events that are coming from the Mediator.
28  	 */
29  	private List<IWorldChangeEvent> currentBatch = new ArrayList<IWorldChangeEvent>();
30  	
31  	/**
32  	 * Whether the world view is locked.
33  	 */
34  	private boolean locked = false;
35  	
36  	/**
37  	 * First BEG message 
38  	 */
39  	private boolean beginCame = false;
40  	
41  	/**
42  	 * Synchronization mutex for this class.
43  	 */
44  	private final Object objectMutex = new Object();
45  
46  	public LockableBatchAwareWorldView(@Named(WORLDVIEW_DEPENDENCY) ComponentDependencies dependencies, IComponentBus bus, IAgentLogger log) {
47          super(dependencies, bus, log);
48  	}
49  	
50  	/**
51       * Is this event a batch begin event? It is needed for the locking to be working correctly.
52       * @param evt
53       * @return true if this is a batch ending event
54       */
55      protected abstract boolean isBatchBeginEvent(IWorldChangeEvent evt);
56  
57  	/**
58  	 * When the world view is locked - no batches are processes until unlocked.
59  	 */
60  	public void lock() {
61  		synchronized(objectMutex ) {
62  			if (isLocked()) return;
63  			locked = true;
64  			if (log.isLoggable(Level.FINER)) log.finer("World view locked.");
65  		}
66  	}
67  	
68  	/**
69  	 * Unlocks the world view - triggers processing of all events till the last EndMessage that
70  	 * came between lock() / unlock() calls.
71  	 */
72  	public void unlock() {
73  		synchronized(objectMutex) {
74  			if (!isLocked()) return;
75  			if (log.isLoggable(Level.FINER)) log.finer("World view is being unlocked.");
76  			locked = false;
77  			for (List<IWorldChangeEvent> batch : batches) {
78  				processBatch(batch);
79  			}
80  			batches.clear();			
81  			if (log.isLoggable(Level.FINER)) log.finer("World view unlocked.");
82  		}
83  	}
84  	
85  	public boolean isLocked() {
86  		return locked;
87  	}
88  	
89  	/**
90  	 * Does super.notifyEvent(event) for each event in the batch. 
91  	 * <p><p>
92  	 * <b>Unsync!</b>
93  	 * @param batch
94  	 */
95  	private void processBatch(List<IWorldChangeEvent> batch) {
96  		for (IWorldChangeEvent event : batch) {
97  			super.notify(event);
98  		}		
99  	}
100 	
101 	/**
102 	 * Implements locking logic.
103 	 */
104 	@Override
105 	public void notify(IWorldChangeEvent event) {
106 		synchronized(objectMutex) {
107 			if (!beginCame ) {
108 				if (isBatchBeginEvent(event)) {
109 					beginCame = true;
110 				} else {
111 					super.notify(event);
112 					return;
113 				}
114 			}
115 			if (isLocked()) {
116 				if (isBatchEndEvent(event)) {
117 					currentBatch .add(event);
118 					batches.add(currentBatch);
119 					currentBatch = new ArrayList<IWorldChangeEvent>(currentBatch.size()+20);
120 				} else {
121 					currentBatch.add(event);				
122 				}
123 			} else {
124 				if (isBatchEndEvent(event)) {
125 					currentBatch.add(event);
126 					processBatch(currentBatch);
127 					currentBatch.clear();
128 				} else {
129 					currentBatch.add(event);
130 				}
131 			}
132 		}
133 	}
134 	
135 }