| /******************************************************************************* |
| * Copyright (c) 2000, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.debug.core.breakpoints; |
| |
| |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspaceRunnable; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.core.DebugEvent; |
| import org.eclipse.debug.core.DebugException; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.IStatusHandler; |
| import org.eclipse.debug.core.model.IBreakpoint; |
| import org.eclipse.debug.core.model.IDebugTarget; |
| import org.eclipse.debug.core.model.ISourceLocator; |
| import org.eclipse.debug.core.model.IValue; |
| import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.dom.Message; |
| import org.eclipse.jdt.debug.core.IJavaDebugTarget; |
| import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; |
| import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; |
| import org.eclipse.jdt.debug.core.IJavaType; |
| import org.eclipse.jdt.debug.core.JDIDebugModel; |
| import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; |
| import org.eclipse.jdt.debug.eval.ICompiledExpression; |
| import org.eclipse.jdt.debug.eval.IEvaluationListener; |
| import org.eclipse.jdt.debug.eval.IEvaluationResult; |
| import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; |
| import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; |
| import org.eclipse.jdt.internal.debug.core.model.JDIReferenceType; |
| import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame; |
| import org.eclipse.jdt.internal.debug.core.model.JDIThread; |
| |
| import com.sun.jdi.AbsentInformationException; |
| import com.sun.jdi.ClassNotPreparedException; |
| import com.sun.jdi.InvalidLineNumberException; |
| import com.sun.jdi.Location; |
| import com.sun.jdi.NativeMethodException; |
| import com.sun.jdi.ObjectReference; |
| import com.sun.jdi.ReferenceType; |
| import com.sun.jdi.ThreadReference; |
| import com.sun.jdi.VMDisconnectedException; |
| import com.sun.jdi.event.Event; |
| import com.sun.jdi.request.BreakpointRequest; |
| import com.sun.jdi.request.EventRequest; |
| import com.sun.jdi.request.EventRequestManager; |
| |
| public class JavaLineBreakpoint extends JavaBreakpoint implements IJavaLineBreakpoint { |
| |
| /** |
| * Breakpoint attribute storing a breakpoint's conditional expression |
| * (value <code>"org.eclipse.jdt.debug.core.condition"</code>). This attribute is stored as a |
| * <code>String</code>. |
| */ |
| protected static final String CONDITION= "org.eclipse.jdt.debug.core.condition"; //$NON-NLS-1$ |
| /** |
| * Breakpoint attribute storing a breakpoint's condition enablement |
| * (value <code>"org.eclipse.jdt.debug.core.conditionEnabled"</code>). This attribute is stored as an |
| * <code>boolean</code>. |
| */ |
| protected static final String CONDITION_ENABLED= "org.eclipse.jdt.debug.core.conditionEnabled"; //$NON-NLS-1$ |
| |
| /** |
| * Breakpoint attribute storing a breakpoint's condition suspend policy |
| * (value <code>" org.eclipse.jdt.debug.core.conditionSuspendOnTrue" |
| * </code>). This attribute is stored as an <code>boolean</code>. |
| */ |
| protected static final String CONDITION_SUSPEND_ON_TRUE= "org.eclipse.jdt.debug.core.conditionSuspendOnTrue"; //$NON-NLS-1$ |
| |
| /** |
| * Breakpoint attribute storing a breakpoint's source file name (debug attribute) |
| * (value <code>"org.eclipse.jdt.debug.core.sourceName"</code>). This attribute is stored as |
| * a <code>String</code>. |
| */ |
| protected static final String SOURCE_NAME= "org.eclipse.jdt.debug.core.sourceName"; //$NON-NLS-1$ |
| |
| private static final String JAVA_LINE_BREAKPOINT = "org.eclipse.jdt.debug.javaLineBreakpointMarker"; //$NON-NLS-1$ |
| |
| /** |
| * Maps suspended threads to the suspend event that suspended them |
| */ |
| private Map fSuspendEvents= new HashMap(); |
| /** |
| * The map of cached compiled expressions (ICompiledExpression) for this breakpoint, keyed by thread. |
| * This value must be cleared everytime the breakpoint is added to a target. |
| */ |
| private Map fCompiledExpressions= new HashMap(); |
| |
| /** |
| * Cache of projects for stack frames to avoid repetitive porject resolution on conditional |
| * breakpoints. |
| */ |
| private Map fProjectsByFrame= new HashMap(); |
| |
| /** |
| * The map of the result value of the condition (IValue) for this |
| * breakpoint, keyed by debug target. |
| */ |
| private Map fConditionValues= new HashMap(); |
| |
| /** |
| * Status code indicating that a request to create a breakpoint in a type |
| * with no line number attributes has occurred. |
| */ |
| public static final int NO_LINE_NUMBERS= 162; |
| |
| public JavaLineBreakpoint() { |
| } |
| |
| /** |
| * @see JDIDebugModel#createLineBreakpoint(IResource, String, int, int, int, int, boolean, Map) |
| */ |
| public JavaLineBreakpoint(IResource resource, String typeName, int lineNumber, int charStart, int charEnd, int hitCount, boolean add, Map attributes) throws DebugException { |
| this(resource, typeName, lineNumber, charStart, charEnd, hitCount, add, attributes, JAVA_LINE_BREAKPOINT); |
| } |
| |
| protected JavaLineBreakpoint(final IResource resource, final String typeName, final int lineNumber, final int charStart, final int charEnd, final int hitCount, final boolean add, final Map attributes, final String markerType) throws DebugException { |
| IWorkspaceRunnable wr= new IWorkspaceRunnable() { |
| public void run(IProgressMonitor monitor) throws CoreException { |
| |
| // create the marker |
| setMarker(resource.createMarker(markerType)); |
| |
| // add attributes |
| addLineBreakpointAttributes(attributes, getModelIdentifier(), true, lineNumber, charStart, charEnd); |
| addTypeNameAndHitCount(attributes, typeName, hitCount); |
| // set attributes |
| ensureMarker().setAttributes(attributes); |
| |
| // add to breakpoint manager if requested |
| register(add); |
| } |
| }; |
| run(getMarkerRule(resource), wr); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#addToTarget(org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) |
| */ |
| public void addToTarget(JDIDebugTarget target) throws CoreException { |
| clearCachedExpressionFor(target); |
| super.addToTarget(target); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#removeFromTarget(org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) |
| */ |
| public void removeFromTarget(JDIDebugTarget target) throws CoreException { |
| clearCachedExpressionFor(target); |
| clearCachedSuspendEvents(target); |
| fConditionValues.remove(target); |
| super.removeFromTarget(target); |
| } |
| |
| /** |
| * Removes all suspend events which are currently |
| * being cached for threads in the given target. |
| */ |
| protected void clearCachedSuspendEvents(JDIDebugTarget target) { |
| removeCachedThreads(fSuspendEvents, target); |
| } |
| |
| private void removeCachedThreads(Map map, JDIDebugTarget target) { |
| Set threads= map.keySet(); |
| List threadsToRemove= new ArrayList(); |
| Iterator iter= threads.iterator(); |
| JDIThread thread; |
| while (iter.hasNext()) { |
| thread= (JDIThread)iter.next(); |
| if (thread.getDebugTarget() == target) { |
| threadsToRemove.add(thread); |
| } |
| } |
| iter= threadsToRemove.iterator(); |
| while (iter.hasNext()) { |
| map.remove(iter.next()); |
| } |
| } |
| |
| /** |
| * Removes all compiled expressions which are currently |
| * being cached for threads in the given target. |
| */ |
| protected void clearCachedExpressionFor(JDIDebugTarget target) { |
| removeCachedThreads(fCompiledExpressions, target); |
| |
| // clean up cached projects for stack frames |
| Set frames= fProjectsByFrame.keySet(); |
| List framesToRemove= new ArrayList(); |
| Iterator iter= frames.iterator(); |
| JDIStackFrame frame; |
| while (iter.hasNext()) { |
| frame= (JDIStackFrame)iter.next(); |
| if (frame.getDebugTarget() == target) { |
| framesToRemove.add(frame); |
| } |
| } |
| iter= framesToRemove.iterator(); |
| while (iter.hasNext()) { |
| fProjectsByFrame.remove(iter.next()); |
| } |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.model.ILineBreakpoint#getLineNumber() |
| */ |
| public int getLineNumber() throws CoreException { |
| return ensureMarker().getAttribute(IMarker.LINE_NUMBER, -1); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.model.ILineBreakpoint#getCharStart() |
| */ |
| public int getCharStart() throws CoreException { |
| return ensureMarker().getAttribute(IMarker.CHAR_START, -1); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.model.ILineBreakpoint#getCharEnd() |
| */ |
| public int getCharEnd() throws CoreException { |
| return ensureMarker().getAttribute(IMarker.CHAR_END, -1); |
| } |
| /** |
| * Returns the type of marker associated with Java line breakpoints |
| */ |
| public static String getMarkerType() { |
| return JAVA_LINE_BREAKPOINT; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#newRequest(org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget, com.sun.jdi.ReferenceType) |
| */ |
| protected EventRequest[] newRequests(JDIDebugTarget target, ReferenceType type) throws CoreException { |
| int lineNumber = getLineNumber(); |
| List locations = determineLocations(lineNumber, type, target); |
| if (locations == null || locations.isEmpty()) { |
| // could be an inner type not yet loaded, or line information not available |
| return null; |
| } |
| EventRequest[] requests = new EventRequest[locations.size()]; |
| int i = 0; |
| Iterator iterator = locations.iterator(); |
| while (iterator.hasNext()) { |
| Location location = (Location) iterator.next(); |
| requests[i] = createLineBreakpointRequest(location, target); |
| i++; |
| } |
| return requests; |
| } |
| |
| /** |
| * Creates, installs, and returns a line breakpoint request at |
| * the given location for this breakpoint. |
| */ |
| protected BreakpointRequest createLineBreakpointRequest(Location location, JDIDebugTarget target) throws CoreException { |
| BreakpointRequest request = null; |
| EventRequestManager manager = target.getEventRequestManager(); |
| if (manager == null) { |
| target.requestFailed(JDIDebugBreakpointMessages.getString("JavaLineBreakpoint.Unable_to_create_breakpoint_request_-_VM_disconnected._1"), null); //$NON-NLS-1$ |
| } |
| try { |
| request= manager.createBreakpointRequest(location); |
| configureRequest(request, target); |
| } catch (VMDisconnectedException e) { |
| if (!target.isAvailable()) { |
| return null; |
| } |
| JDIDebugPlugin.log(e); |
| } catch (RuntimeException e) { |
| target.internalError(e); |
| return null; |
| } |
| return request; |
| } |
| |
| /** |
| * @see JavaBreakpoint#setRequestThreadFilter(EventRequest) |
| */ |
| protected void setRequestThreadFilter(EventRequest request, ThreadReference thread) { |
| ((BreakpointRequest)request).addThreadFilter(thread); |
| } |
| |
| /** |
| * Returns a list of locations of the given line number in the given type. |
| * Returns <code>null</code> if locations cannot be determined. |
| */ |
| protected List determineLocations(int lineNumber, ReferenceType type, JDIDebugTarget target) { |
| List locations= null; |
| try { |
| locations= type.locationsOfLine(lineNumber); |
| } catch (AbsentInformationException aie) { |
| IStatus status= new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), NO_LINE_NUMBERS, JDIDebugBreakpointMessages.getString("JavaLineBreakpoint.Absent_Line_Number_Information_1"), null); //$NON-NLS-1$ |
| IStatusHandler handler= DebugPlugin.getDefault().getStatusHandler(status); |
| if (handler != null) { |
| try { |
| handler.handleStatus(status, type); |
| } catch (CoreException e) { |
| } |
| } |
| return null; |
| } catch (NativeMethodException e) { |
| return null; |
| } catch (InvalidLineNumberException e) { |
| //possibly in a nested type, will be handled when that class is loaded |
| return null; |
| } 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 |
| target.internalError(e); |
| return null; |
| } |
| return locations; |
| } |
| |
| /** |
| * Adds the standard attributes of a line breakpoint to |
| * the given attribute map. |
| * The standard attributes are: |
| * <ol> |
| * <li>IBreakpoint.ID</li> |
| * <li>IBreakpoint.ENABLED</li> |
| * <li>IMarker.LINE_NUMBER</li> |
| * <li>IMarker.CHAR_START</li> |
| * <li>IMarker.CHAR_END</li> |
| * </ol> |
| * |
| */ |
| public void addLineBreakpointAttributes(Map attributes, String modelIdentifier, boolean enabled, int lineNumber, int charStart, int charEnd) { |
| attributes.put(IBreakpoint.ID, modelIdentifier); |
| attributes.put(IBreakpoint.ENABLED, new Boolean(enabled)); |
| attributes.put(IMarker.LINE_NUMBER, new Integer(lineNumber)); |
| attributes.put(IMarker.CHAR_START, new Integer(charStart)); |
| attributes.put(IMarker.CHAR_END, new Integer(charEnd)); |
| } |
| |
| /** |
| * Adds type name and hit count attributes to the given |
| * map. |
| * |
| * If <code>hitCount > 0</code>, adds the <code>HIT_COUNT</code> attribute |
| * to 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 addTypeNameAndHitCount(Map attributes, String typeName, int hitCount) { |
| attributes.put(TYPE_NAME, typeName); |
| if (hitCount > 0) { |
| attributes.put(HIT_COUNT, new Integer(hitCount)); |
| attributes.put(EXPIRED, Boolean.FALSE); |
| } |
| } |
| |
| /** |
| * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#handleBreakpointEvent(com.sun.jdi.event.Event, org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget, org.eclipse.jdt.internal.debug.core.model.JDIThread) |
| * |
| * (From referenced JavaDoc: |
| * Returns whethers the thread should be resumed |
| */ |
| public boolean handleBreakpointEvent(Event event, JDIDebugTarget target, JDIThread thread) { |
| if (hasCondition()) { |
| try { |
| return handleConditionalBreakpointEvent(event, thread, target); |
| } catch (CoreException exception) { |
| JDIDebugPlugin.log(exception); |
| return !suspendForEvent(event, thread); |
| } |
| } |
| return !suspendForEvent(event, thread); // Resume if suspend fails |
| } |
| |
| /** |
| * Returns whether this breakpoint has an enabled condition |
| */ |
| protected boolean hasCondition() { |
| try { |
| String condition = getCondition(); |
| return isConditionEnabled() && condition != null && (condition.length() > 0); |
| } catch (CoreException exception) { |
| JDIDebugPlugin.log(exception); |
| return false; |
| } |
| } |
| |
| /** |
| * Suspends the given thread for the given breakpoint event. Returns |
| * whether the thread suspends. |
| */ |
| protected boolean suspendForEvent(Event event, JDIThread thread) { |
| expireHitCount(event); |
| return suspend(thread); |
| } |
| |
| /** |
| * Suspends the given thread for the given breakpoint event after |
| * a conditional expression evaluation. This method tells the thread |
| * to fire a suspend event immediately instead of queueing the event. |
| * This is required because of the asynchronous nature of expression |
| * evaluation. The EventDispatcher has already fired queued events |
| * by the time the evaluation completes. |
| */ |
| protected boolean suspendForCondition(Event event, JDIThread thread) { |
| expireHitCount(event); |
| return thread.handleSuspendForBreakpoint(this, false); |
| } |
| |
| /** |
| * Returns whether this breakpoint should resume based on the |
| * value of its condition. |
| * |
| * If there is not an enabled condition which evaluates to <code>true</code>, |
| * the thread should resume. |
| */ |
| protected boolean handleConditionalBreakpointEvent(Event event, JDIThread thread, JDIDebugTarget target) throws CoreException { |
| synchronized (thread) { |
| if (thread.isPerformingEvaluation()) { |
| // If an evaluation is already being computed for this thread, |
| // we can't perform another |
| return !suspendForEvent(event, thread); |
| } |
| final String condition= getCondition(); |
| if (!hasCondition()) { |
| return !suspendForEvent(event, thread); |
| } |
| EvaluationListener listener= new EvaluationListener(); |
| |
| int suspendPolicy= SUSPEND_THREAD; |
| try { |
| suspendPolicy= getSuspendPolicy(); |
| } catch (CoreException e) { |
| } |
| if (suspendPolicy == SUSPEND_VM) { |
| ((JDIDebugTarget)thread.getDebugTarget()).prepareToSuspendByBreakpoint(this); |
| } else { |
| thread.handleSuspendForBreakpointQuiet(this); |
| } |
| List frames = thread.computeNewStackFrames(); |
| if (frames.size() == 0) { |
| return !suspendForEvent(event, thread); |
| } |
| JDIStackFrame frame= (JDIStackFrame)frames.get(0); |
| IJavaProject project= getJavaProject(frame); |
| if (project == null) { |
| throw new CoreException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED, |
| JDIDebugBreakpointMessages.getString("JavaLineBreakpoint.Unable_to_compile_conditional_breakpoint_-_missing_Java_project_context._1"), null)); //$NON-NLS-1$ |
| } |
| IAstEvaluationEngine engine = getEvaluationEngine(target, project); |
| if (engine == null) { |
| // If no engine is available, suspend |
| return !suspendForEvent(event, thread); |
| } |
| ICompiledExpression expression= (ICompiledExpression)fCompiledExpressions.get(thread); |
| if (expression == null) { |
| expression= engine.getCompiledExpression(condition, frame); |
| fCompiledExpressions.put(thread, expression); |
| } |
| if (conditionHasErrors(expression)) { |
| fireConditionHasErrors(expression); |
| return !suspendForEvent(event, thread); |
| } |
| fSuspendEvents.put(thread, event); |
| thread.setEvaluatingConditionalBreakpoint(true); |
| engine.evaluateExpression(expression, frame, listener, DebugEvent.EVALUATION_IMPLICIT, false); |
| |
| // Do not resume. When the evaluation returns, the evaluation listener |
| // will resume the thread if necessary or update for suspension. |
| return false; |
| } |
| } |
| |
| private IJavaProject getJavaProject(JDIStackFrame stackFrame) { |
| IJavaProject project= (IJavaProject) fProjectsByFrame.get(stackFrame); |
| if (project == null) { |
| project = computeJavaProject(stackFrame); |
| if (project != null) { |
| fProjectsByFrame.put(stackFrame, project); |
| } |
| } |
| return project; |
| } |
| |
| private IJavaProject computeJavaProject(JDIStackFrame stackFrame) { |
| ILaunch launch = stackFrame.getLaunch(); |
| if (launch == null) { |
| return null; |
| } |
| ISourceLocator locator= launch.getSourceLocator(); |
| if (locator == null) |
| return null; |
| |
| Object sourceElement= null; |
| try { |
| if (locator instanceof ISourceLookupDirector && !stackFrame.isStatic()) { |
| IJavaType thisType = stackFrame.getThis().getJavaType(); |
| if (thisType instanceof JDIReferenceType) { |
| String[] sourcePaths= ((JDIReferenceType) thisType).getSourcePaths(null); |
| if (sourcePaths.length > 0) { |
| sourceElement= ((ISourceLookupDirector) locator).getSourceElement(sourcePaths[0]); |
| } |
| } |
| } |
| } catch (DebugException e) { |
| DebugPlugin.log(e); |
| } |
| if (sourceElement == null) { |
| sourceElement = locator.getSourceElement(stackFrame); |
| } |
| if (!(sourceElement instanceof IJavaElement) && sourceElement instanceof IAdaptable) { |
| Object element= ((IAdaptable)sourceElement).getAdapter(IJavaElement.class); |
| if (element != null) { |
| sourceElement= element; |
| } |
| } |
| if (sourceElement instanceof IJavaElement) { |
| return ((IJavaElement) sourceElement).getJavaProject(); |
| } else if (sourceElement instanceof IResource) { |
| IJavaProject project = JavaCore.create(((IResource)sourceElement).getProject()); |
| if (project.exists()) { |
| return project; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Listens for evaluation completion for condition evaluation. |
| * If an evaluation evaluates <code>true</code> or has an error, this breakpoint |
| * will suspend the thread in which the breakpoint was hit. |
| * If the evaluation returns <code>false</code>, the thread is resumed. |
| */ |
| class EvaluationListener implements IEvaluationListener { |
| public void evaluationComplete(IEvaluationResult result) { |
| JDIThread thread= (JDIThread)result.getThread(); |
| thread.setEvaluatingConditionalBreakpoint(false); |
| Event event= (Event)fSuspendEvents.get(thread); |
| if (result.hasErrors()) { |
| DebugException exception= result.getException(); |
| Throwable wrappedException= exception.getStatus().getException(); |
| if (wrappedException instanceof VMDisconnectedException) { |
| JDIDebugPlugin.log(wrappedException); |
| try { |
| thread.resumeQuiet(); |
| } catch(DebugException e) { |
| JDIDebugPlugin.log(e); |
| } |
| } else { |
| fireConditionHasRuntimeErrors(exception); |
| suspendForCondition(event, thread); |
| return; |
| } |
| } |
| try { |
| IValue value= result.getValue(); |
| if (isConditionSuspendOnTrue()) { |
| if (value instanceof IJavaPrimitiveValue) { |
| // Suspend when the condition evaluates true |
| IJavaPrimitiveValue javaValue= (IJavaPrimitiveValue)value; |
| if (isConditionSuspendOnTrue()) { |
| if (javaValue.getJavaType().getName().equals("boolean") && javaValue.getBooleanValue()) { //$NON-NLS-1$ |
| suspendForCondition(event, thread); |
| return; |
| } |
| } |
| } |
| } else { |
| IDebugTarget debugTarget= thread.getDebugTarget(); |
| IValue lastValue= (IValue)fConditionValues.get(debugTarget); |
| fConditionValues.put(debugTarget, value); |
| if (!value.equals(lastValue)) { |
| suspendForCondition(event, thread); |
| return; |
| } |
| } |
| int suspendPolicy= SUSPEND_THREAD; |
| try { |
| suspendPolicy= getSuspendPolicy(); |
| } catch (CoreException e) { |
| } |
| if (suspendPolicy == SUSPEND_VM) { |
| ((JDIDebugTarget)thread.getDebugTarget()).resumeQuiet(); |
| } else { |
| thread.resumeQuiet(); |
| } |
| return; |
| } catch (DebugException e) { |
| JDIDebugPlugin.log(e); |
| } |
| // Suspend when an error occurs |
| suspendForEvent(event, thread); |
| } |
| } |
| |
| private void fireConditionHasRuntimeErrors(DebugException exception) { |
| JDIDebugPlugin.getDefault().fireBreakpointHasRuntimeException(this, exception); |
| } |
| |
| /** |
| * Notifies listeners that a conditional breakpoint expression has been |
| * compiled that contains errors |
| */ |
| private void fireConditionHasErrors(ICompiledExpression expression) { |
| JDIDebugPlugin.getDefault().fireBreakpointHasCompilationErrors(this, getMessages(expression)); |
| } |
| |
| /** |
| * Convert an array of <code>String</code> to an array of |
| * <code>Message</code>. |
| */ |
| private Message[] getMessages(ICompiledExpression expression) { |
| String[] errorMessages= expression.getErrorMessages(); |
| Message[] messages= new Message[errorMessages.length]; |
| for (int i= 0; i < messages.length; i++) { |
| messages[i]= new Message(errorMessages[i], -1); |
| } |
| return messages; |
| } |
| |
| /** |
| * Returns whether the cached conditional expression has errors or |
| * <code>false</code> if there is no cached expression |
| */ |
| public boolean conditionHasErrors(ICompiledExpression expression) { |
| return expression.hasErrors(); |
| } |
| |
| /** |
| * Returns an evaluation engine for evaluating this breakpoint's condition |
| * in the given target and project context. |
| */ |
| public IAstEvaluationEngine getEvaluationEngine(IJavaDebugTarget vm, IJavaProject project) { |
| return ((JDIDebugTarget)vm).getEvaluationEngine(project); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#supportsCondition() |
| */ |
| public boolean supportsCondition() { |
| return true; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#getCondition() |
| */ |
| public String getCondition() throws CoreException { |
| return ensureMarker().getAttribute(CONDITION, null); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setCondition(java.lang.String) |
| */ |
| public void setCondition(String condition) throws CoreException { |
| // Clear the cached compiled expressions |
| fCompiledExpressions.clear(); |
| fConditionValues.clear(); |
| fSuspendEvents.clear(); |
| if (condition != null && condition.trim().length() == 0) { |
| condition = null; |
| } |
| setAttributes(new String []{CONDITION}, new Object[]{condition}); |
| recreate(); |
| } |
| |
| protected String getMarkerMessage(boolean conditionEnabled, String condition, int hitCount, int suspendPolicy, int lineNumber) { |
| StringBuffer message= new StringBuffer(super.getMarkerMessage(hitCount, suspendPolicy)); |
| if (lineNumber != -1) { |
| message.append(MessageFormat.format(JDIDebugBreakpointMessages.getString("JavaLineBreakpoint._[line__{0}]_1"), new Object[]{Integer.toString(lineNumber)})); //$NON-NLS-1$ |
| } |
| if (conditionEnabled && condition != null) { |
| message.append(MessageFormat.format(JDIDebugBreakpointMessages.getString("JavaLineBreakpoint._[Condition__{0}]_2"), new Object[]{condition})); //$NON-NLS-1$ |
| } |
| |
| return message.toString(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#isConditionEnabled() |
| */ |
| public boolean isConditionEnabled() throws CoreException { |
| return ensureMarker().getAttribute(CONDITION_ENABLED, false); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setConditionEnabled(boolean) |
| */ |
| public void setConditionEnabled(boolean conditionEnabled) throws CoreException { |
| setAttributes(new String[]{CONDITION_ENABLED}, new Object[]{new Boolean(conditionEnabled)}); |
| recreate(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#cleanupForThreadTermination(org.eclipse.jdt.internal.debug.core.model.JDIThread) |
| */ |
| protected void cleanupForThreadTermination(JDIThread thread) { |
| fSuspendEvents.remove(thread); |
| fCompiledExpressions.remove(thread); |
| super.cleanupForThreadTermination(thread); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#addInstanceFilter(com.sun.jdi.request.EventRequest, com.sun.jdi.ObjectReference) |
| */ |
| protected void addInstanceFilter(EventRequest request,ObjectReference object) { |
| if (request instanceof BreakpointRequest) { |
| ((BreakpointRequest)request).addInstanceFilter(object); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#isConditionSuspendOnTrue() |
| */ |
| public boolean isConditionSuspendOnTrue() throws DebugException { |
| return ensureMarker().getAttribute(CONDITION_SUSPEND_ON_TRUE, true); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setConditionSuspendOnTrue(boolean) |
| */ |
| public void setConditionSuspendOnTrue(boolean suspendOnTrue) throws CoreException { |
| if (isConditionSuspendOnTrue() != suspendOnTrue) { |
| setAttributes(new String[]{CONDITION_SUSPEND_ON_TRUE}, new Object[]{new Boolean(suspendOnTrue)}); |
| fConditionValues.clear(); |
| recreate(); |
| } |
| } |
| |
| } |