View Javadoc

1   package org.sourceforge.jemm.client.events;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   
6   import org.sourceforge.jemm.JEMMInternalException;
7   import org.sourceforge.jemm.client.Descriptor;
8   
9   /**
10   * Tracks all stack information for JEMMObjects.
11   * 
12   * This class is thread safe. All listener events however are executed outside
13   * of any lock and can happen in parallel.
14   * 
15   * @author Paul Keeble
16   *
17   */
18  public class EntitiesContext implements StackTracer{
19  	Map<Object,EntityContext> entities;
20  	MethodContextListener listener;
21  
22  	LockTracer lockTracer;
23  	/**
24  	 * Creates an Event Generator with all context aware events going to
25  	 * the passed listener.
26  	 * 
27  	 * @param listener
28  	 */
29  	public EntitiesContext(LockTracer lockTracer, MethodContextListener listener) {
30  		entities = new HashMap<Object,EntityContext>();
31  		this.lockTracer = lockTracer;
32  		this.listener = listener;
33  	}
34  	
35  	/**
36  	 * Marks an method entered and tracks appropriately the current
37  	 * thread as entering the method on the entity.
38  	 * 
39  	 * Calls listener.methodEntered, and if this is the first thread
40  	 * into the Object calls entityEntered first.
41  	 * 
42  	 * @param entity The object entered
43  	 * @param method The method by which it was entered
44  	 */
45  	public void enterMethod(Object entity, Descriptor method) {
46  		boolean created = false;
47  		boolean locked = false;
48  		synchronized(this) {
49  			EntityContext ec = null;
50  			
51  			if(entities.containsKey(entity)) {
52  				ec = entities.get(entity);
53  			} else {
54  				ec = new EntityContext(entity);
55  				entities.put(entity,ec);
56  				created = true;
57  			}
58  			ec.add(method);
59  			
60  			locked = lockTracer.currentTreadHasAnyLock();
61  		}
62  		
63  		if(created) {
64  			listener.entityEntered(new EntityEvent(entity,EntityEventType.ENTER));
65  			listener.methodEntered(new MethodEvent(entity,method,MethodEventType.ENTER,locked));
66  		} else {
67  			listener.methodEntered(new MethodEvent(entity,method,MethodEventType.ENTER,locked));
68  		}
69  	}
70  	
71  	/**
72  	 * Determines if the current thread is currently in the entity and method.
73  	 * 
74  	 * @param entity The object
75  	 * @param method The method on the object
76  	 * @return true if the thread has previously be entered, false otherwise
77  	 */
78  	public synchronized boolean isMethodEntered(Object entity, Descriptor method) {
79  		EntityContext ec = entities.get(entity);
80  		if(ec!=null) {
81  			return ec.has(method);
82  		}
83  		return false;
84  	}
85  	
86  	/**
87  	 * Determines if any thread has entered the entity.
88  	 * 
89  	 * @param entity The object to check
90  	 * @return True if the entity has been entered, false otherwise
91  	 */
92  	public synchronized boolean isEntityEntered(Object entity) {
93  		EntityContext ec = entities.get(entity);
94  		if(ec!=null) {
95  			return ec.hasAny();
96  		}
97  		return false;
98  	}
99  	
100 	/**
101 	 * Exits a method, removing any contexts that have been created.
102 	 * 
103 	 * Calls the listener.methodExit and if this is the last exit of
104 	 * all threads also calls entityExited
105 	 * 
106 	 * @param entity The object being exited
107 	 * @param method The method from which the thread is exiting
108 	 */
109 	public void exitMethod(Object entity,Descriptor method) {
110 		EntityContext ec = null;
111 		boolean stillEntered= false;
112 		boolean locked;
113 		synchronized(this) {
114 			if(!entities.containsKey(entity))
115 				throw new JEMMInternalException("No context for the entity exists " + entity);
116 			
117 			ec = entities.get(entity);
118 			ec.remove(method);
119 			stillEntered = ec.hasAny();
120 			if(!stillEntered)
121 				entities.remove(entity);
122 			
123 			locked = lockTracer.currentTreadHasAnyLock();
124 		}
125 		if(stillEntered) {
126 			listener.methodExited(new MethodEvent(entity,method,MethodEventType.EXIT,locked));
127 		} else {
128 			listener.methodExited(new MethodEvent(entity,method,MethodEventType.EXIT,locked));
129 			listener.entityExited(new EntityEvent(entity,EntityEventType.EXIT));
130 		}
131 	}
132 }