/* * Copyright 2010 Sun Microsystems, Inc. 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. * * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.jdi.event; import org.visage.jdi.VisageMirror; import org.visage.jdi.VisageVirtualMachine; import com.sun.jdi.event.EventQueue; import com.sun.jdi.event.EventSet; import java.util.Collections; import java.util.List; import java.util.ArrayList; /** * This wrapper class allows the client to control which events are suppressed and which are passed to the client while * an internal invokeMethod is in progress. Internal invokeMethods are used by get/setValue(s) methods in VisageReferenceType, * VisageClassType, and VisageObjectReference if the field involved has a getter/setter. * * @author sundar */ public class VisageEventQueue extends VisageMirror implements EventQueue { // Note that this class is not used for the internal EventQueue - // that is not exposed in the Visage-JDI layer // In normal operation, events are not controlled, ie, they are delivered // to the caller in normal JDI fashion. // However, in some cases, NetBeans needs events to be 'controlled'. In these // cases, some events are passed thru in normal fashion and the remaining events are // skipped - their eventSets are just resumed without reporting to the clent. // This flag determines if event control is in effect or not. private volatile boolean eventControl = false; // This flag determines if the calls to change eventControl should be ignored or not. // The idea is that these calls are in Visage-JDI, but by default they are disabled, thus // there is no event control. The debugger can set this flag to true to allow the // calls in Visage-JDI to turn event control on / off. private volatile boolean allowEventControl = false; // If allowEventControl is true, this is the list of Events to pass. EventSets containing // other events are just resumed and discarded. private List<Class> eventsToBePassed = new ArrayList<Class>(); // Filter for EventSets that should be passed thru in controlled mode. private boolean shouldPassEventSet(VisageEventSet eventSet) { if (eventsToBePassed == null) { return true; } VisageEvent newEvt = eventSet.eventIterator().next(); for (Class evtClass: eventsToBePassed) { if (evtClass.isInstance(newEvt)) { return true; } } return false; } /** * JDI addition: This isn't intended to be called by a client. This is * called with a value of true before internal calls to invokeMethod and * is called with a value of false after these calls. This causes some * events to not be generated during these calls; see {@link #setEventsToBePassed(List)}. * @param value true means to suppress selected events while false means to not * suppress events. */ public void setEventControl(boolean value) { if (allowEventControl) { eventControl = value; } } // This can be called by the debugger to disable // the setEventControl calls in visagejdi. EG, if the debugger // does not want events to be 'controlled' during the execution // of internal invokeMethod calls, it can pass false to this. /** * JDI addition: Allow/disallow event suppression via {@link #setEventControl(boolean)}. * This can be called by the debugger to cause events to not be suppressed during * internal invokeMethod calls caused by calls to get/setValue(s). * @param value true means to to allow events to be supressed while false means * to ignore calls to {@link #setEventControl(boolean)} */ public void setAllowEventControl(boolean value) { allowEventControl = value; if (!allowEventControl) { eventControl = false; } } /** * JDI Addition: Specify Events to be passed through while event control is enabled. * If passThese is null, then all events are passed. * By default, these events are passed through when event control is enabled: * ClassPrepareEvent, VMDeathEvent, VMDisconnectEvent, VMStartEvent * * BreakPointEvent, StepEvent, MethodEntryEvent are all handled the same, E.G. * if any of these is on the passThese list, then all three are passed. * @param passThese the list of events to pass on to the client instead of suppressing. */ public void setEventsToBePassed(List<Class> passThese) { if (passThese == null) { eventsToBePassed = null; return; } List<Class> newList = new ArrayList<Class>(passThese.size() + 2); boolean tripleSeen = false; for (Class evtClass: passThese) { if (evtClass.isInstance(VisageBreakpointEvent.class) || evtClass.isInstance(VisageStepEvent.class) || evtClass.isInstance(VisageMethodEntryEvent.class)) { if (!tripleSeen) { newList.add(VisageBreakpointEvent.class); newList.add(VisageStepEvent.class); newList.add(VisageMethodEntryEvent.class); tripleSeen = true; } } else { newList.add(evtClass); } } eventsToBePassed = Collections.unmodifiableList(newList); } /** * JDI Addition: Return a list of events that will be passed to the client while event * control is enabled. * @return a list of events that will be passed to the client while event control is enabled. */ public List<Class> getEventsToBePassed() { return eventsToBePassed; } public VisageEventQueue(VisageVirtualMachine visagevm, EventQueue underlying) { super(visagevm, underlying); eventsToBePassed.add(VisageClassPrepareEvent.class); eventsToBePassed.add(VisageVMDeathEvent.class); eventsToBePassed.add(VisageVMDisconnectEvent.class); eventsToBePassed.add(VisageVMStartEvent.class); } public VisageEventSet remove() throws InterruptedException { return remove(0); } public VisageEventSet remove(long arg0) throws InterruptedException { VisageEventSet eventSet; while(true) { // we are normally waiting under here when eventControl changes eventSet = VisageEventSet.wrap(virtualMachine(), underlying().remove(arg0)); if (!eventControl) { // eventSet will be null if it timed out. return eventSet; } if (eventSet == null) { // timed out, and eventControl is true return null; } if (shouldPassEventSet(eventSet)) { return eventSet; } eventSet.resume(); } } @Override protected EventQueue underlying() { return (EventQueue) super.underlying(); } }