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 
toString()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          */
EventImpl(JDWP.Event.Composite.Events.EventsCommon evt, int requestID)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          */
equals(Object obj)94         public boolean equals(Object obj) {
95             return this == obj;
96         }
97 
hashCode()98         public int hashCode() {
99             return System.identityHashCode(this);
100         }
101 
102         /**
103          * Constructor for VM disconnected events.
104          */
EventImpl(byte eventCmd)105         protected EventImpl(byte eventCmd) {
106             super(EventSetImpl.this.vm);
107             this.eventCmd = eventCmd;
108             this.requestID = 0;
109             this.request = null;
110         }
111 
request()112         public EventRequest request() {
113             return request;
114         }
115 
requestID()116         int requestID() {
117             return requestID;
118         }
119 
destination()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 
eventName()162         abstract String eventName();
163 
toString()164         public String toString() {
165             return eventName();
166         }
167 
168     }
169 
170     abstract class ThreadedEventImpl extends EventImpl {
171         private ThreadReference thread;
172 
ThreadedEventImpl(JDWP.Event.Composite.Events.EventsCommon evt, int requestID, ThreadReference thread)173         ThreadedEventImpl(JDWP.Event.Composite.Events.EventsCommon evt,
174                           int requestID, ThreadReference thread) {
175             super(evt, requestID);
176             this.thread = thread;
177         }
178 
thread()179         public ThreadReference thread() {
180             return thread;
181         }
182 
toString()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 
LocatableEventImpl(JDWP.Event.Composite.Events.EventsCommon evt, int requestID, ThreadReference thread, Location location)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 
location()199         public Location location() {
200             return location;
201         }
202 
203         /**
204          * For MethodEntry and MethodExit
205          */
method()206         public Method method() {
207             return location.method();
208         }
209 
toString()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 {
BreakpointEventImpl(JDWP.Event.Composite.Events.Breakpoint evt)219         BreakpointEventImpl(JDWP.Event.Composite.Events.Breakpoint evt) {
220             super(evt, evt.requestID, evt.thread, evt.location);
221         }
222 
eventName()223         String eventName() {
224             return "BreakpointEvent";
225         }
226     }
227 
228     class StepEventImpl extends LocatableEventImpl implements StepEvent {
StepEventImpl(JDWP.Event.Composite.Events.SingleStep evt)229         StepEventImpl(JDWP.Event.Composite.Events.SingleStep evt) {
230             super(evt, evt.requestID, evt.thread, evt.location);
231         }
232 
eventName()233         String eventName() {
234             return "StepEvent";
235         }
236     }
237 
238     class MethodEntryEventImpl extends LocatableEventImpl
239                             implements MethodEntryEvent {
MethodEntryEventImpl(JDWP.Event.Composite.Events.MethodEntry evt)240         MethodEntryEventImpl(JDWP.Event.Composite.Events.MethodEntry evt) {
241             super(evt, evt.requestID, evt.thread, evt.location);
242         }
243 
eventName()244         String eventName() {
245             return "MethodEntryEvent";
246         }
247     }
248 
249     class MethodExitEventImpl extends LocatableEventImpl
250                             implements MethodExitEvent {
251         private Value returnVal = null;
252 
MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExit evt)253         MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExit evt) {
254             super(evt, evt.requestID, evt.thread, evt.location);
255         }
256 
MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExitWithReturnValue evt)257         MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExitWithReturnValue evt) {
258             super(evt, evt.requestID, evt.thread, evt.location);
259             returnVal = evt.value;
260         }
261 
eventName()262         String eventName() {
263             return "MethodExitEvent";
264         }
265 
returnValue()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 
MonitorContendedEnterEventImpl(JDWP.Event.Composite.Events.MonitorContendedEnter evt)280         MonitorContendedEnterEventImpl(JDWP.Event.Composite.Events.MonitorContendedEnter evt) {
281             super(evt, evt.requestID, evt.thread, evt.location);
282             this.monitor = evt.object;
283         }
284 
eventName()285         String eventName() {
286             return "MonitorContendedEnter";
287         }
288 
monitor()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 
MonitorContendedEnteredEventImpl(JDWP.Event.Composite.Events.MonitorContendedEntered evt)299         MonitorContendedEnteredEventImpl(JDWP.Event.Composite.Events.MonitorContendedEntered evt) {
300             super(evt, evt.requestID, evt.thread, evt.location);
301             this.monitor = evt.object;
302         }
303 
eventName()304         String eventName() {
305             return "MonitorContendedEntered";
306         }
307 
monitor()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 
MonitorWaitEventImpl(JDWP.Event.Composite.Events.MonitorWait evt)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 
eventName()325         String eventName() {
326             return "MonitorWait";
327         }
328 
monitor()329         public ObjectReference  monitor() {
330             return monitor;
331         };
332 
timeout()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 
MonitorWaitedEventImpl(JDWP.Event.Composite.Events.MonitorWaited evt)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 
eventName()349         String eventName() {
350             return "MonitorWaited";
351         }
352 
monitor()353         public ObjectReference  monitor() {
354             return monitor;
355         };
356 
timedout()357         public boolean timedout() {
358             return timed_out;
359         }
360     }
361 
362     class ClassPrepareEventImpl extends ThreadedEventImpl
363                             implements ClassPrepareEvent {
364         private ReferenceType referenceType;
365 
ClassPrepareEventImpl(JDWP.Event.Composite.Events.ClassPrepare evt)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 
referenceType()373         public ReferenceType referenceType() {
374             return referenceType;
375         }
376 
eventName()377         String eventName() {
378             return "ClassPrepareEvent";
379         }
380     }
381 
382     class ClassUnloadEventImpl extends EventImpl implements ClassUnloadEvent {
383         private String classSignature;
384 
ClassUnloadEventImpl(JDWP.Event.Composite.Events.ClassUnload evt)385         ClassUnloadEventImpl(JDWP.Event.Composite.Events.ClassUnload evt) {
386             super(evt, evt.requestID);
387             this.classSignature = evt.signature;
388         }
389 
className()390         public String className() {
391             return classSignature.substring(1, classSignature.length()-1)
392                 .replace('/', '.');
393         }
394 
classSignature()395         public String classSignature() {
396             return classSignature;
397         }
398 
eventName()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 
ExceptionEventImpl(JDWP.Event.Composite.Events.Exception evt)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 
exception()415         public ObjectReference exception() {
416             return exception;
417         }
418 
catchLocation()419         public Location catchLocation() {
420             return catchLocation;
421         }
422 
eventName()423         String eventName() {
424             return "ExceptionEvent";
425         }
426     }
427 
428     class ThreadDeathEventImpl extends ThreadedEventImpl
429                                         implements ThreadDeathEvent {
ThreadDeathEventImpl(JDWP.Event.Composite.Events.ThreadDeath evt)430         ThreadDeathEventImpl(JDWP.Event.Composite.Events.ThreadDeath evt) {
431             super(evt, evt.requestID, evt.thread);
432         }
433 
eventName()434         String eventName() {
435             return "ThreadDeathEvent";
436         }
437     }
438 
439     class ThreadStartEventImpl extends ThreadedEventImpl
440                                         implements ThreadStartEvent {
ThreadStartEventImpl(JDWP.Event.Composite.Events.ThreadStart evt)441         ThreadStartEventImpl(JDWP.Event.Composite.Events.ThreadStart evt) {
442             super(evt, evt.requestID, evt.thread);
443         }
444 
eventName()445         String eventName() {
446             return "ThreadStartEvent";
447         }
448     }
449 
450     class VMStartEventImpl extends ThreadedEventImpl
451                                         implements VMStartEvent {
VMStartEventImpl(JDWP.Event.Composite.Events.VMStart evt)452         VMStartEventImpl(JDWP.Event.Composite.Events.VMStart evt) {
453             super(evt, evt.requestID, evt.thread);
454         }
455 
eventName()456         String eventName() {
457             return "VMStartEvent";
458         }
459     }
460 
461     class VMDeathEventImpl extends EventImpl implements VMDeathEvent {
462 
VMDeathEventImpl(JDWP.Event.Composite.Events.VMDeath evt)463         VMDeathEventImpl(JDWP.Event.Composite.Events.VMDeath evt) {
464             super(evt, evt.requestID);
465         }
466 
eventName()467         String eventName() {
468             return "VMDeathEvent";
469         }
470     }
471 
472     class VMDisconnectEventImpl extends EventImpl
473                                          implements VMDisconnectEvent {
474 
VMDisconnectEventImpl()475         VMDisconnectEventImpl() {
476             super((byte)JDWP.EventKind.VM_DISCONNECTED);
477         }
478 
eventName()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 
WatchpointEventImpl(JDWP.Event.Composite.Events.EventsCommon evt, int requestID, ThreadReference thread, Location location, byte refTypeTag, long typeID, long fieldID, ObjectReference object)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 
field()502         public Field field() {
503             if (field == null) {
504                 field = refType.getFieldMirror(fieldID);
505             }
506             return field;
507         }
508 
object()509         public ObjectReference object() {
510             return object;
511         }
512 
valueCurrent()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 
AccessWatchpointEventImpl(JDWP.Event.Composite.Events.FieldAccess evt)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 
eventName()530         String eventName() {
531             return "AccessWatchpoint";
532         }
533     }
534 
535     class ModificationWatchpointEventImpl extends WatchpointEventImpl
536                            implements ModificationWatchpointEvent {
537         Value newValue;
538 
ModificationWatchpointEventImpl( JDWP.Event.Composite.Events.FieldModification evt)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 
valueToBe()546         public Value valueToBe() {
547             return newValue;
548         }
549 
eventName()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      */
EventSetImpl(VirtualMachine aVm, Packet pkt)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      */
EventSetImpl(VirtualMachine aVm, byte eventCmd)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 
addEvent(EventImpl evt)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      */
build()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      */
userFilter()686     EventSet userFilter() {
687         return this;
688     }
689 
690     /**
691      * Filter out user events.
692      */
internalFilter()693     EventSet internalFilter() {
694         return this.internalEventSet;
695     }
696 
createEvent(JDWP.Event.Composite.Events evt)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 
virtualMachine()780     public VirtualMachine virtualMachine() {
781         return vm;
782     }
783 
suspendPolicy()784     public int suspendPolicy() {
785         return EventRequestManagerImpl.JDWPtoJDISuspendPolicy(suspendPolicy);
786     }
787 
eventThread()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 
resume()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 
iterator()817     public Iterator<Event> iterator() {
818         return new Itr();
819     }
820 
eventIterator()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 
hasNext()831         public boolean hasNext() {
832             return cursor != size();
833         }
834 
next()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 
nextEvent()845         public Event nextEvent() {
846             return next();
847         }
848 
remove()849         public void remove() {
850             throw new UnsupportedOperationException();
851         }
852     }
853 
854     @Override
spliterator()855     public Spliterator<Event> spliterator() {
856         return Spliterators.spliterator(this, Spliterator.DISTINCT);
857     }
858 
859     /* below make this unmodifiable */
860 
add(Event o)861     public boolean add(Event o){
862         throw new UnsupportedOperationException();
863     }
remove(Object o)864     public boolean remove(Object o) {
865         throw new UnsupportedOperationException();
866     }
addAll(Collection<? extends Event> coll)867     public boolean addAll(Collection<? extends Event> coll) {
868         throw new UnsupportedOperationException();
869     }
removeAll(Collection<?> coll)870     public boolean removeAll(Collection<?> coll) {
871         throw new UnsupportedOperationException();
872     }
retainAll(Collection<?> coll)873     public boolean retainAll(Collection<?> coll) {
874         throw new UnsupportedOperationException();
875     }
clear()876     public void clear() {
877         throw new UnsupportedOperationException();
878     }
879 }
880