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