blob: 96572cdb9ee36c99b31a4096376e1502bb0b4525 [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.internal.debug.core.IJavaDebugConstants;
import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
public abstract class AbstractJavaLineBreakpoint extends JavaBreakpoint {
// Marker label String keys
private static final String LINE= "line"; //$NON-NLS-1$
private static final String HITCOUNT= "hitCount"; //$NON-NLS-1$
/**
* Sets of attributes used to configure a line breakpoint
*/
protected static final String[] fgLineBreakpointAttributes= new String[]{IDebugConstants.ENABLED, IMarker.LINE_NUMBER, IMarker.CHAR_START, IMarker.CHAR_END};
public AbstractJavaLineBreakpoint() {
super();
}
/**
* @see ILineBreakpoint
*/
public int getLineNumber() throws CoreException {
return ensureMarker().getAttribute(IMarker.LINE_NUMBER, -1);
}
/**
* @see ILineBreakpoint
*/
public int getCharStart() throws CoreException {
return ensureMarker().getAttribute(IMarker.CHAR_START, -1);
}
/**
* @see ILineBreakpoint
*/
public int getCharEnd() throws CoreException {
return ensureMarker().getAttribute(IMarker.CHAR_END, -1);
}
/**
* @see IJavaLineBreakpoint#addToTarget(JDIDebugTarget)
*/
protected abstract void addToTarget(JDIDebugTarget target) throws CoreException;
/**
* Installs a line breakpoint in the given type, returning whether successful.
*/
protected void createRequest(JDIDebugTarget target, ReferenceType type) throws CoreException {
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;
}
EventRequest request = createLineBreakpointRequest(location, target);
registerRequest(target, request);
}
/**
* Creates, installs, and returns a line breakpoint request at
* the given location for the given breakpoint.
*/
protected BreakpointRequest createLineBreakpointRequest(Location location, JDIDebugTarget target) throws CoreException {
BreakpointRequest request = null;
try {
request= target.getEventRequestManager().createBreakpointRequest(location);
configureRequest(request);
} catch (VMDisconnectedException e) {
return null;
} catch (RuntimeException e) {
logError(e);
return null;
}
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;
}
/**
* Update the hit count of an <code>EventRequest</code>. Return a new request with
* the appropriate settings.
*/
protected EventRequest updateHitCount(EventRequest request, JDIDebugTarget target) throws CoreException {
// 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) && isEnabled())) {
try {
Location location = ((BreakpointRequest) request).location();
// 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
}
request = createLineBreakpointRequest(location, target);
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
logError(e);
}
}
return request;
}
/**
* 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>
* <li><code>IDebugConstants.ENABLED</code></li>
* </ul>
* and sets the suspend policy of the request to suspend
* the event thread.
*/
protected void configureRequest(EventRequest request) throws CoreException {
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.putProperty(JDIDebugPlugin.JAVA_BREAKPOINT_PROPERTY, this);
int hitCount= getHitCount();
if (hitCount > 0) {
request.addCountFilter(hitCount);
request.putProperty(IJavaDebugConstants.HIT_COUNT, new Integer(hitCount));
request.putProperty(IJavaDebugConstants.EXPIRED, Boolean.FALSE);
}
// Important: only enable a request after it has been configured
updateEnabledState(request);
}
/**
* @see JavaBreakpoint#isSupportedBy(VirtualMachine)
*/
public boolean isSupportedBy(VirtualMachine vm) {
return true;
}
/**
* Set standard attributes of a line breakpoint.
* The standard attributes are:
* <ol>
* <li>IDebugConstants.MODEL_IDENTIFIER</li>
* <li>IDebugConstants.ENABLED</li>
* <li>IMarker.LINE_NUMBER</li>
* <li>IMarker.CHAR_START</li>
* <li>IMarker.CHAR_END</li>
* <li>IJavaDebugConstants.CONDITION</li>
*/
public void setLineBreakpointAttributes(String modelIdentifier, boolean enabled, int lineNumber, int charStart, int charEnd) throws CoreException {
Object[] values= new Object[]{new Boolean(true), new Integer(lineNumber), new Integer(charStart), new Integer(charEnd)};
ensureMarker().setAttributes(fgLineBreakpointAttributes, values);
}
/**
* Returns the <code>METHOD_HANDLE</code> attribute of the given breakpoint.
*/
public String getMethodHandleIdentifier() throws CoreException {
return (String) ensureMarker().getAttribute(IJavaDebugConstants.METHOD_HANDLE);
}
/**
* @see IJavaLineBreakpoint#getMember()
*/
public IMember getMember() throws CoreException {
int start = getCharStart();
int end = getCharEnd();
IType type = getType();
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;
}
}