1 /* EventManager.java -- event management and notification infrastructure
2    Copyright (C) 2005, 2006, 2007 Free Software Foundation
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 
40 package gnu.classpath.jdwp.event;
41 
42 import gnu.classpath.jdwp.Jdwp;
43 import gnu.classpath.jdwp.VMVirtualMachine;
44 import gnu.classpath.jdwp.exception.InvalidEventTypeException;
45 import gnu.classpath.jdwp.exception.JdwpException;
46 
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Hashtable;
50 import java.util.Iterator;
51 
52 /**
53  * Manages event requests and filters event notifications.
54  *
55  * The purpose of this class is actually two-fold:
56  *
57  * 1) Maintain a list of event requests from the debugger
58  * 2) Filter event notifications from the VM
59  *
60  * If an event request arrives from the debugger, the back-end will
61  * call {@link #requestEvent}, which will first check for a valid event.
62  * If it is valid, <code>EventManager</code> will record the request
63  * internally and register the event with the virtual machine, which may
64  * choose to handle the request itself (as is likely the case with
65  * breakpoints and other execution-related events), or it may decide to
66  * allow the <code>EventManager</code> to handle notifications and all
67  * filtering (which is convenient for other events such as class (un)loading).
68  *
69  * @author Keith Seitz  (keiths@redhat.com)
70  */
71 public class EventManager
72 {
73   // Single instance
74   private static EventManager _instance = null;
75 
76   // maps event (EVENT_*) to lists of EventRequests
77   private Hashtable _requests = null;
78 
79   /**
80    * Returns an instance of the event manager
81    *
82    * @return the event manager
83    */
getDefault()84   public static EventManager getDefault()
85   {
86     if (_instance == null)
87       _instance = new EventManager();
88 
89     return _instance;
90   }
91 
92   // Private constructs a new <code>EventManager</code>
EventManager()93   private EventManager ()
94   {
95     _requests = new Hashtable ();
96 
97     // Add lists for all the event types
98     _requests.put (new Byte (EventRequest.EVENT_SINGLE_STEP),
99                    new Hashtable ());
100     _requests.put (new Byte (EventRequest.EVENT_BREAKPOINT),
101                    new Hashtable ());
102     _requests.put (new Byte (EventRequest.EVENT_FRAME_POP),
103                    new Hashtable ());
104     _requests.put (new Byte (EventRequest.EVENT_EXCEPTION),
105                    new Hashtable ());
106     _requests.put (new Byte (EventRequest.EVENT_USER_DEFINED),
107                    new Hashtable ());
108     _requests.put (new Byte (EventRequest.EVENT_THREAD_START),
109                    new Hashtable ());
110     _requests.put (new Byte (EventRequest.EVENT_THREAD_END),
111                    new Hashtable ());
112     _requests.put (new Byte (EventRequest.EVENT_CLASS_PREPARE),
113                    new Hashtable ());
114     _requests.put (new Byte (EventRequest.EVENT_CLASS_UNLOAD),
115                    new Hashtable ());
116     _requests.put (new Byte (EventRequest.EVENT_CLASS_LOAD),
117                    new Hashtable ());
118     _requests.put (new Byte (EventRequest.EVENT_FIELD_ACCESS),
119                    new Hashtable ());
120     _requests.put (new Byte (EventRequest.EVENT_FIELD_MODIFY),
121                    new Hashtable ());
122     _requests.put (new Byte (EventRequest.EVENT_METHOD_ENTRY),
123                    new Hashtable ());
124     _requests.put (new Byte (EventRequest.EVENT_METHOD_EXIT),
125                    new Hashtable ());
126     _requests.put (new Byte (EventRequest.EVENT_VM_INIT),
127                    new Hashtable ());
128     _requests.put (new Byte (EventRequest.EVENT_VM_DEATH),
129                    new Hashtable ());
130 
131     // Add auto-generated event notifications
132     // only two: VM_INIT, VM_DEATH
133     try
134       {
135         byte sp = (Jdwp.suspendOnStartup()
136                    ? EventRequest.SUSPEND_THREAD : EventRequest.SUSPEND_NONE);
137         requestEvent (new EventRequest (0,
138                                         EventRequest.EVENT_VM_INIT, sp));
139         requestEvent (new EventRequest (0,
140                                         EventRequest.EVENT_VM_DEATH,
141                                         EventRequest.SUSPEND_NONE));
142       }
143     catch (JdwpException e)
144       {
145         // This can't happen
146       }
147   }
148 
149   /**
150    * Returns all requests for the given event. This method will only
151    * be used if the <code>EventManager</code> is handling event filtering.
152    *
153    * @param  event  the event
154    * @return requests that are interested in this event
155    *         or <code>null</code> if none (and event should not be sent)
156    * @throws IllegalArgumentException for invalid event kind
157    */
getEventRequests(Event event)158   public EventRequest[] getEventRequests(Event event)
159   {
160     ArrayList interestedEvents = new ArrayList();
161     Hashtable requests;
162     Byte kind = new Byte(event.getEventKind());
163     requests = (Hashtable) _requests.get(kind);
164     if (requests == null)
165       {
166         // Did not get a valid event type
167         throw new IllegalArgumentException("invalid event kind: " + kind);
168       }
169 
170     // Loop through the requests. Must look at ALL requests in order
171     // to evaluate all filters (think count filter).
172     Iterator rIter = requests.values().iterator();
173     while (rIter.hasNext())
174       {
175         EventRequest request = (EventRequest) rIter.next();
176         if (request.matches(event))
177           interestedEvents.add(request);
178       }
179 
180     EventRequest[] r = new EventRequest[interestedEvents.size()];
181     interestedEvents.toArray(r);
182     return r;
183   }
184 
185   /**
186    * Requests monitoring of an event.
187    *
188    * The debugger registers for event notification through
189    * an event filter. If no event filter is specified for an event
190    * in the VM, it is assumed that the debugger is not interested in
191    * receiving notifications of this event.
192    *
193    * The virtual machine will be notified of the request.
194    *
195    * @param request  the request to monitor
196    * @throws InvalidEventTypeException for invalid event kind
197    * @throws JdwpException for other errors involving request
198    */
requestEvent(EventRequest request)199   public void requestEvent (EventRequest request)
200     throws JdwpException
201   {
202     // Add request to request list
203     Hashtable requests;
204     Byte kind = new Byte (request.getEventKind ());
205     requests = (Hashtable) _requests.get (kind);
206     if (requests == null)
207       {
208         // Did not get a valid event type
209         throw new InvalidEventTypeException (request.getEventKind ());
210       }
211 
212     // Register the event with the VM
213     VMVirtualMachine.registerEvent (request);
214     requests.put (new Integer (request.getId ()), request);
215   }
216 
217   /**
218    * Deletes the given request from the management table
219    *
220    * @param  kind  the event kind
221    * @param  id    the ID of the request to delete
222    * @throws IllegalArgumentException for invalid event kind
223    * @throws JdwpException for other errors deleting request
224    */
deleteRequest(byte kind, int id)225   public void deleteRequest (byte kind, int id)
226     throws JdwpException
227   {
228     Hashtable requests;
229     requests = (Hashtable) _requests.get (new Byte (kind));
230     if (requests == null)
231       {
232         // Did not get a valid event type
233         throw new IllegalArgumentException ("invalid event kind: " + kind);
234       }
235 
236     Integer iid = new Integer (id);
237     EventRequest request = (EventRequest) requests.get (iid);
238     if (request != null)
239       {
240         VMVirtualMachine.unregisterEvent (request);
241         requests.remove (iid);
242       }
243   }
244 
245   /**
246    * Clears all the requests for a given event
247    *
248    * @param  kind  the event kind
249    * @throws IllegalArgumentException for invalid event kind
250    * @throws JdwpException for error clearing events
251    */
clearRequests(byte kind)252   public void clearRequests (byte kind)
253     throws JdwpException
254   {
255     Hashtable requests = (Hashtable) _requests.get (new Byte (kind));
256     if (requests == null)
257       {
258         // Did not get a valid event type
259         throw new IllegalArgumentException ("invalid event kind: " + kind);
260       }
261 
262     VMVirtualMachine.clearEvents (kind);
263     requests.clear ();
264   }
265 
266   /**
267    * Returns a given event request for an event
268    *
269    * @param  kind  the kind of event for the request
270    * @param  id    the integer request id to return
271    * @return  the request for the given event kind with the given id
272    *          (or <code>null</code> if not found)
273    * @throws IllegalArgumentException for invalid event kind
274    */
getRequest(byte kind, int id)275   public EventRequest getRequest (byte kind, int id)
276   {
277     Hashtable requests = (Hashtable) _requests.get (new Byte (kind));
278     if (requests == null)
279       {
280         // Did not get a valid event type
281         throw new IllegalArgumentException ("invalid event kind: " + kind);
282       }
283 
284     return (EventRequest) requests.get (new Integer (id));
285   }
286 
287   /**
288    * Returns all requests of the given event kind
289    *
290    * @param  kind  the event kind
291    * @returns a <code>Collection</code> of all the registered requests
292    * @throws IllegalArgumentException for invalid event kind
293    */
getRequests(byte kind)294   public Collection getRequests (byte kind)
295   {
296     Hashtable requests = (Hashtable) _requests.get (new Byte (kind));
297     if (requests == null)
298       {
299         // Did not get a valid event type
300         throw new IllegalArgumentException ("invalid event kind: " + kind);
301       }
302 
303     return requests.values ();
304   }
305 }
306