diff --git a/api.debugger.jpda/apichanges.xml b/api.debugger.jpda/apichanges.xml
--- a/api.debugger.jpda/apichanges.xml
+++ b/api.debugger.jpda/apichanges.xml
@@ -857,6 +857,25 @@
+
+
+ Association of breakpoints with source files.
+
+
+
+
+
+ getURL()/setURL() methods are added to breakpoints so that they can
+ be associated with their source files. Changes in these source files
+ can be then reflected in the breakpoint settings.
+
+
+
+
+
+
+
+
diff --git a/api.debugger.jpda/manifest.mf b/api.debugger.jpda/manifest.mf
--- a/api.debugger.jpda/manifest.mf
+++ b/api.debugger.jpda/manifest.mf
@@ -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.45
+OpenIDE-Module-Specification-Version: 2.46
OpenIDE-Module-Package-Dependencies: com.sun.jdi[VirtualMachineManager]
diff --git a/api.debugger.jpda/nbproject/project.xml b/api.debugger.jpda/nbproject/project.xml
--- a/api.debugger.jpda/nbproject/project.xml
+++ b/api.debugger.jpda/nbproject/project.xml
@@ -55,7 +55,7 @@
1
- 1.35
+ 1.44
@@ -68,6 +68,14 @@
+ org.netbeans.libs.javacapi
+
+
+
+ 8.6
+
+
+
org.netbeans.modules.java.source
diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/ClassLoadUnloadBreakpoint.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/ClassLoadUnloadBreakpoint.java
--- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/ClassLoadUnloadBreakpoint.java
+++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/ClassLoadUnloadBreakpoint.java
@@ -51,9 +51,18 @@
import java.util.Arrays;
import java.util.List;
import org.netbeans.api.debugger.DebuggerEngine;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JavaSourceUtils.ElementChangeListener;
+import org.netbeans.api.debugger.jpda.JavaSourceUtils.ElementChangeTracker;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.Task;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
+import org.netbeans.spi.debugger.BreakpointURLHandler;
+import org.netbeans.spi.debugger.BreakpointURLHandler.URLBasedBreakpoint;
import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
@@ -81,6 +90,9 @@
public static final String PROP_CLASS_EXCLUSION_FILTERS = "classExclusionFilters"; // NOI18N
/** Name of property for breakpoint type. */
public static final String PROP_BREAKPOINT_TYPE = "breakpointType"; // NOI18N
+ /** Property name constant
+ * @since 2.46 */
+ public static final String PROP_URL = LineBreakpoint.PROP_URL;
/** Catch type property value constant. */
public static final int TYPE_CLASS_LOADED = 1;
@@ -202,6 +214,23 @@
}
/**
+ * Get URL of the class source file.
+ * @return The URL or null
when there is no association with the source file.
+ * @since 2.46
+ */
+ public String getURL() {
+ return null;
+ }
+
+ /**
+ * Associate this breakpoint with the class source file.
+ * @param url The URL of the class source file.
+ * @since 2.46
+ */
+ public void setURL(String url) {
+ }
+
+ /**
* Returns a string representation of this object.
*
* @return a string representation of the object
@@ -211,8 +240,20 @@
return "ClassLoadUnloadBreakpoint " + Arrays.toString(classFilters);
}
- private static final class ClassLoadUnloadBreakpointImpl extends ClassLoadUnloadBreakpoint implements PropertyChangeListener {
+ private static final class ClassLoadUnloadBreakpointImpl extends ClassLoadUnloadBreakpoint
+ implements URLBasedBreakpoint,
+ PropertyChangeListener,
+ ElementChangeListener{
+ private final BreakpointURLHandler urlHandler;
+ private ElementChangeTracker elementChangeTracker;
+ private final Object elementChangeTrackerLock = new Object();
+
+ ClassLoadUnloadBreakpointImpl() {
+ super();
+ urlHandler = BreakpointURLHandler.create(this);
+ }
+
@Override
public GroupProperties getGroupProperties() {
return new ClassGroupProperties();
@@ -223,6 +264,86 @@
enginePropertyChange(evt);
}
+ @Override
+ public void setClassFilters(String[] classFilters) {
+ super.setClassFilters(classFilters);
+ trackClassElement();
+ }
+
+ @Override
+ public String getURL() {
+ if (urlHandler == null) {
+ return null;
+ } else {
+ return urlHandler.getURL();
+ }
+ }
+
+ @Override
+ public void setURL(String url) {
+ String old = urlHandler.setURL(url);
+ if (old == null || !old.equals(url)) {
+ firePropertyChange (PROP_URL, old, url);
+ if (old != null && !old.isEmpty()) {
+ DebuggerManager.getDebuggerManager().addBreakpoint(this);
+ }
+ firePropertyChange(PROP_GROUP_PROPERTIES, null, null);
+ trackClassElement();
+ }
+ }
+
+ private void trackClassElement() {
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.destroy();
+ }
+ }
+ String[] classFilters = getClassFilters();
+ FileObject fo = urlHandler.getFileObject();
+ if (classFilters.length == 1 && fo != null) {
+ final String clazz = classFilters[0];
+ final JavaSource js = JavaSource.forFileObject(fo);
+ if (js == null) {
+ return ;
+ }
+ try {
+ js.runWhenScanFinished(new Task() {
+ @Override
+ public void run(CompilationController parameter) throws Exception {
+ ElementChangeTracker ect = JavaSourceUtils.createElementChangeTracker(js, clazz, null, null);
+ if (ect != null) {
+ ect.setElementChangeListener(ClassLoadUnloadBreakpointImpl.this);
+ synchronized (elementChangeTrackerLock) {
+ elementChangeTracker = ect;
+ }
+ }
+ }
+ }, true);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ @Override
+ protected void dispose() {
+ super.dispose();
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.destroy();
+ }
+ }
+ }
+
+ @Override
+ public void removed() {
+ DebuggerManager.getDebuggerManager().removeBreakpoint(this);
+ }
+
+ @Override
+ public void changed(String name) {
+ }
+
private final class ClassGroupProperties extends GroupProperties {
diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/ExceptionBreakpoint.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/ExceptionBreakpoint.java
--- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/ExceptionBreakpoint.java
+++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/ExceptionBreakpoint.java
@@ -50,9 +50,18 @@
import java.util.ArrayList;
import java.util.List;
import org.netbeans.api.debugger.DebuggerEngine;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JavaSourceUtils.ElementChangeListener;
+import org.netbeans.api.debugger.jpda.JavaSourceUtils.ElementChangeTracker;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.Task;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
+import org.netbeans.spi.debugger.BreakpointURLHandler;
+import org.netbeans.spi.debugger.BreakpointURLHandler.URLBasedBreakpoint;
import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
@@ -78,6 +87,9 @@
public static final String PROP_CLASS_FILTERS = "classFilters"; // NOI18N
/** Property name constant */
public static final String PROP_CLASS_EXCLUSION_FILTERS = "classExclusionFilters"; // NOI18N
+ /** Property name constant
+ * @since 2.46 */
+ public static final String PROP_URL = LineBreakpoint.PROP_URL;
/** Property name constant. */
public static final String PROP_CATCH_TYPE = "catchType"; // NOI18N
/** Property name constant. */
@@ -187,6 +199,23 @@
}
/**
+ * Get URL of the exception source file.
+ * @return The URL or null
when there is no association with the source file.
+ * @since 2.46
+ */
+ public String getURL() {
+ return null;
+ }
+
+ /**
+ * Associate this breakpoint with an exception source file.
+ * @param url The URL of the exception source file.
+ * @since 2.46
+ */
+ public void setURL(String url) {
+ }
+
+ /**
* Returns condition.
*
* @return cond a condition
@@ -245,9 +274,89 @@
return "ExceptionBreakpoint" + exceptionClassName;
}
- private static final class ExceptionBreakpointImpl extends ExceptionBreakpoint implements PropertyChangeListener {
+ private static final class ExceptionBreakpointImpl extends ExceptionBreakpoint implements URLBasedBreakpoint,
+ PropertyChangeListener,
+ ElementChangeListener {
+ private final BreakpointURLHandler urlHandler;
+ private ElementChangeTracker elementChangeTracker;
+ private final Object elementChangeTrackerLock = new Object();
+
+ ExceptionBreakpointImpl() {
+ super();
+ urlHandler = BreakpointURLHandler.create(this);
+ }
@Override
+ public String getURL() {
+ if (urlHandler == null) {
+ return null;
+ } else {
+ return urlHandler.getURL();
+ }
+ }
+
+ @Override
+ public void setURL(String url) {
+ String old = urlHandler.setURL(url);
+ if (old == null || !old.equals(url)) {
+ firePropertyChange (PROP_URL, old, url);
+ if (old != null && !old.isEmpty()) {
+ DebuggerManager.getDebuggerManager().addBreakpoint(this);
+ }
+ firePropertyChange(PROP_GROUP_PROPERTIES, null, null);
+ trackFieldElement();
+ }
+ }
+
+ @Override
+ public void setExceptionClassName(String cn) {
+ super.setExceptionClassName(cn);
+ trackFieldElement();
+ }
+
+ private void trackFieldElement() {
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.destroy();
+ }
+ }
+ final String clazz = getExceptionClassName();
+ FileObject fo = urlHandler.getFileObject();
+ if (!clazz.isEmpty() && fo != null) {
+ final JavaSource js = JavaSource.forFileObject(fo);
+ if (js == null) {
+ return ;
+ }
+ try {
+ js.runWhenScanFinished(new Task() {
+ @Override
+ public void run(CompilationController parameter) throws Exception {
+ ElementChangeTracker ect = JavaSourceUtils.createElementChangeTracker(js, clazz, null, null);
+ if (ect != null) {
+ ect.setElementChangeListener(ExceptionBreakpointImpl.this);
+ synchronized (elementChangeTrackerLock) {
+ elementChangeTracker = ect;
+ }
+ }
+ }
+ }, true);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ @Override
+ protected void dispose() {
+ super.dispose();
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.destroy();
+ }
+ }
+ }
+
+ @Override
public GroupProperties getGroupProperties() {
return new ExceptionGroupProperties();
}
@@ -257,6 +366,16 @@
enginePropertyChange(evt);
}
+ @Override
+ public void removed() {
+ DebuggerManager.getDebuggerManager().removeBreakpoint(this);
+ }
+
+ @Override
+ public void changed(String name) {
+ setExceptionClassName(name);
+ }
+
private final class ExceptionGroupProperties extends GroupProperties {
@Override
diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/FieldBreakpoint.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/FieldBreakpoint.java
--- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/FieldBreakpoint.java
+++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/FieldBreakpoint.java
@@ -54,10 +54,20 @@
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.netbeans.api.debugger.Breakpoint;
+import static org.netbeans.api.debugger.Breakpoint.PROP_GROUP_PROPERTIES;
import org.netbeans.api.debugger.DebuggerEngine;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JavaSourceUtils.ElementChangeListener;
+import org.netbeans.api.debugger.jpda.JavaSourceUtils.ElementChangeTracker;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.Task;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
+import org.netbeans.spi.debugger.BreakpointURLHandler;
+import org.netbeans.spi.debugger.BreakpointURLHandler.URLBasedBreakpoint;
import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
/**
@@ -81,6 +91,9 @@
public static final String PROP_FIELD_NAME = "fieldName"; // NOI18N
/** Property name constant. */
public static final String PROP_CLASS_NAME = "className"; // NOI18N
+ /** Property name constant
+ * @since 2.46 */
+ public static final String PROP_URL = LineBreakpoint.PROP_URL;
/** Property name constant. */
public static final String PROP_CONDITION = "condition"; // NOI18N
/** Property name constant. */
@@ -180,6 +193,23 @@
}
/**
+ * Get URL of the field source file.
+ * @return The URL or null
when there is no association with the source file.
+ * @since 2.46
+ */
+ public String getURL() {
+ return null;
+ }
+
+ /**
+ * Associate this breakpoint with the field source file.
+ * @param url The URL of the field source file.
+ * @since 2.46
+ */
+ public void setURL(String url) {
+ }
+
+ /**
* Get the instance filter for a specific debugger session.
* @return The instances or null
when there is no instance restriction.
*/
@@ -300,8 +330,96 @@
return "FieldBreakpoint " + className + "." + fieldName;
}
- private static final class FieldBreakpointImpl extends FieldBreakpoint implements ChangeListener,
- PropertyChangeListener {
+ private static final class FieldBreakpointImpl extends FieldBreakpoint implements URLBasedBreakpoint,
+ ChangeListener,
+ PropertyChangeListener,
+ ElementChangeListener {
+
+ private final BreakpointURLHandler urlHandler;
+ private ElementChangeTracker elementChangeTracker;
+ private final Object elementChangeTrackerLock = new Object();
+
+ FieldBreakpointImpl() {
+ super();
+ urlHandler = BreakpointURLHandler.create(this);
+ }
+
+ @Override
+ public String getURL() {
+ if (urlHandler == null) {
+ return null;
+ } else {
+ return urlHandler.getURL();
+ }
+ }
+
+ @Override
+ public void setURL(String url) {
+ String old = urlHandler.setURL(url);
+ if (old == null || !old.equals(url)) {
+ firePropertyChange (PROP_URL, old, url);
+ if (old != null && !old.isEmpty()) {
+ DebuggerManager.getDebuggerManager().addBreakpoint(this);
+ }
+ firePropertyChange(PROP_GROUP_PROPERTIES, null, null);
+ trackFieldElement();
+ }
+ }
+
+ @Override
+ public void setClassName(String className) {
+ super.setClassName(className);
+ trackFieldElement();
+ }
+
+ @Override
+ public void setFieldName(String name) {
+ super.setFieldName(name);
+ trackFieldElement();
+ }
+
+ private void trackFieldElement() {
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.destroy();
+ }
+ }
+ final String clazz = getClassName();
+ FileObject fo = urlHandler.getFileObject();
+ if (!clazz.isEmpty() && fo != null) {
+ final JavaSource js = JavaSource.forFileObject(fo);
+ if (js == null) {
+ return ;
+ }
+ final String fieldName = getFieldName();
+ try {
+ js.runWhenScanFinished(new Task() {
+ @Override
+ public void run(CompilationController parameter) throws Exception {
+ ElementChangeTracker ect = JavaSourceUtils.createElementChangeTracker(js, clazz, fieldName, null);
+ if (ect != null) {
+ ect.setElementChangeListener(FieldBreakpointImpl.this);
+ synchronized (elementChangeTrackerLock) {
+ elementChangeTracker = ect;
+ }
+ }
+ }
+ }, true);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ @Override
+ protected void dispose() {
+ super.dispose();
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.destroy();
+ }
+ }
+ }
@Override
public GroupProperties getGroupProperties() {
@@ -322,6 +440,16 @@
enginePropertyChange(evt);
}
+ @Override
+ public void removed() {
+ DebuggerManager.getDebuggerManager().removeBreakpoint(this);
+ }
+
+ @Override
+ public void changed(String name) {
+ setFieldName(name);
+ }
+
private final class FieldGroupProperties extends GroupProperties {
@Override
diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JavaSourceUtils.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JavaSourceUtils.java
new file mode 100644
--- /dev/null
+++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JavaSourceUtils.java
@@ -0,0 +1,374 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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]"
+ *
+ * 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.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.debugger.jpda;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementScanner6;
+import javax.lang.model.util.Types;
+import org.netbeans.api.java.source.ClassIndex;
+import org.netbeans.api.java.source.ClassIndexListener;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.ElementUtilities;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.RootsEvent;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.api.java.source.TypesEvent;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Exceptions;
+import org.openide.util.Parameters;
+
+/**
+ * Java source utilities.
+ * The main purpose is to track changes in Java elements.
+ *
+ * @author Martin Entlicher
+ */
+final class JavaSourceUtils {
+
+ private JavaSourceUtils() {}
+
+ static Collection> getClasses (final FileObject fo) {
+ Parameters.notNull("fo", fo); //NOI18N
+ if (!fo.isValid()) {
+ throw new IllegalArgumentException ("FileObject : " + FileUtil.getFileDisplayName(fo) + " is not valid."); //NOI18N
+ }
+ if (fo.isVirtual()) {
+ throw new IllegalArgumentException ("FileObject : " + FileUtil.getFileDisplayName(fo) + " is virtual."); //NOI18N
+ }
+ final JavaSource js = JavaSource.forFileObject(fo);
+ if (js == null) {
+ throw new IllegalArgumentException ();
+ }
+ try {
+ final LinkedHashSet> result = new LinkedHashSet>();
+ js.runUserActionTask(new Task() {
+ @Override
+ public void run(final CompilationController control) throws Exception {
+ if (control.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED).compareTo (JavaSource.Phase.ELEMENTS_RESOLVED)>=0) {
+ final List types = new ArrayList();
+ final ElementScanner6 visitor = new ElementScanner6() {
+ @Override
+ public Void visitType(TypeElement e, Void p) {
+ if (e.getEnclosingElement().getKind() == ElementKind.PACKAGE
+ || e.getModifiers().contains(Modifier.STATIC)) {
+ types.add(e);
+ return super.visitType(e, p);
+ } else {
+ return null;
+ }
+ }
+ };
+ visitor.scan(control.getTopLevelElements(), null);
+ for (TypeElement type : types) {
+ result.add (ElementHandle.create(type));
+ }
+ }
+ }
+
+ }, true);
+ return result;
+ } catch (IOException ioe) {
+ Exceptions.printStackTrace(ioe);
+ return Collections.>emptySet();
+ }
+ }
+
+ static ElementChangeTracker createElementChangeTracker(JavaSource js, String clazz, String name, String signature) {
+ ClassIndex classIndex = js.getClasspathInfo().getClassIndex();
+ String packageName = "";
+ int pkgIndex = clazz.lastIndexOf('.');
+ if (pkgIndex > 0) {
+ packageName = clazz.substring(0, pkgIndex);
+ }
+ ClassIndex.SearchScopeType scopeType = new JavaSourceUtils.PackageSearchType(packageName);
+ String prefix = (pkgIndex > 0) ? clazz.substring(pkgIndex+1) : clazz;
+ int i = prefix.lastIndexOf('$');
+ if (i > 0) {
+ prefix = prefix.substring(i+1);
+ }
+ ElementHandle classElement = null;
+ Set> declaredTypes = classIndex.getDeclaredTypes(prefix, ClassIndex.NameKind.PREFIX, Collections.singleton(scopeType));
+ //System.err.println("Declared types of "+clazz+" = "+declaredTypes);
+ for (ElementHandle dt : declaredTypes) {
+ if (clazz.equals(dt.getBinaryName())) {
+ classElement = dt;
+ }
+ }
+ //System.err.println("Class Element of "+clazz+" = "+classElement);
+ if (classElement == null) {
+ return null;
+ }
+ return new ElementChangeTracker(js, classIndex, classElement, name, signature);
+ }
+
+ static final class ElementChangeTracker {
+
+ private final Tracker tracker = new Tracker();
+ private final JavaSource js;
+ private final ClassIndex classIndex;
+ private final ElementHandle classElement;
+ private String name;
+ private String signature;
+ private ElementChangeListener ecl;
+
+ private ElementChangeTracker(JavaSource js, ClassIndex classIndex, ElementHandle classElement, String name, String signature) {
+ assert classElement != null;
+ this.js = js;
+ this.classIndex = classIndex;
+ this.classElement = classElement;
+ this.name = name;
+ this.signature = signature;
+ classIndex.addClassIndexListener(tracker);
+ }
+
+ void setName(String name) {
+ this.name = name;
+ }
+
+ void setSignature(String signature) {
+ this.signature = signature;
+ }
+
+ void setElementChangeListener(ElementChangeListener ecl) {
+ this.ecl = ecl;
+ }
+
+ void destroy() {
+ classIndex.removeClassIndexListener(tracker);
+ }
+
+ class Tracker implements ClassIndexListener {
+
+ @Override
+ public void typesAdded(TypesEvent event) {
+ for (ElementHandle eh : event.getTypes()) {
+ String binaryName = eh.getBinaryName();
+ }
+ }
+
+ @Override
+ public void typesRemoved(TypesEvent event) {
+ for (ElementHandle eh : event.getTypes()) {
+ //String binaryName = eh.getBinaryName();
+ if (classElement.signatureEquals(eh)) {
+ ecl.removed();
+ }
+ }
+ }
+
+ @Override
+ public void typesChanged(TypesEvent event) {
+ for (ElementHandle eh : event.getTypes()) {
+ //String binaryName = eh.getBinaryName();
+ if (classElement.signatureEquals(eh)) {
+ if (name != null && !name.isEmpty()) {
+ if (!doesElementExist(js, eh, name, signature)) {
+ ecl.removed();
+ }
+ }
+ //ecl.changed(name);
+ }
+ }
+ }
+
+ @Override
+ public void rootsAdded(RootsEvent event) {
+ event.toString();
+ }
+
+ @Override
+ public void rootsRemoved(RootsEvent event) {
+ event.toString();
+ }
+ }
+
+ }
+
+ static boolean doesElementExist(final JavaSource js,
+ final ElementHandle typeHandle,
+ final String name,
+ final String signature) {
+ final boolean[] exists = new boolean[] { false };
+ try {
+ js.runUserActionTask(new Task() {
+ @Override
+ public void run(CompilationController cc) throws Exception {
+ if (cc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED).compareTo (JavaSource.Phase.ELEMENTS_RESOLVED) >= 0) {
+ TypeElement type = typeHandle.resolve(cc);
+ if (type == null) {
+ return ;
+ }
+ //List extends Element> allMembers = cc.getElements().getAllMembers(type);
+ List extends Element> allMembers = type.getEnclosedElements();
+ for (Element member : allMembers) {
+ if (!member.getSimpleName().contentEquals(name)) {
+ continue;
+ }
+ if (signature == null) {
+ if (!ElementKind.FIELD.equals(member.getKind())) {
+ continue;
+ }
+ exists[0] = true;
+ break;
+ } else {
+ if (!ElementKind.METHOD.equals(member.getKind())) {
+ continue;
+ }
+ ExecutableElement method = (ExecutableElement) member;
+ if (!signature.isEmpty()) {
+ if (!signature.equals(createSignature(method, cc.getTypes()))) {
+ continue;
+ }
+ }
+ exists[0] = true;
+ break;
+ }
+ }
+ } else {
+ exists[0] = true; // Be optimistic
+ }
+ }
+ }, true);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ return exists[0];
+ }
+
+ private static String createSignature(ExecutableElement elm, Types types) {
+ StringBuilder signature = new StringBuilder("(");
+ for (VariableElement param : elm.getParameters()) {
+ TypeMirror pt = param.asType();
+ pt = types.erasure(pt);
+ String paramType = getTypeBinaryName(pt);
+ signature.append(getSignature(paramType));
+ }
+ signature.append(')');
+ String returnType = getTypeBinaryName(types.erasure(elm.getReturnType()));
+ signature.append(getSignature(returnType));
+ return signature.toString();
+ }
+
+ private static String getTypeBinaryName(TypeMirror t) {
+ if (t instanceof ArrayType) {
+ TypeMirror ct = ((ArrayType) t).getComponentType();
+ return getTypeBinaryName(ct)+"[]";
+ }
+ if (t instanceof DeclaredType) {
+ return ElementUtilities.getBinaryName((TypeElement) ((DeclaredType) t).asElement());
+ }
+ return t.toString();
+ }
+
+ private static String getSignature(String javaType) {
+ if (javaType.equals("boolean")) {
+ return "Z";
+ } else if (javaType.equals("byte")) {
+ return "B";
+ } else if (javaType.equals("char")) {
+ return "C";
+ } else if (javaType.equals("short")) {
+ return "S";
+ } else if (javaType.equals("int")) {
+ return "I";
+ } else if (javaType.equals("long")) {
+ return "J";
+ } else if (javaType.equals("float")) {
+ return "F";
+ } else if (javaType.equals("double")) {
+ return "D";
+ } else if (javaType.equals("void")) {
+ return "V";
+ } else if (javaType.endsWith("[]")) {
+ return "["+getSignature(javaType.substring(0, javaType.length() - 2));
+ } else {
+ return "L"+javaType.replace('.', '/')+";";
+ }
+ }
+
+ static interface ElementChangeListener {
+ void removed();
+ void changed(String name);
+ }
+
+ static final class PackageSearchType implements ClassIndex.SearchScopeType {
+
+ private final Set extends String> packages;
+
+ PackageSearchType(String packageName) {
+ packages = Collections.singleton(packageName);
+ }
+
+ @Override
+ public Set extends String> getPackages() {
+ return packages;
+ }
+
+ @Override
+ public boolean isSources() {
+ return true;
+ }
+
+ @Override
+ public boolean isDependencies() {
+ return false;
+ }
+ }
+
+}
diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/LineBreakpoint.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/LineBreakpoint.java
--- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/LineBreakpoint.java
+++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/LineBreakpoint.java
@@ -59,6 +59,7 @@
import org.netbeans.api.debugger.DebuggerManager;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
+import org.netbeans.spi.debugger.BreakpointURLHandler;
import org.openide.ErrorManager;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeListener;
@@ -430,63 +431,36 @@
public String toString () {
String fileName = null;
try {
- FileObject fo = URLMapper.findFileObject(new URL(url));
+ FileObject fo = URLMapper.findFileObject(new URL(getURL()));
if (fo != null) {
fileName = fo.getNameExt();
}
} catch (MalformedURLException ex) {}
if (fileName == null) {
- fileName = url;
+ fileName = getURL();
}
return "LineBreakpoint " + fileName + " : " + lineNumber;
}
private static class LineBreakpointImpl extends LineBreakpoint
- implements Comparable, FileChangeListener,
+ implements BreakpointURLHandler.URLBasedBreakpoint, Comparable,
ChangeListener, PropertyChangeListener {
// We need to hold our FileObject so that it's not GC'ed, because we'd loose our listener.
- private FileObject fo;
- private ChangeListener registryListener;
- private FileChangeListener fileListener;
+ private final BreakpointURLHandler urlHandler;
public LineBreakpointImpl(String url) {
super(url);
- if (url.length() > 0) {
- try {
- fo = URLMapper.findFileObject(new URL(url));
- if (fo != null) {
- fileListener = WeakListeners.create(FileChangeListener.class, this, fo);
- fo.addFileChangeListener(fileListener);
- registryListener = WeakListeners.change(this, DataObject.getRegistry());
- DataObject.getRegistry().addChangeListener(registryListener);
- }
- } catch (MalformedURLException ex) {
- ErrorManager.getDefault().notify(new IllegalArgumentException("URL = '"+url+"'", ex));
- } catch (IllegalArgumentException ex) {
- ErrorManager.getDefault().notify(new IllegalArgumentException("URL = '"+url+"'", ex));
- }
- }
+ urlHandler = BreakpointURLHandler.create(this);
}
@Override
public void setURL(String url) {
- if (fo != null) {
- fo.removeFileChangeListener(fileListener);
- }
- super.setURL(url);
- if (url.length() > 0) {
- try {
- fo = URLMapper.findFileObject(new URL(url));
- if (fo != null) {
- fileListener = WeakListeners.create(FileChangeListener.class, this, fo);
- fo.addFileChangeListener(fileListener);
- }
- } catch (MalformedURLException ex) {
- ErrorManager.getDefault().notify(new IllegalArgumentException("URL = '"+url+"'", ex));
- } catch (IllegalArgumentException ex) {
- ErrorManager.getDefault().notify(new IllegalArgumentException("URL = '"+url+"'", ex));
- }
+ String old = urlHandler.setURL(url);
+ if (old == null || !old.equals(url)) {
+ super.setURL(url);
+ DebuggerManager.getDebuggerManager().addBreakpoint(this);
+ firePropertyChange(PROP_GROUP_PROPERTIES, null, null);
}
}
@@ -500,7 +474,7 @@
if (o instanceof LineBreakpointImpl) {
LineBreakpoint lbthis = this;
LineBreakpoint lb = (LineBreakpoint) o;
- int uc = lbthis.url.compareTo(lb.url);
+ int uc = lbthis.getURL().compareTo(lb.getURL());
if (uc != 0) {
return uc;
} else {
@@ -523,55 +497,10 @@
}
@Override
- public void fileFolderCreated(FileEvent fe) {
- }
-
- @Override
- public void fileDataCreated(FileEvent fe) {
- }
-
- @Override
- public void fileChanged(FileEvent fe) {
- }
-
- @Override
- public void fileDeleted(FileEvent fe) {
- DebuggerManager.getDebuggerManager().removeBreakpoint(this);
- fo = null;
- }
-
- @Override
- public void fileRenamed(FileRenameEvent fe) {
- this.setURL(((FileObject) fe.getSource()).toURL().toString());
- }
-
- @Override
- public void fileAttributeChanged(FileAttributeEvent fe) {
- }
-
- @Override
public void stateChanged(ChangeEvent chev) {
Object source = chev.getSource();
if (source instanceof Breakpoint.VALIDITY) {
setValidity((Breakpoint.VALIDITY) source, chev.toString());
- } else if (source instanceof Collection) {
- for (Object obj : ((Collection) source)) {
- DataObject dobj = (DataObject) obj;
- if (registryListener != null) {
- FileObject fileObject = this.fo;
- if (fileObject == null) {
- DataObject.getRegistry().removeChangeListener(registryListener);
- registryListener = null;
- return ;
- }
- FileObject primary = dobj.getPrimaryFile();
- if (fileObject.equals(primary)) {
- dobj.addPropertyChangeListener(WeakListeners.propertyChange(this, dobj));
- DataObject.getRegistry().removeChangeListener(registryListener);
- registryListener = null;
- }
- }
- }
} else {
throw new UnsupportedOperationException(chev.toString());
}
@@ -579,18 +508,7 @@
@Override
public void propertyChange(PropertyChangeEvent evt) {
- if (DataObject.PROP_PRIMARY_FILE.equals(evt.getPropertyName())) {
- if (fo != null) {
- fo.removeFileChangeListener(fileListener);
- }
- FileObject newFO = ((DataObject) evt.getSource()).getPrimaryFile();
- fileListener = WeakListeners.create(FileChangeListener.class, this, newFO);
- newFO.addFileChangeListener(fileListener);
- this.setURL(newFO.toURL().toString());
- fo = newFO;
- DebuggerManager.getDebuggerManager().addBreakpoint(this);
- firePropertyChange(PROP_GROUP_PROPERTIES, null, null);
- } else if (DebuggerEngine.class.getName().equals(evt.getPropertyName())) {
+ if (DebuggerEngine.class.getName().equals(evt.getPropertyName())) {
enginePropertyChange(evt);
}
}
@@ -609,12 +527,12 @@
@Override
public FileObject[] getFiles() {
- return new FileObject[] { fo };
+ return new FileObject[] { urlHandler.getFileObject() };
}
@Override
public Project[] getProjects() {
- FileObject f = fo;
+ FileObject f = urlHandler.getFileObject();
while (f != null) {
f = f.getParent();
if (f != null && ProjectManager.getDefault().isProject(f)) {
diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/MethodBreakpoint.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/MethodBreakpoint.java
--- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/MethodBreakpoint.java
+++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/MethodBreakpoint.java
@@ -55,9 +55,18 @@
import javax.swing.event.ChangeListener;
import org.netbeans.api.debugger.Breakpoint;
import org.netbeans.api.debugger.DebuggerEngine;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JavaSourceUtils.ElementChangeListener;
+import org.netbeans.api.debugger.jpda.JavaSourceUtils.ElementChangeTracker;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.Task;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
+import org.netbeans.spi.debugger.BreakpointURLHandler;
+import org.netbeans.spi.debugger.BreakpointURLHandler.URLBasedBreakpoint;
import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
/**
@@ -89,6 +98,9 @@
public static final String PROP_CLASS_FILTERS = "classFilters"; // NOI18N
/** Property name constant */
public static final String PROP_CLASS_EXCLUSION_FILTERS = "classExclusionFilters"; // NOI18N
+ /** Property name constant
+ * @since 2.46 */
+ public static final String PROP_URL = LineBreakpoint.PROP_URL;
/** Property name constant */
public static final String PROP_INSTANCE_FILTERS = "instanceFilters"; // NOI18N
/** Property name constant */
@@ -286,6 +298,23 @@
}
/**
+ * Get URL of the method source file.
+ * @return The URL or null
when there is no association with the source file.
+ * @since 2.46
+ */
+ public String getURL() {
+ return null;
+ }
+
+ /**
+ * Associate this breakpoint with the method source file.
+ * @param url The URL of the method source file.
+ * @since 2.46
+ */
+ public void setURL(String url) {
+ }
+
+ /**
* Get the instance filter for a specific debugger session.
* @return The instances or null
when there is no instance restriction.
*/
@@ -360,8 +389,112 @@
}
- private static final class MethodBreakpointImpl extends MethodBreakpoint implements ChangeListener,
- PropertyChangeListener {
+ private static final class MethodBreakpointImpl extends MethodBreakpoint implements URLBasedBreakpoint,
+ ChangeListener,
+ PropertyChangeListener,
+ ElementChangeListener {
+
+ private final BreakpointURLHandler urlHandler;
+ private ElementChangeTracker elementChangeTracker;
+ private final Object elementChangeTrackerLock = new Object();
+
+ MethodBreakpointImpl() {
+ super();
+ urlHandler = BreakpointURLHandler.create(this);
+ }
+
+ @Override
+ public String getURL() {
+ if (urlHandler == null) {
+ return null;
+ } else {
+ return urlHandler.getURL();
+ }
+ }
+
+ @Override
+ public void setURL(String url) {
+ String old = urlHandler.setURL(url);
+ if (old == null || !old.equals(url)) {
+ firePropertyChange (PROP_URL, old, url);
+ if (old != null && !old.isEmpty()) {
+ DebuggerManager.getDebuggerManager().addBreakpoint(this);
+ }
+ firePropertyChange(PROP_GROUP_PROPERTIES, null, null);
+ trackMethodElement();
+ }
+ }
+
+ @Override
+ public void setClassFilters(String[] classFilters) {
+ super.setClassFilters(classFilters);
+ trackMethodElement();
+ }
+
+ @Override
+ public void setMethodName(String mn) {
+ super.setMethodName(mn);
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.setName(mn);
+ }
+ }
+ }
+
+ @Override
+ public void setMethodSignature(String signature) {
+ super.setMethodSignature(signature);
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.setSignature(signature);
+ }
+ }
+ }
+
+ private void trackMethodElement() {
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.destroy();
+ }
+ }
+ String[] classFilters = getClassFilters();
+ FileObject fo = urlHandler.getFileObject();
+ if (classFilters.length == 1 && fo != null) {
+ final String clazz = classFilters[0];
+ final JavaSource js = JavaSource.forFileObject(fo);
+ if (js == null) {
+ return ;
+ }
+ final String methodName = getMethodName();
+ final String methodSignature = getMethodSignature();
+ try {
+ js.runWhenScanFinished(new Task() {
+ @Override
+ public void run(CompilationController parameter) throws Exception {
+ ElementChangeTracker ect = JavaSourceUtils.createElementChangeTracker(js, clazz, methodName, methodSignature);
+ if (ect != null) {
+ ect.setElementChangeListener(MethodBreakpointImpl.this);
+ synchronized (elementChangeTrackerLock) {
+ elementChangeTracker = ect;
+ }
+ }
+ }
+ }, true);
+ } catch (IOException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ @Override
+ protected void dispose() {
+ super.dispose();
+ synchronized (elementChangeTrackerLock) {
+ if (elementChangeTracker != null) {
+ elementChangeTracker.destroy();
+ }
+ }
+ }
@Override
public GroupProperties getGroupProperties() {
@@ -382,6 +515,16 @@
enginePropertyChange(evt);
}
+ @Override
+ public void removed() {
+ DebuggerManager.getDebuggerManager().removeBreakpoint(this);
+ }
+
+ @Override
+ public void changed(String name) {
+ setMethodName(name);
+ }
+
private final class MethodGroupProperties extends GroupProperties {
diff --git a/api.debugger/apichanges.xml b/api.debugger/apichanges.xml
--- a/api.debugger/apichanges.xml
+++ b/api.debugger/apichanges.xml
@@ -75,6 +75,20 @@
+
+
+ Handling of breakpoint's URL updates.
+
+
+
+
+
+ A class BreakpointURLHandler is added to automatically update
+ breakpoint's URL property when the breakpoint's source URL changes.
+
+
+
+
API for changing enabled state of a Watch
diff --git a/api.debugger/manifest.mf b/api.debugger/manifest.mf
--- a/api.debugger/manifest.mf
+++ b/api.debugger/manifest.mf
@@ -1,5 +1,5 @@
Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.api.debugger/1
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.43
+OpenIDE-Module-Specification-Version: 1.44
OpenIDE-Module-Layer: org/netbeans/api/debugger/layer.xml
diff --git a/api.debugger/nbproject/project.xml b/api.debugger/nbproject/project.xml
--- a/api.debugger/nbproject/project.xml
+++ b/api.debugger/nbproject/project.xml
@@ -76,6 +76,14 @@
+ org.openide.loaders
+
+
+
+ 7.50
+
+
+
org.openide.modules
@@ -84,6 +92,14 @@
+ org.openide.nodes
+
+
+
+ 7.36
+
+
+
org.openide.util
diff --git a/api.debugger/src/org/netbeans/spi/debugger/BreakpointURLHandler.java b/api.debugger/src/org/netbeans/spi/debugger/BreakpointURLHandler.java
new file mode 100644
--- /dev/null
+++ b/api.debugger/src/org/netbeans/spi/debugger/BreakpointURLHandler.java
@@ -0,0 +1,265 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 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]"
+ *
+ * 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.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2013 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.debugger;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collection;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.openide.ErrorManager;
+import org.openide.filesystems.FileAttributeEvent;
+import org.openide.filesystems.FileChangeListener;
+import org.openide.filesystems.FileEvent;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileRenameEvent;
+import org.openide.filesystems.URLMapper;
+import org.openide.loaders.DataObject;
+import org.openide.util.WeakListeners;
+
+/**
+ * A utility class, that keeps an association of the breakpoint with an URL
+ * and reflects the changes of the URL to the breakpoint.
+ *
+ * @author Martin Entlicher
+ * @since 1.44
+ */
+public final class BreakpointURLHandler {
+
+ private final URLBasedBreakpoint breakpoint;
+ private String url;
+ private FileObject fo;
+ private Listener listener;
+
+ private BreakpointURLHandler(URLBasedBreakpoint breakpoint) {
+ this.breakpoint = breakpoint;
+ setURL(breakpoint.getURL());
+ }
+
+ /**
+ * Creates a handler from an URL-based breakpoint.
+ * @param breakpoint The URL-based breakpoint
+ * @return a new instance of the handler
+ */
+ public static BreakpointURLHandler create(URLBasedBreakpoint breakpoint) {
+ return new BreakpointURLHandler(breakpoint);
+ }
+
+ /**
+ * Gets a string representation of URL of the source file,
+ * which contains the breakpoint.
+ *
+ * @return URL of the breakpoint source file.
+ */
+ public String getURL() {
+ return url;
+ }
+
+ /**
+ * Set a string representation of URL of the source file containing the breakpoint.
+ * @param url the URL of the breakpoint source file.
+ * @return an old URL, or null
.
+ */
+ public String setURL(String url) {
+ String old;
+ synchronized (this) {
+ if (url == null) {
+ url = "";
+ }
+ if (url.equals(this.url)) {
+ return this.url;
+ }
+ old = this.url;
+ this.url = url;
+
+ if (listener != null) {
+ listener.removeFrom(fo);
+ }
+ if (url.length() > 0) {
+ try {
+ fo = URLMapper.findFileObject(new URL(url));
+ if (fo != null) {
+ if (listener == null) {
+ listener = new Listener();
+ }
+ listener.addTo(fo);
+ }
+ } catch (MalformedURLException ex) {
+ ErrorManager.getDefault().notify(new IllegalArgumentException("URL = '"+url+"'", ex));
+ } catch (IllegalArgumentException ex) {
+ ErrorManager.getDefault().notify(new IllegalArgumentException("URL = '"+url+"'", ex));
+ }
+ }
+ }
+ return old;
+ }
+
+ /**
+ * Get the FileObject that corresponds to the current URL.
+ * @return The FileObject or null
.
+ */
+ public FileObject getFileObject() {
+ return fo;
+ }
+
+ void setFileObject(FileObject newFO) {
+ synchronized (this) {
+ if (listener != null) {
+ if (fo != null) {
+ listener.removeFrom(fo);
+ }
+ listener.addTo(newFO);
+ }
+ fo = newFO;
+ }
+ breakpoint.setURL(newFO.toURL().toString());
+ }
+
+ private class Listener implements FileChangeListener, ChangeListener, PropertyChangeListener {
+
+ private FileChangeListener fileListener;
+ private ChangeListener registryListener;
+
+ public Listener() {
+ registryListener = WeakListeners.change(this, DataObject.getRegistry());
+ DataObject.getRegistry().addChangeListener(registryListener);
+ }
+
+ void addTo(FileObject fo) {
+ fileListener = WeakListeners.create(FileChangeListener.class, this, fo);
+ fo.addFileChangeListener(fileListener);
+ }
+
+ void removeFrom(FileObject fo) {
+ fo.removeFileChangeListener(fileListener);
+ }
+
+ @Override
+ public void fileFolderCreated(FileEvent fe) {
+ }
+
+ @Override
+ public void fileDataCreated(FileEvent fe) {
+ }
+
+ @Override
+ public void fileChanged(FileEvent fe) {
+ }
+
+ @Override
+ public void fileDeleted(FileEvent fe) {
+ if (breakpoint instanceof Breakpoint) {
+ DebuggerManager.getDebuggerManager().removeBreakpoint((Breakpoint) breakpoint);
+ }
+ fo = null;
+ }
+
+ @Override
+ public void fileRenamed(FileRenameEvent fe) {
+ breakpoint.setURL(((FileObject) fe.getSource()).toURL().toString());
+ }
+
+ @Override
+ public void fileAttributeChanged(FileAttributeEvent fe) {
+ }
+
+ @Override
+ public void stateChanged(ChangeEvent chev) {
+ Object source = chev.getSource();
+ if (source instanceof Collection) {
+ for (Object obj : ((Collection) source)) {
+ DataObject dobj = (DataObject) obj;
+ if (registryListener != null) {
+ FileObject fileObject = fo;
+ if (fileObject == null) {
+ DataObject.getRegistry().removeChangeListener(registryListener);
+ registryListener = null;
+ return ;
+ }
+ FileObject primary = dobj.getPrimaryFile();
+ if (fileObject.equals(primary)) {
+ dobj.addPropertyChangeListener(WeakListeners.propertyChange(this, dobj));
+ DataObject.getRegistry().removeChangeListener(registryListener);
+ registryListener = null;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (DataObject.PROP_PRIMARY_FILE.equals(evt.getPropertyName())) {
+ FileObject newFO = ((DataObject) evt.getSource()).getPrimaryFile();
+ setFileObject(newFO);
+ //DebuggerManager.getDebuggerManager().addBreakpoint(this);
+ //firePropertyChange(PROP_GROUP_PROPERTIES, null, null);
+ }
+ }
+
+ }
+
+ /**
+ * Breakpoints that are associated with an URL should implement this
+ * interface so that they can be updated as the underlying source file changes.
+ */
+ public static interface URLBasedBreakpoint {
+
+ /**
+ * Get the breakpoint's URL.
+ * @return The URL.
+ */
+ String getURL();
+
+ /**
+ * Set the breakpoint to a new URL.
+ * @param url The new URL.
+ */
+ void setURL(String url);
+
+ }
+
+}
diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/actions/ToggleMethodFieldBreakpointAction.java b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/actions/ToggleMethodFieldBreakpointAction.java
--- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/actions/ToggleMethodFieldBreakpointAction.java
+++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/actions/ToggleMethodFieldBreakpointAction.java
@@ -255,7 +255,7 @@
} else if (fn == null && mn == null) {
return ; // line breakpoint only, which was submitted already.
}
- if (submitFieldOrMethodOrClassBreakpoint(cn, fn, mn, ms, null, ln)) {
+ if (submitFieldOrMethodOrClassBreakpoint(cn, fn, mn, ms, url, null, ln)) {
// We've submitted a field or method breakpoint, so delete the line one:
LineBreakpoint lb = ToggleBreakpointActionProvider.findBreakpoint (
url, ln
@@ -278,11 +278,11 @@
if (classDeclaration[0] != null) {
return submitFieldOrMethodOrClassBreakpoint(classDeclaration[0], null,
null, null,
- url, ln);
+ null, url, ln);
} else {
return submitFieldOrMethodOrClassBreakpoint(className[0], fieldName[0],
methodName, methodSignature,
- url, ln);
+ url, url, ln);
}
}
@@ -317,7 +317,7 @@
private boolean submitFieldOrMethodOrClassBreakpoint(final String className, final String fieldName,
final String methodName, final String methodSignature,
- String url, int line) {
+ final String sourceURL, String lineURL, int line) {
if (className == null) {
return false; // Can not do anything without the class name
}
@@ -332,8 +332,8 @@
//} else {
// return false;
}
- if (b == null && url != null) {
- b = ToggleBreakpointActionProvider.findBreakpoint(url, line);
+ if (b == null && lineURL != null) {
+ b = ToggleBreakpointActionProvider.findBreakpoint(lineURL, line);
}
DebuggerManager d = DebuggerManager.getDebuggerManager();
if (b != null) {
@@ -357,13 +357,16 @@
JPDABreakpoint b;
if (fieldName != null) {
b = FieldBreakpoint.create(className, fieldName, FieldBreakpoint.TYPE_MODIFICATION | FieldBreakpoint.TYPE_ACCESS);
+ ((FieldBreakpoint) b).setURL(sourceURL);
b.setPrintText(NbBundle.getMessage(FieldBreakpointPanel.class, "CTL_Field_Breakpoint_Print_Text"));
} else if (methodName != null) {
b = MethodBreakpoint.create(className, methodName);
((MethodBreakpoint) b).setMethodSignature(methodSignature);
+ ((MethodBreakpoint) b).setURL(sourceURL);
b.setPrintText(NbBundle.getMessage(MethodBreakpointPanel.class, "CTL_Method_Breakpoint_Print_Text"));
} else {
b = ClassLoadUnloadBreakpoint.create(className, false, ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED_UNLOADED);
+ ((ClassLoadUnloadBreakpoint) b).setURL(sourceURL);
b.setPrintText (NbBundle.getMessage(ClassBreakpointPanel.class, "CTL_Class_Breakpoint_Print_Text"));
}
DebuggerManager d = DebuggerManager.getDebuggerManager();
diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ClassBreakpointPanel.java b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ClassBreakpointPanel.java
--- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ClassBreakpointPanel.java
+++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ClassBreakpointPanel.java
@@ -57,6 +57,7 @@
import org.netbeans.modules.debugger.jpda.ui.EditorContextBridge;
import org.netbeans.modules.debugger.jpda.ui.completion.JavaClassNbDebugEditorKit;
import org.netbeans.spi.debugger.ui.Controller;
+import org.netbeans.spi.debugger.ui.EditorContextDispatcher;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
@@ -94,6 +95,7 @@
false,
ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED_UNLOADED
);
+ mb.setURL(EditorContextDispatcher.getDefault().getMostRecentURLAsString());
mb.setPrintText (
NbBundle.getBundle (ClassBreakpointPanel.class).getString
("CTL_Class_Breakpoint_Print_Text")
diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ExceptionBreakpointPanel.java b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ExceptionBreakpointPanel.java
--- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ExceptionBreakpointPanel.java
+++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ExceptionBreakpointPanel.java
@@ -54,6 +54,7 @@
import org.netbeans.modules.debugger.jpda.ui.EditorContextBridge;
import org.netbeans.modules.debugger.jpda.ui.completion.ExceptionClassNbDebugEditorKit;
import org.netbeans.spi.debugger.ui.Controller;
+import org.netbeans.spi.debugger.ui.EditorContextDispatcher;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
@@ -91,6 +92,7 @@
className,
ExceptionBreakpoint.TYPE_EXCEPTION_CATCHED_UNCATCHED
);
+ mb.setURL(EditorContextDispatcher.getDefault().getMostRecentURLAsString());
mb.setPrintText (
NbBundle.getBundle (ExceptionBreakpointPanel.class).getString
("CTL_Exception_Breakpoint_Print_Text")
diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/FieldBreakpointPanel.java b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/FieldBreakpointPanel.java
--- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/FieldBreakpointPanel.java
+++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/FieldBreakpointPanel.java
@@ -57,6 +57,7 @@
import org.netbeans.modules.debugger.jpda.ui.completion.JavaClassNbDebugEditorKit;
import org.netbeans.modules.debugger.jpda.ui.completion.JavaFieldNbDebugEditorKit;
import org.netbeans.spi.debugger.ui.Controller;
+import org.netbeans.spi.debugger.ui.EditorContextDispatcher;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
@@ -102,6 +103,7 @@
fieldName,
FieldBreakpoint.TYPE_ACCESS | FieldBreakpoint.TYPE_MODIFICATION
);
+ mb.setURL(EditorContextDispatcher.getDefault().getMostRecentURLAsString());
mb.setPrintText (
NbBundle.getBundle (FieldBreakpointPanel.class).getString
("CTL_Field_Breakpoint_Print_Text")
diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/MethodBreakpointPanel.java b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/MethodBreakpointPanel.java
--- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/MethodBreakpointPanel.java
+++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/MethodBreakpointPanel.java
@@ -55,6 +55,7 @@
import org.netbeans.modules.debugger.jpda.ui.completion.JavaClassNbDebugEditorKit;
import org.netbeans.modules.debugger.jpda.ui.completion.JavaMethodNbDebugEditorKit;
import org.netbeans.spi.debugger.ui.Controller;
+import org.netbeans.spi.debugger.ui.EditorContextDispatcher;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.ErrorManager;
@@ -103,6 +104,7 @@
try {
mb.setMethodSignature(EditorContextBridge.getMostRecentMethodSignature());
} catch (java.awt.IllegalComponentStateException icsex) {}
+ mb.setURL(EditorContextDispatcher.getDefault().getMostRecentURLAsString());
mb.setPrintText (
NbBundle.getBundle (MethodBreakpointPanel.class).getString
("CTL_Method_Breakpoint_Print_Text")
diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsReader.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsReader.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsReader.java
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsReader.java
@@ -178,6 +178,10 @@
MethodBreakpoint.TYPE_METHOD_ENTRY
)
);
+ String url = properties.getString(MethodBreakpoint.PROP_URL, null);
+ if (url != null) {
+ mb.setURL(url);
+ }
synchronized (this) {
cachedSourceRoots.put(mb, properties.getString("sourceRoot", null));
}
@@ -203,6 +207,10 @@
new String [0]
)
);
+ String url = properties.getString(ClassLoadUnloadBreakpoint.PROP_URL, null);
+ if (url != null) {
+ cb.setURL(url);
+ }
synchronized (this) {
cachedSourceRoots.put(cb, properties.getString("sourceRoot", null));
}
@@ -231,6 +239,10 @@
if (classExclusionFilters != null) {
eb.setClassExclusionFilters(classExclusionFilters);
}
+ String url = properties.getString(ExceptionBreakpoint.PROP_URL, null);
+ if (url != null) {
+ eb.setURL(url);
+ }
synchronized (this) {
cachedSourceRoots.put(eb, properties.getString("sourceRoot", null));
}
@@ -249,6 +261,10 @@
fb.setCondition (
properties.getString (FieldBreakpoint.PROP_CONDITION, "")
);
+ String url = properties.getString(FieldBreakpoint.PROP_URL, null);
+ if (url != null) {
+ fb.setURL(url);
+ }
synchronized (this) {
cachedSourceRoots.put(fb, properties.getString("sourceRoot", null));
}
@@ -440,6 +456,10 @@
MethodBreakpoint.PROP_BREAKPOINT_TYPE,
mb.getBreakpointType ()
);
+ properties.setString(
+ MethodBreakpoint.PROP_URL,
+ mb.getURL()
+ );
properties.setString("sourceRoot", findCachedSourceRoot(mb));
return;
} else
@@ -457,6 +477,10 @@
ClassLoadUnloadBreakpoint.PROP_BREAKPOINT_TYPE,
cb.getBreakpointType ()
);
+ properties.setString(
+ ClassLoadUnloadBreakpoint.PROP_URL,
+ cb.getURL()
+ );
properties.setString("sourceRoot", findCachedSourceRoot(cb));
return;
} else
@@ -480,6 +504,10 @@
ExceptionBreakpoint.PROP_CONDITION,
eb.getCondition ()
);
+ properties.setString(
+ ExceptionBreakpoint.PROP_URL,
+ eb.getURL()
+ );
properties.setString("sourceRoot", findCachedSourceRoot(eb));
return;
} else
@@ -501,6 +529,10 @@
FieldBreakpoint.PROP_BREAKPOINT_TYPE,
fb.getBreakpointType ()
);
+ properties.setString(
+ FieldBreakpoint.PROP_URL,
+ fb.getURL()
+ );
properties.setString("sourceRoot", findCachedSourceRoot(fb));
return;
} else