View Javadoc

1   package cz.cuni.amis.pogamut.base3d.worldview.impl;
2   
3   import java.util.Collections;
4   import java.util.HashMap;
5   import java.util.Map;
6   
7   import com.google.inject.name.Named;
8   
9   import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldObjectUpdateResult;
10  import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldObjectUpdatedEvent;
11  import cz.cuni.amis.pogamut.base.communication.worldview.impl.EventDrivenWorldView;
12  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObject;
13  import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectId;
14  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectDestroyedEvent;
15  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectFirstEncounteredEvent;
16  import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
17  import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
18  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
19  import cz.cuni.amis.pogamut.base3d.worldview.IVisionWorldView;
20  import cz.cuni.amis.pogamut.base3d.worldview.object.IViewable;
21  import cz.cuni.amis.pogamut.base3d.worldview.object.event.WorldObjectAppearedEvent;
22  import cz.cuni.amis.pogamut.base3d.worldview.object.event.WorldObjectDisappearedEvent;
23  import cz.cuni.amis.utils.ClassUtils;
24  import cz.cuni.amis.utils.exception.PogamutException;
25  import cz.cuni.amis.utils.maps.HashMapMap;
26  
27  public class VisionWorldView extends EventDrivenWorldView implements IVisionWorldView {
28  	
29  	public static final String WORLDVIEW_DEPENDENCY = "VisionWorldViewDependency";
30  	
31  	/**
32  	 * Unsynchronized map that holds all visible world objects according to their type
33  	 * in the maps.
34  	 * <p><p>
35  	 * Due to nature of generics we can't typed this field, it holds maps of objects
36  	 * according to their classes. 
37  	 * <p>
38  	 * Map &lt; Class, Map &lt; IWorldObjectId, IWorldObject of Class &gt; &gt;
39  	 */
40  	private HashMapMap<Class, WorldObjectId, IViewable> worldVisibleObjects = 
41  		new HashMapMap<Class, WorldObjectId, IViewable>();
42  	
43  	/**
44  	 * Synchronized version of world visible objects.
45  	 */
46  	private Map<Class, Map<WorldObjectId, IViewable>> syncWorldVisibleObjects = 
47  		Collections.synchronizedMap(worldVisibleObjects);
48  			
49  	/**
50  	 * Synchronized map of all visible world objects that are present in the worldview.
51  	 */
52  	private Map<WorldObjectId, IViewable> visibleObjects =
53  		Collections.synchronizedMap(new HashMap<WorldObjectId, IViewable>());
54  
55  	public VisionWorldView(@Named(WORLDVIEW_DEPENDENCY) ComponentDependencies dependencies, IComponentBus bus, IAgentLogger log) {
56  		super(dependencies, bus, log);
57  	}
58  	
59  	@Override
60  	protected void cleanUp() {
61  		super.cleanUp();
62  		synchronized(worldVisibleObjects) {
63  			worldVisibleObjects.clear();
64  		}
65  		synchronized(visibleObjects) {
66  			visibleObjects.clear();
67  		}
68  		synchronized(notifyEventsList) {
69  			notifyEventsList.clear();
70  		}
71  	}
72  	
73  	@Override
74  	public Map<Class, Map<WorldObjectId, IViewable>> getAllVisible() {
75  		return syncWorldVisibleObjects;
76  	}
77  
78  	@SuppressWarnings("unchecked")
79  	@Override
80  	public <T extends IViewable> Map<WorldObjectId, T> getAllVisible(Class<T> type) {
81  		return (Map<WorldObjectId, T>) syncWorldVisibleObjects.get(type);
82  	}
83  
84  	@Override
85  	public Map<WorldObjectId, IViewable> getVisible() {
86  		return visibleObjects;
87  	}
88  
89  	@Override
90  	public IViewable getVisible(WorldObjectId id) {
91  		return visibleObjects.get(id);
92  	}
93  	
94  	//
95  	//
96  	// PROTECTED METHODS
97  	//
98  	//
99  	
100 	/**
101 	 * Method that adds a world object to the visible object maps.
102 	 * <p><p>
103 	 * Synchronized!
104 	 * 
105 	 * @param worldObject
106 	 */
107 	protected synchronized void addVisibleObject(IViewable worldObject) {
108 		visibleObjects.put(worldObject.getId(), worldObject);
109 		for (Class cls : ClassUtils.getSubclasses(worldObject.getClass())) {
110 			syncWorldVisibleObjects.get(cls).put(worldObject.getId(), worldObject);
111 		}		
112 	}
113 	
114 	/**
115 	 * Removes world object from the visible world maps.
116 	 * <p><p>
117 	 * Synchronized!
118 	 * 
119 	 * @param worldObject
120 	 */
121 	protected synchronized void removeVisibleObject(IViewable worldObject) {
122 		visibleObjects.remove(worldObject.getId());
123 		for (Class<?> cls : ClassUtils.getSubclasses(worldObject.getClass())) {
124 			syncWorldVisibleObjects.get(cls).remove(worldObject.getId());
125 		}			
126 	}	
127 	
128 	//
129 	//
130 	// EVENT PROCESSING
131 	//
132 	//
133 	
134 	/**
135 	 * It additionally handles {@link IViewable} objects automatically raising {@link WorldObjectAppearedEvent} and
136 	 * {@link WorldObjectDisappearedEvent}.
137 	 */
138 	@Override
139 	protected void objectUpdatedEvent(IWorldObjectUpdatedEvent updateEvent) {
140         IWorldObject obj = get(updateEvent.getId());
141         
142         boolean wasVisible = obj != null && obj instanceof IViewable && ((IViewable)obj).isVisible();        
143         
144         IWorldObjectUpdateResult updateResult = updateEvent.update(obj);
145         
146         if (updateResult == null) {
147         	throw new PogamutException("Update result is null (updateEvent.update(obj) == null)! Cannot update object of ID " + updateEvent.getId() + "!", this);
148         }
149         
150         switch (updateResult.getResult()) {
151         case CREATED:            	
152             objectCreated(updateResult.getObject());
153             return;
154         case UPDATED:
155         	if (updateResult.getObject() != obj) {
156         		throw new PogamutException("Update event " + updateEvent + " does not returned the same instance of the object (result UPDATED).", this);
157         	}
158         	if (obj instanceof IViewable) {
159         		boolean isVisible = ((IViewable)obj).isVisible();
160         		if (wasVisible) {
161         			objectUpdated(obj);
162         			if (!isVisible) {
163         				objectDisappeared((IViewable) obj);
164         			}
165         		} else {
166         			if (isVisible) {
167         				objectAppeared((IViewable) obj);	
168         			}
169         			objectUpdated(obj);
170         		}        	
171         	} else {
172                     objectUpdated(obj);
173                 }
174 
175         	return;
176         case SAME:
177         	return;
178         case DESTROYED:
179         	objectDestroyed(obj);
180             return;
181         default:
182         	throw new PogamutException("Unhandled object update result " + updateResult.getResult() + " for the object " + obj + ".", this);
183         }
184     }
185 
186 	/**
187      * Additionally, it provides handling of {@link IViewable} objects raising {@link WorldObjectAppearedEvent} automatically (if object is visible).
188      */
189 	@Override
190     protected void objectCreated(IWorldObject obj) {
191     	addWorldObject(obj);
192     	raiseEvent(new WorldObjectFirstEncounteredEvent<IWorldObject>(obj, obj.getSimTime()));
193     	if (obj instanceof IViewable) {
194     		IViewable viewable = (IViewable)obj;
195     		if (viewable.isVisible()) {
196     			objectAppeared(viewable);
197     		}
198     	}
199         objectUpdated(obj);
200     }
201 	
202 	/**
203 	 * Called whenever the object appears in the agent's FOV.
204 	 * @param obj
205 	 */
206 	protected void objectAppeared(IViewable obj) {
207 		addVisibleObject(obj);
208 		raiseEvent(new WorldObjectAppearedEvent<IViewable>(obj, obj.getSimTime()));
209 	}
210 	
211 	/**
212 	 * Called whenever the object disappears from the agent's FOV.
213 	 * @param obj
214 	 */
215 	protected void objectDisappeared(IViewable obj) {
216 		removeVisibleObject(obj);
217 		raiseEvent(new WorldObjectDisappearedEvent<IViewable>(obj, obj.getSimTime()));
218 	}
219        
220     /**
221      * Additionally it handles {@link IViewable} objects automatically raising {@link WorldObjectDisappearedEvent} if object was visible
222      * before it was destroyed.
223      * 
224      * @param obj
225      */
226     protected void objectDestroyed(IWorldObject obj) {
227     	if (obj instanceof IViewable) {
228     		IViewable viewable = (IViewable)obj;
229     		if (viewable.isVisible()) {
230     			objectDisappeared(viewable);
231     		}
232     	}
233     	removeWorldObject(obj);
234         raiseEvent(new WorldObjectDestroyedEvent<IWorldObject>(obj, obj.getSimTime()));        
235     }
236 
237 	
238 }