001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.debug.core.breakpoints;
011:
012: import java.util.ArrayList;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Map;
017: import java.util.Set;
018:
019: import org.eclipse.core.resources.IMarker;
020: import org.eclipse.core.resources.IResource;
021: import org.eclipse.core.resources.IWorkspaceRunnable;
022: import org.eclipse.core.runtime.CoreException;
023: import org.eclipse.core.runtime.IAdaptable;
024: import org.eclipse.core.runtime.IProgressMonitor;
025: import org.eclipse.core.runtime.IStatus;
026: import org.eclipse.core.runtime.Status;
027: import org.eclipse.debug.core.DebugEvent;
028: import org.eclipse.debug.core.DebugException;
029: import org.eclipse.debug.core.DebugPlugin;
030: import org.eclipse.debug.core.ILaunch;
031: import org.eclipse.debug.core.IStatusHandler;
032: import org.eclipse.debug.core.model.IBreakpoint;
033: import org.eclipse.debug.core.model.IDebugTarget;
034: import org.eclipse.debug.core.model.ISourceLocator;
035: import org.eclipse.debug.core.model.IValue;
036: import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
037: import org.eclipse.jdt.core.IJavaElement;
038: import org.eclipse.jdt.core.IJavaProject;
039: import org.eclipse.jdt.core.JavaCore;
040: import org.eclipse.jdt.core.dom.Message;
041: import org.eclipse.jdt.debug.core.IJavaDebugTarget;
042: import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
043: import org.eclipse.jdt.debug.core.IJavaPrimitiveValue;
044: import org.eclipse.jdt.debug.core.IJavaReferenceType;
045: import org.eclipse.jdt.debug.core.IJavaType;
046: import org.eclipse.jdt.debug.core.JDIDebugModel;
047: import org.eclipse.jdt.debug.eval.IAstEvaluationEngine;
048: import org.eclipse.jdt.debug.eval.ICompiledExpression;
049: import org.eclipse.jdt.debug.eval.IEvaluationListener;
050: import org.eclipse.jdt.debug.eval.IEvaluationResult;
051: import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
052: import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
053: import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
054: import org.eclipse.jdt.internal.debug.core.model.JDIThread;
055:
056: import com.ibm.icu.text.MessageFormat;
057: import com.sun.jdi.AbsentInformationException;
058: import com.sun.jdi.ClassNotPreparedException;
059: import com.sun.jdi.Location;
060: import com.sun.jdi.NativeMethodException;
061: import com.sun.jdi.ObjectReference;
062: import com.sun.jdi.ReferenceType;
063: import com.sun.jdi.ThreadReference;
064: import com.sun.jdi.VMDisconnectedException;
065: import com.sun.jdi.event.Event;
066: import com.sun.jdi.request.BreakpointRequest;
067: import com.sun.jdi.request.EventRequest;
068: import com.sun.jdi.request.EventRequestManager;
069:
070: public class JavaLineBreakpoint extends JavaBreakpoint implements
071: IJavaLineBreakpoint {
072:
073: /**
074: * Breakpoint attribute storing a breakpoint's conditional expression
075: * (value <code>"org.eclipse.jdt.debug.core.condition"</code>). This attribute is stored as a
076: * <code>String</code>.
077: */
078: protected static final String CONDITION = "org.eclipse.jdt.debug.core.condition"; //$NON-NLS-1$
079: /**
080: * Breakpoint attribute storing a breakpoint's condition enablement
081: * (value <code>"org.eclipse.jdt.debug.core.conditionEnabled"</code>). This attribute is stored as an
082: * <code>boolean</code>.
083: */
084: protected static final String CONDITION_ENABLED = "org.eclipse.jdt.debug.core.conditionEnabled"; //$NON-NLS-1$
085:
086: /**
087: * Breakpoint attribute storing a breakpoint's condition suspend policy
088: * (value <code>" org.eclipse.jdt.debug.core.conditionSuspendOnTrue"
089: * </code>). This attribute is stored as an <code>boolean</code>.
090: */
091: protected static final String CONDITION_SUSPEND_ON_TRUE = "org.eclipse.jdt.debug.core.conditionSuspendOnTrue"; //$NON-NLS-1$
092:
093: /**
094: * Breakpoint attribute storing a breakpoint's source file name (debug attribute)
095: * (value <code>"org.eclipse.jdt.debug.core.sourceName"</code>). This attribute is stored as
096: * a <code>String</code>.
097: */
098: protected static final String SOURCE_NAME = "org.eclipse.jdt.debug.core.sourceName"; //$NON-NLS-1$
099:
100: private static final String JAVA_LINE_BREAKPOINT = "org.eclipse.jdt.debug.javaLineBreakpointMarker"; //$NON-NLS-1$
101:
102: /**
103: * Maps suspended threads to the suspend event that suspended them
104: */
105: private Map fSuspendEvents = new HashMap();
106: /**
107: * The map of cached compiled expressions (ICompiledExpression) for this breakpoint, keyed by thread.
108: * This value must be cleared every time the breakpoint is added to a target.
109: */
110: private Map fCompiledExpressions = new HashMap();
111:
112: /**
113: * Cache of projects for stack frames to avoid repetitive project resolution on conditional
114: * breakpoints.
115: */
116: private Map fProjectsByFrame = new HashMap();
117:
118: /**
119: * The map of the result value of the condition (IValue) for this
120: * breakpoint, keyed by debug target.
121: */
122: private Map fConditionValues = new HashMap();
123:
124: /**
125: * Status code indicating that a request to create a breakpoint in a type
126: * with no line number attributes has occurred.
127: */
128: public static final int NO_LINE_NUMBERS = 162;
129:
130: public JavaLineBreakpoint() {
131: }
132:
133: /**
134: * @see JDIDebugModel#createLineBreakpoint(IResource, String, int, int, int, int, boolean, Map)
135: */
136: public JavaLineBreakpoint(IResource resource, String typeName,
137: int lineNumber, int charStart, int charEnd, int hitCount,
138: boolean add, Map attributes) throws DebugException {
139: this (resource, typeName, lineNumber, charStart, charEnd,
140: hitCount, add, attributes, JAVA_LINE_BREAKPOINT);
141: }
142:
143: protected JavaLineBreakpoint(final IResource resource,
144: final String typeName, final int lineNumber,
145: final int charStart, final int charEnd, final int hitCount,
146: final boolean add, final Map attributes,
147: final String markerType) throws DebugException {
148: IWorkspaceRunnable wr = new IWorkspaceRunnable() {
149: public void run(IProgressMonitor monitor)
150: throws CoreException {
151:
152: // create the marker
153: setMarker(resource.createMarker(markerType));
154:
155: // add attributes
156: addLineBreakpointAttributes(attributes,
157: getModelIdentifier(), true, lineNumber,
158: charStart, charEnd);
159: addTypeNameAndHitCount(attributes, typeName, hitCount);
160: // set attributes
161: attributes.put(SUSPEND_POLICY, new Integer(
162: getDefaultSuspendPolicy()));
163: ensureMarker().setAttributes(attributes);
164:
165: // add to breakpoint manager if requested
166: register(add);
167: }
168: };
169: run(getMarkerRule(resource), wr);
170: }
171:
172: /* (non-Javadoc)
173: * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#addToTarget(org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget)
174: */
175: public void addToTarget(JDIDebugTarget target) throws CoreException {
176: clearCachedExpressionFor(target);
177: super .addToTarget(target);
178: }
179:
180: /* (non-Javadoc)
181: * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#removeFromTarget(org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget)
182: */
183: public void removeFromTarget(JDIDebugTarget target)
184: throws CoreException {
185: clearCachedExpressionFor(target);
186: clearCachedSuspendEvents(target);
187: fConditionValues.remove(target);
188: super .removeFromTarget(target);
189: }
190:
191: /**
192: * Removes all suspend events which are currently
193: * being cached for threads in the given target.
194: */
195: protected void clearCachedSuspendEvents(JDIDebugTarget target) {
196: removeCachedThreads(fSuspendEvents, target);
197: }
198:
199: private void removeCachedThreads(Map map, JDIDebugTarget target) {
200: Set threads = map.keySet();
201: List threadsToRemove = new ArrayList();
202: Iterator iter = threads.iterator();
203: JDIThread thread;
204: while (iter.hasNext()) {
205: thread = (JDIThread) iter.next();
206: if (thread.getDebugTarget() == target) {
207: threadsToRemove.add(thread);
208: }
209: }
210: iter = threadsToRemove.iterator();
211: while (iter.hasNext()) {
212: map.remove(iter.next());
213: }
214: }
215:
216: /**
217: * Removes all compiled expressions which are currently
218: * being cached for threads in the given target.
219: */
220: protected void clearCachedExpressionFor(JDIDebugTarget target) {
221: removeCachedThreads(fCompiledExpressions, target);
222:
223: // clean up cached projects for stack frames
224: Set frames = fProjectsByFrame.keySet();
225: List framesToRemove = new ArrayList();
226: Iterator iter = frames.iterator();
227: JDIStackFrame frame;
228: while (iter.hasNext()) {
229: frame = (JDIStackFrame) iter.next();
230: if (frame.getDebugTarget() == target) {
231: framesToRemove.add(frame);
232: }
233: }
234: iter = framesToRemove.iterator();
235: while (iter.hasNext()) {
236: fProjectsByFrame.remove(iter.next());
237: }
238:
239: }
240:
241: /* (non-Javadoc)
242: * @see org.eclipse.debug.core.model.ILineBreakpoint#getLineNumber()
243: */
244: public int getLineNumber() throws CoreException {
245: return ensureMarker().getAttribute(IMarker.LINE_NUMBER, -1);
246: }
247:
248: /* (non-Javadoc)
249: * @see org.eclipse.debug.core.model.ILineBreakpoint#getCharStart()
250: */
251: public int getCharStart() throws CoreException {
252: return ensureMarker().getAttribute(IMarker.CHAR_START, -1);
253: }
254:
255: /* (non-Javadoc)
256: * @see org.eclipse.debug.core.model.ILineBreakpoint#getCharEnd()
257: */
258: public int getCharEnd() throws CoreException {
259: return ensureMarker().getAttribute(IMarker.CHAR_END, -1);
260: }
261:
262: /**
263: * Returns the type of marker associated with Java line breakpoints
264: */
265: public static String getMarkerType() {
266: return JAVA_LINE_BREAKPOINT;
267: }
268:
269: /* (non-Javadoc)
270: * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#newRequest(org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget, com.sun.jdi.ReferenceType)
271: */
272: protected EventRequest[] newRequests(JDIDebugTarget target,
273: ReferenceType type) throws CoreException {
274: int lineNumber = getLineNumber();
275: List locations = determineLocations(lineNumber, type, target);
276: if (locations == null || locations.isEmpty()) {
277: // could be an inner type not yet loaded, or line information not available
278: return null;
279: }
280: EventRequest[] requests = new EventRequest[locations.size()];
281: int i = 0;
282: Iterator iterator = locations.iterator();
283: while (iterator.hasNext()) {
284: Location location = (Location) iterator.next();
285: requests[i] = createLineBreakpointRequest(location, target);
286: i++;
287: }
288: return requests;
289: }
290:
291: /**
292: * Creates, installs, and returns a line breakpoint request at
293: * the given location for this breakpoint.
294: */
295: protected BreakpointRequest createLineBreakpointRequest(
296: Location location, JDIDebugTarget target)
297: throws CoreException {
298: BreakpointRequest request = null;
299: EventRequestManager manager = target.getEventRequestManager();
300: if (manager == null) {
301: target
302: .requestFailed(
303: JDIDebugBreakpointMessages.JavaLineBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1,
304: null);
305: }
306: try {
307: request = manager.createBreakpointRequest(location);
308: configureRequest(request, target);
309: } catch (VMDisconnectedException e) {
310: if (!target.isAvailable()) {
311: return null;
312: }
313: JDIDebugPlugin.log(e);
314: } catch (RuntimeException e) {
315: target.internalError(e);
316: return null;
317: }
318: return request;
319: }
320:
321: /**
322: * @see JavaBreakpoint#setRequestThreadFilter(EventRequest)
323: */
324: protected void setRequestThreadFilter(EventRequest request,
325: ThreadReference thread) {
326: ((BreakpointRequest) request).addThreadFilter(thread);
327: }
328:
329: /**
330: * Returns a list of locations of the given line number in the given type.
331: * Returns <code>null</code> if locations cannot be determined.
332: */
333: protected List determineLocations(int lineNumber,
334: ReferenceType type, JDIDebugTarget target) {
335: List locations = null;
336: try {
337: locations = type.locationsOfLine(lineNumber);
338: } catch (AbsentInformationException aie) {
339: IStatus status = new Status(
340: IStatus.ERROR,
341: JDIDebugPlugin.getUniqueIdentifier(),
342: NO_LINE_NUMBERS,
343: JDIDebugBreakpointMessages.JavaLineBreakpoint_Absent_Line_Number_Information_1,
344: null);
345: IStatusHandler handler = DebugPlugin.getDefault()
346: .getStatusHandler(status);
347: if (handler != null) {
348: try {
349: handler.handleStatus(status, type);
350: } catch (CoreException e) {
351: }
352: }
353: return null;
354: } catch (NativeMethodException e) {
355: return null;
356: } catch (VMDisconnectedException e) {
357: return null;
358: } catch (ClassNotPreparedException e) {
359: // could be a nested type that is not yet loaded
360: return null;
361: } catch (RuntimeException e) {
362: // not able to retrieve line information
363: target.internalError(e);
364: return null;
365: }
366: return locations;
367: }
368:
369: /**
370: * Adds the standard attributes of a line breakpoint to
371: * the given attribute map.
372: * The standard attributes are:
373: * <ol>
374: * <li>IBreakpoint.ID</li>
375: * <li>IBreakpoint.ENABLED</li>
376: * <li>IMarker.LINE_NUMBER</li>
377: * <li>IMarker.CHAR_START</li>
378: * <li>IMarker.CHAR_END</li>
379: * </ol>
380: *
381: */
382: public void addLineBreakpointAttributes(Map attributes,
383: String modelIdentifier, boolean enabled, int lineNumber,
384: int charStart, int charEnd) {
385: attributes.put(IBreakpoint.ID, modelIdentifier);
386: attributes.put(IBreakpoint.ENABLED, Boolean.valueOf(enabled));
387: attributes.put(IMarker.LINE_NUMBER, new Integer(lineNumber));
388: attributes.put(IMarker.CHAR_START, new Integer(charStart));
389: attributes.put(IMarker.CHAR_END, new Integer(charEnd));
390: }
391:
392: /**
393: * Adds type name and hit count attributes to the given
394: * map.
395: *
396: * If <code>hitCount > 0</code>, adds the <code>HIT_COUNT</code> attribute
397: * to the given breakpoint, and resets the <code>EXPIRED</code> attribute
398: * to false (since, if the hit count is changed, the breakpoint should no
399: * longer be expired).
400: */
401: public void addTypeNameAndHitCount(Map attributes, String typeName,
402: int hitCount) {
403: attributes.put(TYPE_NAME, typeName);
404: if (hitCount > 0) {
405: attributes.put(HIT_COUNT, new Integer(hitCount));
406: attributes.put(EXPIRED, Boolean.FALSE);
407: }
408: }
409:
410: /**
411: * @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)
412: *
413: * (From referenced JavaDoc:
414: * Returns whether the thread should be resumed
415: */
416: public boolean handleBreakpointEvent(Event event,
417: JDIDebugTarget target, JDIThread thread) {
418: if (hasCondition()) {
419: try {
420: return handleConditionalBreakpointEvent(event, thread,
421: target);
422: } catch (CoreException exception) {
423: JDIDebugPlugin.log(exception);
424: return !suspendForEvent(event, thread);
425: }
426: }
427: return !suspendForEvent(event, thread); // Resume if suspend fails
428: }
429:
430: /**
431: * Returns whether this breakpoint has an enabled condition
432: */
433: protected boolean hasCondition() {
434: try {
435: String condition = getCondition();
436: return isConditionEnabled() && condition != null
437: && (condition.length() > 0);
438: } catch (CoreException exception) {
439: JDIDebugPlugin.log(exception);
440: return false;
441: }
442: }
443:
444: /**
445: * Suspends the given thread for the given breakpoint event. Returns
446: * whether the thread suspends.
447: */
448: protected boolean suspendForEvent(Event event, JDIThread thread) {
449: expireHitCount(event);
450: return suspend(thread);
451: }
452:
453: /**
454: * Suspends the given thread for the given breakpoint event after
455: * a conditional expression evaluation. This method tells the thread
456: * to fire a suspend event immediately instead of queue'ing the event.
457: * This is required because of the asynchronous nature of expression
458: * evaluation. The EventDispatcher has already fired queued events
459: * by the time the evaluation completes.
460: */
461: protected boolean suspendForCondition(Event event, JDIThread thread) {
462: expireHitCount(event);
463: return thread.handleSuspendForBreakpoint(this , false);
464: }
465:
466: /**
467: * Returns whether this breakpoint should resume based on the
468: * value of its condition.
469: *
470: * If there is not an enabled condition which evaluates to <code>true</code>,
471: * the thread should resume.
472: */
473: protected boolean handleConditionalBreakpointEvent(Event event,
474: JDIThread thread, JDIDebugTarget target)
475: throws CoreException {
476: synchronized (thread) {
477: if (thread.isPerformingEvaluation()) {
478: // If an evaluation is already being computed for this thread,
479: // we can't perform another
480: return !suspendForEvent(event, thread);
481: }
482: final String condition = getCondition();
483: if (!hasCondition()) {
484: return !suspendForEvent(event, thread);
485: }
486: EvaluationListener listener = new EvaluationListener();
487:
488: int suspendPolicy = SUSPEND_THREAD;
489: try {
490: suspendPolicy = getSuspendPolicy();
491: } catch (CoreException e) {
492: }
493: if (suspendPolicy == SUSPEND_VM) {
494: ((JDIDebugTarget) thread.getDebugTarget())
495: .prepareToSuspendByBreakpoint(this );
496: } else {
497: thread.handleSuspendForBreakpointQuiet(this );
498: }
499: List frames = thread.computeNewStackFrames();
500: if (frames.size() == 0) {
501: return !suspendForEvent(event, thread);
502: }
503: JDIStackFrame frame = (JDIStackFrame) frames.get(0);
504: IJavaProject project = getJavaProject(frame);
505: if (project == null) {
506: throw new CoreException(
507: new Status(
508: IStatus.ERROR,
509: JDIDebugModel.getPluginIdentifier(),
510: DebugException.REQUEST_FAILED,
511: JDIDebugBreakpointMessages.JavaLineBreakpoint_Unable_to_compile_conditional_breakpoint___missing_Java_project_context__1,
512: null));
513: }
514: IAstEvaluationEngine engine = getEvaluationEngine(target,
515: project);
516: if (engine == null) {
517: // If no engine is available, suspend
518: return !suspendForEvent(event, thread);
519: }
520: ICompiledExpression expression = (ICompiledExpression) fCompiledExpressions
521: .get(thread);
522: if (expression == null) {
523: expression = engine.getCompiledExpression(condition,
524: frame);
525: fCompiledExpressions.put(thread, expression);
526: }
527: if (conditionHasErrors(expression)) {
528: fireConditionHasErrors(expression);
529: return !suspendForEvent(event, thread);
530: }
531: fSuspendEvents.put(thread, event);
532: thread.setEvaluatingConditionalBreakpoint(true);
533: engine.evaluateExpression(expression, frame, listener,
534: DebugEvent.EVALUATION_IMPLICIT, false);
535:
536: // Do not resume. When the evaluation returns, the evaluation listener
537: // will resume the thread if necessary or update for suspension.
538: return false;
539: }
540: }
541:
542: private IJavaProject getJavaProject(JDIStackFrame stackFrame) {
543: IJavaProject project = (IJavaProject) fProjectsByFrame
544: .get(stackFrame);
545: if (project == null) {
546: project = computeJavaProject(stackFrame);
547: if (project != null) {
548: fProjectsByFrame.put(stackFrame, project);
549: }
550: }
551: return project;
552: }
553:
554: private IJavaProject computeJavaProject(JDIStackFrame stackFrame) {
555: ILaunch launch = stackFrame.getLaunch();
556: if (launch == null) {
557: return null;
558: }
559: ISourceLocator locator = launch.getSourceLocator();
560: if (locator == null)
561: return null;
562:
563: Object sourceElement = null;
564: try {
565: if (locator instanceof ISourceLookupDirector
566: && !stackFrame.isStatic()) {
567: IJavaType this Type = stackFrame.getThis().getJavaType();
568: if (this Type instanceof IJavaReferenceType) {
569: String[] sourcePaths = ((IJavaReferenceType) this Type)
570: .getSourcePaths(null);
571: if (sourcePaths != null && sourcePaths.length > 0) {
572: sourceElement = ((ISourceLookupDirector) locator)
573: .getSourceElement(sourcePaths[0]);
574: }
575: }
576: }
577: } catch (DebugException e) {
578: DebugPlugin.log(e);
579: }
580: if (sourceElement == null) {
581: sourceElement = locator.getSourceElement(stackFrame);
582: }
583: if (!(sourceElement instanceof IJavaElement)
584: && sourceElement instanceof IAdaptable) {
585: Object element = ((IAdaptable) sourceElement)
586: .getAdapter(IJavaElement.class);
587: if (element != null) {
588: sourceElement = element;
589: }
590: }
591: if (sourceElement instanceof IJavaElement) {
592: return ((IJavaElement) sourceElement).getJavaProject();
593: } else if (sourceElement instanceof IResource) {
594: IJavaProject project = JavaCore
595: .create(((IResource) sourceElement).getProject());
596: if (project.exists()) {
597: return project;
598: }
599: }
600: return null;
601: }
602:
603: /**
604: * Listens for evaluation completion for condition evaluation.
605: * If an evaluation evaluates <code>true</code> or has an error, this breakpoint
606: * will suspend the thread in which the breakpoint was hit.
607: * If the evaluation returns <code>false</code>, the thread is resumed.
608: */
609: class EvaluationListener implements IEvaluationListener {
610: public void evaluationComplete(IEvaluationResult result) {
611: JDIThread thread = (JDIThread) result.getThread();
612: thread.setEvaluatingConditionalBreakpoint(false);
613: Event event = (Event) fSuspendEvents.get(thread);
614: if (result.hasErrors()) {
615: DebugException exception = result.getException();
616: Throwable wrappedException = exception.getStatus()
617: .getException();
618: if (wrappedException instanceof VMDisconnectedException) {
619: JDIDebugPlugin.log(wrappedException);
620: try {
621: thread.resumeQuiet();
622: } catch (DebugException e) {
623: JDIDebugPlugin.log(e);
624: }
625: } else {
626: fireConditionHasRuntimeErrors(exception);
627: suspendForCondition(event, thread);
628: return;
629: }
630: }
631: try {
632: IValue value = result.getValue();
633: if (isConditionSuspendOnTrue()) {
634: if (value instanceof IJavaPrimitiveValue) {
635: // Suspend when the condition evaluates true
636: IJavaPrimitiveValue javaValue = (IJavaPrimitiveValue) value;
637: if (isConditionSuspendOnTrue()) {
638: if (javaValue.getJavaType().getName()
639: .equals("boolean") && javaValue.getBooleanValue()) { //$NON-NLS-1$
640: suspendForCondition(event, thread);
641: return;
642: }
643: }
644: }
645: } else {
646: IDebugTarget debugTarget = thread.getDebugTarget();
647: IValue lastValue = (IValue) fConditionValues
648: .get(debugTarget);
649: fConditionValues.put(debugTarget, value);
650: if (!value.equals(lastValue)) {
651: suspendForCondition(event, thread);
652: return;
653: }
654: }
655: int suspendPolicy = SUSPEND_THREAD;
656: try {
657: suspendPolicy = getSuspendPolicy();
658: } catch (CoreException e) {
659: }
660: if (suspendPolicy == SUSPEND_VM) {
661: ((JDIDebugTarget) thread.getDebugTarget())
662: .resumeQuiet();
663: } else {
664: thread.resumeQuiet();
665: }
666: return;
667: } catch (DebugException e) {
668: JDIDebugPlugin.log(e);
669: }
670: // Suspend when an error occurs
671: suspendForEvent(event, thread);
672: }
673: }
674:
675: private void fireConditionHasRuntimeErrors(DebugException exception) {
676: JDIDebugPlugin.getDefault().fireBreakpointHasRuntimeException(
677: this , exception);
678: }
679:
680: /**
681: * Notifies listeners that a conditional breakpoint expression has been
682: * compiled that contains errors
683: */
684: private void fireConditionHasErrors(ICompiledExpression expression) {
685: JDIDebugPlugin.getDefault().fireBreakpointHasCompilationErrors(
686: this , getMessages(expression));
687: }
688:
689: /**
690: * Convert an array of <code>String</code> to an array of
691: * <code>Message</code>.
692: */
693: private Message[] getMessages(ICompiledExpression expression) {
694: String[] errorMessages = expression.getErrorMessages();
695: Message[] messages = new Message[errorMessages.length];
696: for (int i = 0; i < messages.length; i++) {
697: messages[i] = new Message(errorMessages[i], -1);
698: }
699: return messages;
700: }
701:
702: /**
703: * Returns whether the cached conditional expression has errors or
704: * <code>false</code> if there is no cached expression
705: */
706: public boolean conditionHasErrors(ICompiledExpression expression) {
707: return expression.hasErrors();
708: }
709:
710: /**
711: * Returns an evaluation engine for evaluating this breakpoint's condition
712: * in the given target and project context.
713: */
714: public IAstEvaluationEngine getEvaluationEngine(
715: IJavaDebugTarget vm, IJavaProject project) {
716: return ((JDIDebugTarget) vm).getEvaluationEngine(project);
717: }
718:
719: /* (non-Javadoc)
720: * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#supportsCondition()
721: */
722: public boolean supportsCondition() {
723: return true;
724: }
725:
726: /* (non-Javadoc)
727: * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#getCondition()
728: */
729: public String getCondition() throws CoreException {
730: return ensureMarker().getAttribute(CONDITION, null);
731: }
732:
733: /* (non-Javadoc)
734: * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setCondition(java.lang.String)
735: */
736: public void setCondition(String condition) throws CoreException {
737: // Clear the cached compiled expressions
738: fCompiledExpressions.clear();
739: fConditionValues.clear();
740: fSuspendEvents.clear();
741: if (condition != null && condition.trim().length() == 0) {
742: condition = null;
743: }
744: setAttributes(new String[] { CONDITION },
745: new Object[] { condition });
746: recreate();
747: }
748:
749: protected String getMarkerMessage(boolean conditionEnabled,
750: String condition, int hitCount, int suspendPolicy,
751: int lineNumber) {
752: StringBuffer message = new StringBuffer(super .getMarkerMessage(
753: hitCount, suspendPolicy));
754: if (lineNumber != -1) {
755: message
756: .append(MessageFormat
757: .format(
758: JDIDebugBreakpointMessages.JavaLineBreakpoint___line___0___1,
759: new Object[] { Integer
760: .toString(lineNumber) }));
761: }
762: if (conditionEnabled && condition != null) {
763: message
764: .append(MessageFormat
765: .format(
766: JDIDebugBreakpointMessages.JavaLineBreakpoint___Condition___0___2,
767: new Object[] { condition }));
768: }
769:
770: return message.toString();
771: }
772:
773: /* (non-Javadoc)
774: * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#isConditionEnabled()
775: */
776: public boolean isConditionEnabled() throws CoreException {
777: return ensureMarker().getAttribute(CONDITION_ENABLED, false);
778: }
779:
780: /* (non-Javadoc)
781: * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setConditionEnabled(boolean)
782: */
783: public void setConditionEnabled(boolean conditionEnabled)
784: throws CoreException {
785: setAttributes(new String[] { CONDITION_ENABLED },
786: new Object[] { Boolean.valueOf(conditionEnabled) });
787: recreate();
788: }
789:
790: /* (non-Javadoc)
791: * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#cleanupForThreadTermination(org.eclipse.jdt.internal.debug.core.model.JDIThread)
792: */
793: protected void cleanupForThreadTermination(JDIThread thread) {
794: fSuspendEvents.remove(thread);
795: fCompiledExpressions.remove(thread);
796: super .cleanupForThreadTermination(thread);
797: }
798:
799: /* (non-Javadoc)
800: * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#addInstanceFilter(com.sun.jdi.request.EventRequest, com.sun.jdi.ObjectReference)
801: */
802: protected void addInstanceFilter(EventRequest request,
803: ObjectReference object) {
804: if (request instanceof BreakpointRequest) {
805: ((BreakpointRequest) request).addInstanceFilter(object);
806: }
807: }
808:
809: /* (non-Javadoc)
810: * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#isConditionSuspendOnTrue()
811: */
812: public boolean isConditionSuspendOnTrue() throws DebugException {
813: return ensureMarker().getAttribute(CONDITION_SUSPEND_ON_TRUE,
814: true);
815: }
816:
817: /* (non-Javadoc)
818: * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setConditionSuspendOnTrue(boolean)
819: */
820: public void setConditionSuspendOnTrue(boolean suspendOnTrue)
821: throws CoreException {
822: if (isConditionSuspendOnTrue() != suspendOnTrue) {
823: setAttributes(new String[] { CONDITION_SUSPEND_ON_TRUE },
824: new Object[] { Boolean.valueOf(suspendOnTrue) });
825: fConditionValues.clear();
826: recreate();
827: }
828: }
829:
830: }
|