*** empty log message ***
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugConstants.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugConstants.java index aea3f56..c8a1f00 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugConstants.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugConstants.java
@@ -21,6 +21,12 @@ public interface IJavaDebugConstants { /** + * Java breakpoint marker type + * (value <code>"org.eclipse.jdt.debug.javaBreakpoint"</code>). + */ + public static final String JAVA_BREAKPOINT= "org.eclipse.jdt.debug.javaBreakpoint"; + + /** * Java line breakpoint marker type * (value <code>"org.eclipse.jdt.debug.javaLineBreakpoint"</code>). */
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java index d174ec0..01bca70 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java
@@ -8,8 +8,7 @@ import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IThread; import org.eclipse.debug.core.model.IVariable; -import org.eclipse.core.resources.IMarker; -import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.internal.debug.core.JavaBreakpoint; /** * A Java thread is an extension of a regular thread, @@ -54,7 +53,7 @@ * * @return breakpoint that caused suspend, or <code>null</code> if none */ - IMarker getBreakpoint(); + JavaBreakpoint getBreakpoint(); /** * Returns a variable with the given name, or <code>null</code> if
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java index 3771588..7b3e2e3 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java
@@ -134,303 +134,25 @@ * to a lower level exception. */ public static IMarker createLineBreakpoint(IType type, int lineNumber, int charStart, int charEnd, int hitCount) throws DebugException { - return createLineBreakpointCommon(type, lineNumber, charStart, charEnd, hitCount, IJavaDebugConstants.JAVA_LINE_BREAKPOINT); - } - - /** - * Creates and returns a run-to-line breakpoint in the - * given type, at the given line number. If a character range within the - * line is known, it may be specified by charStart/charEnd. Run-to-line - * breakpoints have a hit count of 1. - * Note: the breakpoint is not added to the breakpoint manager - * - it is merely created. - * - * @param type the type in which to create the breakpoint - * @param lineNumber the lineNumber on which the breakpoint is created - line - * numbers are 1 based, associated with the compilation unit in which - * the type is defined - * @param charStart the first character index associated with the breakpoint, - * or -1 if unspecified - * @param charEnd the last character index associated with the breakpoint, - * or -1 if unspecified - * @return a run-to-line breakpoint - * @exception DebugException if unable to create the breakpoint marker due - * to a lower level exception. - */ - public static IMarker createRunToLineBreakpoint(IType type, int lineNumber, int charStart, int charEnd) throws DebugException { - return createLineBreakpointCommon(type, lineNumber, charStart, charEnd, 1, IJavaDebugConstants.JAVA_RUN_TO_LINE_BREAKPOINT); - } - - /** - * Common method for creating line breakpoints, either 'regular' or 'run to line' - */ - private static IMarker createLineBreakpointCommon(final IType type, final int lineNumber, final int charStart, final int charEnd, final int hitCount, final String exceptionType) throws DebugException { - - fgBreakpoint= null; - - IWorkspaceRunnable wr= new IWorkspaceRunnable() { - - public void run(IProgressMonitor monitor) throws CoreException { - IResource resource= null; - resource= type.getUnderlyingResource(); - if (resource == null) { - resource= type.getJavaProject().getProject(); - } - - // create the marker - fgBreakpoint= resource.createMarker(exceptionType); - DebugPlugin.getDefault().getBreakpointManager().configureLineBreakpoint(fgBreakpoint, getPluginIdentifier(), true, lineNumber, charStart, charEnd); - - // configure the hit count and type handle - DebugJavaUtils.setTypeAndHitCount(fgBreakpoint, type, hitCount); - - // configure the marker as a Java marker - Map attributes= fgBreakpoint.getAttributes(); - JavaCore.addJavaElementMarkerAttributes(attributes, type); - fgBreakpoint.setAttributes(attributes); - } - }; - - try { - ResourcesPlugin.getWorkspace().run(wr, null); - } catch (CoreException e) { - throw new DebugException(e.getStatus()); - } - - return fgBreakpoint; - } - - /** - * Creates and returns an exception breakpoint for the - * given (throwable) type. Caught and uncaught specify where the exception - * should cause thread suspensions - that is, in caught and/or uncaught locations. - * Checked indicates if the given exception is a checked exception. - * Note: the breakpoint is not added to the breakpoint manager - * - it is merely created. - * - * @param type the exception for which to create the breakpoint - * @param caught whether to suspend in caught locations - * @param uncaught whether to suspend in uncaught locations - * @param checked whether the exception is a checked exception - * @return an exception breakpoint - * @exception DebugException if unable to create the breakpoint marker due - * to a lower level exception. - */ - public static IMarker createExceptionBreakpoint(final IType exception, final boolean caught, final boolean uncaught, final boolean checked) throws DebugException { - // determine the resource to associate the marker with - - fgBreakpoint= null; - - IWorkspaceRunnable wr= new IWorkspaceRunnable() { - - public void run(IProgressMonitor monitor) throws CoreException { - IResource resource= null; - resource= exception.getUnderlyingResource(); - - if (resource == null) { - resource= exception.getJavaProject().getProject(); - } - - // if the exception breakpoint already exists in the breakpoint mgr., - // just use it - IMarker existing= findExistingExceptionBreakpoint(exception); - if (existing != null) { - fgBreakpoint= existing; - return; - } - - // create the marker - fgBreakpoint= resource.createMarker(IJavaDebugConstants.JAVA_EXCEPTION_BREAKPOINT); - // configure the standard attributes - DebugPlugin.getDefault().getBreakpointManager().configureBreakpoint(fgBreakpoint, getPluginIdentifier(), true); - // configure caught, uncaught, checked, and the type attributes - DebugJavaUtils.configureExceptionBreakpoint(fgBreakpoint, caught, uncaught, checked, exception); - - // configure the marker as a Java marker - Map attributes= fgBreakpoint.getAttributes(); - JavaCore.addJavaElementMarkerAttributes(attributes, exception); - fgBreakpoint.setAttributes(attributes); - } - - }; - - try { - ResourcesPlugin.getWorkspace().run(wr, null); - } catch (CoreException e) { - throw new DebugException(e.getStatus()); - } - - return fgBreakpoint; + return (new LineBreakpoint(type, lineNumber, charStart, charEnd, hitCount, IJavaDebugConstants.JAVA_LINE_BREAKPOINT)).getMarker(); } - private static IMarker findExistingExceptionBreakpoint(IType type) { - IBreakpointManager manager= DebugPlugin.getDefault().getBreakpointManager(); - IMarker[] allBreakpoints= manager.getBreakpoints(IJavaDebugConstants.JAVA_EXCEPTION_BREAKPOINT); - for (int i = 0; i < allBreakpoints.length; i++) { - IMarker bp= allBreakpoints[i]; - if (DebugJavaUtils.getType(bp).equals(type)) { - return bp; - } - } - return null; + public static IBreakpointManager getBreakpointManager() { + return DebugPlugin.getDefault().getBreakpointManager(); } /** - * Creates and returns a watchpoint on the - * given field. - * If hitCount > 0, the breakpoint will suspend execution when it is - * "hit" the specified number of times. Note: the breakpoint is not - * added to the breakpoint manager - it is merely created. - * - * @param field the field on which to suspend (on access or modification) - * @param hitCount the number of times the breakpoint will be hit before - * suspending execution - 0 if it should always suspend - * @return a watchpoint - * @exception DebugException if unable to create the breakpoint marker due - * to a lower level exception - */ - public static IMarker createWatchpoint(final IField field, final int hitCount) throws DebugException { - - fgBreakpoint= null; - - IWorkspaceRunnable wr= new IWorkspaceRunnable() { - - public void run(IProgressMonitor monitor) throws CoreException { - - IResource resource = null; - ICompilationUnit compilationUnit = getCompilationUnit(field); - if (compilationUnit != null) { - resource = compilationUnit.getUnderlyingResource(); - } - if (resource == null) { - resource = field.getJavaProject().getProject(); - } - - fgBreakpoint= resource.createMarker(IJavaDebugConstants.JAVA_WATCHPOINT); - - // find the source range if available - int start = -1; - int stop = -1; - ISourceRange range = field.getSourceRange(); - if (range != null) { - start = range.getOffset(); - stop = start + range.getLength() - 1; - } - // configure the standard attributes - DebugPlugin.getDefault().getBreakpointManager().configureLineBreakpoint(fgBreakpoint, getPluginIdentifier(), true, -1, start, stop); - // configure the type handle and hit count - DebugJavaUtils.setTypeAndHitCount(fgBreakpoint, field.getDeclaringType(), hitCount); - // configure the field handle - DebugJavaUtils.setField(fgBreakpoint, field); - // configure the access and modification flags to defaults - DebugJavaUtils.setDefaultAccessAndModification(fgBreakpoint); - DebugJavaUtils.setAutoDisabled(fgBreakpoint, false); - - - // configure the marker as a Java marker - Map attributes= fgBreakpoint.getAttributes(); - JavaCore.addJavaElementMarkerAttributes(attributes, field); - fgBreakpoint.setAttributes(attributes); - } - }; - - try { - ResourcesPlugin.getWorkspace().run(wr, null); - } catch (CoreException e) { - throw new DebugException(e.getStatus()); - } - - return fgBreakpoint; - } - - /** - * Returns the underlying compilation unit of an element. - */ - public static ICompilationUnit getCompilationUnit(IJavaElement element) { - if (element instanceof IWorkingCopy) { - return (ICompilationUnit) ((IWorkingCopy) element).getOriginalElement(); - } - if (element instanceof ICompilationUnit) { - return (ICompilationUnit) element; - } - IJavaElement parent = element.getParent(); - if (parent != null) { - return getCompilationUnit(parent); - } - return null; - } - - /** - * Creates and returns a method entry breakpoint in the - * given method. - * If hitCount is > 0, the breakpoint will suspend execution when it is - * "hit" the specified number of times. Note: the breakpoint is not - * added to the breakpoint manager - it is merely created. - * - * @param method the method in which to suspend on entry - * @param hitCount the number of times the breakpoint will be hit before - * suspending execution - 0 if it should always suspend - * @return a method entry breakpoint - * @exception DebugException if unable to create the breakpoint marker due - * to a lower level exception. - */ - public static IMarker createMethodEntryBreakpoint(final IMethod method, final int hitCount) throws DebugException { - // determine the resource to associate the marker with - - fgBreakpoint= null; - - IWorkspaceRunnable wr= new IWorkspaceRunnable() { - - public void run(IProgressMonitor monitor) throws CoreException { - IResource resource= null; - resource= method.getUnderlyingResource(); - if (resource == null) { - resource= method.getJavaProject().getProject(); - } - - // create the marker - fgBreakpoint= resource.createMarker(IJavaDebugConstants.JAVA_METHOD_ENTRY_BREAKPOINT); - - // find the source range if available - int start = -1; - int end = -1; - ISourceRange range = method.getSourceRange(); - if (range != null) { - start = range.getOffset(); - end = start + range.getLength() - 1; - } - // configure the standard attributes - DebugPlugin.getDefault().getBreakpointManager().configureLineBreakpoint(fgBreakpoint, getPluginIdentifier(), true, -1, start, end); - // configure the type handle and hit count - DebugJavaUtils.setTypeAndHitCount(fgBreakpoint, method.getDeclaringType(), hitCount); - - // configure the method handle - DebugJavaUtils.setMethod(fgBreakpoint, method); - - // configure the marker as a Java marker - Map attributes= fgBreakpoint.getAttributes(); - JavaCore.addJavaElementMarkerAttributes(attributes, method); - fgBreakpoint.setAttributes(attributes); - } - - }; - - try { - ResourcesPlugin.getWorkspace().run(wr, null); - } catch (CoreException e) { - throw new DebugException(e.getStatus()); - } - - return fgBreakpoint; - } - /** * Returns the hit count of the given breakpoint or -1 if the attribute is not set. * * @param breakpoint the breakpoint * @return hit count, or -1 */ - public static int getHitCount(IMarker breakpoint) { - return DebugJavaUtils.getHitCount(breakpoint); + public static int getHitCount(IMarker marker) { + JavaBreakpoint breakpoint= getBreakpoint(marker); + if (breakpoint instanceof LineBreakpoint) { + return ((LineBreakpoint)breakpoint).getHitCount(); + } + return -1; } /** @@ -440,54 +162,14 @@ * @param hitCount the number of times the breakpoint is hit before suspending execution * @exception CoreException if an exception occurrs updating the marker */ - public static void setHitCount(IMarker breakpoint, int hitCount) throws CoreException { - DebugJavaUtils.setHitCount(breakpoint, hitCount); - } - - /** - * Returns the member the given breakpoint is installed in, - * or <code>null</code> if a member is not determinable. - * - * @param breakpoint the breakpoint - * @return a member, or <code>null</code> - */ - public static IMember getMember(IMarker breakpoint) { - try { - return DebugJavaUtils.getMember(breakpoint); - } catch (CoreException e) { - return null; + public static void setHitCount(IMarker marker, int hitCount) throws CoreException { + JavaBreakpoint breakpoint= getBreakpoint(marker); + if (breakpoint instanceof LineBreakpoint) { + ((LineBreakpoint) breakpoint).setHitCount(hitCount); } } - /** - * Returns the method the given breakpoint is installed in - * or <code>null</code> if breakpoint is not installed in a method. - * - * @param breakpoint the breakpoint - * @return a method, or <code>null</code> - */ - public static IMethod getMethod(IMarker breakpoint) { - return DebugJavaUtils.getMethod(breakpoint); - } /** - * Returns the field handle identifier of the given breakpoint - */ - public static String getFieldHandleIdentifier(IMarker breakpoint) { - return DebugJavaUtils.getFieldHandleIdentifier(breakpoint); - } - - /** - * Returns the field the given breakpoint is installed on - * or <code>null</code> if breakpoint is not installed in a method. - * - * @param breakpoint the breakpoint - * @return a field or <code>null</code> - */ - public static IField getField(IMarker breakpoint) { - return DebugJavaUtils.getField(breakpoint); - } - - /** * Returns the type the given breakpoint is installed in * or <code>null</code> if breakpoint is not installed in a type. If * the breakpoint is an exception breakpoint, the type associated with @@ -497,118 +179,27 @@ * @param breakpoint the breakpoint * @return a type, or <code>nulll</code> */ - public static IType getType(IMarker breakpoint) { - return DebugJavaUtils.getType(breakpoint); + public static IType getType(IMarker marker) { + JavaBreakpoint breakpoint= getBreakpoint(marker); + if (breakpoint != null) { + return breakpoint.getBreakpointType(); + } + return null; } + /** - * Returns whether the given breakpoint is an exception - * breakpoint that will suspend in caught locations. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint is an exception - * breakpoint that will suspend in caught locations + * Returns the JavaBreakpoint in the breakpoint manager associated + * with the given marker. If no such breakpoint exists, returns + * <code>null</code>. */ - public static boolean isCaught(IMarker breakpoint) { - return DebugJavaUtils.isCaught(breakpoint); + private static JavaBreakpoint getBreakpoint(IMarker marker) { + IBreakpoint breakpoint= getBreakpointManager().getBreakpoint(marker); + if (breakpoint instanceof JavaBreakpoint) { + return (JavaBreakpoint) breakpoint; + } + return null; } - /** - * Returns whether the given breakpoint is an exception - * breakpoint for a checked exception. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint is an exception - * breakpoint for a checked exception - */ - public static boolean isChecked(IMarker breakpoint) { - return DebugJavaUtils.isChecked(breakpoint); - } - /** - * Returns whether the given breakpoint - * is an exception breakpoint. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint - * is an exception breakpoint - */ - public static boolean isExceptionBreakpoint(IMarker breakpoint) { - return DebugJavaUtils.isExceptionBreakpoint(breakpoint); - } - /** - * Returns whether the given breakpoint is installed in at least one debug target. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint is installed in at least one debug target - */ - public static boolean isInstalled(IMarker breakpoint) { - return DebugJavaUtils.isInstalled(breakpoint); - } - - /** - * Returns whether the given breakpoint is a watchpoint. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint is a watchpoint - */ - public static boolean isWatchpoint(IMarker breakpoint) { - return DebugJavaUtils.isWatchpoint(breakpoint); - } - - /** - * Returns whether the given breakpoint - * is an access watchpoint. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint - * is an access watchpoint - */ - public static boolean isAccess(IMarker breakpoint) { - return DebugJavaUtils.isAccess(breakpoint); - } - - /** - * Returns whether the given breakpoint - * is an modificaion watchpoint. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint - * is an modification watchpoint - */ - public static boolean isModification(IMarker breakpoint) { - return DebugJavaUtils.isModification(breakpoint); - } - - public static boolean isAutoDisabled(IMarker breakpoint) { - return DebugJavaUtils.isAutoDisabled(breakpoint); - } - /** - * Returns whether the given breakpoint is a method entry breakpoint. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint is a method entry breakpoint - */ - public static boolean isMethodEntryBreakpoint(IMarker breakpoint) { - return DebugJavaUtils.isMethodEntryBreakpoint(breakpoint); - } - /** - * Returns whether the given breakpoint is a run to line breakpoint. - * - * @param breakpoint the breakpoint - * @retrun whether the given breakpoint is a run to line breakpoint - */ - public static boolean isRunToLineBreakpoint(IMarker breakpoint) { - return DebugJavaUtils.isRunToLineBreakpoint(breakpoint); - } - /** - * Returns whether the given breakpoint is an exception - * breakpoint that will suspend in uncaught locations. - * - * @param breakpoint the breakpoint - * @return whether the given breakpoint is an exception - * breakpoint that will suspend in uncaught locations - */ - public static boolean isUncaught(IMarker breakpoint) { - return DebugJavaUtils.isUncaught(breakpoint); - } + }
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaResources.properties b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaResources.properties index 5bf68e7..d98730d 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaResources.properties +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaResources.properties
@@ -12,6 +12,25 @@ jdi.common.couldnt_set_breakpoint=Breakpoint could not be set at or near line number {0} ############################################################## +# Breakpoint / Marker +############################################################## +jdi_marker.label.line=line: +jdi_marker.label.hitCount=hit count: + +jdi_marker.label.exception.format={1}: {0} +jdi_marker.label.exception.caught=caught +jdi_marker.label.exception.uncaught=uncaught +jdi_marker.label.exception.both=caught and uncaught + +jdi_marker.label.watchpoint.format={1}: {0} +jdi_marker.label.watchpoint.access=access +jdi_marker.label.watchpoint.modification=modification +jdi_marker.label.watchpoint.both=access and modification + +jdi_breakpoint.error.access_watchpoint.not_supported=VM does not support access watchpoints. +jdi_breakpoint.error.modification_watchpoint.not_supported=VM does not support modification watchpoints. + +############################################################## # JDIDebugTarget ############################################################## @@ -26,8 +45,6 @@ jdi_debug_target.error.resume.not_supported=VM does not support resume. jdi_debug_target.error.suspend.not_supported=VM does not support suspend. jdi_debug_target.error.terminate.not_supported=VM does not support termination. -jdi_debug_target.error.access_watchpoint.not_supported=VM does not support access watchpoints. -jdi_debug_target.error.modification_watchpoint.not_supported=VM does not support modification watchpoints. jdi_debug_target.error.terminate.exception=Exception occurred while terminating VM. jdi_debug_target.error.get_crc=Exception occurred retrieving CRC @@ -76,6 +93,18 @@ jdi_thread.error.no_built_state=Project must be built to perform evaluations jdi_thread.error.invalid_evaluation_location=Unable to perform evaluation at current location. Thread must be suspended by a breakpoint or step. +jdi_thread.label.exception_sys=System Thread [{0}] (Suspended (exception {1})) +jdi_thread.label.exception_usr=Thread [{0}] (Suspended (exception {1})) +jdi_thread.label.line_breakpoint_sys=System Thread [{0}] (Suspended (breakpoint at line {1} in {2})) +jdi_thread.label.line_breakpoint_usr=Thread [{0}] (Suspended (breakpoint at line {1} in {2})) +jdi_thread.label.run_to_line_breakpoint_usr=Thread [{0}] (Suspended (run to line line {1} in {2})) +jdi_thread.label.run_to_line_breakpoint_sys=System Thread [{0}] (Suspended (run to line line {1} in {2})) +jdi_thread.label.access_sys=System Thread [{0}] (Suspended (access of field {1} in {2})) +jdi_thread.label.access_usr=Thread [{0}] (Suspended (access of field {1} in {2})) +jdi_thread.label.modification_sys=System Thread [{0}] (Suspended (modification of field {1} in {2})) +jdi_thread.label.modification_usr=Thread [{0}] (Suspended (modification of field {1} in {2})) +jdi_thread.label.run_to_line_sys=System Thread [{0}] (Suspended (run to line {1} in {2})) +jdi_thread.label.run_to_line_usr=Thread [{0}] (Suspended (run to line {1} in {2})) ############################################################## # JDIStackFrame
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaUtils.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaUtils.java index 102f95b..0dae17f 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaUtils.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/DebugJavaUtils.java Binary files differ
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java index 4af40a4..064469e 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java
@@ -10,9 +10,26 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.IDebugConstants; + import com.sun.jdi.ThreadReference; import com.sun.jdi.VMDisconnectedException; -import com.sun.jdi.event.*; +import com.sun.jdi.event.BreakpointEvent; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventIterator; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.ExceptionEvent; +import com.sun.jdi.event.LocatableEvent; +import com.sun.jdi.event.MethodEntryEvent; +import com.sun.jdi.event.StepEvent; +import com.sun.jdi.event.ThreadDeathEvent; +import com.sun.jdi.event.ThreadStartEvent; +import com.sun.jdi.event.VMDeathEvent; +import com.sun.jdi.event.VMDisconnectEvent; +import com.sun.jdi.event.VMStartEvent; +import com.sun.jdi.event.WatchpointEvent; /** * Dispatches events generated by a debuggable VM. @@ -61,71 +78,45 @@ if (event instanceof StepEvent) { dispatchStepEvent((StepEvent)event); } else - if (event instanceof BreakpointEvent) { - dispatchLocatableEvent((LocatableEvent) event); + if ((event instanceof BreakpointEvent) || + (event instanceof LocatableEvent) || + (event instanceof ExceptionEvent) || + (event instanceof WatchpointEvent) || + (event instanceof MethodEntryEvent)) { + dispatchBreakpointEvent(event); } else - if (event instanceof ExceptionEvent) { - dispatchExceptionEvent((ExceptionEvent) event); + if (event instanceof ThreadStartEvent) { + fTarget.handleThreadStart((ThreadStartEvent) event); } else - if (event instanceof ThreadStartEvent) { - fTarget.handleThreadStart((ThreadStartEvent) event); + if (event instanceof ThreadDeathEvent) { + fTarget.handleThreadDeath((ThreadDeathEvent) event); } else - if (event instanceof ThreadDeathEvent) { - fTarget.handleThreadDeath((ThreadDeathEvent) event); + if (event instanceof ClassPrepareEvent) { + fTarget.handleClassLoad((ClassPrepareEvent) event); } else - if (event instanceof ClassPrepareEvent) { - fTarget.handleClassLoad((ClassPrepareEvent) event); + if (event instanceof VMDeathEvent) { + fTarget.handleVMDeath((VMDeathEvent) event); + fKeepReading= false; // stop listening for events } else - if (event instanceof WatchpointEvent) { - dispatchLocatableEvent((LocatableEvent) event); - } else - if (event instanceof MethodEntryEvent) { - fTarget.handleMethodEntry((MethodEntryEvent) event); - } else - if (event instanceof VMDeathEvent) { - fTarget.handleVMDeath((VMDeathEvent) event); - fKeepReading= false; // stop listening for events - } else - if (event instanceof VMDisconnectEvent) { - fTarget.handleVMDisconnect((VMDisconnectEvent) event); - fKeepReading= false; // stop listening for events - } else if (event instanceof VMStartEvent) { - fTarget.handleVMStart((VMStartEvent)event); - } else { - // Unknown Event Type - } + if (event instanceof VMDisconnectEvent) { + fTarget.handleVMDisconnect((VMDisconnectEvent) event); + fKeepReading= false; // stop listening for events + } else if (event instanceof VMStartEvent) { + fTarget.handleVMStart((VMStartEvent)event); + } else { + // Unknown Event Type + } } } - - protected void dispatchLocatableEvent(LocatableEvent event) { + + protected void dispatchBreakpointEvent(Event event) { if (!fKeepReading) { return; } - ThreadReference threadRef= event.thread(); - JDIThread thread= findThread(threadRef); - if (thread == null) { - fTarget.resume(threadRef); - return; - } else { - thread.handleLocatableEvent(event); - } + JavaBreakpoint breakpoint= (JavaBreakpoint)event.request().getProperty(IDebugConstants.BREAKPOINT); + breakpoint.handleEvent(event, fTarget); } - protected void dispatchExceptionEvent(ExceptionEvent event) { - if (!fKeepReading) { - return; - } - ThreadReference threadRef= event.thread(); - JDIThread thread= findThread(threadRef); - if (thread == null) { - fTarget.resume(threadRef); - return; - } else { - thread.handleException((ExceptionEvent) event); - } - } - - protected void dispatchStepEvent(StepEvent event) { ThreadReference threadRef= event.thread(); JDIThread thread= findThread(threadRef);
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/ExceptionBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/ExceptionBreakpoint.java new file mode 100644 index 0000000..b8aa7ad --- /dev/null +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/ExceptionBreakpoint.java
@@ -0,0 +1,368 @@ +package org.eclipse.jdt.internal.debug.core; + +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.IDebugConstants; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.debug.core.IJavaDebugConstants; + +import com.sun.jdi.*; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.ExceptionEvent; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.ExceptionRequest; + +public class ExceptionBreakpoint extends JavaBreakpoint { + + // Thread label String keys + private static final String EXCEPTION_SYS= THREAD_LABEL + "exception_sys"; + private static final String EXCEPTION_USR= THREAD_LABEL + "exception_usr"; + // Marker label String keys + protected final static String EXCEPTION= MARKER_LABEL + "exception."; + protected final static String FORMAT= EXCEPTION + "format"; + protected final static String CAUGHT= EXCEPTION + "caught"; + protected final static String UNCAUGHT= EXCEPTION + "uncaught"; + protected final static String BOTH= EXCEPTION + "both"; + // Attribute strings + protected static final String[] fgExceptionBreakpointAttributes= new String[]{IJavaDebugConstants.CHECKED, IJavaDebugConstants.TYPE_HANDLE}; + + static String fMarkerType= IJavaDebugConstants.JAVA_EXCEPTION_BREAKPOINT; + + public ExceptionBreakpoint(IMarker marker) { + super(marker); + } + + /** + * Creates and returns an exception breakpoint for the + * given (throwable) type. Caught and uncaught specify where the exception + * should cause thread suspensions - that is, in caught and/or uncaught locations. + * Checked indicates if the given exception is a checked exception. + * Note: the breakpoint is not added to the breakpoint manager + * - it is merely created. + * + * @param type the exception for which to create the breakpoint + * @param caught whether to suspend in caught locations + * @param uncaught whether to suspend in uncaught locations + * @param checked whether the exception is a checked exception + * @return an exception breakpoint + * @exception DebugException if unable to create the breakpoint marker due + * to a lower level exception. + */ + public ExceptionBreakpoint(final IType exception, final boolean caught, final boolean uncaught, final boolean checked) throws DebugException { + IWorkspaceRunnable wr= new IWorkspaceRunnable() { + + public void run(IProgressMonitor monitor) throws CoreException { + IResource resource= null; + resource= exception.getUnderlyingResource(); + + if (resource == null) { + resource= exception.getJavaProject().getProject(); + } + + // create the marker + fMarker= resource.createMarker(fMarkerType); + // configure the standard attributes + configure(getPluginIdentifier(), true); + // configure caught, uncaught, checked, and the type attributes + setDefaultCaughtAndUncaught(); + configureExceptionBreakpoint(checked, exception); + + // configure the marker as a Java marker + Map attributes= getAttributes(); + JavaCore.addJavaElementMarkerAttributes(attributes, exception); + setAttributes(attributes); + } + + }; + run(wr); + } + + /** + * Sets the <code>CAUGHT</code>, <code>UNCAUGHT</code>, <code>CHECKED</code> and + * <code>TYPE_HANDLE</code> attributes of the given exception breakpoint. + */ + public void configureExceptionBreakpoint(boolean checked, IType exception) throws CoreException { + String handle = exception.getHandleIdentifier(); + Object[] values= new Object[]{new Boolean(checked), handle}; + setAttributes(fgExceptionBreakpointAttributes, values); + } + + public void setDefaultCaughtAndUncaught() { + Object[] values= new Object[]{Boolean.TRUE, Boolean.TRUE}; + String[] attributes= new String[]{IJavaDebugConstants.CAUGHT, IJavaDebugConstants.UNCAUGHT}; + try { + setAttributes(attributes, values); + } catch (CoreException ce) { + logError(ce); + } + } + + /** + * @see JavaBreakpoint#installIn(JDIDebugTarget) + */ + public void addToTarget(JDIDebugTarget target) { + fTarget= target; + changeForTarget(target); + } + + /** + * An exception breakpoint has changed + */ + public void changeForTarget(JDIDebugTarget target) { + + boolean caught= isCaught(); + boolean uncaught= isUncaught(); + + if (caught || uncaught) { + IType exceptionType = getBreakpointType(); + if (exceptionType == null) { +// internalError(ERROR_BREAKPOINT_NO_TYPE); + return; + } + String exceptionName = exceptionType.getFullyQualifiedName(); + String topLevelName = getTopLevelTypeName(); + if (topLevelName == null) { +// internalError(ERROR_BREAKPOINT_NO_TYPE); + return; + } + List classes= target.jdiClassesByName(exceptionName); + ReferenceType exClass= null; + if (classes != null && !classes.isEmpty()) { + exClass= (ReferenceType) classes.get(0); + } + if (exClass == null) { + // defer the exception + target.defer(this, topLevelName); + } else { + // new or changed - first delete the old request + if (null != target.getRequest(this)) + removeFromTarget(target); + ExceptionRequest request= null; + try { + request= target.getEventRequestManager().createExceptionRequest(exClass, caught, uncaught); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.putProperty(IDebugConstants.BREAKPOINT, this); + } catch (VMDisconnectedException e) { + return; + } catch (RuntimeException e) { + logError(e); + return; + } + request.setEnabled(isEnabled()); + target.installBreakpoint(this, request); + } + } else { + removeFromTarget(target); + } + } + + /** + * An exception breakpoint has been removed + */ + public void removeFromTarget(JDIDebugTarget target) { + IType type = getBreakpointType(); + if (type == null) { +// internalError(ERROR_BREAKPOINT_NO_TYPE); + return; + } + String name = type.getFullyQualifiedName(); + ExceptionRequest request= (ExceptionRequest) target.uninstallBreakpoint(this); + if (request != null) { + try { + target.getEventRequestManager().deleteEventRequest(request); + } catch (VMDisconnectedException e) { + return; + } catch (RuntimeException e) { + logError(e); + return; + } + } + List deferred = target.getDeferredBreakpointsByClass(name); + if (deferred != null) { + deferred.remove(this); + if (deferred.isEmpty()) { + target.removeDeferredBreakpointByClass(name); + } + } + } + + /** + * @see JavaBreakpoint#handleEvent(Event) + */ + public void handleEvent(Event event, JDIDebugTarget target){ + if (!(event instanceof ExceptionEvent)) { + return; + } + ThreadReference threadRef= ((ExceptionEvent)event).thread(); + JDIThread thread= target.findThread(threadRef); + if (thread == null) { + target.resume(threadRef); + return; + } else { + thread.handleSuspendForBreakpoint(this); + } + } + + /** + * @see JavaBreakpoint#isSupportedBy(VirtualMachine) + */ + public boolean isSupportedBy(VirtualMachine vm) { + return true; + } + + /** + * Enable this exception breakpoint. + * + * If the exception breakpoint is not catching caught or uncaught, + * set the default values. If this isn't done, the resulting + * state (enabled with caught and uncaught both disabled) + * is ambiguous. + */ + public void enable() { + if (!(isCaught() || isUncaught())) { + setDefaultCaughtAndUncaught(); + } + super.enable(); + } + + /** + * Toggle the caught state of this breakpoint + */ + public void toggleCaught() throws CoreException { + setCaught(!isCaught()); + } + + /** + * Returns the <code>CAUGHT</code> attribute of the given breakpoint + * or <code>false</code> if the attribute is not set. + */ + public boolean isCaught() { + return getBooleanAttribute(IJavaDebugConstants.CAUGHT); + } + + /** + * Sets the <code>CAUGHT</code> attribute of the given breakpoint. + */ + public void setCaught(boolean caught) throws CoreException { + if (caught == isCaught()) { + return; + } + try { + setBooleanAttribute(IJavaDebugConstants.CAUGHT, caught); + if (caught && !isEnabled()) { + enable(); + } else if (!(caught || isUncaught())) { + disable(); + } + } catch (CoreException ce) { + logError(ce); + } + if (fTarget != null) { + // Notify the target that this watchpoint has changed + changeForTarget(fTarget); + } + } + + /** + * Toggle the caught state of this breakpoint + */ + public void toggleUncaught() throws CoreException { + setUncaught(!isUncaught()); + } + + /** + * Returns the <code>UNCAUGHT</code> attribute of the given breakpoint + * or <code>false</code> if the attribute is not set. + */ + public boolean isUncaught() { + return getBooleanAttribute(IJavaDebugConstants.UNCAUGHT); + } + + /** + * Sets the <code>UNCAUGHT</code> attribute of the given breakpoint. + */ + public void setUncaught(boolean uncaught) throws CoreException { + + if (uncaught == isUncaught()) { + return; + } + try { + setBooleanAttribute(IJavaDebugConstants.UNCAUGHT, uncaught); + if (uncaught && !isEnabled()) { + enable(); + } else if (!(uncaught || isCaught())) { + disable(); + } + } catch (CoreException ce) { + logError(ce); + } + if (fTarget != null) { + // Notify the target that this watchpoint has changed + changeForTarget(fTarget); + } + } + + /** + * Returns whether the given breakpoint represents a checked exception. + */ + public boolean isChecked() { + return getBooleanAttribute(IJavaDebugConstants.CHECKED); + } + + /** + * Sets the <code>CHECKED</code> attribute of the given breakpoint. + */ + public void setChecked(boolean checked) throws CoreException { + setBooleanAttribute(IJavaDebugConstants.CHECKED, checked); + } + + /** + * @see JavaBreakpoint + */ + public String getFormattedThreadText(String threadName, String typeName, boolean systemThread) { + if (systemThread) { + return getFormattedString(EXCEPTION_SYS, new String[] {threadName, typeName}); + } + return getFormattedString(EXCEPTION_USR, new String[] {threadName, typeName}); + } + + /** + */ + public String getMarkerText(boolean showQualified) { + String name; + if (showQualified) { + name= getBreakpointType().getFullyQualifiedName(); + } else { + name= getBreakpointType().getElementName(); + } + + String state= null; + boolean c= isCaught(); + boolean u= isUncaught(); + if (c && u) { + state= BOTH; + } else if (c) { + state= CAUGHT; + } else if (u) { + state= UNCAUGHT; + } + String label= null; + if (state == null) { + label= name; + } else { + String format= DebugJavaUtils.getResourceString(FORMAT); + state= DebugJavaUtils.getResourceString(state); + label= MessageFormat.format(format, new Object[] {state, name}); + } + return label; + } + +} +
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java index 7517235..f16e0c9 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java
@@ -5,14 +5,10 @@ * All Rights Reserved. */ -import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.IDebugConstants; -import org.eclipse.debug.core.ILaunchManager; -import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPluginDescriptor; -import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.*; +import org.eclipse.debug.core.*; +import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.jdt.debug.core.IJavaDebugConstants; /** @@ -44,24 +40,26 @@ public void startup() throws CoreException { fJavaHCRMgr= new JavaHotCodeReplaceManager(); - fJavaHCRMgr.startup(); + fJavaHCRMgr.startup(); - IMarker[] breakpoints= null; + IMarker[] markers= null; IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot(); try { - breakpoints= root.findMarkers(IJavaDebugConstants.JAVA_LINE_BREAKPOINT, true, IResource.DEPTH_INFINITE); + markers= root.findMarkers(IJavaDebugConstants.JAVA_LINE_BREAKPOINT, true, IResource.DEPTH_INFINITE); } catch (CoreException e) { DebugJavaUtils.logError(e); return; } - - if (breakpoints == null) { + if (markers == null) { return; } - - for (int i = 0; i < breakpoints.length; i++) { - IMarker breakpoint = breakpoints[i]; - DebugJavaUtils.configureBreakpointAtStartup(breakpoint); + + IBreakpointManager manager= DebugPlugin.getDefault().getBreakpointManager(); + for (int i= 0; i < markers.length; i++) { + JavaBreakpoint breakpoint= (JavaBreakpoint)manager.loadMarker(markers[i]); + if (breakpoint != null) { + breakpoint.configureBreakpointAtStartup(); + } } }
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugTarget.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugTarget.java index 9e4fab3..9b1ad20 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugTarget.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugTarget.java
@@ -5,21 +5,20 @@ * All Rights Reserved. */ -import com.sun.jdi.*; +import java.io.ByteArrayInputStream; +import java.util.*; + import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.debug.core.*; import org.eclipse.debug.core.model.*; import org.eclipse.jdt.core.*; import org.eclipse.jdt.core.eval.IEvaluationContext; -import org.eclipse.jdt.debug.core.IJavaDebugConstants; -import org.eclipse.jdt.debug.core.IJavaDebugTarget; -import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.debug.core.*; + +import com.sun.jdi.*; import com.sun.jdi.event.*; import com.sun.jdi.request.*; -import java.io.ByteArrayInputStream; -import java.text.MessageFormat; -import java.util.*; /** * Debug target for JDI debug model. @@ -41,25 +40,12 @@ private final static String ERROR_RESUME_NOT_SUPPORTED = ERROR + "resume.not_supported"; private final static String ERROR_SUSPEND_NOT_SUPPORTED = ERROR + "suspend.not_supported"; private final static String ERROR_TERMINATE_NOT_SUPPORTED = ERROR + "terminate.not_supported"; - private final static String ERROR_ACCESS_WATCHPOINT_NOT_SUPPORTED = ERROR + "access.not_supported"; - private final static String ERROR_MODIFICATION_WATCHPOINT_NOT_SUPPORTED = ERROR + "modification.net_supported"; private final static String ERROR_TERMINATE = ERROR + "terminate.exception"; private static final String ERROR_GET_CRC= ERROR + "get_crc"; private static final int MAX_THREAD_DEATH_ATTEMPTS = 1; /** - * Key used to store the class name attribute pertinent to a - * specific method entry request. Used for method entry breakpoints. - */ - protected final static String CLASS_NAME= "className"; - /** - * Key used to store the name and signature - * attribute pertinent to a specific method - * entry request breakpoint. Used for method entry breakpoints. - */ - protected final static String BREAKPOINT_INFO= "breakpointInfo"; - /** * Associated system process, or <code>null</code> if not available. */ protected IProcess fProcess; @@ -84,8 +70,8 @@ * corresponding class is not yet loaded). * <p> * Key: the fully qualified name of the class - * Value: a <code>List</code> of <code>IMarker</code>s representing the - * deferred breakpointsin that class. + * Value: a <code>List</code> of <code>JavaBreakpoint</code>s representing the + * deferred breakpoints in that class. */ protected Map fDeferredBreakpointsByClass; /** @@ -98,9 +84,8 @@ /** * Table of installed breakpoints * <p> - * Key: breakpoint (<code>IMarker</code>) - * Value: the event request associated with the breakpoint (one - * of <code>BreakpointRequest</code> or <code>MethodEntryRequest</code>). + * Key: breakpoint (<code>JavaBreakpoint</code>) + * Value: the event request associated with the breakpoint (<code>Object</code>). */ protected HashMap fInstalledBreakpoints; @@ -263,9 +248,11 @@ * Installs all breakpoints that currently exist in the breakpoint manager */ protected void initializeBreakpoints() { - IMarker[] bps = getBreakpointManager().getBreakpoints(JDIDebugModel.getPluginIdentifier()); + IBreakpoint[] bps = (IBreakpoint[]) getBreakpointManager().getBreakpoints(JDIDebugModel.getPluginIdentifier()); for (int i = 0; i < bps.length; i++) { - breakpointAdded(bps[i]); + if (bps[i] instanceof JavaBreakpoint) { + breakpointAdded((JavaBreakpoint)bps[i]); + } } } @@ -403,7 +390,7 @@ * @param breakpoint the breakpoint to defer * @param typeName name of the type the given breakpoint is associated with */ - protected void defer(IMarker breakpoint, String typeName) { + protected void defer(JavaBreakpoint breakpoint, String typeName) { List bps= (List) fDeferredBreakpointsByClass.get(typeName); if (bps == null) { // listen for the load of the type @@ -595,99 +582,6 @@ createThreadDeathInstance(threadRef); resume(threadRef); } - - /** - * Handles a method entry event. If this method entry event is - * in a method that a method entry breakpoint has been set for, - * handle the event as a breakpoint. - */ - protected void handleMethodEntry(MethodEntryEvent event) { - Method enteredMethod = event.method(); - MethodEntryRequest request = (MethodEntryRequest)event.request(); - List breakpoints = (List)request.getProperty(IDebugConstants.BREAKPOINT_MARKER); - Iterator requestBreakpoints= breakpoints.iterator(); - IMarker breakpoint= null; - int index= 0; - while (requestBreakpoints.hasNext()) { - IMarker aBreakpoint= (IMarker)requestBreakpoints.next(); - Object[] nameSignature= getMethodEntryBreakpointInfo(request, aBreakpoint, index); - String enteredMethodName= enteredMethod.name(); - if (nameSignature != null && nameSignature[0].equals(enteredMethodName) && - nameSignature[1].equals(enteredMethod.signature())) { - breakpoint= aBreakpoint; - break; - } - index++; - } - if (breakpoint == null) { - handleMethodEntryResume(event.thread()); - return; - } - - List counts = (List)request.getProperty(IJavaDebugConstants.HIT_COUNT); - Integer count= (Integer)counts.get(index); - if (count != null) { - handleHitCountMethodEntryBreakpoint(event, breakpoint, counts, count, index); - } else { - // no hit count - suspend - handleMethodEntryBreakpoint(event.thread(), breakpoint); - } - } - - protected void handleMethodEntryResume(ThreadReference thread) { - if (!hasPendingEvents()) { - resume(thread); - } - } - - protected void handleHitCountMethodEntryBreakpoint(MethodEntryEvent event, IMarker breakpoint, List counts, Integer count, int index) { - // decrement count and suspend if 0 - int hitCount = count.intValue(); - if (hitCount > 0) { - hitCount--; - count = new Integer(hitCount); - counts.set(index, count); - if (hitCount == 0) { - // the count has reached 0, breakpoint hit - handleMethodEntryBreakpoint(event.thread(), breakpoint); - try { - // make a note that we auto-disabled the breakpoint - // order is important here...see methodEntryChanged - DebugJavaUtils.setExpired(breakpoint, true); - getBreakpointManager().setEnabled(breakpoint, false); - } catch (CoreException e) { - internalError(e); - } - } else { - // count still > 0, keep running - handleMethodEntryResume(event.thread()); - } - } else { - // hit count expired, keep running - handleMethodEntryResume(event.thread()); - } - } - protected String[] getMethodEntryBreakpointInfo(MethodEntryRequest request, IMarker breakpoint, int index) { - List nameSignatures = (List)request.getProperty(BREAKPOINT_INFO); - if (nameSignatures.get(index) != null) { - return (String[])nameSignatures.get(index); - } - String[] nameSignature= new String[2]; - IMethod aMethod= DebugJavaUtils.getMethod(breakpoint); - try { - if (aMethod.isConstructor()) { - nameSignature[0]= "<init>"; - } else { - nameSignature[0]= aMethod.getElementName(); - } - nameSignature[1]= aMethod.getSignature(); - nameSignatures.add(index, nameSignature); - return nameSignature; - } catch (JavaModelException e) { - logError(e); - return null; - } - } /** * Resumes the given thread @@ -701,9 +595,9 @@ } } - protected void handleMethodEntryBreakpoint(ThreadReference thread, IMarker breakpoint) { + protected void handleMethodEntryBreakpoint(ThreadReference thread, JavaBreakpoint breakpoint) { JDIThread jdiThread = findThread(thread); - jdiThread.handleSuspendMethodEntry(breakpoint); + jdiThread.handleSuspendForBreakpoint(breakpoint); } /** * Handles a thread death event. @@ -742,107 +636,51 @@ terminate0(); } - /** - * Returns the top-level type name associated with the type - * the given breakpoint is associated with, or <code>null</code>. - */ - protected String getTopLevelTypeName(IMarker breakpoint) { - IType type = DebugJavaUtils.getType(breakpoint); - if (type != null) { - while (type.getDeclaringType() != null) { - type = type.getDeclaringType(); - } - return type.getFullyQualifiedName(); - } - return null; - } - + /** * Installs or defers the given breakpoint */ - public void breakpointAdded(IMarker breakpoint) { - if (DebugJavaUtils.isExceptionBreakpoint(breakpoint)) { - exceptionBreakpointAdded(breakpoint); - } else if (DebugJavaUtils.isMethodEntryBreakpoint(breakpoint)) { - methodEntryBreakpointAdded(breakpoint); - } else if (DebugJavaUtils.isWatchpoint(breakpoint)) { - watchpointAdded(breakpoint); - } else { - lineBreakpointAdded(breakpoint); - } + public void breakpointAdded(IBreakpoint breakpoint) { + breakpoint.addToTarget(this); } - protected void lineBreakpointAdded(IMarker breakpoint) { - String topLevelName= getTopLevelTypeName(breakpoint); - if (topLevelName == null) { - internalError(ERROR_BREAKPOINT_NO_TYPE); - return; - } - - // look for the top-level class - if it is loaded, inner classes may also be loaded - List classes= jdiClassesByName(topLevelName); - if (classes == null || classes.isEmpty()) { - // defer - defer(breakpoint, topLevelName); - } else { - // try to install - ReferenceType type= (ReferenceType) classes.get(0); - if (!installLineBreakpoint(breakpoint, type)) { - // install did not succeed - could be an inner type not yet loaded - defer(breakpoint, topLevelName); - } - } + /** + * Add a breakpoint to the installed breakpoints collection + */ + public void installBreakpoint(JavaBreakpoint breakpoint, Object request) { + fInstalledBreakpoints.put(breakpoint, request); } /** - * Installs a line breakpoint in the given type, returning whether successful. + * Remove a breakpoint from the installed breakpoints collection */ - protected boolean installLineBreakpoint(IMarker marker, ReferenceType type) { - Location location= null; - IBreakpointManager manager= getBreakpointManager(); - int lineNumber= manager.getLineNumber(marker); - location= determineLocation(lineNumber, type); - if (location == null) { - // could be an inner type not yet loaded, or line information not available - return false; - } - - if (createLineBreakpointRequest(location, marker) != null) { - // update the install attibute on the breakpoint - if (!fInHCR) { - try { - DebugJavaUtils.incrementInstallCount(marker); - } catch (CoreException e) { - internalError(e); - } - } - return true; - } else { - return false; - } - + public Object uninstallBreakpoint(JavaBreakpoint breakpoint) { + return fInstalledBreakpoints.remove(breakpoint); } /** - * Creates, installs, and returns a line breakpoint request at - * the given location for the given breakpoint. + * Return the request object associated with the given breakpoint */ - protected BreakpointRequest createLineBreakpointRequest(Location location, IMarker breakpoint) { - BreakpointRequest request = null; - try { - request= getEventRequestManager().createBreakpointRequest(location); - configureRequest(request, breakpoint); - } catch (VMDisconnectedException e) { - fInstalledBreakpoints.remove(breakpoint); - return null; - } catch (RuntimeException e) { - fInstalledBreakpoints.remove(breakpoint); - internalError(e); - return null; - } - request.setEnabled(getBreakpointManager().isEnabled(breakpoint)); - fInstalledBreakpoints.put(breakpoint, request); - return request; + public Object getRequest(JavaBreakpoint breakpoint) { + return fInstalledBreakpoints.get(breakpoint); + } + + /** + * Return the deferred breakpoints + */ + public List getDeferredBreakpointsByClass(String name) { + return (List)fDeferredBreakpointsByClass.get(name); + } + + /** + * Remove a deferred breakpoint + */ + public void removeDeferredBreakpointByClass(String name) { + fDeferredBreakpointsByClass.remove(name); + } + + public boolean inHCR() { + return fInHCR; } /** @@ -900,424 +738,8 @@ /** * @see IBreakpointSupport */ - public void breakpointChanged(IMarker breakpoint, IMarkerDelta delta) { - if (DebugJavaUtils.isExceptionBreakpoint(breakpoint)) { - exceptionBreakpointChanged(breakpoint); - } else if (DebugJavaUtils.isMethodEntryBreakpoint(breakpoint)) { - methodEntryBreakpointChanged(breakpoint, delta); - } else if (DebugJavaUtils.isWatchpoint(breakpoint)) { - watchpointChanged(breakpoint); - } else { - lineBreakpointChanged(breakpoint); - } - } - - protected void lineBreakpointChanged(IMarker breakpoint) { - EventRequest request= (BreakpointRequest) fInstalledBreakpoints.get(breakpoint); - if (request != null) { - // already installed - could be a change in the enabled state or hit count - //may result in a new request being generated - request= updateHitCount(request, breakpoint); - if (request != null) { - updateEnabledState(request, breakpoint); - fInstalledBreakpoints.put(breakpoint, request); - } - } - } - - protected void updateMethodEntryEnabledState(MethodEntryRequest request) { - IBreakpointManager manager= getBreakpointManager(); - Iterator breakpoints= ((List)request.getProperty(IDebugConstants.BREAKPOINT_MARKER)).iterator(); - boolean requestEnabled= false; - while (breakpoints.hasNext()) { - IMarker breakpoint= (IMarker)breakpoints.next(); - if (manager.isEnabled(breakpoint)) { - requestEnabled = true; - break; - } - } - updateEnabledState0(request, requestEnabled); - } - - protected void updateEnabledState(EventRequest request, IMarker breakpoint) { - updateEnabledState0(request, getBreakpointManager().isEnabled(breakpoint)); - - } - - private void updateEnabledState0(EventRequest request, boolean enabled) { - if (request.isEnabled() != enabled) { - // change the enabled state - try { - // if the request has expired, and is not a method entry request, do not disable. - // BreakpointRequests that have expired cannot be deleted. However method entry - // requests that are expired can be deleted (since we simulate the hit count) - if (request instanceof MethodEntryRequest || !isExpired(request)) { - request.setEnabled(enabled); - } - } catch (VMDisconnectedException e) { - } catch (RuntimeException e) { - internalError(e); - } - } - } - - /** - * Update the hit count of an <code>EventRequest</code>. Return a new request with - * the appropriate settings. - */ - protected EventRequest updateHitCount(EventRequest request, IMarker marker) { - - // if the hit count has changed, or the request has expired and is being re-enabled, - // create a new request - if (hasHitCountChanged(marker, request) || (isExpired(request) && getBreakpointManager().isEnabled(marker))) { - try { - // delete old request - //on JDK you cannot delete (disable) an event request that has hit its count filter - if (!isExpired(request)) { - getEventRequestManager().deleteEventRequest(request); // disable & remove - } - if (request instanceof BreakpointRequest) { - Location location = ((BreakpointRequest) request).location(); - request = createLineBreakpointRequest(location, marker); - } else { - Field field= ((WatchpointRequest) request).field(); - if (request instanceof AccessWatchpointRequest) { - request= createAccessWatchpoint(marker, field); - } else if (request instanceof ModificationWatchpointRequest) { - request= createModificationWatchpoint(marker, field); - } - } - } catch (VMDisconnectedException e) { - } catch (RuntimeException e) { - internalError(e); - } - } - return request; - } - - /** - * Returns whether the hitCount of a marker is equal to the hitCount of - * the associated request. - */ - protected boolean hasHitCountChanged(IMarker marker, EventRequest request) { - int hitCount= DebugJavaUtils.getHitCount(marker); - Integer requestCount= (Integer) request.getProperty(IJavaDebugConstants.HIT_COUNT); - int oldCount = -1; - if (requestCount != null) { - oldCount = requestCount.intValue(); - } - return hitCount != oldCount; - } - - /** - * An exception breakpoint has been added. - */ - protected void exceptionBreakpointAdded(IMarker exceptionBreakpoint) { - exceptionBreakpointChanged(exceptionBreakpoint); - } - - /** - * An exception breakpoint has changed - */ - protected void exceptionBreakpointChanged(IMarker exceptionBreakpoint) { - - boolean caught= DebugJavaUtils.isCaught(exceptionBreakpoint); - boolean uncaught= DebugJavaUtils.isUncaught(exceptionBreakpoint); - - if (caught || uncaught) { - IType exceptionType = DebugJavaUtils.getType(exceptionBreakpoint); - if (exceptionType == null) { - internalError(ERROR_BREAKPOINT_NO_TYPE); - return; - } - String exceptionName = exceptionType.getFullyQualifiedName(); - String topLevelName = getTopLevelTypeName(exceptionBreakpoint); - if (topLevelName == null) { - internalError(ERROR_BREAKPOINT_NO_TYPE); - return; - } - List classes= jdiClassesByName(exceptionName); - ReferenceType exClass= null; - if (classes != null && !classes.isEmpty()) { - exClass= (ReferenceType) classes.get(0); - } - if (exClass == null) { - // defer the exception - defer(exceptionBreakpoint, topLevelName); - } else { - // new or changed - first delete the old request - if (null != fInstalledBreakpoints.get(exceptionBreakpoint)) - exceptionBreakpointRemoved(exceptionBreakpoint); - ExceptionRequest request= null; - try { - request= getEventRequestManager().createExceptionRequest(exClass, caught, uncaught); - configureRequest(request, exceptionBreakpoint); - } catch (VMDisconnectedException e) { - return; - } catch (RuntimeException e) { - internalError(e); - return; - } - request.setEnabled(getBreakpointManager().isEnabled(exceptionBreakpoint)); - fInstalledBreakpoints.put(exceptionBreakpoint, request); - } - } else { - exceptionBreakpointRemoved(exceptionBreakpoint); - } - } - - /** - * An exception breakpoint has been removed - */ - protected void exceptionBreakpointRemoved(IMarker exceptionBreakpoint) { - IType type = DebugJavaUtils.getType(exceptionBreakpoint); - if (type == null) { - internalError(ERROR_BREAKPOINT_NO_TYPE); - return; - } - String name = type.getFullyQualifiedName(); - ExceptionRequest request= (ExceptionRequest) fInstalledBreakpoints.remove(exceptionBreakpoint); - if (request != null) { - try { - getEventRequestManager().deleteEventRequest(request); - } catch (VMDisconnectedException e) { - return; - } catch (RuntimeException e) { - internalError(e); - return; - } - } - List deferred = (List)fDeferredBreakpointsByClass.get(name); - if (deferred != null) { - deferred.remove(exceptionBreakpoint); - if (deferred.isEmpty()) { - fDeferredBreakpointsByClass.remove(name); - } - } - } - - /** - * A watchpoint has been added. - * Create or update the request. - */ - protected void watchpointAdded(IMarker breakpoint) { - selectiveWatchpointAdded(breakpoint, true, true); - - } - - /** - * A single watchpoint can create multiple requests. This method provides control over this - * property for explicitly choosing which requests (access, modification, or both) to - * potentially add. - */ - protected void selectiveWatchpointAdded(IMarker breakpoint, boolean accessCheck, boolean modificationCheck) { - String topLevelName= getTopLevelTypeName(breakpoint); - if (topLevelName == null) { - internalError(ERROR_BREAKPOINT_NO_TYPE); - return; - } - - List classes= jdiClassesByName(topLevelName); - if (classes == null || classes.isEmpty()) { - // defer - defer(breakpoint, topLevelName); - return; - } - - IField javaField= DebugJavaUtils.getField(breakpoint); - Field field= null; - ReferenceType reference= null; - for (int i=0; i<classes.size(); i++) { - reference= (ReferenceType) classes.get(i); - field= reference.fieldByName(javaField.getElementName()); - if (field == null) { - return; - } - AccessWatchpointRequest accessRequest= null; - ModificationWatchpointRequest modificationRequest= null; - // If we're not supposed to check access or modification, just retrieve the - // existing request - if (!accessCheck) { - accessRequest= getAccessWatchpointRequest(field); - } - if (!modificationCheck) { - modificationRequest= getModificationWatchpointRequest(field); - } - if (DebugJavaUtils.isAccess(breakpoint) && accessCheck) { - if (getVM().canWatchFieldAccess()) { - accessRequest= accessWatchpointAdded(breakpoint, field); - } else { - try { - notSupported(ERROR_ACCESS_WATCHPOINT_NOT_SUPPORTED); - } catch (DebugException e) { - internalError(e); - } - } - } - if (DebugJavaUtils.isModification(breakpoint) && modificationCheck) { - if (getVM().canWatchFieldModification()) { - modificationRequest= modificationWatchpointAdded(breakpoint, field); - } else { - try { - notSupported(ERROR_MODIFICATION_WATCHPOINT_NOT_SUPPORTED); - } catch (DebugException e) { - internalError(e); - } - } - } - if (!(accessRequest == null && modificationRequest == null)) { - Object[] requests= {accessRequest, modificationRequest}; - fInstalledBreakpoints.put(breakpoint, requests); - try { - DebugJavaUtils.incrementInstallCount(breakpoint); - } catch (CoreException e) { - internalError(e); - } - } - } - } - - /** - * An access watchpoint has been added. - * Create or update the request. - */ - protected AccessWatchpointRequest accessWatchpointAdded(IMarker breakpoint, Field field) { - AccessWatchpointRequest request= getAccessWatchpointRequest(field); - if (request == null) { - request= createAccessWatchpoint(breakpoint, field); - } - // Important: Enable only after request has been configured - request.setEnabled(getBreakpointManager().isEnabled(breakpoint)); - return request; - } - - /** - * Create an access watchpoint for the given breakpoint and associated field - */ - protected AccessWatchpointRequest createAccessWatchpoint(IMarker breakpoint, Field field) { - AccessWatchpointRequest request= null; - try { - request= getEventRequestManager().createAccessWatchpointRequest(field); - configureRequest(request, breakpoint); - } catch (VMDisconnectedException e) { - return null; - } catch (RuntimeException e) { - internalError(e); - return null; - } - return request; - } - - /** - * A modification watchpoint has been added. - * Create or update the request. - */ - protected ModificationWatchpointRequest modificationWatchpointAdded(IMarker breakpoint, Field field) { - ModificationWatchpointRequest request= getModificationWatchpointRequest(field); - if (request == null) { - request= createModificationWatchpoint(breakpoint, field); - } - // Important: only enable a request after it has been configured - request.setEnabled(getBreakpointManager().isEnabled(breakpoint)); - return request; - } - - /** - * Create a modification watchpoint for the given breakpoint and associated field - */ - protected ModificationWatchpointRequest createModificationWatchpoint(IMarker breakpoint, Field field) { - ModificationWatchpointRequest request= null; - try { - request= getEventRequestManager().createModificationWatchpointRequest(field); - configureRequest(request, breakpoint); - } catch (VMDisconnectedException e) { - return null; - } catch (RuntimeException e) { - internalError(e); - return null; - } - return request; - } - - /** - * Configure a request with common properties: - * <ul> - * <li><code>IDebugConstants.BREAKPOINT_MARKER</code></li> - * <li><code>IJavaDebugConstants.HIT_COUNT</code></li> - * <li><code>IJavaDebugConstants.EXPIRED</code></li> - * </ul> - * and sets the suspend policy of the request to suspend the event thread. - */ - protected void configureRequest(EventRequest request, IMarker breakpoint) { - request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); - request.putProperty(IDebugConstants.BREAKPOINT_MARKER, breakpoint); - int hitCount= DebugJavaUtils.getHitCount(breakpoint); - if (hitCount > 0) { - request.addCountFilter(hitCount); - request.putProperty(IJavaDebugConstants.HIT_COUNT, new Integer(hitCount)); - request.putProperty(IJavaDebugConstants.EXPIRED, Boolean.FALSE); - } - } - - /** - * Enable a request and increment the install count of the associated breakpoint. - */ - protected void completeConfiguration(EventRequest request, IMarker breakpoint) { - // Important: Enable only after request has been configured - request.setEnabled(getBreakpointManager().isEnabled(breakpoint)); - try { - DebugJavaUtils.incrementInstallCount(breakpoint); - } catch (CoreException e) { - internalError(e); - } - } - - /** - * A method entry breakpoint has been added. - * Create or update the request. - */ - protected void methodEntryBreakpointAdded(IMarker breakpoint) { - IType type = DebugJavaUtils.getType(breakpoint); - if (type == null) { - internalError(ERROR_BREAKPOINT_NO_TYPE); - return; - } - String className = type.getFullyQualifiedName(); - - MethodEntryRequest request = getMethodEntryRequest(className); - - if (request == null) { - try { - request= getEventRequestManager().createMethodEntryRequest(); - request.addClassFilter(className); - request.putProperty(CLASS_NAME, className); - request.putProperty(BREAKPOINT_INFO, new ArrayList(1)); - request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); - request.putProperty(IDebugConstants.BREAKPOINT_MARKER, new ArrayList(3)); - request.putProperty(IJavaDebugConstants.HIT_COUNT, new ArrayList(3)); - } catch (VMDisconnectedException e) { - return; - } catch (RuntimeException e) { - internalError(e); - return; - } - } - List breakpointInfo= (List)request.getProperty(BREAKPOINT_INFO); - breakpointInfo.add(null); - - List breakpoints= (List)request.getProperty(IDebugConstants.BREAKPOINT_MARKER); - breakpoints.add(breakpoint); - - - List hitCounts = (List)request.getProperty(IJavaDebugConstants.HIT_COUNT); - int hitCount = DebugJavaUtils.getHitCount(breakpoint); - if (hitCount > 0) { - hitCounts.add(new Integer(hitCount)); - } else { - hitCounts.add(null); - } - completeConfiguration(request, breakpoint); - fInstalledBreakpoints.put(breakpoint, request); + public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { + breakpoint.changeForTarget(this); } /** @@ -1356,152 +778,18 @@ Iterator requests= getEventRequestManager().methodEntryRequests().iterator(); while (requests.hasNext()) { MethodEntryRequest existingRequest= (MethodEntryRequest)requests.next(); - if (className.equals(existingRequest.getProperty(CLASS_NAME))) { + if (className.equals(existingRequest.getProperty(MethodEntryBreakpoint.CLASS_NAME))) { return existingRequest; } } return null; } - - /** - * A watchpoint has been changed. - * Update the request. - */ - protected void watchpointChanged(IMarker breakpoint) { - Object[] requests= (Object[])fInstalledBreakpoints.get(breakpoint); - for (int i=0; i < requests.length; i++) { - WatchpointRequest request= (WatchpointRequest)requests[i]; - if (request == null) { - if ((i == 0) && DebugJavaUtils.isAccess(breakpoint)) { - selectiveWatchpointAdded(breakpoint, true, false); - } - if ((i == 1) && DebugJavaUtils.isModification(breakpoint)) { - selectiveWatchpointAdded(breakpoint, false, true); - } - continue; - } - if ((!DebugJavaUtils.isAccess(breakpoint) && (request instanceof AccessWatchpointRequest)) || - (!DebugJavaUtils.isModification(breakpoint) && (request instanceof ModificationWatchpointRequest))) { - getEventRequestManager().deleteEventRequest(request); // disable & remove - continue; - } - request= (WatchpointRequest)updateHitCount(request, breakpoint); - - if (request != null) { - updateEnabledState(request, breakpoint); - requests[i]= request; - } - } - } - - /** - * A method entry breakpoint has been changed. - * Update the request. - */ - protected void methodEntryBreakpointChanged(IMarker breakpoint, IMarkerDelta delta) { - MethodEntryRequest request = (MethodEntryRequest)fInstalledBreakpoints.get(breakpoint); - if (request == null) { - return; - } - // check the enabled state - updateMethodEntryEnabledState(request); - - List breakpoints= (List)request.getProperty(IDebugConstants.BREAKPOINT_MARKER); - int index= breakpoints.indexOf(breakpoint); - // update the breakpoints hit count - int newCount = DebugJavaUtils.getHitCount(breakpoint); - List hitCounts= (List)request.getProperty(IJavaDebugConstants.HIT_COUNT); - if (newCount > 0) { - hitCounts.set(index, new Integer(newCount)); - } else { - //back to a regular breakpoint - hitCounts.set(index, null); - } - } - - /** - * A watchpoint has been removed. - * Remove the request. - */ - protected void watchpointRemoved(IMarker breakpoint) { - Object[] requests= (Object[]) fInstalledBreakpoints.remove(breakpoint); - if (requests == null) { - //deferred breakpoint - if (!breakpoint.exists()) { - //resource no longer exists - return; - } - String name= getTopLevelTypeName(breakpoint); - if (name == null) { - internalError(ERROR_BREAKPOINT_NO_TYPE); - return; - } - List markers= (List) fDeferredBreakpointsByClass.get(name); - if (markers == null) { - return; - } - - markers.remove(breakpoint); - if (markers.isEmpty()) { - fDeferredBreakpointsByClass.remove(name); - } - } else { - //installed breakpoint - try { - for (int i=0; i<requests.length; i++) { - WatchpointRequest request= (WatchpointRequest)requests[i]; - if (request == null) { - continue; - } - getEventRequestManager().deleteEventRequest(request); // disable & remove - } - try { - DebugJavaUtils.decrementInstallCount(breakpoint); - } catch (CoreException e) { - internalError(e); - } - } catch (VMDisconnectedException e) { - return; - } catch (RuntimeException e) { - internalError(e); - } - } - } - - /** - * A method entry breakpoint has been removed. - * Update the request. - */ - protected void methodEntryBreakpointRemoved(IMarker breakpoint) { - MethodEntryRequest request = (MethodEntryRequest)fInstalledBreakpoints.remove(breakpoint); - if (request != null) { - try { - DebugJavaUtils.decrementInstallCount(breakpoint); - } catch (CoreException e) { - internalError(e); - } - List breakpoints= (List)request.getProperty(IDebugConstants.BREAKPOINT_MARKER); - int index = breakpoints.indexOf(breakpoint); - breakpoints.remove(index); - if (breakpoints.isEmpty()) { - try { - getEventRequestManager().deleteEventRequest(request); // disable & remove - } catch (VMDisconnectedException e) { - } catch (RuntimeException e) { - internalError(e); - } - } else { - List hitCounts= (List)request.getProperty(IJavaDebugConstants.HIT_COUNT); - hitCounts.remove(index); - } - } - } /** * @see IBreakpointSupport */ - public boolean supportsBreakpoint(IMarker breakpoint) { - return !isTerminated() && !isDisconnected() && JDIDebugModel.getPluginIdentifier().equals(getBreakpointManager().getModelIdentifier(breakpoint)); + public boolean supportsBreakpoint(IBreakpoint breakpoint) { + return !isTerminated() && !isDisconnected() && JDIDebugModel.getPluginIdentifier().equals(breakpoint.getModelIdentifier()); } /** @@ -1575,15 +863,15 @@ //inner class load...resolve the top level type name topLevelName= className.substring(0, index); } - ArrayList markers= (ArrayList) fDeferredBreakpointsByClass.remove(topLevelName); - if (markers != null) { + ArrayList breakpoints= (ArrayList) fDeferredBreakpointsByClass.remove(topLevelName); + if (breakpoints != null) { //no longer need to listen for this class load ClassPrepareRequest request= (ClassPrepareRequest) fClassPrepareRequestsByClass.remove(topLevelName); getEventRequestManager().deleteEventRequest(request); - Iterator itr= ((ArrayList) markers.clone()).iterator(); + Iterator itr= ((ArrayList) breakpoints.clone()).iterator(); while (itr.hasNext()) { - IMarker marker= (IMarker) itr.next(); - breakpointAdded(marker); + JavaBreakpoint breakpoint= (JavaBreakpoint) itr.next(); + breakpoint.addToTarget(this); } } } @@ -1592,11 +880,11 @@ * Sets all the breakpoints to be uninstalled. */ protected void uninstallAllBreakpoints() { - Iterator markers= ((Map)((HashMap)fInstalledBreakpoints).clone()).keySet().iterator(); - while (markers.hasNext()) { - IMarker marker= (IMarker) markers.next(); + Iterator breakpoints= ((Map)((HashMap)fInstalledBreakpoints).clone()).keySet().iterator(); + while (breakpoints.hasNext()) { + JavaBreakpoint breakpoint= (JavaBreakpoint) breakpoints.next(); try { - DebugJavaUtils.decrementInstallCount(marker); + breakpoint.decrementInstallCount(); } catch (CoreException e) { internalError(e); } @@ -1607,53 +895,8 @@ /** * @see IBreakpointSupport */ - public void breakpointRemoved(IMarker breakpoint, IMarkerDelta delta) { - if (DebugJavaUtils.isExceptionBreakpoint(breakpoint)) { - exceptionBreakpointRemoved(breakpoint); - } else if (DebugJavaUtils.isMethodEntryBreakpoint(breakpoint)) { - methodEntryBreakpointRemoved(breakpoint); - } else if (DebugJavaUtils.isWatchpoint(breakpoint)) { - watchpointRemoved(breakpoint); - } else { - lineBreakpointRemoved(breakpoint); - } - } - - protected void lineBreakpointRemoved(IMarker breakpoint) { - BreakpointRequest request= (BreakpointRequest) fInstalledBreakpoints.remove(breakpoint); - if (request == null) { - //deferred breakpoint - if (!breakpoint.exists()) { - //resource no longer exists - return; - } - String name= getTopLevelTypeName(breakpoint); - if (name == null) { - internalError(ERROR_BREAKPOINT_NO_TYPE); - return; - } - List markers= (List) fDeferredBreakpointsByClass.get(name); - if (markers == null) { - return; - } - - markers.remove(breakpoint); - if (markers.isEmpty()) { - fDeferredBreakpointsByClass.remove(name); - } - } else { - //installed breakpoint - try { - // cannot delete an expired request - if (!isExpired(request)) { - getEventRequestManager().deleteEventRequest(request); // disable & remove - } - } catch (VMDisconnectedException e) { - return; - } catch (RuntimeException e) { - internalError(e); - } - } + public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { + breakpoint.removeFromTarget(this); } /** @@ -1666,16 +909,9 @@ while (itr.hasNext()) { // do not notify the breakpoint manager of uninstall, as we // are in a resource change callback and cannot modify the resource tree - IMarker marker= (IMarker) itr.next(); - boolean watchpointMarker= false; - try { - watchpointMarker= marker.isSubtypeOf(IJavaDebugConstants.JAVA_WATCHPOINT); - } catch (CoreException ce) { - logError(ce); - continue; - } - if (watchpointMarker) { - Object[] requests= (Object[])fInstalledBreakpoints.remove(marker); + JavaBreakpoint breakpoint= (JavaBreakpoint) itr.next(); + if (breakpoint instanceof Watchpoint) { + Object[] requests= (Object[])fInstalledBreakpoints.remove(breakpoint); for (int i=0; i<requests.length; i++) { EventRequest req = (EventRequest)requests[i]; if (req != null) { @@ -1683,10 +919,10 @@ } } } else { - EventRequest req = (EventRequest)fInstalledBreakpoints.remove(marker); + EventRequest req = (EventRequest)fInstalledBreakpoints.remove(breakpoint); getEventRequestManager().deleteEventRequest(req); } - breakpointAdded(marker); + breakpoint.addToTarget(this); } } } @@ -1755,29 +991,6 @@ } return null; } - - /** - * Called by a JDI thread when a breakpoint or - * watchpoint is encountered. - */ - public void expireHitCount(LocatableEvent event) { - EventRequest request= (EventRequest)event.request(); - Integer requestCount= (Integer) request.getProperty(IJavaDebugConstants.HIT_COUNT); - if (requestCount != null) { - IMarker breakpoint= (IMarker)request.getProperty(IDebugConstants.BREAKPOINT_MARKER); - if (breakpoint == null) { - return; - } - try { - request.putProperty(IJavaDebugConstants.EXPIRED, Boolean.TRUE); - getBreakpointManager().setEnabled(breakpoint, false); - // make a note that we auto-disabled this breakpoint. - DebugJavaUtils.setExpired(breakpoint, true); - } catch (CoreException ce) { - internalError(ce); - } - } - } /** * @see IDebugElement @@ -1792,7 +1005,7 @@ * * @see IAdaptable */ - protected Object getAdpater(Class adapter) { + public Object getAdapter(Class adapter) { if (adapter == IJavaDebugTarget.class) { return this; } @@ -1903,18 +1116,7 @@ } return context; } - - /** - * Returns whether the given request is expired - */ - protected boolean isExpired(EventRequest request) { - Boolean requestExpired= (Boolean) request.getProperty(IJavaDebugConstants.EXPIRED); - if (requestExpired == null) { - return false; - } - return requestExpired.booleanValue(); - } - + /** * The JDIDebugPlugin is shutting down. * Shutdown the event dispatcher.
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIThread.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIThread.java index 8cb02c1..cf6f26f 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIThread.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIThread.java
@@ -109,7 +109,7 @@ * The breakpoint that caused the last suspend, or * <code>null</code> if none. */ - protected IMarker fCurrentBreakpoint; + protected JavaBreakpoint fCurrentBreakpoint; /** * The cached named of the underlying thread. @@ -137,7 +137,6 @@ * invocations cannot be performed. */ protected boolean fInEvaluation = false; - protected boolean fEvaluationAborted = false; /** * Creates a new thread on the underlying thread reference. @@ -191,7 +190,7 @@ /** * @see IJavaThread */ - public IMarker getBreakpoint() { + public JavaBreakpoint getBreakpoint() { if (fCurrentBreakpoint != null && !fCurrentBreakpoint.exists()) { fCurrentBreakpoint= null; } @@ -444,24 +443,10 @@ } invokeComplete(timeout); - if (fEvaluationAborted) { - fEvaluationAborted = false; - resume(); - } return result; } /** - * Called by JDIValue when an evaluation of - * #toString times out. Causes this thread to - * be automatically resumed when it returns from - * its evaluation - see <code>invokeMethod</code>. - */ - protected void abortEvaluation() { - fEvaluationAborted = true; - } - - /** * Invokes a method in this thread, creating a new instance of the given * class using the specified constructor, and returns the result. */ @@ -595,24 +580,11 @@ */ protected void handleLocatableEvent(LocatableEvent event) { abortDropAndStep(); - fCurrentBreakpoint= (IMarker) event.request().getProperty(IDebugConstants.BREAKPOINT_MARKER); + fCurrentBreakpoint= (JavaBreakpoint) event.request().getProperty(IDebugConstants.BREAKPOINT); setRunning(false, DebugEvent.BREAKPOINT); - ((JDIDebugTarget) getDebugTarget()).expireHitCount(event); } - /** - * Suspend the thread based on an exception event - */ - protected void handleException(ExceptionEvent event) { - abortDropAndStep(); - fCurrentBreakpoint= (IMarker) event.request().getProperty(IDebugConstants.BREAKPOINT_MARKER); - setRunning(false, DebugEvent.BREAKPOINT); - } - - /** - * Suspend the thread based on the method entry event - */ - protected void handleSuspendMethodEntry(IMarker breakpoint) { + protected void handleSuspendForBreakpoint(JavaBreakpoint breakpoint) { abortDropAndStep(); fCurrentBreakpoint= breakpoint; setRunning(false, DebugEvent.BREAKPOINT);
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIValue.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIValue.java index aa1e95c..c2c76ef 100644 --- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIValue.java +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIValue.java Binary files differ
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaBreakpoint.java new file mode 100644 index 0000000..7c0adf8 --- /dev/null +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaBreakpoint.java
@@ -0,0 +1,383 @@ +package org.eclipse.jdt.internal.debug.core; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.*; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.internal.core.Breakpoint; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.debug.core.IJavaDebugConstants; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.event.Event; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.MethodEntryRequest; + +public abstract class JavaBreakpoint extends Breakpoint { + + // Thread and marker label resource String keys + protected static final String THREAD_PREFIX= "jdi_thread."; + protected static final String MARKER_PREFIX= "jdi_marker."; + protected static final String LABEL= "label."; + protected static final String THREAD_LABEL= THREAD_PREFIX + LABEL; + protected static final String MARKER_LABEL= MARKER_PREFIX + LABEL; + /** + * JavaBreakpoint attributes + */ + protected static final String[] fgExpiredEnabledAttributes= new String[]{IJavaDebugConstants.EXPIRED, IDebugConstants.ENABLED}; + + protected JDIDebugTarget fTarget= null; + + public JavaBreakpoint() { + } + + public JavaBreakpoint(IMarker marker) { + super(marker); + } + + /** + * @see Breakpoint#addToTarget(IDebugTarget) + */ + public void addToTarget(IDebugTarget target) { + if (target instanceof JDIDebugTarget) { + addToTarget((JDIDebugTarget) target); + } + } + + /** + * This breakpoint is being added to the target + * Create or update the request. + */ + public abstract void addToTarget(JDIDebugTarget target); + + /** + * @see Breakpoint#changeForTarget + */ + public void changeForTarget(IDebugTarget target) { + if (target instanceof JDIDebugTarget) { + changeForTarget((JDIDebugTarget) target); + } + } + + /** + * This breakpoint has been changed. + * Update the request from the given target. + */ + public abstract void changeForTarget(JDIDebugTarget target); + + /** + * @see Breakpoint#removeFromTarget(IDebugTarget) + */ + public void removeFromTarget(IDebugTarget target) { + if (target instanceof JDIDebugTarget) { + removeFromTarget((JDIDebugTarget) target); + } + } + + /** + * This breakpoint has been removed. + * Remove the request from the given target. + */ + public abstract void removeFromTarget(JDIDebugTarget target); + + /** + * Update the enabled state of the given request, which is associated + * with this breakpoint. Set the enabled state of the request + * to the enabled state of this breakpoint. + */ + protected void updateEnabledState(EventRequest request) { + updateEnabledState0(request, this.isEnabled()); + } + + /** + * Set the enabled state of the given request as specified by the enabled + * parameter + */ + protected void updateEnabledState0(EventRequest request, boolean enabled) { + if (request.isEnabled() != enabled) { + // change the enabled state + try { + // if the request has expired, and is not a method entry request, do not disable. + // BreakpointRequests that have expired cannot be deleted. However method entry + // requests that are expired can be deleted (since we simulate the hit count) + if (request instanceof MethodEntryRequest || !isExpired(request)) { + request.setEnabled(enabled); + } + } catch (VMDisconnectedException e) { + } catch (RuntimeException e) { + logError(e); + } + } + } + + /** + * Returns whether this kind of breakpoint is supported by the given + * virtual machine. + */ + public abstract boolean isSupportedBy(VirtualMachine vm); + + /** + * Return whether this breakpoint is enabled + */ + public boolean isEnabled() { + try { + return super.isEnabled(); + } catch (CoreException ce) { + logError(ce); + return false; + } + } + + /** + * Returns whether this breakpoint has expired. + */ + public boolean isExpired() { + return getBooleanAttribute(IJavaDebugConstants.EXPIRED); + } + + /** + * Returns whether the given request is expired + */ + protected boolean isExpired(EventRequest request) { + Boolean requestExpired= (Boolean) request.getProperty(IJavaDebugConstants.EXPIRED); + if (requestExpired == null) { + return false; + } + return requestExpired.booleanValue(); + } + + /** + * An event request has been fired for this breakpoint. Handle it. + */ + public abstract void handleEvent(Event event, JDIDebugTarget target); + + /** + * Enable this breakpoint + */ + public void enable() { + try { + super.enable(); + } catch (CoreException ce) { + logError(ce); + } + } + + /** + * Disable this breakpoint + */ + public void disable() { + try { + super.disable(); + } catch (CoreException ce) { + logError(ce); + } + } + + /** + * Returns whether this breakpoint is installed in at least + * one debug target. + */ + public boolean isInstalled() { + return getAttribute(IJavaDebugConstants.INSTALL_COUNT, 0) > 0; + } + + /** + * Increments the install count on this breakpoint + */ + public void incrementInstallCount() throws CoreException { + int count = getInstallCount(); + setAttribute(IJavaDebugConstants.INSTALL_COUNT, count + 1); + } + + /** + * Returns the <code>INSTALL_COUNT</code> attribute of this breakpoint + * or 0 if the attribute is not set. + */ + public int getInstallCount() { + return getAttribute(IJavaDebugConstants.INSTALL_COUNT, 0); + } + + /** + * Decrements the install count on this breakpoint. If the new + * install count is 0, the <code>EXPIRED</code> attribute is reset to + * <code>false</code> (since any hit count breakpoints that auto-expired + * should be re-enabled when the debug session is over). + */ + public void decrementInstallCount() throws CoreException { + int count= getInstallCount(); + if (count > 0) { + setAttribute(IJavaDebugConstants.INSTALL_COUNT, count - 1); + } + if (count == 1) { + if (isExpired()) { + // if breakpoint was auto-disabled, re-enable it + setAttributes(fgExpiredEnabledAttributes, + new Object[]{Boolean.FALSE, Boolean.TRUE}); + } + } + } + + /** + * Sets the <code>TYPE_HANDLE</code> attribute of the given breakpoint, associated + * with the given IType. + */ + public void setType(IType type) throws CoreException { + String handle = type.getHandleIdentifier(); + setTypeHandleIdentifier(handle); + } + + /** + * Sets the <code>TYPE_HANDLE</code> attribute of the given breakpoint. + */ + public void setTypeHandleIdentifier(String identifier) throws CoreException { + setAttribute(IJavaDebugConstants.TYPE_HANDLE, identifier); + } + + /** + * Returns the type the given breakpoint is installed in + * or <code>null</code> a type cannot be resolved. + */ + public IType getBreakpointType() { + try { + String handle = getTypeHandleIdentifier(); + if (handle != null) { + return (IType)JavaCore.create(handle); + } + } catch (CoreException e) { + logError(e); + } + return null; + } + + /** + * Returns the <code>TYPE_HANDLE</code> attribute of the given breakpoint. + */ + public String getTypeHandleIdentifier() throws CoreException { + return (String)getAttribute(IJavaDebugConstants.TYPE_HANDLE); + } + + /** + * Returns the top-level type name associated with the type + * the given breakpoint is associated with, or <code>null</code>. + */ + public String getTopLevelTypeName() { + IType type = getBreakpointType(); + if (type != null) { + while (type.getDeclaringType() != null) { + type = type.getDeclaringType(); + } + return type.getFullyQualifiedName(); + } + return null; + } + + /** + * Returns the text that should be displayed on a thread when the + * breakpoint is hit. + */ + public String getThreadText(String threadName, boolean qualified, boolean systemThread) { + String typeName= getBreakpointTypeName(qualified); + return getFormattedThreadText(threadName, typeName, systemThread); + } + + /** + * Returns the formatted text that should be displayed on a thread + * when the breakpoint is hit. + */ + public abstract String getFormattedThreadText(String threadName, String typeName, boolean systemThread); + + public String getBreakpointTypeName(boolean qualified) { + String typeName= ""; + typeName= getBreakpointType().getFullyQualifiedName(); + if (!qualified) { + int index= typeName.lastIndexOf('.'); + if (index != -1) { + typeName= typeName.substring(index + 1); + } + } + return typeName; + } + + /** + * Returns the identifier for this JDI debug model plug-in + * + * @return plugin identifier + */ + public static String getPluginIdentifier() { + return JDIDebugPlugin.getDefault().getDescriptor().getUniqueIdentifier(); + } + + /** + * Plug in the single argument to the resource String for the key to get a formatted resource String + */ + public static String getFormattedString(String key, String arg) { + return getFormattedString(key, new String[] {arg}); + } + + /** + * Plug in the arguments to the resource String for the key to get a formatted resource String + */ + public static String getFormattedString(String key, String[] args) { + String string= DebugJavaUtils.getResourceString(key); + return MessageFormat.format(string, args); + } + + /** + * Returns the VM this breakpoint is contained in + * or <code>null</code> if it is not installed. + */ + public VirtualMachine getVM() { + if (fTarget == null) { + return null; + } + return fTarget.getVM(); + } + + /** + * Convenience method to log internal errors + */ + protected void logError(Exception e) { + DebugJavaUtils.logError(e); + } + + protected void run(IWorkspaceRunnable wr) throws DebugException { + try { + ResourcesPlugin.getWorkspace().run(wr, null); + } catch (CoreException e) { + throw new DebugException(e.getStatus()); + } + } + + /** + * Resets the install count attribute on the breakpoint marker + * to "0". Resets the expired attribute on the breakpoint marker to <code>false</code>. + * Resets the enabled attribute on the breakpoint marker to <code>true</code>. + */ + protected void configureBreakpointAtStartup() throws CoreException { + List attributes= new ArrayList(3); + List values= new ArrayList(3); + if (isInstalled()) { + attributes.add(IJavaDebugConstants.INSTALL_COUNT); + values.add(new Integer(0)); + } + if (isExpired()) { + // if breakpoint was auto-disabled, re-enable it + attributes.add(IJavaDebugConstants.EXPIRED); + values.add(Boolean.FALSE); + attributes.add(IDebugConstants.ENABLED); + values.add(Boolean.TRUE); + } + if (!attributes.isEmpty()) { + String[] strAttributes= new String[attributes.size()]; + setAttributes((String[])attributes.toArray(strAttributes), values.toArray()); + } + } + +} +
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaBreakpointFactory.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaBreakpointFactory.java new file mode 100644 index 0000000..90f079c --- /dev/null +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaBreakpointFactory.java
@@ -0,0 +1,37 @@ +package org.eclipse.jdt.internal.debug.core; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.IBreakpoint; +import org.eclipse.debug.core.model.IBreakpointFactoryDelegate; +import org.eclipse.jdt.debug.core.IJavaDebugConstants; + +public class JavaBreakpointFactory implements IBreakpointFactoryDelegate { + + public JavaBreakpointFactory() { + } + + public IBreakpoint createBreakpointFor(IMarker marker) throws DebugException { + String markerType= null; + try { + markerType= marker.getType(); + } catch (CoreException ce) { + throw new DebugException(ce.getStatus()); + } + if (markerType.equals(IJavaDebugConstants.JAVA_LINE_BREAKPOINT)) { + return new LineBreakpoint(marker); + } else if (markerType.equals(IJavaDebugConstants.JAVA_WATCHPOINT)) { + return new Watchpoint(marker); + } else if (markerType.equals(IJavaDebugConstants.JAVA_METHOD_ENTRY_BREAKPOINT)) { + return new MethodEntryBreakpoint(marker); + } else if (markerType.equals(IJavaDebugConstants.JAVA_RUN_TO_LINE_BREAKPOINT)) { + return new RunToLineBreakpoint(marker); + } else if (markerType.equals(IJavaDebugConstants.JAVA_EXCEPTION_BREAKPOINT)) { + return new ExceptionBreakpoint(marker); + } + return null; + } + +} +
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/LineBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/LineBreakpoint.java new file mode 100644 index 0000000..082bf2a --- /dev/null +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/LineBreakpoint.java
@@ -0,0 +1,573 @@ +package org.eclipse.jdt.internal.debug.core; + +import java.util.*; + +import org.eclipse.core.resources.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.IDebugConstants; +import org.eclipse.jdt.core.*; +import org.eclipse.jdt.debug.core.IJavaDebugConstants; + +import com.sun.jdi.*; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.LocatableEvent; +import com.sun.jdi.request.BreakpointRequest; +import com.sun.jdi.request.EventRequest; + +public class LineBreakpoint extends JavaBreakpoint { + + // Thread label String keys + private static final String LINE_BREAKPOINT_SYS= THREAD_LABEL + "line_breakpoint_sys"; + private static final String LINE_BREAKPOINT_USR= THREAD_LABEL + "line_breakpoint_usr"; + // Marker label String keys + private static final String LINE= "line"; + private static final String HITCOUNT= "hitCount"; + + static String fMarkerType= IJavaDebugConstants.JAVA_LINE_BREAKPOINT; + /** + * Sets of attributes used to configure a line breakpoint + */ + protected static final String[] fgTypeAndHitCountAttributes= new String[]{IJavaDebugConstants.TYPE_HANDLE, IJavaDebugConstants.HIT_COUNT, IJavaDebugConstants.EXPIRED}; + protected static final String[] fgLineBreakpointAttributes= new String[]{IDebugConstants.MODEL_IDENTIFIER, IDebugConstants.ENABLED, IMarker.LINE_NUMBER, IMarker.CHAR_START, IMarker.CHAR_END}; + + public LineBreakpoint(){ + } + + public LineBreakpoint(IMarker marker) { + super(marker); + } + + public LineBreakpoint(IType type, int lineNumber, int charStart, int charEnd, int hitCount) throws DebugException { + this(type, lineNumber, charStart, charEnd, hitCount, fMarkerType); + } + + public LineBreakpoint(final IType type, final int lineNumber, final int charStart, final int charEnd, final int hitCount, final String markerType) throws DebugException { + IWorkspaceRunnable wr= new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + IResource resource= null; + resource= type.getUnderlyingResource(); + if (resource == null) { + resource= type.getJavaProject().getProject(); + } + + // create the marker + fMarker= resource.createMarker(markerType); + setLineBreakpointAttributes(getPluginIdentifier(), true, lineNumber, charStart, charEnd); + + // configure the hit count and type handle + setTypeAndHitCount(type, hitCount); + + // configure the marker as a Java marker + Map attributes= getAttributes(); + JavaCore.addJavaElementMarkerAttributes(attributes, type); + setAttributes(attributes); + } + }; + run(wr); + } + + /** + * @see JavaBreakpoint#installIn(JDIDebugTarget) + */ + public void addToTarget(JDIDebugTarget target) { + String topLevelName= getTopLevelTypeName(); + if (topLevelName == null) { +// internalError(ERROR_BREAKPOINT_NO_TYPE); + return; + } + + // look for the top-level class - if it is loaded, inner classes may also be loaded + List classes= target.jdiClassesByName(topLevelName); + if (classes == null || classes.isEmpty()) { + // defer + target.defer(this, topLevelName); + } else { + // try to install + ReferenceType type= (ReferenceType) classes.get(0); + if (!installLineBreakpoint(target, type)) { + // install did not succeed - could be an inner type not yet loaded + target.defer(this, topLevelName); + } + } + } + + /** + * Installs a line breakpoint in the given type, returning whether successful. + */ + protected boolean installLineBreakpoint(JDIDebugTarget target, ReferenceType type) { + Location location= null; + int lineNumber= getLineNumber(); + location= determineLocation(lineNumber, type); + if (location == null) { + // could be an inner type not yet loaded, or line information not available + return false; + } + + if (createLineBreakpointRequest(location, target) != null) { + // update the install attibute on the breakpoint + if (!target.inHCR()) { + try { + incrementInstallCount(); + } catch (CoreException e) { + logError(e); + } + } + return true; + } else { + return false; + } + + } + + /** + * Creates, installs, and returns a line breakpoint request at + * the given location for the given breakpoint. + */ + protected BreakpointRequest createLineBreakpointRequest(Location location, JDIDebugTarget target) { + BreakpointRequest request = null; + try { + request= target.getEventRequestManager().createBreakpointRequest(location); + configureRequest(request); + } catch (VMDisconnectedException e) { + target.uninstallBreakpoint(this); + return null; + } catch (RuntimeException e) { + target.uninstallBreakpoint(this); + logError(e); + return null; + } + request.setEnabled(isEnabled()); + target.installBreakpoint(this, request); + return request; + } + + + /** + * Returns a location for the line number in the given type, or any of its + * nested types. Returns <code>null</code> if a location cannot be determined. + */ + protected Location determineLocation(int lineNumber, ReferenceType type) { + List locations= null; + try { + locations= type.locationsOfLine(lineNumber); + } catch (AbsentInformationException e) { + return null; + } catch (NativeMethodException e) { + return null; + } catch (InvalidLineNumberException e) { + //possible in a nested type, fall through and traverse nested types + } catch (VMDisconnectedException e) { + return null; + } catch (ClassNotPreparedException e) { + // could be a nested type that is not yet loaded + return null; + } catch (RuntimeException e) { + // not able to retrieve line info + logError(e); + return null; + } + + if (locations != null && locations.size() > 0) { + return (Location) locations.get(0); + } else { + Iterator nestedTypes= null; + try { + nestedTypes= type.nestedTypes().iterator(); + } catch (RuntimeException e) { + // not able to retrieve line info + logError(e); + return null; + } + while (nestedTypes.hasNext()) { + ReferenceType nestedType= (ReferenceType) nestedTypes.next(); + Location innerLocation= determineLocation(lineNumber, nestedType); + if (innerLocation != null) { + return innerLocation; + } + } + } + + return null; + } + + public void changeForTarget(JDIDebugTarget target) { + BreakpointRequest request= (BreakpointRequest) target.getRequest(this); + if (request != null) { + // already installed - could be a change in the enabled state or hit count + //may result in a new request being generated + request= updateHitCount(request, target); + if (request != null) { + updateEnabledState(request); + target.installBreakpoint(this, request); + } + } + } + + /** + * Update the hit count of an <code>EventRequest</code>. Return a new request with + * the appropriate settings. + */ + protected BreakpointRequest updateHitCount(BreakpointRequest request, JDIDebugTarget target) { + + // if the hit count has changed, or the request has expired and is being re-enabled, + // create a new request + if (hasHitCountChanged(request) || (isExpired(request) && this.isEnabled())) { + try { + // delete old request + //on JDK you cannot delete (disable) an event request that has hit its count filter + if (!isExpired(request)) { + target.getEventRequestManager().deleteEventRequest(request); // disable & remove + } + Location location = ((BreakpointRequest) request).location(); + request = createLineBreakpointRequest(location, target); + } catch (VMDisconnectedException e) { + } catch (RuntimeException e) { + logError(e); + } + } + return request; + } + + /** + * Returns whether the hitCount of this breakpoint is equal to the hitCount of + * the associated request. + */ + protected boolean hasHitCountChanged(EventRequest request) { + int hitCount= getHitCount(); + Integer requestCount= (Integer) request.getProperty(IJavaDebugConstants.HIT_COUNT); + int oldCount = -1; + if (requestCount != null) { + oldCount = requestCount.intValue(); + } + return hitCount != oldCount; + } + + + /** + * Configure a breakpoint request with common properties: + * <ul> + * <li><code>IDebugConstants.BREAKPOINT_MARKER</code></li> + * <li><code>IJavaDebugConstants.HIT_COUNT</code></li> + * <li><code>IJavaDebugConstants.EXPIRED</code></li> + * </ul> + * and sets the suspend policy of the request to suspend the event thread. + */ + protected void configureRequest(EventRequest request) { + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.putProperty(IDebugConstants.BREAKPOINT, this); + int hitCount= getHitCount(); + if (hitCount > 0) { + request.addCountFilter(hitCount); + request.putProperty(IJavaDebugConstants.HIT_COUNT, new Integer(hitCount)); + request.putProperty(IJavaDebugConstants.EXPIRED, Boolean.FALSE); + } + } + + /** + * Enable a request and increment the install count of the associated breakpoint. + */ + protected void completeConfiguration(EventRequest request) { + // Important: Enable only after request has been configured + try { + request.setEnabled(isEnabled()); + incrementInstallCount(); + } catch (CoreException e) { + logError(e); + } + } + + /** + * @see JavaBreakpoint#handleEvent(Event) + */ + public void handleEvent(Event event, JDIDebugTarget target) { + if (!(event instanceof LocatableEvent)) { + return; + } + ThreadReference threadRef= ((LocatableEvent)event).thread(); + JDIThread thread= target.findThread(threadRef); + if (thread == null) { + target.resume(threadRef); + return; + } else { + thread.handleSuspendForBreakpoint(this); + expireHitCount((LocatableEvent)event); + } + } + + /** + * Called when a breakpoint event is encountered + */ + public void expireHitCount(LocatableEvent event) { + EventRequest request= (EventRequest)event.request(); + Integer requestCount= (Integer) request.getProperty(IJavaDebugConstants.HIT_COUNT); + if (requestCount != null) { + try { + request.putProperty(IJavaDebugConstants.EXPIRED, Boolean.TRUE); + this.disable(); + // make a note that we auto-disabled this breakpoint. + setExpired(true); + } catch (CoreException ce) { + logError(ce); + } + } + } + + /** + * @see JavaBreakpoint#removeFromTarget(JDIDebugTarget) + */ + public void removeFromTarget(JDIDebugTarget target) { + BreakpointRequest request= (BreakpointRequest) target.getRequest(this); + if (request == null) { + //deferred breakpoint + if (!this.exists()) { + //resource no longer exists + return; + } + String name= getTopLevelTypeName(); + if (name == null) { +// internalError(ERROR_BREAKPOINT_NO_TYPE); + return; + } + List breakpoints= (List) target.getDeferredBreakpointsByClass(name); + if (breakpoints == null) { + return; + } + + breakpoints.remove(this); + if (breakpoints.isEmpty()) { + target.removeDeferredBreakpointByClass(name); + } + } else { + //installed breakpoint + try { + // cannot delete an expired request + if (!isExpired(request)) { + target.getEventRequestManager().deleteEventRequest(request); // disable & remove + } + } catch (VMDisconnectedException e) { + return; + } catch (RuntimeException e) { + logError(e); + } + } + } + + /** + * Returns the <code>HIT_COUNT</code> attribute of the given breakpoint + * or -1 if the attribute is not set. + */ + public int getHitCount() { + return getAttribute(IJavaDebugConstants.HIT_COUNT, -1); + } + + /** + * Sets the <code>HIT_COUNT</code> attribute of the given breakpoint, + * and resets the <code>EXPIRED</code> attribute to false (since, if + * the hit count is changed, the breakpoint should no longer be expired). + */ + public void setHitCount(int count) throws CoreException { + setAttributes(new String[]{IJavaDebugConstants.HIT_COUNT, IJavaDebugConstants.EXPIRED}, + new Object[]{new Integer(count), Boolean.FALSE}); + } + + /** + * @see JavaBreakpoint#isSupportedBy(VirtualMachine) + */ + public boolean isSupportedBy(VirtualMachine vm) { + return true; + } + + /** + * Returns whether the given breakpoint has expired. + */ + public boolean isExpired() { + return getBooleanAttribute( IJavaDebugConstants.EXPIRED); + } + + /** + * Sets the <code>EXPIRED</code> attribute of the given breakpoint. + */ + public void setExpired(boolean expired) throws CoreException { + setBooleanAttribute(IJavaDebugConstants.EXPIRED, expired); + } + + /** + * Returns the method the given breakpoint is installed in + * or <code>null</code> if a method cannot be resolved. + */ + public IMethod getMethod() { + try { + String handle = getMethodHandleIdentifier(); + if (handle != null) { + return (IMethod)JavaCore.create(handle); + } + } catch (CoreException e) { + logError(e); + } + return null; + } + + /** + * Set standard attributes of a line breakpoint + */ + public void setLineBreakpointAttributes(String modelIdentifier, boolean enabled, int lineNumber, int charStart, int charEnd) throws CoreException { + Object[] values= new Object[]{getPluginIdentifier(), new Boolean(true), new Integer(lineNumber), new Integer(charStart), new Integer(charEnd)}; + setAttributes(fgLineBreakpointAttributes, values); + } + + /** + * Sets the <code>TYPE_HANDLE</code> attribute of the given breakpoint, associated + * with the given IType. + * + * If <code>hitCount > 0</code>, sets the <code>HIT_COUNT</code> attribute of the given breakpoint, + * and resets the <code>EXPIRED</code> attribute to false (since, if + * the hit count is changed, the breakpoint should no longer be expired). + */ + public void setTypeAndHitCount(IType type, int hitCount) throws CoreException { + if (hitCount == 0) { + setType(type); + return; + } + String handle = type.getHandleIdentifier(); + Object[] values= new Object[]{handle, new Integer(hitCount), Boolean.FALSE}; + setAttributes(fgTypeAndHitCountAttributes, values); + } + + /** + * Returns the <code>METHOD_HANDLE</code> attribute of the given breakpoint. + */ + public String getMethodHandleIdentifier() throws CoreException { + return (String)getAttribute(IJavaDebugConstants.METHOD_HANDLE); + } + + /** + * Returns the smallest determinable <code>IMember</code> the given breakpoint is installed in. + */ + public IMember getMember() { + int start = getCharStart(); + int end = getCharEnd(); + IType type = getBreakpointType(); + IMember member = null; + if (type != null && end >= start && start >= 0) { + try { + if (type.isBinary()) { + member= binSearch(type.getClassFile(), type, start, end); + } else { + member= binSearch(type.getCompilationUnit(), type, start, end); + } + } catch (CoreException ce) { + logError(ce); + } + } + if (member == null) { + member= type; + } + return member; + } + + /** + * Searches the given source range of the container for a member that is + * not the same as the given type. + */ + protected IMember binSearch(IClassFile container, IType type, int start, int end) throws JavaModelException { + IJavaElement je = container.getElementAt(start); + if (je != null && !je.equals(type)) { + return (IMember)je; + } + if (end > start) { + je = container.getElementAt(end); + if (je != null && !je.equals(type)) { + return (IMember)je; + } + int mid = ((end - start) / 2) + start; + if (mid > start) { + je = binSearch(container, type, start + 1, mid); + if (je == null) { + je = binSearch(container, type, mid + 1, end - 1); + } + return (IMember)je; + } + } + return null; + } + + /** + * Searches the given source range of the container for a member that is + * not the same as the given type. + */ + protected IMember binSearch(ICompilationUnit container, IType type, int start, int end) throws JavaModelException { + IJavaElement je = container.getElementAt(start); + if (je != null && !je.equals(type)) { + return (IMember)je; + } + if (end > start) { + je = container.getElementAt(end); + if (je != null && !je.equals(type)) { + return (IMember)je; + } + int mid = ((end - start) / 2) + start; + if (mid > start) { + je = binSearch(container, type, start + 1, mid); + if (je == null) { + je = binSearch(container, type, mid + 1, end - 1); + } + return (IMember)je; + } + } + return null; + } + + /** + * @see JavaBreakpoint + */ + public String getFormattedThreadText(String threadName, String typeName, boolean systemThread) { + int lineNumber= getAttribute(IMarker.LINE_NUMBER, -1); + if (lineNumber > -1) { + if (systemThread) { + return getFormattedString(LINE_BREAKPOINT_SYS, new String[] {threadName, String.valueOf(lineNumber), typeName}); + } else { + return getFormattedString(LINE_BREAKPOINT_USR, new String[] {threadName, String.valueOf(lineNumber), typeName}); + } + } + return ""; + } + + public String getMarkerText(boolean showQualified, String memberString) { + IType type= getBreakpointType(); + if (type != null) { + StringBuffer label= new StringBuffer(); + if (showQualified) { + label.append(type.getFullyQualifiedName()); + } else { + label.append(type.getElementName()); + } + int lineNumber= getLineNumber(); + if (lineNumber > 0) { + label.append(" ["); + label.append(DebugJavaUtils.getResourceString(MARKER_LABEL + LINE)); + label.append(' '); + label.append(lineNumber); + label.append(']'); + + } + int hitCount= getHitCount(); + if (hitCount > 0) { + label.append(" ["); + label.append(DebugJavaUtils.getResourceString(MARKER_LABEL + HITCOUNT)); + label.append(' '); + label.append(hitCount); + label.append(']'); + } + if (memberString != null) { + label.append(" - "); + label.append(memberString); + } + return label.toString(); + } + return ""; + } + +} +
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/MethodEntryBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/MethodEntryBreakpoint.java new file mode 100644 index 0000000..838dadc --- /dev/null +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/MethodEntryBreakpoint.java
@@ -0,0 +1,231 @@ +package org.eclipse.jdt.internal.debug.core; + +import java.util.*; + +import org.eclipse.core.resources.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.*; +import org.eclipse.jdt.core.*; +import org.eclipse.jdt.debug.core.IJavaDebugConstants; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.MethodEntryRequest; + +public class MethodEntryBreakpoint extends LineBreakpoint { + + static String fMarkerType= IJavaDebugConstants.JAVA_METHOD_ENTRY_BREAKPOINT; + + /** + * Key used to store the class name attribute pertinent to a + * specific method entry request. Used for method entry breakpoints. + */ + public final static String CLASS_NAME= "className"; + /** + * Key used to store the name and signature + * attribute pertinent to a specific method + * entry request breakpoint. Used for method entry breakpoints. + */ + public final static String BREAKPOINT_INFO= "breakpointInfo"; + + /** + * Create a method entry breakpoint on the given marker + */ + public MethodEntryBreakpoint(IMarker marker) { + fMarker= marker; + } + + /** + * Creates and returns a method entry breakpoint in the + * given method. + * If hitCount is > 0, the breakpoint will suspend execution when it is + * "hit" the specified number of times. Note: the breakpoint is not + * added to the breakpoint manager - it is merely created. + * + * @param method the method in which to suspend on entry + * @param hitCount the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @return a method entry breakpoint + * @exception DebugException if unable to create the breakpoint marker due + * to a lower level exception. + */ + public MethodEntryBreakpoint(final IMethod method, final int hitCount) throws DebugException { + IWorkspaceRunnable wr= new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + // determine the resource to associate the marker with + IResource resource= null; + resource= method.getUnderlyingResource(); + if (resource == null) { + resource= method.getJavaProject().getProject(); + } + + // create the marker + fMarker= resource.createMarker(fMarkerType); + + // find the source range if available + int start = -1; + int end = -1; + ISourceRange range = method.getSourceRange(); + if (range != null) { + start = range.getOffset(); + end = start + range.getLength() - 1; + } + // configure the standard attributes + setLineBreakpointAttributes(getPluginIdentifier(), true, -1, start, end); + // configure the type handle and hit count + setTypeAndHitCount(method.getDeclaringType(), hitCount); + + // configure the method handle + setMethod(method); + + // configure the marker as a Java marker + Map attributes= getAttributes(); + JavaCore.addJavaElementMarkerAttributes(attributes, method); + setAttributes(attributes); + } + + }; + run(wr); + } + + /** + * A method entry breakpoint has been added. + * Create or update the request. + */ + public void addToTarget(JDIDebugTarget target) { + IType type = getBreakpointType(); + if (type == null) { +// internalError(ERROR_BREAKPOINT_NO_TYPE); + return; + } + String className = type.getFullyQualifiedName(); + + MethodEntryRequest request = target.getMethodEntryRequest(className); + + if (request == null) { + try { + request= target.getEventRequestManager().createMethodEntryRequest(); + request.addClassFilter(className); + request.putProperty(CLASS_NAME, className); + request.putProperty(BREAKPOINT_INFO, new ArrayList(1)); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.putProperty(IDebugConstants.BREAKPOINT_MARKER, new ArrayList(3)); + request.putProperty(IJavaDebugConstants.HIT_COUNT, new ArrayList(3)); + } catch (VMDisconnectedException e) { + return; + } catch (RuntimeException e) { + logError(e); + return; + } + } + List breakpointInfo= (List)request.getProperty(BREAKPOINT_INFO); + breakpointInfo.add(null); + + List breakpoints= (List)request.getProperty(IDebugConstants.BREAKPOINT); + breakpoints.add(this); + + + List hitCounts = (List)request.getProperty(IJavaDebugConstants.HIT_COUNT); + int hitCount = getHitCount(); + if (hitCount > 0) { + hitCounts.add(new Integer(hitCount)); + } else { + hitCounts.add(null); + } + completeConfiguration(request); + target.installBreakpoint(this, request); + } + + /** + * A method entry breakpoint has been changed. + * Update the request. + */ + public void changeForTarget(JDIDebugTarget target) { + MethodEntryRequest request = (MethodEntryRequest)target.getRequest(this); + if (request == null) { + return; + } + // check the enabled state + updateMethodEntryEnabledState(request); + + List breakpoints= (List)request.getProperty(IDebugConstants.BREAKPOINT); + int index= breakpoints.indexOf(this); + // update the breakpoints hit count + int newCount = getHitCount(); + List hitCounts= (List)request.getProperty(IJavaDebugConstants.HIT_COUNT); + if (newCount > 0) { + hitCounts.set(index, new Integer(newCount)); + } else { + //back to a regular breakpoint + hitCounts.set(index, null); + } + } + + /** + * Update the enabled state of the request associated with this + * method entry breakpoint. Since a request is potentially associated + * with multiple method entry breakpoints, it should be enabled if + * any of them are enabled. + */ + protected void updateMethodEntryEnabledState(MethodEntryRequest request) { + IBreakpointManager manager= DebugPlugin.getDefault().getBreakpointManager(); + Iterator breakpoints= ((List)request.getProperty(IDebugConstants.BREAKPOINT)).iterator(); + boolean requestEnabled= false; + while (breakpoints.hasNext()) { + JavaBreakpoint breakpoint= (JavaBreakpoint)breakpoints.next(); + if (breakpoint.isEnabled()) { + requestEnabled = true; + break; + } + } + updateEnabledState0(request, requestEnabled); + } + + /** + * @see JavaBreakpoint#removeFromTarget(JDIDebugTarget) + */ + public void removeFromTarget(JDIDebugTarget target) { + MethodEntryRequest request = (MethodEntryRequest)target.getRequest(this); + if (request != null) { + try { + decrementInstallCount(); + } catch (CoreException e) { + logError(e); + } + List breakpoints= (List)request.getProperty(IDebugConstants.BREAKPOINT); + int index = breakpoints.indexOf(this); + breakpoints.remove(index); + if (breakpoints.isEmpty()) { + try { + target.getEventRequestManager().deleteEventRequest(request); // disable & remove + } catch (VMDisconnectedException e) { + } catch (RuntimeException e) { + logError(e); + } + } else { + List hitCounts= (List)request.getProperty(IJavaDebugConstants.HIT_COUNT); + hitCounts.remove(index); + } + } + } + + /** + * Sets the <code>METHOD_HANDLE</code> attribute of this breakpoint, associated + * with the given IMethod. + */ + public void setMethod(IMethod method) throws CoreException { + String handle = method.getHandleIdentifier(); + setMethodHandleIdentifier(handle); + } + + + /** + * Sets the <code>METHOD_HANDLE</code> attribute of this breakpoint. + */ + public void setMethodHandleIdentifier(String identifier) throws CoreException { + setAttribute(IJavaDebugConstants.METHOD_HANDLE, identifier); + } + +} +
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/RunToLineBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/RunToLineBreakpoint.java new file mode 100644 index 0000000..0d505e8 --- /dev/null +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/RunToLineBreakpoint.java
@@ -0,0 +1,61 @@ +package org.eclipse.jdt.internal.debug.core; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.debug.core.IJavaDebugConstants; + +public class RunToLineBreakpoint extends LineBreakpoint { + + // Thread label String keys + private static final String RUN_TO_LINE_SYS= THREAD_LABEL + "run_to_line_sys"; + private static final String RUN_TO_LINE_USR= THREAD_LABEL + "run_to_line_usr"; + + static String fMarkerType= IJavaDebugConstants.JAVA_RUN_TO_LINE_BREAKPOINT; + + /** + * Create a run to line breakpoint on the given marker + */ + public RunToLineBreakpoint(IMarker marker) { + fMarker= marker; + } + + /** + * Creates a run-to-line breakpoint in the + * given type, at the given line number. If a character range within the + * line is known, it may be specified by charStart/charEnd. Run-to-line + * breakpoints have a hit count of 1. + * + * @param type the type in which to create the breakpoint + * @param lineNumber the lineNumber on which the breakpoint is created - line + * numbers are 1 based, associated with the compilation unit in which + * the type is defined + * @param charStart the first character index associated with the breakpoint, + * or -1 if unspecified + * @param charEnd the last character index associated with the breakpoint, + * or -1 if unspecified + * @return a run-to-line breakpoint + * @exception DebugException if unable to create the breakpoint marker due + * to a lower level exception. + */ + public RunToLineBreakpoint(IType type, int lineNumber, int charStart, int charEnd) throws DebugException { + super(type, lineNumber, charStart, charEnd, 1, fMarkerType); + } + + /** + * @see JavaBreakpoint + */ + public String getFormattedThreadText(String threadName, String typeName, boolean systemThread) { + int lineNumber= getAttribute(IMarker.LINE_NUMBER, -1); + if (lineNumber > -1) { + if (systemThread) { + return getFormattedString(RUN_TO_LINE_SYS, new String[] {threadName, String.valueOf(lineNumber), typeName}); + } else { + return getFormattedString(RUN_TO_LINE_USR, new String[] {threadName, String.valueOf(lineNumber), typeName}); + } + } + return ""; + } + +} +
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/Watchpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/Watchpoint.java new file mode 100644 index 0000000..8b0a9ca --- /dev/null +++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/Watchpoint.java
@@ -0,0 +1,674 @@ +package org.eclipse.jdt.internal.debug.core; + +import java.text.MessageFormat; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.*; +import org.eclipse.jdt.debug.core.IJavaDebugConstants; + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; + +public class Watchpoint extends LineBreakpoint { + + // Thread label String keys + private static final String ACCESS_SYS= THREAD_LABEL + "access_sys"; + private static final String ACCESS_USR= THREAD_LABEL + "access_usr"; + private static final String MODIFICATION_SYS= THREAD_LABEL + "modification_sys"; + private static final String MODIFICATION_USR= THREAD_LABEL + "modification_usr"; + // Error String keys + private final static String PREFIX= "jdi_breakpoint."; + private final static String ERROR = PREFIX + "error."; + private final static String ERROR_ACCESS_WATCHPOINT_NOT_SUPPORTED = ERROR + "access.not_supported"; + private final static String ERROR_MODIFICATION_WATCHPOINT_NOT_SUPPORTED = ERROR + "modification.net_supported"; + // Marker label String keys + protected final static String WATCHPOINT= MARKER_LABEL + "watchpoint."; + protected final static String FORMAT= WATCHPOINT + "format"; + protected final static String ACCESS= WATCHPOINT + "access"; + protected final static String MODIFICATION= WATCHPOINT + "modification"; + protected final static String BOTH= WATCHPOINT + "both"; + + static String fMarkerType= IJavaDebugConstants.JAVA_WATCHPOINT; + + private final static int ACCESS_EVENT= 0; + private final static int MODIFICATION_EVENT= 1; + private int fLastEventType= -1; + + /** + * Create a watchpoint for the given marker + */ + public Watchpoint(IMarker marker) { + super(marker); + } + + /** + * Creates and returns a watchpoint on the + * given field. + * If hitCount > 0, the breakpoint will suspend execution when it is + * "hit" the specified number of times. Note: the breakpoint is not + * added to the breakpoint manager - it is merely created. + * + * @param field the field on which to suspend (on access or modification) + * @param hitCount the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @return a watchpoint + * @exception DebugException if unable to create the breakpoint marker due + * to a lower level exception + */ + public Watchpoint(final IField field) throws DebugException { + IWorkspaceRunnable wr= new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + IResource resource = null; + ICompilationUnit compilationUnit = getCompilationUnit(field); + if (compilationUnit != null) { + resource = compilationUnit.getUnderlyingResource(); + } + if (resource == null) { + resource = field.getJavaProject().getProject(); + } + + if (fMarker == null) { + // Only create a marker if one is not already assigned + fMarker= resource.createMarker(fMarkerType); + } + + // configure the standard attributes + setStandardAttributes(field); + // configure the type handle and hit count + setTypeAndHitCount(field.getDeclaringType(), 0); + // configure the field handle + setField(field); + // configure the access and modification flags to defaults + setDefaultAccessAndModification(); + setAutoDisabled(false); + + + // configure the marker as a Java marker + Map attributes= getAttributes(); + JavaCore.addJavaElementMarkerAttributes(attributes, field); + setAttributes(attributes); + } + }; + run(wr); + } + + /** + * @see JavaBreakpoint#installIn(JDIDebugTarget) + */ + public void addToTarget(JDIDebugTarget target) { + selectiveAdd(target, true, true); + } + + /** + * A single watchpoint can create multiple requests. This method provides control over this + * property for explicitly choosing which requests (access, modification, or both) to + * potentially add. + */ + protected void selectiveAdd(JDIDebugTarget target, boolean accessCheck, boolean modificationCheck) { + fTarget= target; + String topLevelName= getTopLevelTypeName(); + if (topLevelName == null) { +// internalError(ERROR_BREAKPOINT_NO_TYPE); + return; + } + + List classes= target.jdiClassesByName(topLevelName); + if (classes == null || classes.isEmpty()) { + // defer + target.defer(this, topLevelName); + return; + } + + IField javaField= getField(); + Field field= null; + ReferenceType reference= null; + for (int i=0; i<classes.size(); i++) { + reference= (ReferenceType) classes.get(i); + field= reference.fieldByName(javaField.getElementName()); + if (field == null) { + return; + } + AccessWatchpointRequest accessRequest= null; + ModificationWatchpointRequest modificationRequest= null; + // If we're not supposed to check access or modification, just retrieve the + // existing request + if (!accessCheck) { + accessRequest= target.getAccessWatchpointRequest(field); + } + if (!modificationCheck) { + modificationRequest= target.getModificationWatchpointRequest(field); + } + if (isAccess() && accessCheck) { + if (accessSupportedBy(target.getVM())) { + accessRequest= accessWatchpointAdded(target, field); + } else { + notSupported(ERROR_ACCESS_WATCHPOINT_NOT_SUPPORTED); + } + } + if (isModification() && modificationCheck) { + if (modificationSupportedBy(target.getVM())) { + modificationRequest= modificationWatchpointAdded(target, field); + } else { + notSupported(ERROR_MODIFICATION_WATCHPOINT_NOT_SUPPORTED); + } + } + if (!(accessRequest == null && modificationRequest == null)) { + Object[] requests= {accessRequest, modificationRequest}; + target.installBreakpoint(this, requests); + try { + incrementInstallCount(); + } catch (CoreException e) { + target.internalError(e); + } + } + } + } + + /** + * Returns whether this kind of breakpoint is supported by the given + * virtual machine. A watchpoint is supported if both access and + * modification watchpoints are supported. + */ + public boolean isSupportedBy(VirtualMachine vm) { + return (modificationSupportedBy(vm) && accessSupportedBy(vm)); + } + + /** + * Returns whether the given virtual machine supports modification watchpoints + */ + public boolean modificationSupportedBy(VirtualMachine vm) { + return vm.canWatchFieldModification(); + } + + /** + * Returns whether the given virtual machine supports access watchpoints + */ + public boolean accessSupportedBy(VirtualMachine vm) { + return vm.canWatchFieldAccess(); + } + + /** + * This watchpoint is not supported for some reason. Alert the user. + */ + protected void notSupported(String error_key) { + } + + /** + * An access watchpoint has been added. + * Create or update the request. + */ + protected AccessWatchpointRequest accessWatchpointAdded(JDIDebugTarget target, Field field) { + AccessWatchpointRequest request= target.getAccessWatchpointRequest(field); + if (request == null) { + request= createAccessWatchpoint(target, field); + } + // Important: Enable only after request has been configured + request.setEnabled(isEnabled()); + return request; + } + + /** + * Create an access watchpoint for the given breakpoint and associated field + */ + protected AccessWatchpointRequest createAccessWatchpoint(JDIDebugTarget target, Field field) { + AccessWatchpointRequest request= null; + try { + request= target.getEventRequestManager().createAccessWatchpointRequest(field); + configureRequest(request); + } catch (VMDisconnectedException e) { + return null; + } catch (RuntimeException e) { + target.internalError(e); + return null; + } + return request; + } + + /** + * A modification watchpoint has been added. + * Create or update the request. + */ + protected ModificationWatchpointRequest modificationWatchpointAdded(JDIDebugTarget target, Field field) { + ModificationWatchpointRequest request= target.getModificationWatchpointRequest(field); + if (request == null) { + request= createModificationWatchpoint(target, field); + } + // Important: only enable a request after it has been configured + request.setEnabled(isEnabled()); + return request; + } + + /** + * Create a modification watchpoint for the given breakpoint and associated field + */ + protected ModificationWatchpointRequest createModificationWatchpoint(JDIDebugTarget target, Field field) { + ModificationWatchpointRequest request= null; + try { + request= target.getEventRequestManager().createModificationWatchpointRequest(field); + configureRequest(request); + } catch (VMDisconnectedException e) { + return null; + } catch (RuntimeException e) { + target.internalError(e); + return null; + } + return request; + } + + /** + * A watchpoint has been changed. + * Update the request. + */ + public void changeForTarget(JDIDebugTarget target) { + Object[] requests= (Object[])target.getRequest(this); + for (int i=0; i < requests.length; i++) { + WatchpointRequest request= (WatchpointRequest)requests[i]; + if (request == null) { + if ((i == 0) && isAccess()) { + selectiveAdd(target, true, false); + } + if ((i == 1) && isModification()) { + selectiveAdd(target, false, true); + } + continue; + } + if ((!isAccess() && (request instanceof AccessWatchpointRequest)) || + (!isModification() && (request instanceof ModificationWatchpointRequest))) { + target.getEventRequestManager().deleteEventRequest(request); // disable & remove + continue; + } + request= (WatchpointRequest)updateHitCount(request, target); + + if (request != null) { + updateEnabledState(request); + requests[i]= request; + } + } + } + + /** + * Update the hit count of an <code>EventRequest</code>. Return a new request with + * the appropriate settings. + */ + protected EventRequest updateHitCount(EventRequest request, JDIDebugTarget target) { + + // if the hit count has changed, or the request has expired and is being re-enabled, + // create a new request + if (hasHitCountChanged(request) || (isExpired(request) && this.isEnabled())) { + try { + // delete old request + //on JDK you cannot delete (disable) an event request that has hit its count filter + if (!isExpired(request)) { + target.getEventRequestManager().deleteEventRequest(request); // disable & remove + } + Field field= ((WatchpointRequest) request).field(); + if (request instanceof AccessWatchpointRequest) { + request= createAccessWatchpoint(target, field); + } else if (request instanceof ModificationWatchpointRequest) { + request= createModificationWatchpoint(target, field); + } + } catch (VMDisconnectedException e) { + } catch (RuntimeException e) { + logError(e); + } + } + return request; + } + + /** + * @see JavaBreakpoint#removeFromTarget(JDIDebugTarget) + */ + public void removeFromTarget(JDIDebugTarget target) { + Object[] requests= (Object[]) target.getRequest(this); + if (requests == null) { + //deferred breakpoint + if (!this.exists()) { + //resource no longer exists + return; + } + String name= getTopLevelTypeName(); + if (name == null) { +// internalError(ERROR_BREAKPOINT_NO_TYPE); + return; + } + List breakpoints= (List) target.getDeferredBreakpointsByClass(name); + if (breakpoints == null) { + return; + } + + breakpoints.remove(this); + if (breakpoints.isEmpty()) { + target.removeDeferredBreakpointByClass(name); + } + } else { + //installed breakpoint + try { + for (int i=0; i<requests.length; i++) { + WatchpointRequest request= (WatchpointRequest)requests[i]; + if (request == null) { + continue; + } + target.getEventRequestManager().deleteEventRequest(request); // disable & remove + } + try { + decrementInstallCount(); + } catch (CoreException e) { + fTarget= null; + logError(e); + } + } catch (VMDisconnectedException e) { + fTarget= null; + return; + } catch (RuntimeException e) { + fTarget= null; + logError(e); + } + } + fTarget= null; + } + + /** + * Enable this watchpoint. + * + * If the watchpoint is not watching access or modification, + * set the default values. If this isn't done, the resulting + * state (enabled with access and modification both disabled) + * is ambiguous. + */ + public void enable() { + if (!(isAccess() || isModification())) { + setDefaultAccessAndModification(); + } + super.enable(); + } + + /** + * Returns whether this watchpoint is an access watchpoint + */ + public boolean isAccess() { + return getAttribute(IJavaDebugConstants.ACCESS, false); + } + + /** + * Toggle the access attribute of this watchpoint + */ + public void toggleAccess() { + setAccess(!isAccess()); + } + + /** + * Sets the access attribute of this watchpoint. If access is set to true + * and the watchpoint is disabled, enable the watchpoint. If both access and + * modification are false, disable the watchpoint. + */ + public void setAccess(boolean access) { + if (access == isAccess()) { + return; + } + try { + setAttribute(IJavaDebugConstants.ACCESS, access); + if (access && !isEnabled()) { + enable(); + } else if (!(access || isModification())) { + disable(); + } + } catch (CoreException ce) { + logError(ce); + } + if (fTarget != null) { + // Notify the target that this watchpoint has changed + changeForTarget(fTarget); + } + } + + /** + * Returns whether this watchpoint is a modification watchpoint + */ + public boolean isModification() { + return getAttribute(IJavaDebugConstants.MODIFICATION, false); + } + + /** + * Toggle the modification attribute of this watchpoint + */ + public void toggleModification() { + setModification(!isModification()); + } + + /** + * Sets the modification attribute of this watchpoint. If modification is set to true + * and the watchpoint is disabled, enable the watchpoint. If both access and + * modification are false, disable the watchpoint. + */ + public void setModification(boolean modification) { + if (modification == isModification()) { + return; + } + try { + setAttribute(IJavaDebugConstants.MODIFICATION, modification); + if (modification && !isEnabled()) { + enable(); + } else if (!(modification || isAccess())) { + disable(); + } + } catch (CoreException ce) { + logError(ce); + } + if (fTarget != null) { + // Notify the target that this watchpoint has changed + changeForTarget(fTarget); + } + } + + /** + * Sets the default access and modification attributes of the watchpoint. + * The default values are: + * <ul> + * <li>access = <code>false</code> + * <li>modification = <code>true</code> + * <ul> + */ + public void setDefaultAccessAndModification() { + Object[] values= new Object[]{Boolean.FALSE, Boolean.TRUE}; + String[] attributes= new String[]{IJavaDebugConstants.ACCESS, IJavaDebugConstants.MODIFICATION}; + try { + setAttributes(attributes, values); + } catch (CoreException ce) { + logError(ce); + } + } + + /** + * Sets the <code>FIELD_HANDLE</code> attribute of the given breakpoint, associated + * with the given IField. + */ + public void setField(IField field) throws CoreException { + String handle = field.getHandleIdentifier(); + setFieldHandleIdentifier(handle); + } + + /** + * Sets the <code>FIELD_HANDLE</code> attribute of the given breakpoint. + */ + public void setFieldHandleIdentifier(String handle) throws CoreException { + setAttribute(IJavaDebugConstants.FIELD_HANDLE, handle); + } + + /** + * Set standard attributes of a watchpoint + */ + public void setStandardAttributes(IField field) throws CoreException { + // find the source range if available + int start = -1; + int stop = -1; + ISourceRange range = field.getSourceRange(); + if (range != null) { + start = range.getOffset(); + stop = start + range.getLength() - 1; + } + super.setLineBreakpointAttributes(getPluginIdentifier(), true, -1, start, stop); + } + + /** + * Sets the <code>AUTO_DISABLED</code> attribute of the given breakpoint. + */ + public void setAutoDisabled(boolean autoDisabled) throws CoreException { + setAttribute(IJavaDebugConstants.AUTO_DISABLED, autoDisabled); + } + + /** + * Returns the underlying compilation unit of an element. + */ + public static ICompilationUnit getCompilationUnit(IJavaElement element) { + if (element instanceof IWorkingCopy) { + return (ICompilationUnit) ((IWorkingCopy) element).getOriginalElement(); + } + if (element instanceof ICompilationUnit) { + return (ICompilationUnit) element; + } + IJavaElement parent = element.getParent(); + if (parent != null) { + return getCompilationUnit(parent); + } + return null; + } + + /** + * Generate the field associated with the given marker + */ + public IField getField(IMarker marker) { + String handle= getFieldHandleIdentifier(marker); + if (handle != null && handle != "") { + return (IField)JavaCore.create(handle); + } + return null; + } + + /** + * Generate the field associated with this watchpoint + */ + public IField getField() { + String handle= getFieldHandleIdentifier(); + if (handle != null && handle != "") { + return (IField)JavaCore.create(handle); + } + return null; + } + + /** + * Returns the <code>FIELD_HANDLE</code> attribute of the given marker. + */ + public String getFieldHandleIdentifier(IMarker marker) { + String handle; + try { + handle= (String)marker.getAttribute(IJavaDebugConstants.FIELD_HANDLE); + } catch (CoreException ce) { + handle= ""; + logError(ce); + } + return handle; + } + + /** + * Returns the <code>FIELD_HANDLE</code> attribute of this watchpoint. + */ + public String getFieldHandleIdentifier() { + String handle; + try { + handle= (String)getAttribute(IJavaDebugConstants.FIELD_HANDLE); + } catch (CoreException ce) { + handle= ""; + logError(ce); + } + return handle; + } + + /** + * @see JavaBreakpoint + */ + public String getFormattedThreadText(String threadName, String typeName, boolean systemThread) { + String fieldName= getField().getElementName(); + if (fLastEventType == ACCESS_EVENT) { + if (systemThread) { + return getFormattedString(ACCESS_SYS, new String[] {threadName, fieldName, typeName}); + } else { + return getFormattedString(ACCESS_USR, new String[] {threadName, fieldName, typeName}); + } + } else if (fLastEventType == MODIFICATION_EVENT) { + // modification + if (systemThread) { + return getFormattedString(MODIFICATION_SYS, new String[] {threadName, fieldName, typeName}); + } else { + return getFormattedString(MODIFICATION_USR, new String[] {threadName, fieldName, typeName}); + } + } + return ""; + } + + public String getMarkerText(boolean qualified, String memberString) { + String lineInfo= super.getMarkerText(qualified, memberString); + + String state= null; + boolean access= isAccess(); + boolean modification= isModification(); + if (access && modification) { + state= BOTH; + } else if (access) { + state= ACCESS; + } else if (modification) { + state= MODIFICATION; + } + String label= null; + if (state == null) { + label= lineInfo; + } else { + String format= DebugJavaUtils.getResourceString(FORMAT); + state= DebugJavaUtils.getResourceString(state); + label= MessageFormat.format(format, new Object[] {state, lineInfo}); + } + return label; + } + + /** + * Store the type of the event, then handle it as specified in + * the superclass. This is useful for correctly generating the + * thread text when asked (assumes thread text is requested after + * the event is passed to this breakpoint. + * + * Also, @see JavaBreakpoint#handleEvent(Event) + */ + public void handleEvent(Event event, JDIDebugTarget target) { + if (event instanceof AccessWatchpointEvent) { + fLastEventType= ACCESS_EVENT; + } else if (event instanceof ModificationWatchpointEvent) { + fLastEventType= MODIFICATION_EVENT; + } + super.handleEvent(event, target); + } + + /** + * Returns the <code>HIT_COUNT</code> attribute of the given breakpoint + * or -1 if the attribute is not set. + */ + public int getHitCount() { + return getAttribute(IJavaDebugConstants.HIT_COUNT, -1); + } + + /** + * Sets the <code>HIT_COUNT</code> attribute of the given breakpoint, + * and resets the <code>EXPIRED</code> attribute to false (since, if + * the hit count is changed, the breakpoint should no longer be expired). + */ + public void setHitCount(int count) throws CoreException { + setAttributes(new String[]{IJavaDebugConstants.HIT_COUNT, IJavaDebugConstants.EXPIRED}, + new Object[]{new Integer(count), Boolean.FALSE}); + } + +} +
diff --git a/org.eclipse.jdt.debug/plugin.xml b/org.eclipse.jdt.debug/plugin.xml index d6cc702..fc7a07b 100644 --- a/org.eclipse.jdt.debug/plugin.xml +++ b/org.eclipse.jdt.debug/plugin.xml
@@ -27,17 +27,30 @@ <!-- Extensions --> <!-- Extension points --> <extension - id="javaLineBreakpoint" - point="org.eclipse.core.resources.markers"> - <super - type="org.eclipse.debug.core.lineBreakpoint"> - </super> + id="javaBreakpoint" + point="org.eclipse.core.resources.markers"> + <super + type="org.eclipse.debug.core.breakpoint"> + </super> <persistent value="true"> </persistent> <attribute name="typeHandle"> - </attribute> + </attribute> +</extension> +<extension + id="javaLineBreakpoint" + point="org.eclipse.core.resources.markers"> + <super + type="org.eclipse.jdt.debug.javaBreakpoint"> + </super> + <super + type="org.eclipse.debug.core.lineBreakpoint"> + </super> + <persistent + value="true"> + </persistent> <attribute name="installCount"> </attribute> @@ -62,14 +75,11 @@ id="javaExceptionBreakpoint" point="org.eclipse.core.resources.markers"> <super - type="org.eclipse.debug.core.breakpoint"> + type="org.eclipse.jdt.debug.javaBreakpoint"> </super> <persistent value="true"> - </persistent> - <attribute - name="typeHandle"> - </attribute> + </persistent> <attribute name="caught"> </attribute> @@ -86,9 +96,9 @@ <super type="org.eclipse.jdt.debug.javaLineBreakpoint"> </super> - <persistent - value="true"> - </persistent> + <persistent + value="true"> + </persistent> <attribute name="fieldHandle"> </attribute> @@ -115,4 +125,10 @@ name="methodHandle"> </attribute> </extension> +<extension point = "org.eclipse.debug.core.breakpoint_factories"> +<breakpoint_factory + id="org.eclipse.jdt.core.JavaBreakpointFactory" + class="org.eclipse.jdt.internal.debug.core.JavaBreakpointFactory" + type="org.eclipse.jdt.debug.javaBreakpoint"/> +</extension> </plugin>