| /* EventManager.java -- event management and notification infrastructure |
| Copyright (C) 2005, 2006 Free Software Foundation |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.classpath.jdwp.event; |
| |
| import gnu.classpath.jdwp.VMVirtualMachine; |
| import gnu.classpath.jdwp.exception.InvalidEventTypeException; |
| import gnu.classpath.jdwp.exception.JdwpException; |
| |
| import java.util.Collection; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| |
| /** |
| * Manages event requests and filters event notifications. |
| * |
| * The purpose of this class is actually two-fold: |
| * |
| * 1) Maintain a list of event requests from the debugger |
| * 2) Filter event notifications from the VM |
| * |
| * If an event request arrives from the debugger, the back-end will |
| * call {@link #requestEvent}, which will first check for a valid event. |
| * If it is valid, <code>EventManager</code> will record the request |
| * internally and register the event with the virtual machine, which may |
| * choose to handle the request itself (as is likely the case with |
| * breakpoints and other execution-related events), or it may decide to |
| * allow the <code>EventManager</code> to handle notifications and all |
| * filtering (which is convenient for other events such as class (un)loading). |
| * |
| * @author Keith Seitz (keiths@redhat.com) |
| */ |
| public class EventManager |
| { |
| // Single instance |
| private static EventManager _instance = null; |
| |
| // maps event (EVENT_*) to lists of EventRequests |
| private Hashtable _requests = null; |
| |
| /** |
| * Returns an instance of the event manager |
| * |
| * @return the event manager |
| */ |
| public static EventManager getDefault() |
| { |
| if (_instance == null) |
| _instance = new EventManager(); |
| |
| return _instance; |
| } |
| |
| // Private constructs a new <code>EventManager</code> |
| private EventManager () |
| { |
| _requests = new Hashtable (); |
| |
| // Add lists for all the event types |
| _requests.put (new Byte (EventRequest.EVENT_SINGLE_STEP), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_BREAKPOINT), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_FRAME_POP), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_EXCEPTION), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_USER_DEFINED), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_THREAD_START), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_THREAD_END), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_CLASS_PREPARE), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_CLASS_UNLOAD), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_CLASS_LOAD), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_FIELD_ACCESS), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_FIELD_MODIFY), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_METHOD_ENTRY), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_METHOD_EXIT), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_VM_INIT), |
| new Hashtable ()); |
| _requests.put (new Byte (EventRequest.EVENT_VM_DEATH), |
| new Hashtable ()); |
| |
| // Add auto-generated event notifications |
| // only two: VM_INIT, VM_DEATH |
| try |
| { |
| requestEvent (new EventRequest (0, |
| EventRequest.EVENT_VM_INIT, |
| EventRequest.SUSPEND_NONE)); |
| requestEvent (new EventRequest (0, |
| EventRequest.EVENT_VM_DEATH, |
| EventRequest.SUSPEND_NONE)); |
| } |
| catch (JdwpException e) |
| { |
| // This can't happen |
| } |
| } |
| |
| /** |
| * Returns a request for the given event. This method will only |
| * be used if the <code>EventManager</code> is handling event filtering. |
| * |
| * @param event the event |
| * @return request that was interested in this event |
| * or <code>null</code> if none (and event should not be sent) |
| * @throws IllegalArgumentException for invalid event kind |
| */ |
| public EventRequest getEventRequest (Event event) |
| { |
| EventRequest interestedRequest = null; |
| Hashtable requests; |
| Byte kind = new Byte (event.getEventKind ()); |
| requests = (Hashtable) _requests.get (kind); |
| if (requests == null) |
| { |
| // Did not get a valid event type |
| throw new IllegalArgumentException ("invalid event kind: " + kind); |
| } |
| boolean match = false; |
| |
| // Loop through the requests. Must look at ALL requests in order |
| // to evaluate all filters (think count filter). |
| // TODO: What if multiple matches? Spec isn't so clear on this. |
| Iterator rIter = requests.values().iterator (); |
| while (rIter.hasNext ()) |
| { |
| EventRequest request = (EventRequest) rIter.next (); |
| if (request.matches (event)) |
| interestedRequest = request; |
| } |
| |
| return interestedRequest; |
| } |
| |
| /** |
| * Requests monitoring of an event. |
| * |
| * The debugger registers for event notification through |
| * an event filter. If no event filter is specified for an event |
| * in the VM, it is assumed that the debugger is not interested in |
| * receiving notifications of this event. |
| * |
| * The virtual machine will be notified of the request. |
| * |
| * @param request the request to monitor |
| * @throws InvalidEventTypeException for invalid event kind |
| * @throws JdwpException for other errors involving request |
| */ |
| public void requestEvent (EventRequest request) |
| throws JdwpException |
| { |
| // Add request to request list |
| Hashtable requests; |
| Byte kind = new Byte (request.getEventKind ()); |
| requests = (Hashtable) _requests.get (kind); |
| if (requests == null) |
| { |
| // Did not get a valid event type |
| throw new InvalidEventTypeException (request.getEventKind ()); |
| } |
| |
| // Register the event with the VM |
| VMVirtualMachine.registerEvent (request); |
| requests.put (new Integer (request.getId ()), request); |
| } |
| |
| /** |
| * Deletes the given request from the management table |
| * |
| * @param kind the event kind |
| * @param id the ID of the request to delete |
| * @throws IllegalArgumentException for invalid event kind |
| * @throws JdwpException for other errors deleting request |
| */ |
| public void deleteRequest (byte kind, int id) |
| throws JdwpException |
| { |
| Hashtable requests; |
| requests = (Hashtable) _requests.get (new Byte (kind)); |
| if (requests == null) |
| { |
| // Did not get a valid event type |
| throw new IllegalArgumentException ("invalid event kind: " + kind); |
| } |
| |
| Integer iid = new Integer (id); |
| EventRequest request = (EventRequest) requests.get (iid); |
| if (request != null) |
| { |
| VMVirtualMachine.unregisterEvent (request); |
| requests.remove (iid); |
| } |
| } |
| |
| /** |
| * Clears all the requests for a given event |
| * |
| * @param kind the event kind |
| * @throws IllegalArgumentException for invalid event kind |
| * @throws JdwpException for error clearing events |
| */ |
| public void clearRequests (byte kind) |
| throws JdwpException |
| { |
| Hashtable requests = (Hashtable) _requests.get (new Byte (kind)); |
| if (requests == null) |
| { |
| // Did not get a valid event type |
| throw new IllegalArgumentException ("invalid event kind: " + kind); |
| } |
| |
| VMVirtualMachine.clearEvents (kind); |
| requests.clear (); |
| } |
| |
| /** |
| * Returns a given event request for an event |
| * |
| * @param kind the kind of event for the request |
| * @param id the integer request id to return |
| * @return the request for the given event kind with the given id |
| * (or <code>null</code> if not found) |
| * @throws IllegalArgumentException for invalid event kind |
| */ |
| public EventRequest getRequest (byte kind, int id) |
| { |
| Hashtable requests = (Hashtable) _requests.get (new Byte (kind)); |
| if (requests == null) |
| { |
| // Did not get a valid event type |
| throw new IllegalArgumentException ("invalid event kind: " + kind); |
| } |
| |
| return (EventRequest) requests.get (new Integer (id)); |
| } |
| |
| /** |
| * Returns all requests of the given event kind |
| * |
| * @param kind the event kind |
| * @returns a <code>Collection</code> of all the registered requests |
| * @throws IllegalArgumentException for invalid event kind |
| */ |
| public Collection getRequests (byte kind) |
| { |
| Hashtable requests = (Hashtable) _requests.get (new Byte (kind)); |
| if (requests == null) |
| { |
| // Did not get a valid event type |
| throw new IllegalArgumentException ("invalid event kind: " + kind); |
| } |
| |
| return requests.values (); |
| } |
| } |