| /* |
| * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.tools.jdi; |
| |
| import com.sun.jdi.*; |
| import com.sun.jdi.event.*; |
| import com.sun.jdi.request.*; |
| |
| import java.util.*; |
| enum EventDestination {UNKNOWN_EVENT, INTERNAL_EVENT, CLIENT_EVENT}; |
| |
| /* |
| * An EventSet is normally created by the transport reader thread when |
| * it reads a JDWP Composite command. The constructor doesn't unpack |
| * the events contained in the Composite command and create EventImpls |
| * for them because that process might involve calling back into the back-end |
| * which should not be done by the transport reader thread. Instead, |
| * the raw bytes of the packet are read and stored in the EventSet. |
| * The EventSet is then added to each EventQueue. When an EventSet is |
| * removed from an EventQueue, the EventSetImpl.build() method is called. |
| * This method reads the packet bytes and creates the actual EventImpl objects. |
| * build() also filters out events for our internal handler and puts them in |
| * their own EventSet. This means that the EventImpls that are in the EventSet |
| * that is on the queues are all for client requests. |
| */ |
| public class EventSetImpl extends ArrayList<Event> implements EventSet { |
| private static final long serialVersionUID = -4857338819787924570L; |
| private VirtualMachineImpl vm; // we implement Mirror |
| private Packet pkt; |
| private byte suspendPolicy; |
| private EventSetImpl internalEventSet; |
| |
| public String toString() { |
| String string = "event set, policy:" + suspendPolicy + |
| ", count:" + this.size() + " = {"; |
| boolean first = true; |
| for (Event event : this) { |
| if (!first) { |
| string += ", "; |
| } |
| string += event.toString(); |
| first = false; |
| } |
| string += "}"; |
| return string; |
| } |
| |
| abstract class EventImpl extends MirrorImpl implements Event { |
| |
| private final byte eventCmd; |
| private final int requestID; |
| // This is set only for client requests, not internal requests. |
| private final EventRequest request; |
| |
| /** |
| * Constructor for events. |
| */ |
| protected EventImpl(JDWP.Event.Composite.Events.EventsCommon evt, |
| int requestID) { |
| super(EventSetImpl.this.vm); |
| this.eventCmd = evt.eventKind(); |
| this.requestID = requestID; |
| EventRequestManagerImpl ermi = EventSetImpl.this. |
| vm.eventRequestManagerImpl(); |
| this.request = ermi.request(eventCmd, requestID); |
| } |
| |
| /* |
| * Override superclass back to default equality |
| */ |
| public boolean equals(Object obj) { |
| return this == obj; |
| } |
| |
| public int hashCode() { |
| return System.identityHashCode(this); |
| } |
| |
| /** |
| * Constructor for VM disconnected events. |
| */ |
| protected EventImpl(byte eventCmd) { |
| super(EventSetImpl.this.vm); |
| this.eventCmd = eventCmd; |
| this.requestID = 0; |
| this.request = null; |
| } |
| |
| public EventRequest request() { |
| return request; |
| } |
| |
| int requestID() { |
| return requestID; |
| } |
| |
| EventDestination destination() { |
| /* |
| * We need to decide if this event is for |
| * 1. an internal request |
| * 2. a client request that is no longer available, ie |
| * it has been deleted, or disabled and re-enabled |
| * which gives it a new ID. |
| * 3. a current client request that is disabled |
| * 4. a current enabled client request. |
| * |
| * We will filter this set into a set |
| * that contains only 1s for our internal queue |
| * and a set that contains only 4s for our client queue. |
| * If we get an EventSet that contains only 2 and 3 |
| * then we have to resume it if it is not SUSPEND_NONE |
| * because no one else will. |
| */ |
| if (requestID == 0) { |
| /* An unsolicited event. These have traditionally |
| * been treated as client events. |
| */ |
| return EventDestination.CLIENT_EVENT; |
| } |
| |
| // Is this an event for a current client request? |
| if (request == null) { |
| // Nope. Is it an event for an internal request? |
| EventRequestManagerImpl ermi = this.vm.getInternalEventRequestManager(); |
| if (ermi.request(eventCmd, requestID) != null) { |
| // Yep |
| return EventDestination.INTERNAL_EVENT; |
| } |
| return EventDestination.UNKNOWN_EVENT; |
| } |
| |
| // We found a client request |
| if (request.isEnabled()) { |
| return EventDestination.CLIENT_EVENT; |
| } |
| return EventDestination.UNKNOWN_EVENT; |
| } |
| |
| abstract String eventName(); |
| |
| public String toString() { |
| return eventName(); |
| } |
| |
| } |
| |
| abstract class ThreadedEventImpl extends EventImpl { |
| private ThreadReference thread; |
| |
| ThreadedEventImpl(JDWP.Event.Composite.Events.EventsCommon evt, |
| int requestID, ThreadReference thread) { |
| super(evt, requestID); |
| this.thread = thread; |
| } |
| |
| public ThreadReference thread() { |
| return thread; |
| } |
| |
| public String toString() { |
| return eventName() + " in thread " + thread.name(); |
| } |
| } |
| |
| abstract class LocatableEventImpl extends ThreadedEventImpl |
| implements Locatable { |
| private Location location; |
| |
| LocatableEventImpl(JDWP.Event.Composite.Events.EventsCommon evt, |
| int requestID, |
| ThreadReference thread, Location location) { |
| super(evt, requestID, thread); |
| this.location = location; |
| } |
| |
| public Location location() { |
| return location; |
| } |
| |
| /** |
| * For MethodEntry and MethodExit |
| */ |
| public Method method() { |
| return location.method(); |
| } |
| |
| public String toString() { |
| return eventName() + "@" + |
| ((location() == null) ? " null" : location().toString()) + |
| " in thread " + thread().name(); |
| } |
| } |
| |
| class BreakpointEventImpl extends LocatableEventImpl |
| implements BreakpointEvent { |
| BreakpointEventImpl(JDWP.Event.Composite.Events.Breakpoint evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| } |
| |
| String eventName() { |
| return "BreakpointEvent"; |
| } |
| } |
| |
| class StepEventImpl extends LocatableEventImpl implements StepEvent { |
| StepEventImpl(JDWP.Event.Composite.Events.SingleStep evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| } |
| |
| String eventName() { |
| return "StepEvent"; |
| } |
| } |
| |
| class MethodEntryEventImpl extends LocatableEventImpl |
| implements MethodEntryEvent { |
| MethodEntryEventImpl(JDWP.Event.Composite.Events.MethodEntry evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| } |
| |
| String eventName() { |
| return "MethodEntryEvent"; |
| } |
| } |
| |
| class MethodExitEventImpl extends LocatableEventImpl |
| implements MethodExitEvent { |
| private Value returnVal = null; |
| |
| MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExit evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| } |
| |
| MethodExitEventImpl(JDWP.Event.Composite.Events.MethodExitWithReturnValue evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| returnVal = evt.value; |
| } |
| |
| String eventName() { |
| return "MethodExitEvent"; |
| } |
| |
| public Value returnValue() { |
| if (!this.vm.canGetMethodReturnValues()) { |
| throw new UnsupportedOperationException( |
| "target does not support return values in MethodExit events"); |
| } |
| return returnVal; |
| } |
| |
| } |
| |
| class MonitorContendedEnterEventImpl extends LocatableEventImpl |
| implements MonitorContendedEnterEvent { |
| private ObjectReference monitor = null; |
| |
| MonitorContendedEnterEventImpl(JDWP.Event.Composite.Events.MonitorContendedEnter evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| this.monitor = evt.object; |
| } |
| |
| String eventName() { |
| return "MonitorContendedEnter"; |
| } |
| |
| public ObjectReference monitor() { |
| return monitor; |
| }; |
| |
| } |
| |
| class MonitorContendedEnteredEventImpl extends LocatableEventImpl |
| implements MonitorContendedEnteredEvent { |
| private ObjectReference monitor = null; |
| |
| MonitorContendedEnteredEventImpl(JDWP.Event.Composite.Events.MonitorContendedEntered evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| this.monitor = evt.object; |
| } |
| |
| String eventName() { |
| return "MonitorContendedEntered"; |
| } |
| |
| public ObjectReference monitor() { |
| return monitor; |
| }; |
| |
| } |
| |
| class MonitorWaitEventImpl extends LocatableEventImpl |
| implements MonitorWaitEvent { |
| private ObjectReference monitor = null; |
| private long timeout; |
| |
| MonitorWaitEventImpl(JDWP.Event.Composite.Events.MonitorWait evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| this.monitor = evt.object; |
| this.timeout = evt.timeout; |
| } |
| |
| String eventName() { |
| return "MonitorWait"; |
| } |
| |
| public ObjectReference monitor() { |
| return monitor; |
| }; |
| |
| public long timeout() { |
| return timeout; |
| } |
| } |
| |
| class MonitorWaitedEventImpl extends LocatableEventImpl |
| implements MonitorWaitedEvent { |
| private ObjectReference monitor = null; |
| private boolean timed_out; |
| |
| MonitorWaitedEventImpl(JDWP.Event.Composite.Events.MonitorWaited evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| this.monitor = evt.object; |
| this.timed_out = evt.timed_out; |
| } |
| |
| String eventName() { |
| return "MonitorWaited"; |
| } |
| |
| public ObjectReference monitor() { |
| return monitor; |
| }; |
| |
| public boolean timedout() { |
| return timed_out; |
| } |
| } |
| |
| class ClassPrepareEventImpl extends ThreadedEventImpl |
| implements ClassPrepareEvent { |
| private ReferenceType referenceType; |
| |
| ClassPrepareEventImpl(JDWP.Event.Composite.Events.ClassPrepare evt) { |
| super(evt, evt.requestID, evt.thread); |
| referenceType = this.vm.referenceType(evt.typeID, evt.refTypeTag, |
| evt.signature); |
| ((ReferenceTypeImpl)referenceType).setStatus(evt.status); |
| } |
| |
| public ReferenceType referenceType() { |
| return referenceType; |
| } |
| |
| String eventName() { |
| return "ClassPrepareEvent"; |
| } |
| } |
| |
| class ClassUnloadEventImpl extends EventImpl implements ClassUnloadEvent { |
| private String classSignature; |
| |
| ClassUnloadEventImpl(JDWP.Event.Composite.Events.ClassUnload evt) { |
| super(evt, evt.requestID); |
| this.classSignature = evt.signature; |
| } |
| |
| public String className() { |
| return classSignature.substring(1, classSignature.length()-1) |
| .replace('/', '.'); |
| } |
| |
| public String classSignature() { |
| return classSignature; |
| } |
| |
| String eventName() { |
| return "ClassUnloadEvent"; |
| } |
| } |
| |
| class ExceptionEventImpl extends LocatableEventImpl |
| implements ExceptionEvent { |
| private ObjectReference exception; |
| private Location catchLocation; |
| |
| ExceptionEventImpl(JDWP.Event.Composite.Events.Exception evt) { |
| super(evt, evt.requestID, evt.thread, evt.location); |
| this.exception = evt.exception; |
| this.catchLocation = evt.catchLocation; |
| } |
| |
| public ObjectReference exception() { |
| return exception; |
| } |
| |
| public Location catchLocation() { |
| return catchLocation; |
| } |
| |
| String eventName() { |
| return "ExceptionEvent"; |
| } |
| } |
| |
| class ThreadDeathEventImpl extends ThreadedEventImpl |
| implements ThreadDeathEvent { |
| ThreadDeathEventImpl(JDWP.Event.Composite.Events.ThreadDeath evt) { |
| super(evt, evt.requestID, evt.thread); |
| } |
| |
| String eventName() { |
| return "ThreadDeathEvent"; |
| } |
| } |
| |
| class ThreadStartEventImpl extends ThreadedEventImpl |
| implements ThreadStartEvent { |
| ThreadStartEventImpl(JDWP.Event.Composite.Events.ThreadStart evt) { |
| super(evt, evt.requestID, evt.thread); |
| } |
| |
| String eventName() { |
| return "ThreadStartEvent"; |
| } |
| } |
| |
| class VMStartEventImpl extends ThreadedEventImpl |
| implements VMStartEvent { |
| VMStartEventImpl(JDWP.Event.Composite.Events.VMStart evt) { |
| super(evt, evt.requestID, evt.thread); |
| } |
| |
| String eventName() { |
| return "VMStartEvent"; |
| } |
| } |
| |
| class VMDeathEventImpl extends EventImpl implements VMDeathEvent { |
| |
| VMDeathEventImpl(JDWP.Event.Composite.Events.VMDeath evt) { |
| super(evt, evt.requestID); |
| } |
| |
| String eventName() { |
| return "VMDeathEvent"; |
| } |
| } |
| |
| class VMDisconnectEventImpl extends EventImpl |
| implements VMDisconnectEvent { |
| |
| VMDisconnectEventImpl() { |
| super((byte)JDWP.EventKind.VM_DISCONNECTED); |
| } |
| |
| String eventName() { |
| return "VMDisconnectEvent"; |
| } |
| } |
| |
| abstract class WatchpointEventImpl extends LocatableEventImpl |
| implements WatchpointEvent { |
| private final ReferenceTypeImpl refType; |
| private final long fieldID; |
| private final ObjectReference object; |
| private Field field = null; |
| |
| WatchpointEventImpl(JDWP.Event.Composite.Events.EventsCommon evt, |
| int requestID, |
| ThreadReference thread, Location location, |
| byte refTypeTag, long typeID, long fieldID, |
| ObjectReference object) { |
| super(evt, requestID, thread, location); |
| this.refType = this.vm.referenceType(typeID, refTypeTag); |
| this.fieldID = fieldID; |
| this.object = object; |
| } |
| |
| public Field field() { |
| if (field == null) { |
| field = refType.getFieldMirror(fieldID); |
| } |
| return field; |
| } |
| |
| public ObjectReference object() { |
| return object; |
| } |
| |
| public Value valueCurrent() { |
| if (object == null) { |
| return refType.getValue(field()); |
| } else { |
| return object.getValue(field()); |
| } |
| } |
| } |
| |
| class AccessWatchpointEventImpl extends WatchpointEventImpl |
| implements AccessWatchpointEvent { |
| |
| AccessWatchpointEventImpl(JDWP.Event.Composite.Events.FieldAccess evt) { |
| super(evt, evt.requestID, evt.thread, evt.location, |
| evt.refTypeTag, evt.typeID, evt.fieldID, evt.object); |
| } |
| |
| String eventName() { |
| return "AccessWatchpoint"; |
| } |
| } |
| |
| class ModificationWatchpointEventImpl extends WatchpointEventImpl |
| implements ModificationWatchpointEvent { |
| Value newValue; |
| |
| ModificationWatchpointEventImpl( |
| JDWP.Event.Composite.Events.FieldModification evt) { |
| super(evt, evt.requestID, evt.thread, evt.location, |
| evt.refTypeTag, evt.typeID, evt.fieldID, evt.object); |
| this.newValue = evt.valueToBe; |
| } |
| |
| public Value valueToBe() { |
| return newValue; |
| } |
| |
| String eventName() { |
| return "ModificationWatchpoint"; |
| } |
| } |
| |
| /** |
| * Events are constructed on the thread which reads all data from the |
| * transport. This means that the packet cannot be converted to real |
| * JDI objects as that may involve further communications with the |
| * back end which would deadlock. |
| * |
| * Hence the {@link #build()} method below called by EventQueue. |
| */ |
| EventSetImpl(VirtualMachine aVm, Packet pkt) { |
| super(); |
| |
| // From "MirrorImpl": |
| // Yes, its a bit of a hack. But by doing it this |
| // way, this is the only place we have to change |
| // typing to substitute a new impl. |
| vm = (VirtualMachineImpl)aVm; |
| |
| this.pkt = pkt; |
| } |
| |
| /** |
| * Constructor for special events like VM disconnected |
| */ |
| EventSetImpl(VirtualMachine aVm, byte eventCmd) { |
| this(aVm, null); |
| suspendPolicy = JDWP.SuspendPolicy.NONE; |
| switch (eventCmd) { |
| case JDWP.EventKind.VM_DISCONNECTED: |
| addEvent(new VMDisconnectEventImpl()); |
| break; |
| |
| default: |
| throw new InternalException("Bad singleton event code"); |
| } |
| } |
| |
| private void addEvent(EventImpl evt) { |
| // Note that this class has a public add method that throws |
| // an exception so that clients can't modify the EventSet |
| super.add(evt); |
| } |
| |
| /* |
| * Complete the construction of an EventSet. This is called from |
| * an event handler thread. It upacks the JDWP events inside |
| * the packet and creates EventImpls for them. The EventSet is already |
| * on EventQueues when this is called, so it has to be synch. |
| */ |
| synchronized void build() { |
| if (pkt == null) { |
| return; |
| } |
| PacketStream ps = new PacketStream(vm, pkt); |
| JDWP.Event.Composite compEvt = new JDWP.Event.Composite(vm, ps); |
| suspendPolicy = compEvt.suspendPolicy; |
| if ((vm.traceFlags & VirtualMachine.TRACE_EVENTS) != 0) { |
| switch(suspendPolicy) { |
| case JDWP.SuspendPolicy.ALL: |
| vm.printTrace("EventSet: SUSPEND_ALL"); |
| break; |
| |
| case JDWP.SuspendPolicy.EVENT_THREAD: |
| vm.printTrace("EventSet: SUSPEND_EVENT_THREAD"); |
| break; |
| |
| case JDWP.SuspendPolicy.NONE: |
| vm.printTrace("EventSet: SUSPEND_NONE"); |
| break; |
| } |
| } |
| |
| ThreadReference fix6485605 = null; |
| for (int i = 0; i < compEvt.events.length; i++) { |
| EventImpl evt = createEvent(compEvt.events[i]); |
| if ((vm.traceFlags & VirtualMachine.TRACE_EVENTS) != 0) { |
| try { |
| vm.printTrace("Event: " + evt); |
| } catch (VMDisconnectedException ee) { |
| // ignore - see bug 6502716 |
| } |
| } |
| |
| switch (evt.destination()) { |
| case UNKNOWN_EVENT: |
| // Ignore disabled, deleted, unknown events, but |
| // save the thread if there is one since we might |
| // have to resume it. Note that events for different |
| // threads can't be in the same event set. |
| if (evt instanceof ThreadedEventImpl && |
| suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) { |
| fix6485605 = ((ThreadedEventImpl)evt).thread(); |
| } |
| continue; |
| case CLIENT_EVENT: |
| addEvent(evt); |
| break; |
| case INTERNAL_EVENT: |
| if (internalEventSet == null) { |
| internalEventSet = new EventSetImpl(this.vm, null); |
| } |
| internalEventSet.addEvent(evt); |
| break; |
| default: |
| throw new InternalException("Invalid event destination"); |
| } |
| } |
| pkt = null; // No longer needed - free it up |
| |
| // Avoid hangs described in 6296125, 6293795 |
| if (super.size() == 0) { |
| // This set has no client events. If we don't do |
| // needed resumes, no one else is going to. |
| if (suspendPolicy == JDWP.SuspendPolicy.ALL) { |
| vm.resume(); |
| } else if (suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) { |
| // See bug 6485605. |
| if (fix6485605 != null) { |
| fix6485605.resume(); |
| } else { |
| // apparently, there is nothing to resume. |
| } |
| } |
| suspendPolicy = JDWP.SuspendPolicy.NONE; |
| |
| } |
| |
| } |
| |
| /** |
| * Filter out internal events |
| */ |
| EventSet userFilter() { |
| return this; |
| } |
| |
| /** |
| * Filter out user events. |
| */ |
| EventSet internalFilter() { |
| return this.internalEventSet; |
| } |
| |
| EventImpl createEvent(JDWP.Event.Composite.Events evt) { |
| JDWP.Event.Composite.Events.EventsCommon comm = evt.aEventsCommon; |
| switch (evt.eventKind) { |
| case JDWP.EventKind.THREAD_START: |
| return new ThreadStartEventImpl( |
| (JDWP.Event.Composite.Events.ThreadStart)comm); |
| |
| case JDWP.EventKind.THREAD_END: |
| return new ThreadDeathEventImpl( |
| (JDWP.Event.Composite.Events.ThreadDeath)comm); |
| |
| case JDWP.EventKind.EXCEPTION: |
| return new ExceptionEventImpl( |
| (JDWP.Event.Composite.Events.Exception)comm); |
| |
| case JDWP.EventKind.BREAKPOINT: |
| return new BreakpointEventImpl( |
| (JDWP.Event.Composite.Events.Breakpoint)comm); |
| |
| case JDWP.EventKind.METHOD_ENTRY: |
| return new MethodEntryEventImpl( |
| (JDWP.Event.Composite.Events.MethodEntry)comm); |
| |
| case JDWP.EventKind.METHOD_EXIT: |
| return new MethodExitEventImpl( |
| (JDWP.Event.Composite.Events.MethodExit)comm); |
| |
| case JDWP.EventKind.METHOD_EXIT_WITH_RETURN_VALUE: |
| return new MethodExitEventImpl( |
| (JDWP.Event.Composite.Events.MethodExitWithReturnValue)comm); |
| |
| case JDWP.EventKind.FIELD_ACCESS: |
| return new AccessWatchpointEventImpl( |
| (JDWP.Event.Composite.Events.FieldAccess)comm); |
| |
| case JDWP.EventKind.FIELD_MODIFICATION: |
| return new ModificationWatchpointEventImpl( |
| (JDWP.Event.Composite.Events.FieldModification)comm); |
| |
| case JDWP.EventKind.SINGLE_STEP: |
| return new StepEventImpl( |
| (JDWP.Event.Composite.Events.SingleStep)comm); |
| |
| case JDWP.EventKind.CLASS_PREPARE: |
| return new ClassPrepareEventImpl( |
| (JDWP.Event.Composite.Events.ClassPrepare)comm); |
| |
| case JDWP.EventKind.CLASS_UNLOAD: |
| return new ClassUnloadEventImpl( |
| (JDWP.Event.Composite.Events.ClassUnload)comm); |
| |
| case JDWP.EventKind.MONITOR_CONTENDED_ENTER: |
| return new MonitorContendedEnterEventImpl( |
| (JDWP.Event.Composite.Events.MonitorContendedEnter)comm); |
| |
| case JDWP.EventKind.MONITOR_CONTENDED_ENTERED: |
| return new MonitorContendedEnteredEventImpl( |
| (JDWP.Event.Composite.Events.MonitorContendedEntered)comm); |
| |
| case JDWP.EventKind.MONITOR_WAIT: |
| return new MonitorWaitEventImpl( |
| (JDWP.Event.Composite.Events.MonitorWait)comm); |
| |
| case JDWP.EventKind.MONITOR_WAITED: |
| return new MonitorWaitedEventImpl( |
| (JDWP.Event.Composite.Events.MonitorWaited)comm); |
| |
| case JDWP.EventKind.VM_START: |
| return new VMStartEventImpl( |
| (JDWP.Event.Composite.Events.VMStart)comm); |
| |
| case JDWP.EventKind.VM_DEATH: |
| return new VMDeathEventImpl( |
| (JDWP.Event.Composite.Events.VMDeath)comm); |
| |
| default: |
| // Ignore unknown event types |
| System.err.println("Ignoring event cmd " + |
| evt.eventKind + " from the VM"); |
| return null; |
| } |
| } |
| |
| public VirtualMachine virtualMachine() { |
| return vm; |
| } |
| |
| public int suspendPolicy() { |
| return EventRequestManagerImpl.JDWPtoJDISuspendPolicy(suspendPolicy); |
| } |
| |
| private ThreadReference eventThread() { |
| for (Event event : this) { |
| if (event instanceof ThreadedEventImpl) { |
| return ((ThreadedEventImpl)event).thread(); |
| } |
| } |
| return null; |
| } |
| |
| public void resume() { |
| switch (suspendPolicy()) { |
| case EventRequest.SUSPEND_ALL: |
| vm.resume(); |
| break; |
| case EventRequest.SUSPEND_EVENT_THREAD: |
| ThreadReference thread = eventThread(); |
| if (thread == null) { |
| throw new InternalException("Inconsistent suspend policy"); |
| } |
| thread.resume(); |
| break; |
| case EventRequest.SUSPEND_NONE: |
| // Do nothing |
| break; |
| default: |
| throw new InternalException("Invalid suspend policy"); |
| } |
| } |
| |
| public Iterator<Event> iterator() { |
| return new Itr(); |
| } |
| |
| public EventIterator eventIterator() { |
| return new Itr(); |
| } |
| |
| public class Itr implements EventIterator { |
| /** |
| * Index of element to be returned by subsequent call to next. |
| */ |
| int cursor = 0; |
| |
| public boolean hasNext() { |
| return cursor != size(); |
| } |
| |
| public Event next() { |
| try { |
| Event nxt = get(cursor); |
| ++cursor; |
| return nxt; |
| } catch(IndexOutOfBoundsException e) { |
| throw new NoSuchElementException(); |
| } |
| } |
| |
| public Event nextEvent() { |
| return next(); |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| } |
| |
| @Override |
| public Spliterator<Event> spliterator() { |
| return Spliterators.spliterator(this, Spliterator.DISTINCT); |
| } |
| |
| /* below make this unmodifiable */ |
| |
| public boolean add(Event o){ |
| throw new UnsupportedOperationException(); |
| } |
| public boolean remove(Object o) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean addAll(Collection<? extends Event> coll) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean removeAll(Collection<?> coll) { |
| throw new UnsupportedOperationException(); |
| } |
| public boolean retainAll(Collection<?> coll) { |
| throw new UnsupportedOperationException(); |
| } |
| public void clear() { |
| throw new UnsupportedOperationException(); |
| } |
| } |