Source for gnu.classpath.jdwp.event.EventManager

   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:    */
  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>
  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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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: }