Source for gnu.classpath.jdwp.event.EventManager

   1: /* EventManager.java -- event management and notification infrastructure
   2:    Copyright (C) 2005 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.VMVirtualMachine;
  43: import gnu.classpath.jdwp.exception.InvalidEventTypeException;
  44: 
  45: import java.util.Collection;
  46: import java.util.Hashtable;
  47: import java.util.Iterator;
  48: 
  49: /**
  50:  * Manages event requests and filters event notifications.
  51:  *
  52:  * The purpose of this class is actually two-fold:
  53:  * 
  54:  * 1) Maintain a list of event requests from the debugger
  55:  * 2) Filter event notifications from the VM
  56:  * 
  57:  * If an event request arrives from the debugger, the back-end will
  58:  * call {@link #reqestEvent}, which will first check for a valid event.
  59:  * If it is valid, <code>EventManager</code> will record the request
  60:  * internally and register the event with the virtual machine, which may
  61:  * choose to handle the request itself (as is likely the case with
  62:  * breakpoints and other execution-related events), or it may decide to
  63:  * allow the <code>EventManager</code> to handle notifications and all
  64:  * filtering (which is convenient for other events such as class (un)loading).
  65:  * 
  66:  * @author Keith Seitz  (keiths@redhat.com)
  67:  */
  68: public class EventManager
  69: {
  70:   // Single instance
  71:   private static EventManager _instance = new EventManager ();
  72: 
  73:   // maps event (EVENT_*) to lists of EventRequests
  74:   private Hashtable _requests = null;
  75: 
  76:   /**
  77:    * Returns an instance of the event manager
  78:    *
  79:    * @return the event manager
  80:    */
  81:   public static EventManager getDefault ()
  82:   {
  83:     return _instance;
  84:   }
  85: 
  86:   // Private constructs a new <code>EventManager</code>
  87:   private EventManager ()
  88:   {
  89:     _requests = new Hashtable ();
  90: 
  91:     // Add lists for all the event types
  92:     _requests.put (new Byte (EventRequest.EVENT_SINGLE_STEP),
  93:            new Hashtable ());
  94:     _requests.put (new Byte (EventRequest.EVENT_BREAKPOINT),
  95:            new Hashtable ());
  96:     _requests.put (new Byte (EventRequest.EVENT_FRAME_POP),
  97:            new Hashtable ());
  98:     _requests.put (new Byte (EventRequest.EVENT_EXCEPTION),
  99:            new Hashtable ());
 100:     _requests.put (new Byte (EventRequest.EVENT_USER_DEFINED),
 101:            new Hashtable ());
 102:     _requests.put (new Byte (EventRequest.EVENT_THREAD_START),
 103:            new Hashtable ());
 104:     _requests.put (new Byte (EventRequest.EVENT_THREAD_END),
 105:            new Hashtable ());
 106:     _requests.put (new Byte (EventRequest.EVENT_CLASS_PREPARE),
 107:            new Hashtable ());
 108:     _requests.put (new Byte (EventRequest.EVENT_CLASS_UNLOAD),
 109:            new Hashtable ());
 110:     _requests.put (new Byte (EventRequest.EVENT_CLASS_LOAD),
 111:            new Hashtable ());
 112:     _requests.put (new Byte (EventRequest.EVENT_FIELD_ACCESS),
 113:            new Hashtable ());
 114:     _requests.put (new Byte (EventRequest.EVENT_FIELD_MODIFY),
 115:            new Hashtable ());
 116:     _requests.put (new Byte (EventRequest.EVENT_METHOD_ENTRY),
 117:            new Hashtable ());
 118:     _requests.put (new Byte (EventRequest.EVENT_METHOD_EXIT),
 119:            new Hashtable ());
 120:     _requests.put (new Byte (EventRequest.EVENT_VM_INIT),
 121:            new Hashtable ());
 122:     _requests.put (new Byte (EventRequest.EVENT_VM_DEATH),
 123:            new Hashtable ());
 124: 
 125:     // Add auto-generated event notifications
 126:     // only two: VM_INIT, VM_DEATH
 127:     try
 128:       {
 129:     requestEvent (new EventRequest (0,
 130:                     EventRequest.EVENT_VM_INIT,
 131:                     EventRequest.SUSPEND_NONE));
 132:     requestEvent (new EventRequest (0,
 133:                     EventRequest.EVENT_VM_DEATH,
 134:                     EventRequest.SUSPEND_NONE));
 135:       }
 136:     catch (InvalidEventTypeException e)
 137:       {
 138:     // This can't happen
 139:       }
 140:   }
 141: 
 142:   /**
 143:    * Returns a request for the given event. This method will only
 144:    * be used if the <code>EventManager</code> is handling event filtering.
 145:    *
 146:    * @param  event  the event
 147:    * @return request that was interested in this event
 148:    *         or <code>null</code> if none (and event should not be sent)
 149:    * @throws IllegalArgumentException for invalid event kind
 150:    */
 151:   public EventRequest getEventRequest (Event event)
 152:   {
 153:     EventRequest interestedRequest = null;
 154:     Hashtable requests;
 155:     Byte kind = new Byte (event.getEventKind ());
 156:     requests = (Hashtable) _requests.get (kind);
 157:     if (requests == null)
 158:       {
 159:     // Did not get a valid event type
 160:     throw new IllegalArgumentException ("invalid event kind: " + kind);
 161:       }
 162:     boolean match = false;
 163: 
 164:     // Loop through the requests. Must look at ALL requests in order
 165:     // to evaluate all filters (think count filter).
 166:     // TODO: What if multiple matches? Spec isn't so clear on this.
 167:     Iterator rIter = requests.values().iterator ();
 168:     while (rIter.hasNext ())
 169:       {
 170:     EventRequest request = (EventRequest) rIter.next ();
 171:     if (request.matches (event))
 172:       interestedRequest = request;
 173:       }
 174: 
 175:     return interestedRequest;
 176:   }
 177: 
 178:   /**
 179:    * Requests monitoring of an event.
 180:    *
 181:    * The debugger registers for event notification through
 182:    * an event filter. If no event filter is specified for an event
 183:    * in the VM, it is assumed that the debugger is not interested in
 184:    * receiving notifications of this event.
 185:    *
 186:    * The virtual machine will be notified of the request.
 187:    *
 188:    * @param request  the request to monitor
 189:    * @throws InvalidEventTypeException for invalid event kind
 190:    */
 191:   public void requestEvent (EventRequest request)
 192:     throws InvalidEventTypeException
 193:   {
 194:     // Add request to request list
 195:     Hashtable requests;
 196:     Byte kind = new Byte (request.getEventKind ());
 197:     requests = (Hashtable) _requests.get (kind);
 198:     if (requests == null)
 199:       {
 200:     // Did not get a valid event type
 201:     throw new InvalidEventTypeException (request.getEventKind ());
 202:       }
 203: 
 204:     // Register the event with the VM
 205:     VMVirtualMachine.registerEvent (request);
 206:     requests.put (new Integer (request.getId ()), request);
 207:   }
 208: 
 209:   /**
 210:    * Deletes the given request from the management table
 211:    *
 212:    * @param  kind  the event kind
 213:    * @param  id    the ID of the request to delete
 214:    * @throws IllegalArgumentException for invalid event kind
 215:    */
 216:   public void deleteRequest (byte kind, int id)
 217:   {
 218:     Hashtable requests;
 219:     requests = (Hashtable) _requests.get (new Byte (kind));
 220:     if (requests == null)
 221:       {
 222:     // Did not get a valid event type
 223:     throw new IllegalArgumentException ("invalid event kind: " + kind);
 224:       }
 225: 
 226:     Integer iid = new Integer (id);
 227:     EventRequest request = (EventRequest) requests.get (iid);
 228:     if (request != null)
 229:       {
 230:     VMVirtualMachine.unregisterEvent (request);
 231:     requests.remove (iid);
 232:       }
 233:   }
 234: 
 235:   /**
 236:    * Clears all the requests for a given event
 237:    *
 238:    * @param  kind  the event kind
 239:    * @throws IllegalArgumentException for invalid event kind
 240:    */
 241:   public void clearRequests (byte kind)
 242:   {
 243:     Hashtable requests = (Hashtable) _requests.get (new Byte (kind));
 244:     if (requests == null)
 245:       {
 246:     // Did not get a valid event type
 247:     throw new IllegalArgumentException ("invalid event kind: " + kind);
 248:       }
 249: 
 250:     VMVirtualMachine.clearEvents (kind);
 251:     requests.clear ();
 252:   }
 253: 
 254:   /**
 255:    * Returns a given event request for an event
 256:    *
 257:    * @param  kind  the kind of event for the request
 258:    * @param  id    the integer request id to return
 259:    * @return  the request for the given event kind with the given id
 260:    *          (or <code>null</code> if not found)
 261:    * @throws IllegalArgumentException for invalid event kind
 262:    */
 263:   public EventRequest getRequest (byte kind, int id)
 264:   {
 265:     Hashtable requests = (Hashtable) _requests.get (new Byte (kind));
 266:     if (requests == null)
 267:       {
 268:     // Did not get a valid event type
 269:     throw new IllegalArgumentException ("invalid event kind: " + kind);
 270:       }
 271: 
 272:     return (EventRequest) requests.get (new Integer (id));
 273:   }
 274: 
 275:   /**
 276:    * Returns all requests of the given event kind
 277:    *
 278:    * @param  kind  the event kind
 279:    * @returns a <code>Collection</code> of all the registered requests
 280:    * @throws IllegalArgumentException for invalid event kind
 281:    */
 282:   public Collection getRequests (byte kind)
 283:   {
 284:     Hashtable requests = (Hashtable) _requests.get (new Byte (kind));
 285:     if (requests == null)
 286:       {
 287:     // Did not get a valid event type
 288:     throw new IllegalArgumentException ("invalid event kind: " + kind);
 289:       }
 290:     
 291:     return requests.values ();
 292:   }
 293: }