diff -r d86a5e4e1ac5 api.debugger.jpda/apichanges.xml
--- a/api.debugger.jpda/apichanges.xml Tue Feb 19 12:00:33 2013 +0100
+++ b/api.debugger.jpda/apichanges.xml Wed Feb 20 14:31:06 2013 +0100
@@ -816,6 +816,24 @@
+
+
+ Breakpoints can deactivated.
+
+
+
+
+
+ Two methods are added to JPDADebugger class: areBreakpointsActive()
+ and setBreakpointsActive(boolean). The set method fires PROP_BREAKPOINTS_ACTIVE
+ event.
+ These methods are used to activate/deactivate all breakpoints in the
+ debugger session.
+
+
+
+
+
diff -r d86a5e4e1ac5 api.debugger.jpda/manifest.mf
--- a/api.debugger.jpda/manifest.mf Tue Feb 19 12:00:33 2013 +0100
+++ b/api.debugger.jpda/manifest.mf Wed Feb 20 14:31:06 2013 +0100
@@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.api.debugger.jpda/2
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/jpda/Bundle.properties
-OpenIDE-Module-Specification-Version: 2.41
+OpenIDE-Module-Specification-Version: 2.42
OpenIDE-Module-Package-Dependencies: com.sun.jdi[VirtualMachineManager]
diff -r d86a5e4e1ac5 api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDADebugger.java
--- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDADebugger.java Tue Feb 19 12:00:33 2013 +0100
+++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDADebugger.java Wed Feb 20 14:31:06 2013 +0100
@@ -107,6 +107,9 @@
/** Property name constant.
* @since 2.25 */
public static final String PROP_CLASSES_FIXED = "classesFixed"; // NOI18N
+ /** Property name constant. Fired when breakpoints are activated / deactivated.
+ * @since 2.42 */
+ public static final String PROP_BREAKPOINTS_ACTIVE = "breakpointsActive"; // NOI18N
/** Suspend property value constant. */
public static final int SUSPEND_ALL = EventRequest.SUSPEND_ALL;
@@ -488,6 +491,32 @@
}
/**
+ * Test, if breakpoints are active.
+ * @return true
when breakpoints are active, false
+ * otherwise. The default implementation returns true
, to be overridden
+ * when needed.
+ * @since 2.42
+ */
+ public boolean areBreakpointsActive() {
+ return true;
+ }
+
+ /**
+ * Set all breakpoints to be active / inactive.
+ * Activation or deactivation of breakpoints should not alter the enabled/disabled
+ * state of individual breakpoints.
+ * The default implementation throws UnsupportedOperationException, override
+ * together with {@link #areBreakpointsActive()} when needed.
+ * @param active true
to make all breakpoints active,
+ * false
to make all breakpoints inactive.
+ * @throws UnsupportedOperationException when not supported.
+ * @since 2.42
+ */
+ public void setBreakpointsActive(boolean active) {
+ throw new UnsupportedOperationException("This method must be overridden.");
+ }
+
+ /**
* Adds property change listener.
*
* @param l new listener.
diff -r d86a5e4e1ac5 debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/BreakpointAnnotationProvider.java
--- a/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/BreakpointAnnotationProvider.java Tue Feb 19 12:00:33 2013 +0100
+++ b/debugger.jpda.projects/src/org/netbeans/modules/debugger/jpda/projects/BreakpointAnnotationProvider.java Wed Feb 20 14:31:06 2013 +0100
@@ -63,14 +63,18 @@
import org.netbeans.api.debugger.Breakpoint.VALIDITY;
import org.netbeans.api.debugger.DebuggerEngine;
import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.DebuggerManagerAdapter;
import org.netbeans.api.debugger.DebuggerManagerListener;
+import org.netbeans.api.debugger.LazyDebuggerManagerListener;
import org.netbeans.api.debugger.Session;
import org.netbeans.api.debugger.Watch;
import org.netbeans.api.debugger.jpda.ClassLoadUnloadBreakpoint;
import org.netbeans.api.debugger.jpda.FieldBreakpoint;
import org.netbeans.api.debugger.jpda.JPDABreakpoint;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.LineBreakpoint;
import org.netbeans.api.debugger.jpda.MethodBreakpoint;
+import org.netbeans.spi.debugger.DebuggerServiceRegistration;
import org.netbeans.spi.debugger.jpda.EditorContext;
import org.openide.cookies.LineCookie;
@@ -94,14 +98,18 @@
* @author Jan Jancura, Martin Entlicher
*/
@org.openide.util.lookup.ServiceProvider(service=org.openide.text.AnnotationProvider.class)
-public class BreakpointAnnotationProvider implements AnnotationProvider,
- DebuggerManagerListener {
+@DebuggerServiceRegistration(types=LazyDebuggerManagerListener.class)
+public class BreakpointAnnotationProvider extends DebuggerManagerAdapter
+ implements AnnotationProvider/*,
+ DebuggerManagerListener*/ {
private final Map> breakpointToAnnotations =
new IdentityHashMap>();
private final Set annotatedFiles = new WeakSet();
private Set dataObjectListeners;
private boolean attachManagerListener = true;
+ private volatile JPDADebugger currentDebugger = null;
+ private volatile boolean breakpointsActive = true;
private RequestProcessor annotationProcessor = new RequestProcessor("Annotation Refresh", 1);
private RequestProcessor contextWaitingProcessor = new RequestProcessor("Annotation Refresh Context Waiting", 1);
@@ -176,6 +184,11 @@
}
@Override
+ public String[] getProperties() {
+ return new String[] { DebuggerManager.PROP_BREAKPOINTS, DebuggerManager.PROP_DEBUGGER_ENGINES };
+ }
+
+ @Override
public void breakpointAdded(Breakpoint breakpoint) {
if (isAnnotatable(breakpoint)) {
JPDABreakpoint b = (JPDABreakpoint) breakpoint;
@@ -207,6 +220,30 @@
if (propertyName == null) {
return;
}
+ if (DebuggerManager.PROP_CURRENT_ENGINE.equals(propertyName)) {
+ JPDADebugger oldDebugger = currentDebugger;
+ if (oldDebugger != null) {
+ oldDebugger.removePropertyChangeListener(JPDADebugger.PROP_BREAKPOINTS_ACTIVE, this);
+ }
+ DebuggerEngine engine = DebuggerManager.getDebuggerManager().getCurrentEngine();
+ boolean active = true;
+ JPDADebugger debugger = null;
+ if (engine != null) {
+ debugger = engine.lookupFirst(null, JPDADebugger.class);
+ if (debugger != null) {
+ debugger.addPropertyChangeListener(JPDADebugger.PROP_BREAKPOINTS_ACTIVE, this);
+ active = debugger.areBreakpointsActive();
+ }
+ }
+ currentDebugger = debugger;
+ setBreakpointsActive(active);
+ }
+ if (JPDADebugger.PROP_BREAKPOINTS_ACTIVE.equals(propertyName)) {
+ JPDADebugger debugger = currentDebugger;
+ if (debugger != null) {
+ setBreakpointsActive(debugger.areBreakpointsActive());
+ }
+ }
if ( (!JPDABreakpoint.PROP_ENABLED.equals (propertyName)) &&
(!JPDABreakpoint.PROP_VALIDITY.equals (propertyName)) &&
(!LineBreakpoint.PROP_CONDITION.equals (propertyName)) &&
@@ -238,6 +275,13 @@
annotationProcessor.post(new AnnotationRefresh(b, true, true));
}
+ private void setBreakpointsActive(boolean active) {
+ if (breakpointsActive == active) {
+ return ;
+ }
+ annotationProcessor.post(new AnnotationRefresh(null, true, true));
+ }
+
private final class AnnotationRefresh implements Runnable {
private JPDABreakpoint b;
@@ -252,17 +296,28 @@
@Override
public void run() {
synchronized (breakpointToAnnotations) {
- if (remove) {
- removeAnnotations(b);
- if (!add) {
- breakpointToAnnotations.remove(b);
+ if (b != null) {
+ refreshAnnotation(b);
+ } else {
+ List bpts = new ArrayList(breakpointToAnnotations.keySet());
+ for (JPDABreakpoint bp : bpts) {
+ refreshAnnotation(bp);
}
}
- if (add) {
- breakpointToAnnotations.put(b, new WeakSet());
- for (FileObject fo : annotatedFiles) {
- addAnnotationTo(b, fo);
- }
+ }
+ }
+
+ private void refreshAnnotation(JPDABreakpoint b) {
+ if (remove) {
+ removeAnnotations(b);
+ if (!add) {
+ breakpointToAnnotations.remove(b);
+ }
+ }
+ if (add) {
+ breakpointToAnnotations.put(b, new WeakSet());
+ for (FileObject fo : annotatedFiles) {
+ addAnnotationTo(b, fo);
}
}
}
@@ -277,7 +332,8 @@
!((JPDABreakpoint) b).isHidden();
}
- private static String getAnnotationType(JPDABreakpoint b, boolean isConditional) {
+ private static String getAnnotationType(JPDABreakpoint b, boolean isConditional,
+ boolean active) {
boolean isInvalid = b.getValidity() == VALIDITY.INVALID;
String annotationType;
if (b instanceof LineBreakpoint) {
@@ -301,8 +357,10 @@
} else {
throw new IllegalStateException(b.toString());
}
- if (isInvalid && b.isEnabled ()) {
- annotationType += "_broken";
+ if (!active) {
+ annotationType = annotationType + "_stroke"; // NOI18N
+ } else if (isInvalid && b.isEnabled ()) {
+ annotationType += "_broken"; // NOI18N
}
return annotationType;
}
@@ -481,7 +539,7 @@
throw new IllegalStateException(b.toString());
}
boolean isConditional = (condition != null) && condition.trim().length() > 0;
- String annotationType = getAnnotationType(b, isConditional);
+ String annotationType = getAnnotationType(b, isConditional, breakpointsActive);
DataObject dataObject;
try {
dataObject = DataObject.find(fo);
@@ -526,7 +584,7 @@
}
}
-
+ /*
// Not used
@Override
public Breakpoint[] initBreakpoints() { return new Breakpoint[] {}; }
@@ -558,5 +616,5 @@
// Not used
@Override
public void engineRemoved(DebuggerEngine engine) {}
-
+ */
}
diff -r d86a5e4e1ac5 debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/resources/mf-layer.xml
--- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/resources/mf-layer.xml Tue Feb 19 12:00:33 2013 +0100
+++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/resources/mf-layer.xml Wed Feb 20 14:31:06 2013 +0100
@@ -291,6 +291,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -r d86a5e4e1ac5 debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java Tue Feb 19 12:00:33 2013 +0100
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDADebuggerImpl.java Wed Feb 20 14:31:06 2013 +0100
@@ -206,6 +206,7 @@
private boolean doContinue = true; // Whether resume() will actually resume
private Boolean singleThreadStepResumeDecision = null;
private Boolean stepInterruptByBptResumeDecision = null;
+ private boolean breakpointsActive = true;
private InputOutput io;
@@ -554,6 +555,22 @@
}
}
+ @Override
+ public boolean areBreakpointsActive() {
+ return breakpointsActive;
+ }
+
+ @Override
+ public void setBreakpointsActive(boolean active) {
+ synchronized (this) {
+ if (breakpointsActive == active) {
+ return ;
+ }
+ breakpointsActive = active;
+ }
+ firePropertyChange(PROP_BREAKPOINTS_ACTIVE, !active, active);
+ }
+
public Session getSession() {
return lookupProvider.lookupFirst(null, Session.class);
}
diff -r d86a5e4e1ac5 debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointImpl.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointImpl.java Tue Feb 19 12:00:33 2013 +0100
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointImpl.java Wed Feb 20 14:31:06 2013 +0100
@@ -133,6 +133,7 @@
*/
final void set () {
breakpoint.addPropertyChangeListener (this);
+ debugger.addPropertyChangeListener(JPDADebugger.PROP_BREAKPOINTS_ACTIVE, this);
if (breakpoint instanceof PropertyChangeListener && isApplicable()) {
Session s = debugger.getSession();
DebuggerEngine de = s.getEngineForLanguage ("Java");
@@ -159,7 +160,7 @@
(getDebugger ().getState () == JPDADebugger.STATE_DISCONNECTED)
) return;
removeAllEventRequests ();
- if (breakpoint.isEnabled () && isEnabled()) {
+ if (breakpoint.isEnabled () && isEnabled() && debugger.areBreakpointsActive()) {
setRequests ();
}
}
@@ -186,7 +187,7 @@
} else if (!Breakpoint.PROP_VALIDITY.equals(propertyName) &&
!Breakpoint.PROP_GROUP_NAME.equals(propertyName) &&
!Breakpoint.PROP_GROUP_PROPERTIES.equals(propertyName)) {
- if (reader != null) {
+ if (reader != null && !JPDADebugger.PROP_BREAKPOINTS_ACTIVE.equals(propertyName)) {
reader.storeCachedClassName(breakpoint, null);
}
debugger.getRequestProcessor().post(new Runnable() {
@@ -214,6 +215,7 @@
removeAllEventRequests ();
}
breakpoint.removePropertyChangeListener(this);
+ debugger.removePropertyChangeListener(JPDADebugger.PROP_BREAKPOINTS_ACTIVE, this);
setValidity(Breakpoint.VALIDITY.UNKNOWN, null);
if (breakpoint instanceof PropertyChangeListener) {
Session s = debugger.getSession();
diff -r d86a5e4e1ac5 debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/BreakpointsDeactivationTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/BreakpointsDeactivationTest.java Wed Feb 20 14:31:06 2013 +0100
@@ -0,0 +1,216 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+
+package org.netbeans.api.debugger.jpda;
+
+import junit.framework.Test;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.event.JPDABreakpointEvent;
+import org.netbeans.api.debugger.jpda.event.JPDABreakpointListener;
+import org.netbeans.junit.NbTestCase;
+
+/**
+ * Tests breakpoints deactivation.
+ *
+ */
+public class BreakpointsDeactivationTest extends NbTestCase {
+
+ private static final String TEST_APP_PATH = System.getProperty ("test.dir.src") +
+ "org/netbeans/api/debugger/jpda/testapps/LineBreakpointApp.java";
+
+ private JPDASupport support;
+
+
+ public BreakpointsDeactivationTest (String s) {
+ super (s);
+ }
+
+ public static Test suite() {
+ return JPDASupport.createTestSuite(BreakpointsDeactivationTest.class);
+ }
+
+ public void testBreakpointsDeactivation () throws Exception {
+ try {
+ Utils.BreakPositions bp = Utils.getBreakPositions(TEST_APP_PATH);
+ LineBreakpoint[] lb = bp.getBreakpoints().toArray(new LineBreakpoint[0]);
+ {
+ LineBreakpoint b;
+ b = lb[4];
+ lb[4] = lb[2];
+ lb[2] = b;
+ }
+ /*
+ LineBreakpoint lb1 = LineBreakpoint.create (TEST_APP, 32);
+ LineBreakpoint lb2 = LineBreakpoint.create (TEST_APP, 37);
+ LineBreakpoint lb3 = LineBreakpoint.create (TEST_APP, 109);
+ lb3.setPreferredClassName("org.netbeans.api.debugger.jpda.testapps.LineBreakpointApp$Inner");
+ LineBreakpoint lb4 = LineBreakpoint.create (TEST_APP, 92);
+ lb4.setPreferredClassName("org.netbeans.api.debugger.jpda.testapps.LineBreakpointApp$InnerStatic");
+ LineBreakpoint lb5 = LineBreakpoint.create (TEST_APP, 41);
+ */
+ DebuggerManager dm = DebuggerManager.getDebuggerManager ();
+ for (int i = 0; i < lb.length; i++) {
+ dm.addBreakpoint (lb[i]);
+ }
+
+ TestBreakpointListener[] tb = new TestBreakpointListener[lb.length];
+ for (int i = 0; i < lb.length; i++) {
+ tb[i] = new TestBreakpointListener (lb[i]);
+ lb[i].addJPDABreakpointListener (tb[i]);
+ }
+ support = JPDASupport.attach (
+ "org.netbeans.api.debugger.jpda.testapps.LineBreakpointApp"
+ );
+ JPDADebugger debugger = support.getDebugger();
+ assertEquals("Breakpoints should be active initially.", true, debugger.areBreakpointsActive());
+
+ support.waitState (JPDADebugger.STATE_STOPPED); // stopped on the first breakpoint
+
+ debugger.setBreakpointsActive(false);
+ assertEquals("Breakpoints should be inactive after deactivation.", false, debugger.areBreakpointsActive());
+
+ int j = 0;
+ assertEquals (
+ "Debugger stopped at wrong line for breakpoint " + j,
+ lb[j].getLineNumber (),
+ debugger.getCurrentCallStackFrame ().getLineNumber (null)
+ );
+ for (int i = j+1; i < tb.length; i++) {
+ tb[i].checkNotNotified();
+ }
+ if (j < lb.length - 1) {
+ support.doContinue();
+ }
+
+ for (int i = 0; i < tb.length; i++) {
+ dm.removeBreakpoint (lb[i]);
+ }
+ support.waitState (JPDADebugger.STATE_DISCONNECTED);
+ } finally {
+ if (support != null) support.doFinish ();
+ }
+ }
+
+ // innerclasses ............................................................
+
+ private class TestBreakpointListener implements JPDABreakpointListener {
+
+ private LineBreakpoint lineBreakpoint;
+ private int conditionResult;
+
+ private JPDABreakpointEvent event;
+ private AssertionError failure;
+
+ public TestBreakpointListener (LineBreakpoint lineBreakpoint) {
+ this (lineBreakpoint, JPDABreakpointEvent.CONDITION_NONE);
+ }
+
+ public TestBreakpointListener (
+ LineBreakpoint lineBreakpoint,
+ int conditionResult
+ ) {
+ this.lineBreakpoint = lineBreakpoint;
+ this.conditionResult = conditionResult;
+ }
+
+ public void breakpointReached (JPDABreakpointEvent event) {
+ try {
+ checkEvent (event);
+ } catch (AssertionError e) {
+ failure = e;
+ } catch (Throwable e) {
+ failure = new AssertionError (e);
+ }
+ }
+
+ private void checkEvent (JPDABreakpointEvent event) {
+ this.event = event;
+ assertEquals (
+ "Breakpoint event: Wrong source breakpoint",
+ lineBreakpoint,
+ event.getSource ()
+ );
+ assertNotNull (
+ "Breakpoint event: Context thread is null",
+ event.getThread ()
+ );
+
+ int result = event.getConditionResult ();
+ if ( result == JPDABreakpointEvent.CONDITION_FAILED &&
+ conditionResult != JPDABreakpointEvent.CONDITION_FAILED
+ )
+ failure = new AssertionError (event.getConditionException ());
+ else
+ if (result != conditionResult)
+ failure = new AssertionError (
+ "Unexpected breakpoint condition result: " + result
+ );
+ }
+
+ public void checkResult () {
+ if (event == null) {
+ CallStackFrame f = support.getDebugger ().
+ getCurrentCallStackFrame ();
+ int ln = -1;
+ if (f != null) {
+ ln = f.getLineNumber (null);
+ }
+ throw new AssertionError (
+ "Breakpoint was not hit (listener was not notified) " + ln
+ );
+ }
+ if (failure != null) throw failure;
+ }
+
+ public void checkNotNotified() {
+ if (event != null) {
+ JPDAThread t = event.getThread();
+ throw new AssertionError (
+ "Breakpoint was hit (listener was notified) in thread " + t
+ );
+ }
+ if (failure != null) throw failure;
+ }
+ }
+}