blob: 09740f00a718a067faa3c0691a11c758cf4f902a [file] [log] [blame]
package org.eclipse.dltk.internal.debug.core.model;
import java.util.Map;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.dltk.debug.core.DLTKDebugPlugin;
import org.eclipse.dltk.debug.core.model.IScriptExceptionBreakpoint;
public class ScriptExceptionBreakpoint extends AbstractScriptBreakpoint
implements IScriptExceptionBreakpoint {
private static final String SCRIPT_EXCEPTION_BREAKPOINT = "org.eclipse.dltk.debug.scriptExceptionBreakpointMarker"; //$NON-NLS-1$
/**
* Breakpoint attribute storing the fully qualified name of the type this
* breakpoint is located in. (value
* <code>"org.eclipse.jdt.debug.core.typeName"</code>). This attribute is a
* <code>String</code>.
*/
protected static final String TYPE_NAME = DLTKDebugPlugin.PLUGIN_ID
+ ".typeName"; //$NON-NLS-1$
/**
* Exception breakpoint attribute storing the suspend on caught value (value
* <code>"org.eclipse.dltk.debug.core.caught"</code>). This attribute is
* stored as a <code>boolean</code>. When this attribute is
* <code>true</code>, a caught exception of the associated type will cause
* excecution to suspend .
*/
protected static final String CAUGHT = DLTKDebugPlugin.PLUGIN_ID
+ ".caught"; //$NON-NLS-1$
/**
* Exception breakpoint attribute storing the suspend on uncaught value
* (value <code>"org.eclipse.dltk.debug.core.uncaught"</code>). This
* attribute is stored as a <code>boolean</code>. When this attribute is
* <code>true</code>, an uncaught exception of the associated type will
* cause excecution to suspend.
*/
protected static final String UNCAUGHT = DLTKDebugPlugin.PLUGIN_ID
+ ".uncaught"; //$NON-NLS-1$
/**
* Allows the user to specify whether we should suspend if subclasses of the
* specified exception are thrown/caught
*/
protected static final String SUSPEND_ON_SUBCLASSES = DLTKDebugPlugin.PLUGIN_ID
+ ".suspend_on_subclasses"; //$NON-NLS-1$
/**
* Name of the exception that was actually hit (could be a subtype of the
* type that is being caught).
*/
protected String fExceptionName = null;
public ScriptExceptionBreakpoint() {
}
/**
* Creates and returns an exception breakpoint for the given 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.
*
* @param resource
* the resource on which to create the associated
* breakpoint marker
* @param exceptionName
* the fully qualified name of 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
* @param add
* whether to add this breakpoint to the breakpoint
* manager
* @return a Java exception breakpoint
* @exception DebugException
* if unable to create the associated marker
* due to a lower level exception.
*/
public ScriptExceptionBreakpoint(final String debugModelId,
final IResource resource, final String exceptionName,
final boolean caught, final boolean uncaught, final boolean add,
final Map<String, Object> attributes) throws DebugException {
IWorkspaceRunnable wr = monitor -> {
// create the marker
setMarker(resource.createMarker(SCRIPT_EXCEPTION_BREAKPOINT));
// add general breakpoint attributes
addScriptBreakpointAttributes(attributes, debugModelId, true);
// add exception breakpoint attributes
attributes.put(TYPE_NAME, exceptionName);
attributes.put(CAUGHT, Boolean.valueOf(caught));
attributes.put(UNCAUGHT, Boolean.valueOf(uncaught));
ensureMarker().setAttributes(attributes);
register(add);
};
run(getMarkerRule(resource), wr);
}
/**
* Enable this exception breakpoint.
*
* If the exception breakpoint is not catching caught or uncaught, turn both
* modes on. If this isn't done, the resulting state (enabled with caught
* and uncaught both disabled) is ambiguous.
*/
@Override
public void setEnabled(boolean enabled) throws CoreException {
if (enabled) {
if (!(isCaught() || isUncaught())) {
setAttributes(new String[] { CAUGHT, UNCAUGHT },
new Object[] { Boolean.TRUE, Boolean.TRUE });
}
}
super.setEnabled(enabled);
}
@Override
public boolean isCaught() throws CoreException {
return ensureMarker().getAttribute(CAUGHT, false);
}
@Override
public void setCaught(boolean caught) throws CoreException {
if (caught == isCaught()) {
return;
}
setAttribute(CAUGHT, caught);
if (caught && !isEnabled()) {
setEnabled(true);
} else if (!(caught || isUncaught())) {
setEnabled(false);
}
}
@Override
public void setSuspendOnSubclasses(boolean suspend) throws CoreException {
if (suspend != isSuspendOnSubclasses()) {
setAttribute(SUSPEND_ON_SUBCLASSES, suspend);
}
}
@Override
public boolean isSuspendOnSubclasses() throws CoreException {
return ensureMarker().getAttribute(SUSPEND_ON_SUBCLASSES, false);
}
@Override
public boolean isUncaught() throws CoreException {
return ensureMarker().getAttribute(UNCAUGHT, false);
}
@Override
public void setUncaught(boolean uncaught) throws CoreException {
if (uncaught == isUncaught()) {
return;
}
setAttribute(UNCAUGHT, uncaught);
if (uncaught && !isEnabled()) {
setEnabled(true);
} else if (!(uncaught || isCaught())) {
setEnabled(false);
}
}
/**
* Sets the name of the exception that was last hit
*
* @param name
* fully qualified exception name
*/
protected void setExceptionTypeName(String name) {
fExceptionName = name;
}
@Override
public String getExceptionTypeName() {
return fExceptionName;
}
private static final String[] UPDATABLE_ATTRS = new String[] {
IBreakpoint.ENABLED, AbstractScriptBreakpoint.HIT_CONDITION,
AbstractScriptBreakpoint.HIT_VALUE, CAUGHT, UNCAUGHT,
SUSPEND_ON_SUBCLASSES };
@Override
public String[] getUpdatableAttributes() {
return UPDATABLE_ATTRS;
}
@Override
public String getTypeName() throws CoreException {
return (String) ensureMarker().getAttribute(TYPE_NAME);
}
}