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
@@ -786,6 +786,21 @@
+
+
+ BreakpointsClassFilter provider introduced.
+
+
+
+
+
+ BreakpointsClassFilter introduced to provide a customized set of classes
+ for breakpoints.
+
+
+
+
+
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.36
+OpenIDE-Module-Specification-Version: 2.37
OpenIDE-Module-Package-Dependencies: com.sun.jdi[VirtualMachineManager]
diff --git a/api.debugger.jpda/src/org/netbeans/modules/debugger/jpda/apiregistry/DebuggerProcessor.java b/api.debugger.jpda/src/org/netbeans/modules/debugger/jpda/apiregistry/DebuggerProcessor.java
--- a/api.debugger.jpda/src/org/netbeans/modules/debugger/jpda/apiregistry/DebuggerProcessor.java
+++ b/api.debugger.jpda/src/org/netbeans/modules/debugger/jpda/apiregistry/DebuggerProcessor.java
@@ -64,6 +64,7 @@
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.spi.debugger.ContextProvider;
+import org.netbeans.spi.debugger.jpda.BreakpointsClassFilter;
import org.netbeans.spi.debugger.jpda.EditorContext;
import org.netbeans.spi.debugger.jpda.Evaluator;
import org.netbeans.spi.debugger.jpda.SmartSteppingCallback;
@@ -91,7 +92,8 @@
SourcePathProvider.Registration.class.getCanonicalName(),
EditorContext.Registration.class.getCanonicalName(),
VariablesFilter.Registration.class.getCanonicalName(),
- Evaluator.Registration.class.getCanonicalName()
+ Evaluator.Registration.class.getCanonicalName(),
+ BreakpointsClassFilter.Registration.class.getCanonicalName()
));
}
@@ -147,6 +149,13 @@
handleEvaluatorRegistration(e, language);
cnt++;
}
+ for (Element e : env.getElementsAnnotatedWith(BreakpointsClassFilter.Registration.class)) {
+ BreakpointsClassFilter.Registration reg = e.getAnnotation(BreakpointsClassFilter.Registration.class);
+
+ final String path = reg.path();
+ handleProviderRegistration(e, BreakpointsClassFilter.class, path);
+ cnt++;
+ }
return cnt == annotations.size();
}
diff --git a/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/BreakpointsClassFilter.java b/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/BreakpointsClassFilter.java
new file mode 100644
--- /dev/null
+++ b/api.debugger.jpda/src/org/netbeans/spi/debugger/jpda/BreakpointsClassFilter.java
@@ -0,0 +1,161 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 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 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.debugger.jpda;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Map;
+import org.netbeans.api.debugger.jpda.JPDABreakpoint;
+import org.netbeans.modules.debugger.jpda.apiregistry.DebuggerProcessor;
+import org.netbeans.spi.debugger.ContextAwareService;
+import org.netbeans.spi.debugger.ContextAwareSupport;
+import org.netbeans.spi.debugger.ContextProvider;
+
+/**
+ * Filter of breakpoint class names.
+ * Breakpoints have defined names of classes, which they are to be submitted for.
+ * But there can be a need to customize the class names for a specific use.
+ * For instance, add versioned classes for JRebel, etc.
+ *
+ * @author Martin Entlicher
+ * @since 2.37
+ */
+public abstract class BreakpointsClassFilter {
+
+ /**
+ * Provide a modified set of class names.
+ *
+ * @param classNames The original set of class names that the breakpoint acts on
+ * @param breakpoint The associated breakpoint
+ * @return A modified set of class names, for which the breakpoint is to be submitted.
+ */
+ public abstract ClassNames filterClassNames(ClassNames classNames, JPDABreakpoint breakpoint);
+
+ /**
+ * The set of class names and excluded class names.
+ */
+ public static class ClassNames {
+
+ private final String[] classNames;
+ private final String[] excludedClassNames;
+
+ /**
+ * Create a new set of class names and excluded class names.
+ * The names can start or end with '*' character.
+ * @param classNames The (binary) class names
+ * @param excludedClassNames The excluded (binary) class names
+ */
+ public ClassNames(String[] classNames, String[] excludedClassNames) {
+ this.classNames = classNames;
+ this.excludedClassNames = excludedClassNames;
+ }
+
+ /**
+ * Get the list of class names
+ * @return The array of (binary) class names
+ */
+ public String[] getClassNames() {
+ return classNames;
+ }
+
+ /**
+ * Get the list of excluded class names
+ * @return The array of excluded (binary) class names
+ */
+ public String[] getExcludedClassNames() {
+ return excludedClassNames;
+ }
+
+ }
+
+ /**
+ * Declarative registration of BreakpointsClassFilter implementation.
+ * By marking the implementation class with this annotation,
+ * you automatically register that implementation for use by debugger.
+ * The class must be public and have a public constructor which takes
+ * no arguments or takes {@link ContextProvider} as an argument.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE})
+ public @interface Registration {
+
+ /**
+ * An optional path to register this implementation in.
+ */
+ String path() default "";
+
+ }
+
+ static class ContextAware extends BreakpointsClassFilter implements ContextAwareService {
+
+ private String serviceName;
+
+ private ContextAware(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ @Override
+ public BreakpointsClassFilter forContext(ContextProvider context) {
+ return (BreakpointsClassFilter) ContextAwareSupport.createInstance(serviceName, context);
+ }
+
+ @Override
+ public ClassNames filterClassNames(ClassNames classNames, JPDABreakpoint breakpoint) {
+ return classNames;
+ }
+
+ /**
+ * Creates instance of ContextAwareService
based on layer.xml
+ * attribute values
+ *
+ * @param attrs attributes loaded from layer.xml
+ * @return new ContextAwareService
instance
+ */
+ static ContextAwareService createService(Map attrs) throws ClassNotFoundException {
+ String serviceName = (String) attrs.get(DebuggerProcessor.SERVICE_NAME);
+ return new ContextAware(serviceName);
+ }
+
+ }
+}
diff --git a/debugger.jpda/nbproject/project.xml b/debugger.jpda/nbproject/project.xml
--- a/debugger.jpda/nbproject/project.xml
+++ b/debugger.jpda/nbproject/project.xml
@@ -64,6 +64,7 @@
2
+ 2.37
diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ClassBasedBreakpoint.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ClassBasedBreakpoint.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ClassBasedBreakpoint.java
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ClassBasedBreakpoint.java
@@ -83,6 +83,7 @@
import org.netbeans.modules.debugger.jpda.jdi.request.ClassUnloadRequestWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestManagerWrapper;
import org.netbeans.modules.debugger.jpda.util.JPDAUtils;
+import org.netbeans.spi.debugger.jpda.BreakpointsClassFilter;
import org.netbeans.spi.debugger.jpda.SourcePathProvider;
import org.openide.ErrorManager;
import org.openide.filesystems.FileUtil;
@@ -101,6 +102,7 @@
private final Object SOURCE_ROOT_LOCK = new Object();
private SourceRootsChangedListener srChListener;
private PropertyChangeListener weakSrChListener;
+ private BreakpointsClassFilter classFilter;
private static final Logger logger = Logger.getLogger("org.netbeans.modules.debugger.jpda.breakpoints"); // NOI18N
@@ -109,7 +111,7 @@
JPDADebuggerImpl debugger,
Session session
) {
- super (breakpoint, null, debugger, session);
+ this (breakpoint, null, debugger, session);
}
public ClassBasedBreakpoint (
@@ -119,6 +121,11 @@
Session session
) {
super (breakpoint, reader, debugger, session);
+ classFilter = new CompoundClassFilter(session.lookup(null, BreakpointsClassFilter.class));
+ }
+
+ protected final BreakpointsClassFilter getClassFilter() {
+ return classFilter;
}
protected final void setSourceRoot(String sourceRoot) {
@@ -227,7 +234,7 @@
return compareSourceRoots(sourceRoot, urlRoot);
}
- protected void setClassRequests (
+ protected final void setClassRequests (
String[] classFilters,
String[] classExclusionFilters,
int breakpointType
@@ -235,7 +242,7 @@
setClassRequests(classFilters, classExclusionFilters, breakpointType, true);
}
- protected void setClassRequests (
+ protected final void setClassRequests (
String[] classFilters,
String[] classExclusionFilters,
int breakpointType,
@@ -244,39 +251,37 @@
try {
if ((breakpointType & ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED) != 0
) {
- ClassPrepareRequest cpr = EventRequestManagerWrapper.
- createClassPrepareRequest (getEventRequestManager());
int i, k = classFilters.length;
for (i = 0; i < k; i++) {
+ ClassPrepareRequest cpr = EventRequestManagerWrapper.
+ createClassPrepareRequest (getEventRequestManager());
ClassPrepareRequestWrapper.addClassFilter (cpr, classFilters [i]);
if (logger.isLoggable(Level.FINE))
logger.fine("Set class load request: " + classFilters [i]);
+ for (String exclusionFilter : classExclusionFilters) {
+ ClassPrepareRequestWrapper.addClassExclusionFilter (cpr, exclusionFilter);
+ if (logger.isLoggable(Level.FINE))
+ logger.fine("Set class load exclusion request: " + exclusionFilter);
+ }
+ addEventRequest (cpr, ignoreHitCountOnClassLoad);
}
- k = classExclusionFilters.length;
- for (i = 0; i < k; i++) {
- ClassPrepareRequestWrapper.addClassExclusionFilter (cpr, classExclusionFilters [i]);
- if (logger.isLoggable(Level.FINE))
- logger.fine("Set class load exclusion request: " + classExclusionFilters [i]);
- }
- addEventRequest (cpr, ignoreHitCountOnClassLoad);
}
if ((breakpointType & ClassLoadUnloadBreakpoint.TYPE_CLASS_UNLOADED) != 0
) {
- ClassUnloadRequest cur = EventRequestManagerWrapper.
- createClassUnloadRequest (getEventRequestManager());
int i, k = classFilters.length;
for (i = 0; i < k; i++) {
+ ClassUnloadRequest cur = EventRequestManagerWrapper.
+ createClassUnloadRequest (getEventRequestManager());
ClassUnloadRequestWrapper.addClassFilter (cur, classFilters [i]);
if (logger.isLoggable(Level.FINE))
logger.fine("Set class unload request: " + classFilters [i]);
+ for (String exclusionFilter : classExclusionFilters) {
+ ClassUnloadRequestWrapper.addClassExclusionFilter (cur, exclusionFilter);
+ if (logger.isLoggable(Level.FINE))
+ logger.fine("Set class unload exclusion request: " + exclusionFilter);
+ }
+ addEventRequest (cur, false);
}
- k = classExclusionFilters.length;
- for (i = 0; i < k; i++) {
- ClassUnloadRequestWrapper.addClassExclusionFilter (cur, classExclusionFilters [i]);
- if (logger.isLoggable(Level.FINE))
- logger.fine("Set class unload exclusion request: " + classExclusionFilters [i]);
- }
- addEventRequest (cur, false);
}
} catch (VMDisconnectedExceptionWrapper e) {
} catch (InternalExceptionWrapper e) {
@@ -404,5 +409,23 @@
}
}
+
+ private class CompoundClassFilter extends BreakpointsClassFilter {
+
+ private List extends BreakpointsClassFilter> filters;
+
+ public CompoundClassFilter(List extends BreakpointsClassFilter> filters) {
+ this.filters = filters;
+ }
+
+ @Override
+ public ClassNames filterClassNames(ClassNames classNames, JPDABreakpoint breakpoint) {
+ for (BreakpointsClassFilter f : filters) {
+ classNames = f.filterClassNames(classNames, breakpoint);
+ }
+ return classNames;
+ }
+
+ }
}
diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ClassBreakpointImpl.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ClassBreakpointImpl.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ClassBreakpointImpl.java
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ClassBreakpointImpl.java
@@ -64,6 +64,7 @@
import org.netbeans.modules.debugger.jpda.jdi.request.ClassPrepareRequestWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.ClassUnloadRequestWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestManagerWrapper;
+import org.netbeans.spi.debugger.jpda.BreakpointsClassFilter.ClassNames;
/**
* Implementation of breakpoint on method.
@@ -87,9 +88,16 @@
@Override
protected void setRequests () {
+ ClassNames classNames = getClassFilter().filterClassNames(
+ new ClassNames(
+ breakpoint.getClassFilters(),
+ breakpoint.getClassExclusionFilters()),
+ breakpoint);
+ String[] names = classNames.getClassNames();
+ String[] excludedNames = classNames.getExcludedClassNames();
setClassRequests (
- breakpoint.getClassFilters (),
- breakpoint.getClassExclusionFilters (),
+ names,
+ excludedNames,
breakpoint.getBreakpointType (),
false
);
diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ExceptionBreakpointImpl.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ExceptionBreakpointImpl.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ExceptionBreakpointImpl.java
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/ExceptionBreakpointImpl.java
@@ -65,6 +65,7 @@
import org.netbeans.modules.debugger.jpda.jdi.event.LocatableEventWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestManagerWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.ExceptionRequestWrapper;
+import org.netbeans.spi.debugger.jpda.BreakpointsClassFilter.ClassNames;
import org.openide.util.Exceptions;
/**
@@ -86,12 +87,23 @@
@Override
protected void setRequests () {
+ ClassNames classNames = getClassFilter().filterClassNames(
+ new ClassNames(
+ new String[] {
+ breakpoint.getExceptionClassName()
+ },
+ new String [0]),
+ breakpoint);
+ String[] names = classNames.getClassNames();
+ String[] excludedNames = classNames.getExcludedClassNames();
setClassRequests (
- new String[] {breakpoint.getExceptionClassName ()},
- new String[0],
+ names,
+ excludedNames,
ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED
);
- checkLoadedClasses (breakpoint.getExceptionClassName (), null);
+ for (String cn : names) {
+ checkLoadedClasses (cn, excludedNames);
+ }
}
@Override
diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/FieldBreakpointImpl.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/FieldBreakpointImpl.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/FieldBreakpointImpl.java
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/FieldBreakpointImpl.java
@@ -84,6 +84,7 @@
import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestManagerWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.WatchpointRequestWrapper;
import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
+import org.netbeans.spi.debugger.jpda.BreakpointsClassFilter.ClassNames;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
@@ -107,6 +108,16 @@
@Override
protected void setRequests () {
+ ClassNames classNames = getClassFilter().filterClassNames(
+ new ClassNames(
+ new String[] {
+ breakpoint.getClassName()
+ },
+ new String [0]),
+ breakpoint);
+ String[] names = classNames.getClassNames();
+ String[] excludedNames = classNames.getExcludedClassNames();
+
boolean access = (breakpoint.getBreakpointType () &
FieldBreakpoint.TYPE_ACCESS) != 0;
try {
@@ -123,11 +134,13 @@
return ;
}
setClassRequests (
- new String[] {breakpoint.getClassName ()},
- new String[0],
+ names,
+ excludedNames,
ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED
);
- checkLoadedClasses (breakpoint.getClassName (), null);
+ for (String cn : names) {
+ checkLoadedClasses (cn, excludedNames);
+ }
} catch (InternalExceptionWrapper e) {
} catch (VMDisconnectedExceptionWrapper e) {
}
diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/LineBreakpointImpl.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/LineBreakpointImpl.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/LineBreakpointImpl.java
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/LineBreakpointImpl.java
@@ -110,6 +110,7 @@
import org.netbeans.modules.debugger.jpda.jdi.request.BreakpointRequestWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestManagerWrapper;
import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
+import org.netbeans.spi.debugger.jpda.BreakpointsClassFilter.ClassNames;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.ErrorManager;
import org.openide.cookies.EditorCookie;
@@ -267,14 +268,23 @@
return ;
}
logger.fine("LineBreakpoint "+breakpoint+" - setting request for "+className);
+ ClassNames classNames = getClassFilter().filterClassNames(
+ new ClassNames(
+ new String[] {
+ className // The class name is correct even for inner classes now
+ },
+ new String [0]),
+ breakpoint);
+ String[] names = classNames.getClassNames();
+ String[] excludedNames = classNames.getExcludedClassNames();
setClassRequests (
- new String[] {
- className // The class name is correct even for inner classes now
- },
- new String [0],
+ names,
+ excludedNames,
ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED
);
- checkLoadedClasses (className, null);
+ for (String cn : names) {
+ checkLoadedClasses (cn, excludedNames);
+ }
}
private void setInvalid(String reason) {
diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/MethodBreakpointImpl.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/MethodBreakpointImpl.java
--- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/MethodBreakpointImpl.java
+++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/MethodBreakpointImpl.java
@@ -94,6 +94,7 @@
import org.netbeans.modules.debugger.jpda.jdi.request.MethodEntryRequestWrapper;
import org.netbeans.modules.debugger.jpda.jdi.request.MethodExitRequestWrapper;
import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
+import org.netbeans.spi.debugger.jpda.BreakpointsClassFilter.ClassNames;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
@@ -115,13 +116,20 @@
@Override
protected void setRequests () {
+ ClassNames classNames = getClassFilter().filterClassNames(
+ new ClassNames(
+ breakpoint.getClassFilters(),
+ breakpoint.getClassExclusionFilters()),
+ breakpoint);
+ String[] names = classNames.getClassNames();
+ String[] excludedNames = classNames.getExcludedClassNames();
setClassRequests (
- breakpoint.getClassFilters (),
- breakpoint.getClassExclusionFilters (),
+ names,
+ excludedNames,
ClassLoadUnloadBreakpoint.TYPE_CLASS_LOADED
);
- for(String filter : breakpoint.getClassFilters()) {
- checkLoadedClasses (filter, breakpoint.getClassExclusionFilters());
+ for(String filter : names) {
+ checkLoadedClasses (filter, excludedNames);
}
}
diff --git a/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/BreakpointsClassFilterTest.java b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/BreakpointsClassFilterTest.java
new file mode 100644
--- /dev/null
+++ b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/BreakpointsClassFilterTest.java
@@ -0,0 +1,237 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 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 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.debugger.jpda;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+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;
+import org.netbeans.spi.debugger.jpda.BreakpointsClassFilter;
+
+/**
+ * Test of {@link BreakpointsClassFilter}.
+ *
+ * @author Martin Entlicher
+ */
+public class BreakpointsClassFilterTest extends NbTestCase {
+
+ private static final String TEST_APP_PATH = System.getProperty ("test.dir.src") +
+ "org/netbeans/api/debugger/jpda/testapps/BreakpointsClassFilterApp.java";
+ private static final String FILTER_GROUP_NAME = "filtered";
+ private static final String APP_CLASS_NAME = "org.netbeans.api.debugger.jpda.testapps.BreakpointsClassFilterApp";
+ private static final String APP2_CLASS_NAME = APP_CLASS_NAME + "2";
+
+ private JPDASupport support;
+
+ /*
+ public static Test suite() {
+ return JPDASupport.createTestSuite(BreakpointsClassFilterTest.class);
+ }
+ */
+
+ public BreakpointsClassFilterTest(String s) {
+ super(s);
+ }
+
+ /**
+ * Two breakpoints of each kind are submitted,
+ * the first is hit in BreakpointsClassFilterApp class only,
+ * but the second is hit also in BreakpointsClassFilterApp2 class.
+ * The latter has {@link #FILTER_GROUP_NAME} set as a group name to
+ * distinguish the filtered breakpoints.
+ * Hits in the two application classes are checked by TestBreakpointListener.
+ *
+ * @throws Exception
+ */
+ public void testFilteredBreakpoints() throws Exception {
+ JPDASupport.removeAllBreakpoints ();
+ List breakpoints = new ArrayList();
+ Utils.BreakPositions bp = Utils.getBreakPositions(TEST_APP_PATH);
+ List lineBreakpoints = bp.getLineBreakpoints();
+ lineBreakpoints.get(1).setGroupName(FILTER_GROUP_NAME);
+
+ MethodBreakpoint mb1 = MethodBreakpoint.create(APP_CLASS_NAME, "test");
+ mb1.setBreakpointType(MethodBreakpoint.TYPE_METHOD_ENTRY);
+
+ FieldBreakpoint fb1 = FieldBreakpoint.create(APP_CLASS_NAME, "field", FieldBreakpoint.TYPE_ACCESS);
+ FieldBreakpoint fb2 = FieldBreakpoint.create(APP_CLASS_NAME, "field2", FieldBreakpoint.TYPE_ACCESS);
+ fb2.setGroupName(FILTER_GROUP_NAME);
+
+ ExceptionBreakpoint eb1 = ExceptionBreakpoint.create(NegativeArraySizeException.class.getName(), ExceptionBreakpoint.TYPE_EXCEPTION_CATCHED_UNCATCHED);
+ ExceptionBreakpoint eb2 = ExceptionBreakpoint.create(ArithmeticException.class.getName(), ExceptionBreakpoint.TYPE_EXCEPTION_CATCHED_UNCATCHED);
+ eb2.setGroupName(FILTER_GROUP_NAME);
+
+ MethodBreakpoint mb2 = MethodBreakpoint.create(APP_CLASS_NAME, "test");
+ mb2.setBreakpointType(MethodBreakpoint.TYPE_METHOD_EXIT);
+ mb2.setGroupName(FILTER_GROUP_NAME);
+
+ breakpoints.add(lineBreakpoints.get(0));
+ breakpoints.add(mb1);
+ breakpoints.add(fb1);
+ breakpoints.add(eb1);
+ breakpoints.add(lineBreakpoints.get(1));
+ breakpoints.add(mb2);
+ breakpoints.add(fb2);
+ breakpoints.add(eb2);
+
+ List listeners = new ArrayList();
+ for (JPDABreakpoint b : breakpoints) {
+ TestBreakpointListener tbl = new TestBreakpointListener
+ (b, FILTER_GROUP_NAME.equals(b.getGroupName()), breakpoints);
+ b.addJPDABreakpointListener(tbl);
+ DebuggerManager.getDebuggerManager ().addBreakpoint (b);
+ listeners.add(tbl);
+ }
+
+ support = JPDASupport.attach (
+ APP_CLASS_NAME
+ );
+ support.waitState(JPDADebugger.STATE_DISCONNECTED);
+ assertTrue(Arrays.toString(breakpoints.toArray()), breakpoints.isEmpty());
+ for (TestBreakpointListener l : listeners) {
+ assertTrue(l.getMessage(), l.isOK());
+ }
+ }
+
+ private class TestBreakpointListener implements JPDABreakpointListener {
+
+ private final JPDABreakpoint breakpoint;
+ private final boolean isFiltered;
+ private final List allBreakpoints;
+ private Boolean ok = null;
+ private String message = "Not hit yet.";
+ private final Set toBeHitIn;
+
+ public TestBreakpointListener(JPDABreakpoint breakpoint, boolean isFiltered,
+ List allBreakpoints) {
+ this.breakpoint = breakpoint;
+ this.isFiltered = isFiltered;
+ this.allBreakpoints = allBreakpoints;
+ if (isFiltered) {
+ toBeHitIn = new HashSet();
+ toBeHitIn.add(APP_CLASS_NAME);
+ toBeHitIn.add(APP2_CLASS_NAME);
+ } else {
+ toBeHitIn = null;
+ }
+ }
+
+ @Override
+ public void breakpointReached(JPDABreakpointEvent event) {
+ //System.err.println("breakpointReached("+event+", isFiltered = "+isFiltered+"), referenceType = "+event.getReferenceType());
+ if (!isFiltered) {
+ boolean removed = allBreakpoints.remove(breakpoint);
+ if (ok == null && removed) {
+ ok = Boolean.TRUE;
+ message = "O.K.";
+ } else {
+ if (ok != null) {
+ message += "Hit again at "+event.getReferenceType()+" ";
+ ok = Boolean.FALSE;
+ } else if (!removed) {
+ message += "BP not in list. ";
+ ok = Boolean.FALSE;
+ }
+ }
+ } else { // Filtered, expected to hit twice (in APP_CLASS_NAME and APP2_CLASS_NAME)
+ //System.err.println("breakpointReached("+event+", isFiltered = "+isFiltered+"), referenceType = "+event.getReferenceType());
+ String className = event.getReferenceType().name();//event.getThread().getClassName();
+ boolean removed = toBeHitIn.remove(className);
+ if (ok == null && removed && toBeHitIn.isEmpty()) {
+ allBreakpoints.remove(breakpoint);
+ ok = Boolean.TRUE;
+ message = "O.K.";
+ } else {
+ if (!removed) {
+ message += "Hit again at "+className+" ";
+ ok = Boolean.FALSE;
+ }
+ }
+ }
+ event.resume();
+ }
+
+ public boolean isOK() {
+ return Boolean.TRUE.equals(ok);
+ }
+
+ public String getMessage() {
+ return message + " " + breakpoint+" with group "+breakpoint.getGroupName();
+ }
+
+ }
+
+ @BreakpointsClassFilter.Registration(path="netbeans-JPDASession")
+ public static class TestBreakpointsClassFilter extends BreakpointsClassFilter {
+
+ public TestBreakpointsClassFilter() {
+ //System.err.println("NEW TestBreakpointsClassFilter()");
+ }
+
+ @Override
+ public ClassNames filterClassNames(ClassNames classNames, JPDABreakpoint breakpoint) {
+ //System.err.println("filterClassNames("+Arrays.toString(classNames.getClassNames()));
+ String groupName = breakpoint.getGroupName();
+ if (FILTER_GROUP_NAME.equals(groupName)) {
+ String[] classes = classNames.getClassNames();
+ String[] newClasses = new String[classes.length + 1];
+ System.arraycopy(classes, 0, newClasses, 0, classes.length);
+ if (breakpoint instanceof ExceptionBreakpoint) {
+ newClasses[classes.length] = NullPointerException.class.getName();
+ } else {
+ newClasses[classes.length] = APP2_CLASS_NAME;
+ }
+ return new ClassNames(newClasses, classNames.getExcludedClassNames());
+ } else {
+ return classNames;
+ }
+ }
+
+ }
+
+}
diff --git a/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/BreakpointsClassFilterApp.java b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/BreakpointsClassFilterApp.java
new file mode 100644
--- /dev/null
+++ b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/BreakpointsClassFilterApp.java
@@ -0,0 +1,89 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 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 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.debugger.jpda.testapps;
+
+import java.util.Random;
+
+/**
+ * Test app for breakpoints class filters.
+ * Some breakpoints stop in this class only, some get filter class names,
+ * that add BreakpointsClassFilterApp2 as well.
+ *
+ * @author Martin Entlicher
+ */
+public class BreakpointsClassFilterApp {
+
+ private double field = 111.111;
+ private double field2 = 111.111;
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(final String[] args) {
+ Thread t = new Thread(BreakpointsClassFilterApp2.class.getName()) {
+ @Override public void run() {
+ BreakpointsClassFilterApp2.main(args);
+ }
+ }; t.start();
+ new BreakpointsClassFilterApp().test(t);
+ }
+
+ public double test(Thread t) {
+ double d = 0; // LBREAKPOINT
+ int n = new Random(Math.round(field)).nextInt();
+ n = n - n;
+ try {
+ n += new Double[-10].length;
+ } catch (NegativeArraySizeException nasex) {
+ }
+ d = d + field2 + Math.atan(n) + Math.PI + Math.E; // LBREAKPOINT
+ try {
+ d += 1/n;
+ } catch (ArithmeticException aex) {
+ }
+ try {
+ t.join();
+ } catch (InterruptedException ex) {
+ }
+ return d;
+ }
+}
diff --git a/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/BreakpointsClassFilterApp2.java b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/BreakpointsClassFilterApp2.java
new file mode 100644
--- /dev/null
+++ b/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/BreakpointsClassFilterApp2.java
@@ -0,0 +1,85 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 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 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.debugger.jpda.testapps;
+
+import java.util.Random;
+
+/**
+ * Test app for breakpoints class filters.
+ * Some breakpoints get this in filter class names, causing pauses in here
+ * even when submitted for BreakpointsClassFilterApp only.
+ *
+ * @author Martin Entlicher
+ */
+public class BreakpointsClassFilterApp2 {
+
+ private double field = 111.111;
+ private double field2 = 111.111;
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String[] args) {
+ // TODO code application logic here
+ // Keep the identical line numbers with BreakpointsClassFilterApp
+
+
+
+ new BreakpointsClassFilterApp2().test();
+ }
+
+ public double test() {
+ double d = 0;
+ int n = new Random(Math.round(field)).nextInt();
+ n = n - n;
+ try {
+ throw new IllegalStateException("TEST");
+ } catch (IllegalStateException nasex) {
+ }
+ d = d + field2 + Math.atan(n) + Math.PI + Math.E;
+ try {
+ Double dbl = null; d += dbl;
+ } catch (NullPointerException npex) {
+ }
+ return d;
+ }
+}