View Javadoc

1   package cz.cuni.amis.pogamut.multi.communication.worldview.impl;
2   
3   import java.util.Collections;
4   import java.util.HashMap;
5   import java.util.Map;
6   import java.util.Set;
7   import java.util.WeakHashMap;
8   
9   import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldChangeEvent;
10  import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldObjectUpdateResult;
11  import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectId;
12  import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
13  import cz.cuni.amis.pogamut.base.component.lifecyclebus.ILifecycleBus;
14  import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
15  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
16  import cz.cuni.amis.pogamut.base3d.worldview.object.IViewable;
17  import cz.cuni.amis.pogamut.base3d.worldview.object.event.WorldObjectDisappearedEvent;
18  import cz.cuni.amis.pogamut.multi.agent.ITeamedAgentId;
19  import cz.cuni.amis.pogamut.multi.communication.translator.event.ICompositeWorldObjectUpdatedEvent;
20  import cz.cuni.amis.pogamut.multi.communication.translator.event.ILocalWorldObjectUpdatedEvent;
21  import cz.cuni.amis.pogamut.multi.communication.worldview.ISharedWorldView;
22  import cz.cuni.amis.pogamut.multi.communication.worldview.IVisionLocalWorldView;
23  import cz.cuni.amis.pogamut.multi.communication.worldview.object.ILocalViewable;
24  import cz.cuni.amis.pogamut.multi.communication.worldview.object.ILocalWorldObject;
25  import cz.cuni.amis.pogamut.multi.utils.timekey.TimeKey;
26  import cz.cuni.amis.utils.ClassUtils;
27  import cz.cuni.amis.utils.exception.PogamutException;
28  import cz.cuni.amis.utils.maps.WeakHashMapMap;
29  
30  /**
31   * VisionLocalWorldView manages information about all objects currently in the bot's FOV (field-of-view)
32   * by implementing methods from {@link IVisionLocalWorldView} interface.
33   * 
34   * @author srlok
35   *
36   */
37  @AgentScoped
38  public abstract class VisionLocalWorldView extends EventDrivenLocalWorldView implements IVisionLocalWorldView {
39  
40  	public VisionLocalWorldView(
41  			ComponentDependencies dependencies,
42  			ILifecycleBus bus, IAgentLogger logger,
43  			ISharedWorldView parentWorldView, ITeamedAgentId agentId
44  	) {
45  		super(dependencies, bus, logger, parentWorldView, agentId);
46  	}
47  
48  	@Override
49  	public void notify(IWorldChangeEvent event)
50  	{
51  		if ( event instanceof ILocalWorldObjectUpdatedEvent)
52  		{
53  			objectUpdatedEvent( (ILocalWorldObjectUpdatedEvent)event );
54  		}
55  		else if ( event instanceof ICompositeWorldObjectUpdatedEvent)
56  		{
57  			objectUpdatedEvent( ((ICompositeWorldObjectUpdatedEvent)event).getLocalEvent() );
58  		}
59  		else
60  		{
61  			super.notify(event);
62  		}
63  	}
64  	
65  	/**
66  	 * Map of all currently visible objects.
67  	 */
68  	protected Map<TimeKey, Map<WorldObjectId, IViewable>> visibleMap = 
69  		new WeakHashMap<TimeKey, Map<WorldObjectId, IViewable>>();
70  	
71  	/**
72  	 * Synchronized version of visible objects.
73  	 */
74  	protected Map< TimeKey, Map<WorldObjectId, IViewable>> syncVisibleMap = 
75  		Collections.synchronizedMap(visibleMap);
76  	
77  	/**
78  	 * Map of all currently visible objects, sorted according to their classes.
79  	 */
80  	@SuppressWarnings("rawtypes")
81  	protected Map<TimeKey, Map<Class, Map<WorldObjectId, IViewable>>> visibleClassMap =
82  		new WeakHashMapMap<TimeKey, Class, Map<WorldObjectId, IViewable>>();
83  
84  	/**
85  	 * Synchronized version of visible objects sorted according to class.
86  	 */
87  	@SuppressWarnings("rawtypes")
88  	protected Map<TimeKey, Map< Class, Map<WorldObjectId,IViewable>>> syncVisibleClassMap =
89  		Collections.synchronizedMap(visibleClassMap);
90  	
91  	@Override
92  	protected void objectUpdatedEvent(ILocalWorldObjectUpdatedEvent updateEvent) 
93  	{
94  		//log.fine("VisionLocalWorldView notify : " + updateEvent.getId() )
95  		
96          ILocalWorldObject obj = getMostRecentLocalWorldObject( updateEvent.getId() );
97          
98          boolean oldVisible = false;
99          boolean isViewable = false;
100         
101         ILocalWorldObject copy = null;
102         //if old timeKeys are held, store the original value, create a new copy, which will be updated
103         if ( obj != null)
104         {
105         	if ( obj instanceof ILocalViewable) 
106         	{
107         		oldVisible = ((ILocalViewable)obj).isVisible();
108         		isViewable = true;
109         	}
110         	copy = obj.clone();
111         }
112         else //may be created event
113         {
114         	copy = null;
115         }
116        
117         IWorldObjectUpdateResult<ILocalWorldObject> updateResult = updateEvent.update(copy);
118         //log.fine("Update result for id :" + updateEvent.getId() + " ; : " + updateResult.getResult() );
119         switch (updateResult.getResult()) {
120         case CREATED:            	
121             objectCreated(updateResult.getObject(), updateEvent.getSimTime());
122             return;
123         case UPDATED:
124         	if (updateResult.getObject() != copy) {
125         		throw new PogamutException("Update event " + updateEvent + " does not returned the same instance of the object (result UPDATED).", this);
126         	}
127         	
128         	super.addOldLocalWorldObject(obj, updateEvent.getSimTime());        	
129         	
130         	boolean appearedDisappeared = false; //if the object will appear or disappear we won't need to call the objectUpdatedMethod
131         	
132         	if (isViewable)
133         	{
134         		boolean visible = ((ILocalViewable)copy).isVisible();
135         		if ( visible != oldVisible)
136         		{
137         			appearedDisappeared = true;
138         			if ( visible )
139         			{
140         				objectAppeared((ILocalViewable)copy, updateEvent.getSimTime());
141         			}
142         			else
143         			{
144         				objectDisappeared((ILocalViewable)copy, updateEvent.getSimTime());
145         			}
146         		}
147         		else
148         		{
149         			//this is here because we have to add the visible objects to a map with greater timeKey
150         			//this is more effective then copying and then disappearing later
151         			if ( visible )
152         			{
153         				addVisible((ILocalViewable)obj, updateEvent.getSimTime());
154         			}
155         		}
156         	}
157         	
158         	if ( !appearedDisappeared )
159         	objectUpdated(copy, updateEvent.getSimTime());	
160         	
161         	actLocalWorldObjects.put(copy.getId(), copy);    	
162         	
163         	return;
164         case SAME:
165         	if (isViewable && oldVisible)
166         	{
167         		addVisible((ILocalViewable)obj, updateEvent.getSimTime());
168         	}
169         	return;
170         case DESTROYED:
171         	
172         	super.addOldLocalWorldObject(obj, updateEvent.getSimTime());
173         	objectDestroyed(copy, updateEvent.getSimTime());
174         	
175             return;
176         default:
177         	throw new PogamutException("Unhandled object update result " + updateResult.getResult() + " for the object " + obj + ".", this);
178         }
179     }
180 	
181 	
182 	protected void objectCreated( ILocalWorldObject obj , long time )
183 	{
184 		if ( obj instanceof ILocalViewable)
185 		{
186 			if ( ((ILocalViewable)obj).isVisible() )
187 			{
188 				objectAppeared( (ILocalViewable)obj, time );
189 			}
190 		}
191 		
192 		super.objectCreated(obj, time);
193 	}
194 	
195 	
196 	protected void objectDestroyed( ILocalWorldObject obj , long time)
197 	{
198 		/*if ( obj instanceof ILocalViewable)
199 		{
200 			removeVisible((ILocalViewable)obj , time);
201 		}*/
202 		super.objectDestroyed(obj, time);
203 	}
204 	
205 	/**
206 	 * Handles events for making the object visible.
207 	 * @param obj
208 	 */
209 	protected void objectAppeared( ILocalViewable obj, long time )
210 	{
211 		//log.info("Object appeared : " + obj);
212 		addVisible(obj, time);
213 	}
214 	
215 	/**
216 	 * Handles events for making the object not visible.
217 	 * @param obj
218 	 */
219 	protected void objectDisappeared( ILocalViewable obj, long time )
220 	{
221 		
222 	}
223 
224 	
225 	/**
226 	 * Adds the provided object as visible into all visibleMaps int the worldView.
227 	 * Note that since the cached visible objects are composite and the parameter for this method is a local object,
228 	 * only the id and the getCompositeClass of the object are actually used.
229 	 * @param obj
230 	 */
231 	protected synchronized void addVisible( ILocalViewable obj , long time )
232 	{
233 		//log.info("["+time+"]AddingVisible of id : " + obj.getId() + " ; class : " + obj.getCompositeClass() );
234 		synchronized(visibleMap)
235 		{
236 			Map map = visibleMap.get(TimeKey.get(time));
237 			if ( map == null )
238 			{
239 				map = new LazyCompositeObjectMap<IViewable>( time );
240 				visibleMap.put(TimeKey.get(time), map );
241 			}
242 			((LazyCompositeObjectMap<IViewable>)visibleMap.get(TimeKey.get(time))).addKey(obj.getId());
243 		}
244 		synchronized( visibleClassMap )
245 		{
246 			Map clsMap = visibleClassMap.get(time);
247 			if ( clsMap == null )
248 			{
249 				clsMap = new HashMap<Class,Map>();
250 				visibleClassMap.put(TimeKey.get(time),clsMap);
251 			}
252 			for ( Class cls : ClassUtils.getSubclasses(obj.getCompositeClass()) )
253 			{
254 				LazyCompositeObjectMap<IViewable> map = ((LazyCompositeObjectMap<IViewable>)visibleClassMap.get(TimeKey.get(time)).get(cls));
255 				if ( map == null )
256 				{
257 					map = new LazyCompositeObjectMap<IViewable>( getCurrentTimeKey().getTime() );
258 					visibleClassMap.get(TimeKey.get(time)).put(cls, map);
259 				}
260 				map.addKey(obj.getId());
261 			}
262 		}
263 	}
264 	
265 	/**
266 	 * Removes object of the same objectId as the provided localObject from visible maps.
267 	 * Note that the provided ILocalViewable object has to implement the getCompositeClass() method to return the correct composite object class.
268 	 * @param obj
269 	 */
270 	protected synchronized void removeVisible( ILocalViewable obj, long time )
271 	{
272 		synchronized(visibleMap)
273 		{
274 			((LazyCompositeObjectMap<IViewable>)visibleMap.get(TimeKey.get(time))).remove(obj.getId());
275 		}
276 		synchronized( visibleClassMap )
277 		{
278 			for ( Class cls : ClassUtils.getSubclasses(obj.getCompositeClass()) )
279 			{
280 				LazyCompositeObjectMap<IViewable> map = ((LazyCompositeObjectMap<IViewable>)visibleClassMap.get(TimeKey.get(time)).get(cls));
281 				if ( map == null )
282 				{
283 					map = new LazyCompositeObjectMap<IViewable>( getCurrentTimeKey().getTime() );
284 					visibleClassMap.get(TimeKey.get(time)).put(cls, map);
285 				}
286 				map.remove(obj.getId());
287 			}
288 		}
289 	}
290 		
291 	@Override
292 	public Map<Class, Map<WorldObjectId, IViewable>> getAllVisible() {
293 		
294 		return syncVisibleClassMap.get(currentTimeKey);
295 	}
296 
297 	@Override
298 	public <T extends IViewable> Map<WorldObjectId, T> getAllVisible(
299 			Class<T> type) 
300 	{
301 		
302 		Map<WorldObjectId,T> map = (Map<WorldObjectId, T>) syncVisibleClassMap.get(currentTimeKey).get(type);
303 		if ( map == null )
304 		{
305 			map = new LazyCompositeObjectMap<T>( currentTimeKey.getTime() );
306 		}
307 		return map;
308 	}
309 
310 	@Override
311 	public Map<WorldObjectId, IViewable> getVisible() {
312 		return syncVisibleMap.get(currentTimeKey);
313 	}
314 
315 	@Override
316 	public IViewable getVisible(WorldObjectId id) {
317 		return syncVisibleMap.get(currentTimeKey).get(id);
318 	}
319 	
320 }