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