blob: 272708fe188899bd03eb3a6cc7fb5edce09cb016 [file] [log] [blame]
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.IJavaLineBreakpoint;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
public class JavaLineBreakpoint extends AbstractJavaLineBreakpoint implements IJavaLineBreakpoint {
/**
* Java line breakpoint marker type
* (value <code>"org.eclipse.jdt.debug.javaLineBreakpointMarker"</code>).
*/
private static final String JAVA_LINE_BREAKPOINT = "org.eclipse.jdt.debug.javaLineBreakpointMarker"; //$NON-NLS-1$
/**
* Sets of attributes used to configure a line breakpoint
*/
protected static final String[] fgTypeAndHitCountAttributes= new String[]{TYPE_HANDLE, HIT_COUNT, EXPIRED};
public JavaLineBreakpoint() {
}
public JavaLineBreakpoint(IType type, int lineNumber, int charStart, int charEnd, int hitCount) throws DebugException {
this(type, lineNumber, charStart, charEnd, hitCount, JAVA_LINE_BREAKPOINT);
}
public JavaLineBreakpoint(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= getResource(type);
// 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
IMarker marker = ensureMarker();
Map attributes= marker.getAttributes();
JavaCore.addJavaElementMarkerAttributes(attributes, type);
marker.setAttributes(attributes);
// Lastly, add the breakpoint manager
addToBreakpointManager();
}
};
run(wr);
}
public static String getMarkerType() {
return JAVA_LINE_BREAKPOINT;
}
/**
* Get the resource associated with the given type. This is
* used to set the breakpoint's resource during initialization.
*/
protected IResource getResource(IType type) throws CoreException {
IResource resource= null;
resource= type.getUnderlyingResource();
if (resource == null) {
resource= type.getJavaProject().getProject();
}
return resource;
}
/**
* Creates the event requests to:<ul>
* <li>Listen to class loads related to the breakpoint</li>
* <li>Respond to the breakpoint being hti</li>
* </ul>
*/
protected void addToTarget(JDIDebugTarget target) throws CoreException {
String topLevelName= getTopLevelTypeName();
if (topLevelName == null) {
return;
}
// create request to listen to class loads
registerRequest(target, target.createClassPrepareRequest(topLevelName));
// create breakpoint requests for each class currently loaded
List classes= target.jdiClassesByName(topLevelName);
if (!classes.isEmpty()) {
Iterator iter = classes.iterator();
while (iter.hasNext()) {
ReferenceType type= (ReferenceType) iter.next();
createRequest(target, type);
}
}
}
/**
* 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
JDIDebugPlugin.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
JDIDebugPlugin.logError(e);
return null;
}
while (nestedTypes.hasNext()) {
ReferenceType nestedType= (ReferenceType) nestedTypes.next();
Location innerLocation= determineLocation(lineNumber, nestedType);
if (innerLocation != null) {
return innerLocation;
}
}
}
return null;
}
/**
* 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};
ensureMarker().setAttributes(fgTypeAndHitCountAttributes, values);
}
/**
* 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;
}
}