Home | History | Annotate | Download | only in jdi
      1 /*
      2  * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package com.sun.tools.jdi;
     27 
     28 import com.sun.jdi.*;
     29 import com.sun.jdi.event.*;
     30 import com.sun.jdi.request.*;
     31 
     32 import java.util.*;
     33 enum EventDestination {UNKNOWN_EVENT, INTERNAL_EVENT, CLIENT_EVENT};
     34 
     35 /*
     36  * An EventSet is normally created by the transport reader thread when
     37  * it reads a JDWP Composite command.  The constructor doesn't unpack
     38  * the events contained in the Composite command and create EventImpls
     39  * for them because that process might involve calling back into the back-end
     40  * which should not be done by the transport reader thread.  Instead,
     41  * the raw bytes of the packet are read and stored in the EventSet.
     42  * The EventSet is then added to each EventQueue. When an EventSet is
     43  * removed from an EventQueue, the EventSetImpl.build() method is called.
     44  * This method reads the packet bytes and creates the actual EventImpl objects.
     45  * build() also filters out events for our internal handler and puts them in
     46  * their own EventSet.  This means that the EventImpls that are in the EventSet
     47  * that is on the queues are all for client requests.
     48  */
     49 public class EventSetImpl extends ArrayList<Event> implements EventSet {
     50     private static final long serialVersionUID = -4857338819787924570L;
     51     private VirtualMachineImpl vm; // we implement Mirror
     52     private Packet pkt;
     53     private byte suspendPolicy;
     54     private EventSetImpl internalEventSet;
     55 
     56     public String toString() {
     57         String string = "event set, policy:" + suspendPolicy +
     58                         ", count:" + this.size() + " = {";
     59         boolean first = true;
     60         for (Event event : this) {
     61             if (!first) {
     62                 string += ", ";
     63             }
     64             string += event.toString();
     65             first = false;
     66         }
     67         string += "}";
     68         return string;
     69     }
     70 
     71     abstract class EventImpl extends MirrorImpl implements Event {
     72 
     73         private final byte eventCmd;
     74         private final int requestID;
     75         // This is set only for client requests, not internal requests.
     76         private final EventRequest request;
     77 
     78         /**
     79          * Constructor for events.
     80          */
     81         protected EventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
     82                             int requestID) {
     83             super(EventSetImpl.this.vm);
     84             this.eventCmd = evt.eventKind();
     85             this.requestID = requestID;
     86             EventRequestManagerImpl ermi = EventSetImpl.this.
     87                 vm.eventRequestManagerImpl();
     88             this.request =  ermi.request(eventCmd, requestID);
     89         }
     90 
     91         /*
     92          * Override superclass back to default equality
     93          */
     94         public boolean equals(Object obj) {
     95             return this == obj;
     96         }
     97 
     98         public int hashCode() {
     99             return System.identityHashCode(this);
    100         }
    101 
    102         /**
    103          * Constructor for VM disconnected events.
    104          */
    105         protected EventImpl(byte eventCmd) {
    106             super(EventSetImpl.this.vm);
    107             this.eventCmd = eventCmd;
    108             this.requestID = 0;
    109             this.request = null;
    110         }
    111 
    112         public EventRequest request() {
    113             return request;
    114         }
    115 
    116         int requestID() {
    117             return requestID;
    118         }
    119 
    120         EventDestination destination() {
    121             /*
    122              * We need to decide if this event is for
    123              * 1. an internal request
    124              * 2. a client request that is no longer available, ie
    125              *    it has been deleted, or disabled and re-enabled
    126              *    which gives it a new ID.
    127              * 3. a current client request that is disabled
    128              * 4. a current enabled client request.
    129              *
    130              * We will filter this set into a set
    131              * that contains only 1s for our internal queue
    132              * and a set that contains only 4s for our client queue.
    133              * If we get an EventSet that contains only 2 and 3
    134              * then we have to resume it if it is not SUSPEND_NONE
    135              * because no one else will.
    136              */
    137             if (requestID == 0) {
    138                 /* An unsolicited event.  These have traditionally
    139                  * been treated as client events.
    140                  */
    141                 return EventDestination.CLIENT_EVENT;
    142             }
    143 
    144             // Is this an event for a current client request?
    145             if (request == null) {
    146                 // Nope.  Is it an event for an internal request?
    147                 EventRequestManagerImpl ermi = this.vm.getInternalEventRequestManager();
    148                 if (ermi.request(eventCmd, requestID) != null) {
    149                     // Yep
    150                     return EventDestination.INTERNAL_EVENT;
    151                 }
    152                 return EventDestination.UNKNOWN_EVENT;
    153             }
    154 
    155             // We found a client request
    156             if (request.isEnabled()) {
    157                 return EventDestination.CLIENT_EVENT;
    158             }
    159             return EventDestination.UNKNOWN_EVENT;
    160         }
    161 
    162         abstract String eventName();
    163 
    164         public String toString() {
    165             return eventName();
    166         }
    167 
    168     }
    169 
    170     abstract class ThreadedEventImpl extends EventImpl {
    171         private ThreadReference thread;
    172 
    173         ThreadedEventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
    174                           int requestID, ThreadReference thread) {
    175             super(evt, requestID);
    176             this.thread = thread;
    177         }
    178 
    179         public ThreadReference thread() {
    180             return thread;
    181         }
    182 
    183         public String toString() {
    184             return eventName() + " in thread " + thread.name();
    185         }
    186     }
    187 
    188     abstract class LocatableEventImpl extends ThreadedEventImpl
    189                                             implements Locatable {
    190         private Location location;
    191 
    192         LocatableEventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
    193                            int requestID,
    194                            ThreadReference thread, Location location) {
    195             super(evt, requestID, thread);
    196             this.location = location;
    197         }
    198 
    199         public Location location() {
    200             return location;
    201         }
    202 
    203         /**
    204          * For MethodEntry and MethodExit
    205          */
    206         public Method method() {
    207             return location.method();
    208         }
    209 
    210         public String toString() {
    211             return eventName() + "@" +
    212                    ((location() == null) ? " null" : location().toString()) +
    213                    " in thread " + thread().name();
    214         }
    215     }
    216 
    217     class BreakpointEventImpl extends LocatableEventImpl
    218                             implements BreakpointEvent {
    219         BreakpointEventImpl(JDWP.Event.Composite.Events.Breakpoint evt) {
    220             super(evt, evt.requestID, evt.thread, evt.location);
    221         }
    222 
    223         String eventName() {
    224             return "BreakpointEvent";
    225         }
    226     }
    227 
    228     class StepEventImpl extends LocatableEventImpl implements StepEvent {
    229         StepEventImpl(JDWP.Event.Composite.Events.SingleStep evt) {
    230             super(evt, evt.requestID, evt.thread, evt.location);
    231         }
    232 
    233         String eventName() {
    234             return "StepEvent";
    235         }
    236     }
    237 
    238     class MethodEntryEventImpl extends LocatableEventImpl
    239                             implements MethodEntryEvent {
    240         MethodEntryEventImpl(JDWP.Event.Composite.Events.MethodEntry evt) {
    241             super(evt, evt.requestID, evt.thread, evt.location);
    242         }
    243 
    244         String eventName() {
    245             return "MethodEntryEvent";
    246         }
    247     }
    248 
    249     class MethodExitEventImpl extends LocatableEventImpl
    250                             implements MethodExitEvent {
    251         private Value returnVal = null;
    252 
    253         MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExit evt) {
    254             super(evt, evt.requestID, evt.thread, evt.location);
    255         }
    256 
    257         MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExitWithReturnValue evt) {
    258             super(evt, evt.requestID, evt.thread, evt.location);
    259             returnVal = evt.value;
    260         }
    261 
    262         String eventName() {
    263             return "MethodExitEvent";
    264         }
    265 
    266         public Value returnValue() {
    267             if (!this.vm.canGetMethodReturnValues()) {
    268                 throw new UnsupportedOperationException(
    269                 "target does not support return values in MethodExit events");
    270             }
    271             return returnVal;
    272         }
    273 
    274     }
    275 
    276     class MonitorContendedEnterEventImpl extends LocatableEventImpl
    277                             implements MonitorContendedEnterEvent {
    278         private ObjectReference monitor = null;
    279 
    280         MonitorContendedEnterEventImpl(JDWP.Event.Composite.Events.MonitorContendedEnter evt) {
    281             super(evt, evt.requestID, evt.thread, evt.location);
    282             this.monitor = evt.object;
    283         }
    284 
    285         String eventName() {
    286             return "MonitorContendedEnter";
    287         }
    288 
    289         public ObjectReference  monitor() {
    290             return monitor;
    291         };
    292 
    293     }
    294 
    295     class MonitorContendedEnteredEventImpl extends LocatableEventImpl
    296                             implements MonitorContendedEnteredEvent {
    297         private ObjectReference monitor = null;
    298 
    299         MonitorContendedEnteredEventImpl(JDWP.Event.Composite.Events.MonitorContendedEntered evt) {
    300             super(evt, evt.requestID, evt.thread, evt.location);
    301             this.monitor = evt.object;
    302         }
    303 
    304         String eventName() {
    305             return "MonitorContendedEntered";
    306         }
    307 
    308         public ObjectReference  monitor() {
    309             return monitor;
    310         };
    311 
    312     }
    313 
    314     class MonitorWaitEventImpl extends LocatableEventImpl
    315                             implements MonitorWaitEvent {
    316         private ObjectReference monitor = null;
    317         private long timeout;
    318 
    319         MonitorWaitEventImpl(JDWP.Event.Composite.Events.MonitorWait evt) {
    320             super(evt, evt.requestID, evt.thread, evt.location);
    321             this.monitor = evt.object;
    322             this.timeout = evt.timeout;
    323         }
    324 
    325         String eventName() {
    326             return "MonitorWait";
    327         }
    328 
    329         public ObjectReference  monitor() {
    330             return monitor;
    331         };
    332 
    333         public long timeout() {
    334             return timeout;
    335         }
    336     }
    337 
    338     class MonitorWaitedEventImpl extends LocatableEventImpl
    339                             implements MonitorWaitedEvent {
    340         private ObjectReference monitor = null;
    341         private boolean timed_out;
    342 
    343         MonitorWaitedEventImpl(JDWP.Event.Composite.Events.MonitorWaited evt) {
    344             super(evt, evt.requestID, evt.thread, evt.location);
    345             this.monitor = evt.object;
    346             this.timed_out = evt.timed_out;
    347         }
    348 
    349         String eventName() {
    350             return "MonitorWaited";
    351         }
    352 
    353         public ObjectReference  monitor() {
    354             return monitor;
    355         };
    356 
    357         public boolean timedout() {
    358             return timed_out;
    359         }
    360     }
    361 
    362     class ClassPrepareEventImpl extends ThreadedEventImpl
    363                             implements ClassPrepareEvent {
    364         private ReferenceType referenceType;
    365 
    366         ClassPrepareEventImpl(JDWP.Event.Composite.Events.ClassPrepare evt) {
    367             super(evt, evt.requestID, evt.thread);
    368             referenceType = this.vm.referenceType(evt.typeID, evt.refTypeTag,
    369                                                   evt.signature);
    370             ((ReferenceTypeImpl)referenceType).setStatus(evt.status);
    371         }
    372 
    373         public ReferenceType referenceType() {
    374             return referenceType;
    375         }
    376 
    377         String eventName() {
    378             return "ClassPrepareEvent";
    379         }
    380     }
    381 
    382     class ClassUnloadEventImpl extends EventImpl implements ClassUnloadEvent {
    383         private String classSignature;
    384 
    385         ClassUnloadEventImpl(JDWP.Event.Composite.Events.ClassUnload evt) {
    386             super(evt, evt.requestID);
    387             this.classSignature = evt.signature;
    388         }
    389 
    390         public String className() {
    391             return classSignature.substring(1, classSignature.length()-1)
    392                 .replace('/', '.');
    393         }
    394 
    395         public String classSignature() {
    396             return classSignature;
    397         }
    398 
    399         String eventName() {
    400             return "ClassUnloadEvent";
    401         }
    402     }
    403 
    404     class ExceptionEventImpl extends LocatableEventImpl
    405                                              implements ExceptionEvent {
    406         private ObjectReference exception;
    407         private Location catchLocation;
    408 
    409         ExceptionEventImpl(JDWP.Event.Composite.Events.Exception evt) {
    410             super(evt, evt.requestID, evt.thread, evt.location);
    411             this.exception = evt.exception;
    412             this.catchLocation = evt.catchLocation;
    413         }
    414 
    415         public ObjectReference exception() {
    416             return exception;
    417         }
    418 
    419         public Location catchLocation() {
    420             return catchLocation;
    421         }
    422 
    423         String eventName() {
    424             return "ExceptionEvent";
    425         }
    426     }
    427 
    428     class ThreadDeathEventImpl extends ThreadedEventImpl
    429                                         implements ThreadDeathEvent {
    430         ThreadDeathEventImpl(JDWP.Event.Composite.Events.ThreadDeath evt) {
    431             super(evt, evt.requestID, evt.thread);
    432         }
    433 
    434         String eventName() {
    435             return "ThreadDeathEvent";
    436         }
    437     }
    438 
    439     class ThreadStartEventImpl extends ThreadedEventImpl
    440                                         implements ThreadStartEvent {
    441         ThreadStartEventImpl(JDWP.Event.Composite.Events.ThreadStart evt) {
    442             super(evt, evt.requestID, evt.thread);
    443         }
    444 
    445         String eventName() {
    446             return "ThreadStartEvent";
    447         }
    448     }
    449 
    450     class VMStartEventImpl extends ThreadedEventImpl
    451                                         implements VMStartEvent {
    452         VMStartEventImpl(JDWP.Event.Composite.Events.VMStart evt) {
    453             super(evt, evt.requestID, evt.thread);
    454         }
    455 
    456         String eventName() {
    457             return "VMStartEvent";
    458         }
    459     }
    460 
    461     class VMDeathEventImpl extends EventImpl implements VMDeathEvent {
    462 
    463         VMDeathEventImpl(JDWP.Event.Composite.Events.VMDeath evt) {
    464             super(evt, evt.requestID);
    465         }
    466 
    467         String eventName() {
    468             return "VMDeathEvent";
    469         }
    470     }
    471 
    472     class VMDisconnectEventImpl extends EventImpl
    473                                          implements VMDisconnectEvent {
    474 
    475         VMDisconnectEventImpl() {
    476             super((byte)JDWP.EventKind.VM_DISCONNECTED);
    477         }
    478 
    479         String eventName() {
    480             return "VMDisconnectEvent";
    481         }
    482     }
    483 
    484     abstract class WatchpointEventImpl extends LocatableEventImpl
    485                                             implements WatchpointEvent {
    486         private final ReferenceTypeImpl refType;
    487         private final long fieldID;
    488         private final ObjectReference object;
    489         private Field field = null;
    490 
    491         WatchpointEventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
    492                             int requestID,
    493                             ThreadReference thread, Location location,
    494                             byte refTypeTag, long typeID, long fieldID,
    495                             ObjectReference object) {
    496             super(evt, requestID, thread, location);
    497             this.refType = this.vm.referenceType(typeID, refTypeTag);
    498             this.fieldID = fieldID;
    499             this.object = object;
    500         }
    501 
    502         public Field field() {
    503             if (field == null) {
    504                 field = refType.getFieldMirror(fieldID);
    505             }
    506             return field;
    507         }
    508 
    509         public ObjectReference object() {
    510             return object;
    511         }
    512 
    513         public Value valueCurrent() {
    514             if (object == null) {
    515                 return refType.getValue(field());
    516             } else {
    517                 return object.getValue(field());
    518             }
    519         }
    520     }
    521 
    522     class AccessWatchpointEventImpl extends WatchpointEventImpl
    523                                             implements AccessWatchpointEvent {
    524 
    525         AccessWatchpointEventImpl(JDWP.Event.Composite.Events.FieldAccess evt) {
    526             super(evt, evt.requestID, evt.thread, evt.location,
    527                   evt.refTypeTag, evt.typeID, evt.fieldID, evt.object);
    528         }
    529 
    530         String eventName() {
    531             return "AccessWatchpoint";
    532         }
    533     }
    534 
    535     class ModificationWatchpointEventImpl extends WatchpointEventImpl
    536                            implements ModificationWatchpointEvent {
    537         Value newValue;
    538 
    539         ModificationWatchpointEventImpl(
    540                         JDWP.Event.Composite.Events.FieldModification evt) {
    541             super(evt, evt.requestID, evt.thread, evt.location,
    542                   evt.refTypeTag, evt.typeID, evt.fieldID, evt.object);
    543             this.newValue = evt.valueToBe;
    544         }
    545 
    546         public Value valueToBe() {
    547             return newValue;
    548         }
    549 
    550         String eventName() {
    551             return "ModificationWatchpoint";
    552         }
    553     }
    554 
    555     /**
    556      * Events are constructed on the thread which reads all data from the
    557      * transport. This means that the packet cannot be converted to real
    558      * JDI objects as that may involve further communications with the
    559      * back end which would deadlock.
    560      *
    561      * Hence the {@link #build()} method below called by EventQueue.
    562      */
    563     EventSetImpl(VirtualMachine aVm, Packet pkt) {
    564         super();
    565 
    566         // From "MirrorImpl":
    567         // Yes, its a bit of a hack. But by doing it this
    568         // way, this is the only place we have to change
    569         // typing to substitute a new impl.
    570         vm = (VirtualMachineImpl)aVm;
    571 
    572         this.pkt = pkt;
    573     }
    574 
    575     /**
    576      * Constructor for special events like VM disconnected
    577      */
    578     EventSetImpl(VirtualMachine aVm, byte eventCmd) {
    579         this(aVm, null);
    580         suspendPolicy = JDWP.SuspendPolicy.NONE;
    581         switch (eventCmd) {
    582             case JDWP.EventKind.VM_DISCONNECTED:
    583                 addEvent(new VMDisconnectEventImpl());
    584                 break;
    585 
    586             default:
    587                 throw new InternalException("Bad singleton event code");
    588         }
    589     }
    590 
    591     private void addEvent(EventImpl evt) {
    592         // Note that this class has a public add method that throws
    593         // an exception so that clients can't modify the EventSet
    594         super.add(evt);
    595     }
    596 
    597     /*
    598      * Complete the construction of an EventSet.  This is called from
    599      * an event handler thread.  It upacks the JDWP events inside
    600      * the packet and creates EventImpls for them.  The EventSet is already
    601      * on EventQueues when this is called, so it has to be synch.
    602      */
    603     synchronized void build() {
    604         if (pkt == null) {
    605             return;
    606         }
    607         PacketStream ps = new PacketStream(vm, pkt);
    608         JDWP.Event.Composite compEvt = new JDWP.Event.Composite(vm, ps);
    609         suspendPolicy = compEvt.suspendPolicy;
    610         if ((vm.traceFlags & VirtualMachine.TRACE_EVENTS) != 0) {
    611             switch(suspendPolicy) {
    612                 case JDWP.SuspendPolicy.ALL:
    613                     vm.printTrace("EventSet: SUSPEND_ALL");
    614                     break;
    615 
    616                 case JDWP.SuspendPolicy.EVENT_THREAD:
    617                     vm.printTrace("EventSet: SUSPEND_EVENT_THREAD");
    618                     break;
    619 
    620                 case JDWP.SuspendPolicy.NONE:
    621                     vm.printTrace("EventSet: SUSPEND_NONE");
    622                     break;
    623             }
    624         }
    625 
    626         ThreadReference fix6485605 = null;
    627         for (int i = 0; i < compEvt.events.length; i++) {
    628             EventImpl evt = createEvent(compEvt.events[i]);
    629             if ((vm.traceFlags & VirtualMachine.TRACE_EVENTS) != 0) {
    630                 try {
    631                     vm.printTrace("Event: " + evt);
    632                 } catch (VMDisconnectedException ee) {
    633                     // ignore - see bug 6502716
    634                 }
    635             }
    636 
    637             switch (evt.destination()) {
    638                 case UNKNOWN_EVENT:
    639                     // Ignore disabled, deleted, unknown events, but
    640                     // save the thread if there is one since we might
    641                     // have to resume it.  Note that events for different
    642                     // threads can't be in the same event set.
    643                     if (evt instanceof ThreadedEventImpl &&
    644                         suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) {
    645                         fix6485605 = ((ThreadedEventImpl)evt).thread();
    646                     }
    647                     continue;
    648                 case CLIENT_EVENT:
    649                     addEvent(evt);
    650                     break;
    651                 case INTERNAL_EVENT:
    652                     if (internalEventSet == null) {
    653                         internalEventSet = new EventSetImpl(this.vm, null);
    654                     }
    655                     internalEventSet.addEvent(evt);
    656                     break;
    657                 default:
    658                     throw new InternalException("Invalid event destination");
    659             }
    660         }
    661         pkt = null; // No longer needed - free it up
    662 
    663         // Avoid hangs described in 6296125, 6293795
    664         if (super.size() == 0) {
    665             // This set has no client events.  If we don't do
    666             // needed resumes, no one else is going to.
    667             if (suspendPolicy == JDWP.SuspendPolicy.ALL) {
    668                 vm.resume();
    669             } else if (suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) {
    670                 // See bug 6485605.
    671                 if (fix6485605 != null) {
    672                     fix6485605.resume();
    673                 } else {
    674                     // apparently, there is nothing to resume.
    675                 }
    676             }
    677             suspendPolicy = JDWP.SuspendPolicy.NONE;
    678 
    679         }
    680 
    681     }
    682 
    683     /**
    684      * Filter out internal events
    685      */
    686     EventSet userFilter() {
    687         return this;
    688     }
    689 
    690     /**
    691      * Filter out user events.
    692      */
    693     EventSet internalFilter() {
    694         return this.internalEventSet;
    695     }
    696 
    697     EventImpl createEvent(JDWP.Event.Composite.Events evt) {
    698         JDWP.Event.Composite.Events.EventsCommon comm = evt.aEventsCommon;
    699         switch (evt.eventKind) {
    700             case JDWP.EventKind.THREAD_START:
    701                 return new ThreadStartEventImpl(
    702                       (JDWP.Event.Composite.Events.ThreadStart)comm);
    703 
    704             case JDWP.EventKind.THREAD_END:
    705                 return new ThreadDeathEventImpl(
    706                       (JDWP.Event.Composite.Events.ThreadDeath)comm);
    707 
    708             case JDWP.EventKind.EXCEPTION:
    709                 return new ExceptionEventImpl(
    710                       (JDWP.Event.Composite.Events.Exception)comm);
    711 
    712             case JDWP.EventKind.BREAKPOINT:
    713                 return new BreakpointEventImpl(
    714                       (JDWP.Event.Composite.Events.Breakpoint)comm);
    715 
    716             case JDWP.EventKind.METHOD_ENTRY:
    717                 return new MethodEntryEventImpl(
    718                       (JDWP.Event.Composite.Events.MethodEntry)comm);
    719 
    720             case JDWP.EventKind.METHOD_EXIT:
    721                 return new MethodExitEventImpl(
    722                       (JDWP.Event.Composite.Events.MethodExit)comm);
    723 
    724             case JDWP.EventKind.METHOD_EXIT_WITH_RETURN_VALUE:
    725                 return new MethodExitEventImpl(
    726                       (JDWP.Event.Composite.Events.MethodExitWithReturnValue)comm);
    727 
    728             case JDWP.EventKind.FIELD_ACCESS:
    729                 return new AccessWatchpointEventImpl(
    730                       (JDWP.Event.Composite.Events.FieldAccess)comm);
    731 
    732             case JDWP.EventKind.FIELD_MODIFICATION:
    733                 return new ModificationWatchpointEventImpl(
    734                       (JDWP.Event.Composite.Events.FieldModification)comm);
    735 
    736             case JDWP.EventKind.SINGLE_STEP:
    737                 return new StepEventImpl(
    738                       (JDWP.Event.Composite.Events.SingleStep)comm);
    739 
    740             case JDWP.EventKind.CLASS_PREPARE:
    741                 return new ClassPrepareEventImpl(
    742                       (JDWP.Event.Composite.Events.ClassPrepare)comm);
    743 
    744             case JDWP.EventKind.CLASS_UNLOAD:
    745                 return new ClassUnloadEventImpl(
    746                       (JDWP.Event.Composite.Events.ClassUnload)comm);
    747 
    748             case JDWP.EventKind.MONITOR_CONTENDED_ENTER:
    749                 return new MonitorContendedEnterEventImpl(
    750                       (JDWP.Event.Composite.Events.MonitorContendedEnter)comm);
    751 
    752             case JDWP.EventKind.MONITOR_CONTENDED_ENTERED:
    753                 return new MonitorContendedEnteredEventImpl(
    754                       (JDWP.Event.Composite.Events.MonitorContendedEntered)comm);
    755 
    756             case JDWP.EventKind.MONITOR_WAIT:
    757                 return new MonitorWaitEventImpl(
    758                       (JDWP.Event.Composite.Events.MonitorWait)comm);
    759 
    760             case JDWP.EventKind.MONITOR_WAITED:
    761                 return new MonitorWaitedEventImpl(
    762                       (JDWP.Event.Composite.Events.MonitorWaited)comm);
    763 
    764             case JDWP.EventKind.VM_START:
    765                 return new VMStartEventImpl(
    766                       (JDWP.Event.Composite.Events.VMStart)comm);
    767 
    768             case JDWP.EventKind.VM_DEATH:
    769                 return new VMDeathEventImpl(
    770                       (JDWP.Event.Composite.Events.VMDeath)comm);
    771 
    772             default:
    773                 // Ignore unknown event types
    774                 System.err.println("Ignoring event cmd " +
    775                                    evt.eventKind + " from the VM");
    776                 return null;
    777         }
    778     }
    779 
    780     public VirtualMachine virtualMachine() {
    781         return vm;
    782     }
    783 
    784     public int suspendPolicy() {
    785         return EventRequestManagerImpl.JDWPtoJDISuspendPolicy(suspendPolicy);
    786     }
    787 
    788     private ThreadReference eventThread() {
    789         for (Event event : this) {
    790             if (event instanceof ThreadedEventImpl) {
    791                 return ((ThreadedEventImpl)event).thread();
    792             }
    793         }
    794         return null;
    795     }
    796 
    797     public void resume() {
    798         switch (suspendPolicy()) {
    799             case EventRequest.SUSPEND_ALL:
    800                 vm.resume();
    801                 break;
    802             case EventRequest.SUSPEND_EVENT_THREAD:
    803                 ThreadReference thread = eventThread();
    804                 if (thread == null) {
    805                     throw new InternalException("Inconsistent suspend policy");
    806                 }
    807                 thread.resume();
    808                 break;
    809             case EventRequest.SUSPEND_NONE:
    810                 // Do nothing
    811                 break;
    812             default:
    813                 throw new InternalException("Invalid suspend policy");
    814         }
    815     }
    816 
    817     public Iterator<Event> iterator() {
    818         return new Itr();
    819     }
    820 
    821     public EventIterator eventIterator() {
    822         return new Itr();
    823     }
    824 
    825     public class Itr implements EventIterator {
    826         /**
    827          * Index of element to be returned by subsequent call to next.
    828          */
    829         int cursor = 0;
    830 
    831         public boolean hasNext() {
    832             return cursor != size();
    833         }
    834 
    835         public Event next() {
    836             try {
    837                 Event nxt = get(cursor);
    838                 ++cursor;
    839                 return nxt;
    840             } catch(IndexOutOfBoundsException e) {
    841                 throw new NoSuchElementException();
    842             }
    843         }
    844 
    845         public Event nextEvent() {
    846             return next();
    847         }
    848 
    849         public void remove() {
    850             throw new UnsupportedOperationException();
    851         }
    852     }
    853 
    854     @Override
    855     public Spliterator<Event> spliterator() {
    856         return Spliterators.spliterator(this, Spliterator.DISTINCT);
    857     }
    858 
    859     /* below make this unmodifiable */
    860 
    861     public boolean add(Event o){
    862         throw new UnsupportedOperationException();
    863     }
    864     public boolean remove(Object o) {
    865         throw new UnsupportedOperationException();
    866     }
    867     public boolean addAll(Collection<? extends Event> coll) {
    868         throw new UnsupportedOperationException();
    869     }
    870     public boolean removeAll(Collection<?> coll) {
    871         throw new UnsupportedOperationException();
    872     }
    873     public boolean retainAll(Collection<?> coll) {
    874         throw new UnsupportedOperationException();
    875     }
    876     public void clear() {
    877         throw new UnsupportedOperationException();
    878     }
    879 }
    880