Source for gnu.classpath.jdwp.event.EventManager

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