1 11 package org.eclipse.jdt.internal.debug.core.breakpoints; 12 13 14 import java.util.ArrayList ; 15 import java.util.HashMap ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 import java.util.Map ; 19 import java.util.Set ; 20 21 import org.eclipse.core.resources.IMarker; 22 import org.eclipse.core.resources.IResource; 23 import org.eclipse.core.resources.IWorkspaceRunnable; 24 import org.eclipse.core.runtime.CoreException; 25 import org.eclipse.core.runtime.IAdaptable; 26 import org.eclipse.core.runtime.IProgressMonitor; 27 import org.eclipse.core.runtime.IStatus; 28 import org.eclipse.core.runtime.Status; 29 import org.eclipse.debug.core.DebugEvent; 30 import org.eclipse.debug.core.DebugException; 31 import org.eclipse.debug.core.DebugPlugin; 32 import org.eclipse.debug.core.ILaunch; 33 import org.eclipse.debug.core.IStatusHandler; 34 import org.eclipse.debug.core.model.IBreakpoint; 35 import org.eclipse.debug.core.model.IDebugTarget; 36 import org.eclipse.debug.core.model.ISourceLocator; 37 import org.eclipse.debug.core.model.IValue; 38 import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; 39 import org.eclipse.jdt.core.IJavaElement; 40 import org.eclipse.jdt.core.IJavaProject; 41 import org.eclipse.jdt.core.JavaCore; 42 import org.eclipse.jdt.core.dom.Message; 43 import org.eclipse.jdt.debug.core.IJavaDebugTarget; 44 import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; 45 import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; 46 import org.eclipse.jdt.debug.core.IJavaReferenceType; 47 import org.eclipse.jdt.debug.core.IJavaType; 48 import org.eclipse.jdt.debug.core.JDIDebugModel; 49 import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; 50 import org.eclipse.jdt.debug.eval.ICompiledExpression; 51 import org.eclipse.jdt.debug.eval.IEvaluationListener; 52 import org.eclipse.jdt.debug.eval.IEvaluationResult; 53 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; 54 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; 55 import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame; 56 import org.eclipse.jdt.internal.debug.core.model.JDIThread; 57 58 import com.ibm.icu.text.MessageFormat; 59 import com.sun.jdi.AbsentInformationException; 60 import com.sun.jdi.ClassNotPreparedException; 61 import com.sun.jdi.Location; 62 import com.sun.jdi.NativeMethodException; 63 import com.sun.jdi.ObjectReference; 64 import com.sun.jdi.ReferenceType; 65 import com.sun.jdi.ThreadReference; 66 import com.sun.jdi.VMDisconnectedException; 67 import com.sun.jdi.event.Event; 68 import com.sun.jdi.request.BreakpointRequest; 69 import com.sun.jdi.request.EventRequest; 70 import com.sun.jdi.request.EventRequestManager; 71 72 public class JavaLineBreakpoint extends JavaBreakpoint implements IJavaLineBreakpoint { 73 74 79 protected static final String CONDITION= "org.eclipse.jdt.debug.core.condition"; 85 protected static final String CONDITION_ENABLED= "org.eclipse.jdt.debug.core.conditionEnabled"; 87 92 protected static final String CONDITION_SUSPEND_ON_TRUE= "org.eclipse.jdt.debug.core.conditionSuspendOnTrue"; 94 99 protected static final String SOURCE_NAME= "org.eclipse.jdt.debug.core.sourceName"; 101 private static final String JAVA_LINE_BREAKPOINT = "org.eclipse.jdt.debug.javaLineBreakpointMarker"; 103 106 private Map fSuspendEvents= new HashMap (); 107 111 private Map fCompiledExpressions= new HashMap (); 112 113 117 private Map fProjectsByFrame= new HashMap (); 118 119 123 private Map fConditionValues= new HashMap (); 124 125 129 public static final int NO_LINE_NUMBERS= 162; 130 131 public JavaLineBreakpoint() { 132 } 133 134 137 public JavaLineBreakpoint(IResource resource, String typeName, int lineNumber, int charStart, int charEnd, int hitCount, boolean add, Map attributes) throws DebugException { 138 this(resource, typeName, lineNumber, charStart, charEnd, hitCount, add, attributes, JAVA_LINE_BREAKPOINT); 139 } 140 141 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 { 142 IWorkspaceRunnable wr= new IWorkspaceRunnable() { 143 public void run(IProgressMonitor monitor) throws CoreException { 144 145 setMarker(resource.createMarker(markerType)); 147 148 addLineBreakpointAttributes(attributes, getModelIdentifier(), true, lineNumber, charStart, charEnd); 150 addTypeNameAndHitCount(attributes, typeName, hitCount); 151 attributes.put(SUSPEND_POLICY, new Integer (getDefaultSuspendPolicy())); 153 ensureMarker().setAttributes(attributes); 154 155 register(add); 157 } 158 }; 159 run(getMarkerRule(resource), wr); 160 } 161 162 165 public void addToTarget(JDIDebugTarget target) throws CoreException { 166 clearCachedExpressionFor(target); 167 super.addToTarget(target); 168 } 169 170 173 public void removeFromTarget(JDIDebugTarget target) throws CoreException { 174 clearCachedExpressionFor(target); 175 clearCachedSuspendEvents(target); 176 fConditionValues.remove(target); 177 super.removeFromTarget(target); 178 } 179 180 184 protected void clearCachedSuspendEvents(JDIDebugTarget target) { 185 removeCachedThreads(fSuspendEvents, target); 186 } 187 188 private void removeCachedThreads(Map map, JDIDebugTarget target) { 189 Set threads= map.keySet(); 190 List threadsToRemove= new ArrayList (); 191 Iterator iter= threads.iterator(); 192 JDIThread thread; 193 while (iter.hasNext()) { 194 thread= (JDIThread)iter.next(); 195 if (thread.getDebugTarget() == target) { 196 threadsToRemove.add(thread); 197 } 198 } 199 iter= threadsToRemove.iterator(); 200 while (iter.hasNext()) { 201 map.remove(iter.next()); 202 } 203 } 204 205 209 protected void clearCachedExpressionFor(JDIDebugTarget target) { 210 removeCachedThreads(fCompiledExpressions, target); 211 212 Set frames= fProjectsByFrame.keySet(); 214 List framesToRemove= new ArrayList (); 215 Iterator iter= frames.iterator(); 216 JDIStackFrame frame; 217 while (iter.hasNext()) { 218 frame= (JDIStackFrame)iter.next(); 219 if (frame.getDebugTarget() == target) { 220 framesToRemove.add(frame); 221 } 222 } 223 iter= framesToRemove.iterator(); 224 while (iter.hasNext()) { 225 fProjectsByFrame.remove(iter.next()); 226 } 227 228 } 229 230 233 public int getLineNumber() throws CoreException { 234 return ensureMarker().getAttribute(IMarker.LINE_NUMBER, -1); 235 } 236 237 240 public int getCharStart() throws CoreException { 241 return ensureMarker().getAttribute(IMarker.CHAR_START, -1); 242 } 243 244 247 public int getCharEnd() throws CoreException { 248 return ensureMarker().getAttribute(IMarker.CHAR_END, -1); 249 } 250 253 public static String getMarkerType() { 254 return JAVA_LINE_BREAKPOINT; 255 } 256 257 260 protected EventRequest[] newRequests(JDIDebugTarget target, ReferenceType type) throws CoreException { 261 int lineNumber = getLineNumber(); 262 List locations = determineLocations(lineNumber, type, target); 263 if (locations == null || locations.isEmpty()) { 264 return null; 266 } 267 EventRequest[] requests = new EventRequest[locations.size()]; 268 int i = 0; 269 Iterator iterator = locations.iterator(); 270 while (iterator.hasNext()) { 271 Location location = (Location) iterator.next(); 272 requests[i] = createLineBreakpointRequest(location, target); 273 i++; 274 } 275 return requests; 276 } 277 278 282 protected BreakpointRequest createLineBreakpointRequest(Location location, JDIDebugTarget target) throws CoreException { 283 BreakpointRequest request = null; 284 EventRequestManager manager = target.getEventRequestManager(); 285 if (manager == null) { 286 target.requestFailed(JDIDebugBreakpointMessages.JavaLineBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1, null); 287 } 288 try { 289 request= manager.createBreakpointRequest(location); 290 configureRequest(request, target); 291 } catch (VMDisconnectedException e) { 292 if (!target.isAvailable()) { 293 return null; 294 } 295 JDIDebugPlugin.log(e); 296 } catch (RuntimeException e) { 297 target.internalError(e); 298 return null; 299 } 300 return request; 301 } 302 303 306 protected void setRequestThreadFilter(EventRequest request, ThreadReference thread) { 307 ((BreakpointRequest)request).addThreadFilter(thread); 308 } 309 310 314 protected List determineLocations(int lineNumber, ReferenceType type, JDIDebugTarget target) { 315 List locations= null; 316 try { 317 locations= type.locationsOfLine(lineNumber); 318 } catch (AbsentInformationException aie) { 319 IStatus status= new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), NO_LINE_NUMBERS, JDIDebugBreakpointMessages.JavaLineBreakpoint_Absent_Line_Number_Information_1, null); 320 IStatusHandler handler= DebugPlugin.getDefault().getStatusHandler(status); 321 if (handler != null) { 322 try { 323 handler.handleStatus(status, type); 324 } catch (CoreException e) { 325 } 326 } 327 return null; 328 } catch (NativeMethodException e) { 329 return null; 330 } catch (VMDisconnectedException e) { 331 return null; 332 } catch (ClassNotPreparedException e) { 333 return null; 335 } catch (RuntimeException e) { 336 target.internalError(e); 338 return null; 339 } 340 return locations; 341 } 342 343 356 public void addLineBreakpointAttributes(Map attributes, String modelIdentifier, boolean enabled, int lineNumber, int charStart, int charEnd) { 357 attributes.put(IBreakpoint.ID, modelIdentifier); 358 attributes.put(IBreakpoint.ENABLED, Boolean.valueOf(enabled)); 359 attributes.put(IMarker.LINE_NUMBER, new Integer (lineNumber)); 360 attributes.put(IMarker.CHAR_START, new Integer (charStart)); 361 attributes.put(IMarker.CHAR_END, new Integer (charEnd)); 362 } 363 364 373 public void addTypeNameAndHitCount(Map attributes, String typeName, int hitCount) { 374 attributes.put(TYPE_NAME, typeName); 375 if (hitCount > 0) { 376 attributes.put(HIT_COUNT, new Integer (hitCount)); 377 attributes.put(EXPIRED, Boolean.FALSE); 378 } 379 } 380 381 387 public boolean handleBreakpointEvent(Event event, JDIDebugTarget target, JDIThread thread) { 388 if (hasCondition()) { 389 try { 390 return handleConditionalBreakpointEvent(event, thread, target); 391 } catch (CoreException exception) { 392 JDIDebugPlugin.log(exception); 393 return !suspendForEvent(event, thread); 394 } 395 } 396 return !suspendForEvent(event, thread); } 398 399 402 protected boolean hasCondition() { 403 try { 404 String condition = getCondition(); 405 return isConditionEnabled() && condition != null && (condition.length() > 0); 406 } catch (CoreException exception) { 407 JDIDebugPlugin.log(exception); 408 return false; 409 } 410 } 411 412 416 protected boolean suspendForEvent(Event event, JDIThread thread) { 417 expireHitCount(event); 418 return suspend(thread); 419 } 420 421 429 protected boolean suspendForCondition(Event event, JDIThread thread) { 430 expireHitCount(event); 431 return thread.handleSuspendForBreakpoint(this, false); 432 } 433 434 441 protected boolean handleConditionalBreakpointEvent(Event event, JDIThread thread, JDIDebugTarget target) throws CoreException { 442 synchronized (thread) { 443 if (thread.isPerformingEvaluation()) { 444 return !suspendForEvent(event, thread); 447 } 448 final String condition= getCondition(); 449 if (!hasCondition()) { 450 return !suspendForEvent(event, thread); 451 } 452 EvaluationListener listener= new EvaluationListener(); 453 454 int suspendPolicy= SUSPEND_THREAD; 455 try { 456 suspendPolicy= getSuspendPolicy(); 457 } catch (CoreException e) { 458 } 459 if (suspendPolicy == SUSPEND_VM) { 460 ((JDIDebugTarget)thread.getDebugTarget()).prepareToSuspendByBreakpoint(this); 461 } else { 462 thread.handleSuspendForBreakpointQuiet(this); 463 } 464 List frames = thread.computeNewStackFrames(); 465 if (frames.size() == 0) { 466 return !suspendForEvent(event, thread); 467 } 468 JDIStackFrame frame= (JDIStackFrame)frames.get(0); 469 IJavaProject project= getJavaProject(frame); 470 if (project == null) { 471 throw new CoreException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED, 472 JDIDebugBreakpointMessages.JavaLineBreakpoint_Unable_to_compile_conditional_breakpoint___missing_Java_project_context__1, null)); 473 } 474 IAstEvaluationEngine engine = getEvaluationEngine(target, project); 475 if (engine == null) { 476 return !suspendForEvent(event, thread); 478 } 479 ICompiledExpression expression= (ICompiledExpression)fCompiledExpressions.get(thread); 480 if (expression == null) { 481 expression= engine.getCompiledExpression(condition, frame); 482 fCompiledExpressions.put(thread, expression); 483 } 484 if (conditionHasErrors(expression)) { 485 fireConditionHasErrors(expression); 486 return !suspendForEvent(event, thread); 487 } 488 fSuspendEvents.put(thread, event); 489 thread.setEvaluatingConditionalBreakpoint(true); 490 engine.evaluateExpression(expression, frame, listener, DebugEvent.EVALUATION_IMPLICIT, false); 491 492 return false; 495 } 496 } 497 498 private IJavaProject getJavaProject(JDIStackFrame stackFrame) { 499 IJavaProject project= (IJavaProject) fProjectsByFrame.get(stackFrame); 500 if (project == null) { 501 project = computeJavaProject(stackFrame); 502 if (project != null) { 503 fProjectsByFrame.put(stackFrame, project); 504 } 505 } 506 return project; 507 } 508 509 private IJavaProject computeJavaProject(JDIStackFrame stackFrame) { 510 ILaunch launch = stackFrame.getLaunch(); 511 if (launch == null) { 512 return null; 513 } 514 ISourceLocator locator= launch.getSourceLocator(); 515 if (locator == null) 516 return null; 517 518 Object sourceElement= null; 519 try { 520 if (locator instanceof ISourceLookupDirector && !stackFrame.isStatic()) { 521 IJavaType thisType = stackFrame.getThis().getJavaType(); 522 if (thisType instanceof IJavaReferenceType) { 523 String [] sourcePaths= ((IJavaReferenceType) thisType).getSourcePaths(null); 524 if (sourcePaths != null && sourcePaths.length > 0) { 525 sourceElement= ((ISourceLookupDirector) locator).getSourceElement(sourcePaths[0]); 526 } 527 } 528 } 529 } catch (DebugException e) { 530 DebugPlugin.log(e); 531 } 532 if (sourceElement == null) { 533 sourceElement = locator.getSourceElement(stackFrame); 534 } 535 if (!(sourceElement instanceof IJavaElement) && sourceElement instanceof IAdaptable) { 536 Object element= ((IAdaptable)sourceElement).getAdapter(IJavaElement.class); 537 if (element != null) { 538 sourceElement= element; 539 } 540 } 541 if (sourceElement instanceof IJavaElement) { 542 return ((IJavaElement) sourceElement).getJavaProject(); 543 } else if (sourceElement instanceof IResource) { 544 IJavaProject project = JavaCore.create(((IResource)sourceElement).getProject()); 545 if (project.exists()) { 546 return project; 547 } 548 } 549 return null; 550 } 551 552 558 class EvaluationListener implements IEvaluationListener { 559 public void evaluationComplete(IEvaluationResult result) { 560 JDIThread thread= (JDIThread)result.getThread(); 561 thread.setEvaluatingConditionalBreakpoint(false); 562 Event event= (Event)fSuspendEvents.get(thread); 563 if (result.hasErrors()) { 564 DebugException exception= result.getException(); 565 Throwable wrappedException= exception.getStatus().getException(); 566 if (wrappedException instanceof VMDisconnectedException) { 567 JDIDebugPlugin.log(wrappedException); 568 try { 569 thread.resumeQuiet(); 570 } catch(DebugException e) { 571 JDIDebugPlugin.log(e); 572 } 573 } else { 574 fireConditionHasRuntimeErrors(exception); 575 suspendForCondition(event, thread); 576 return; 577 } 578 } 579 try { 580 IValue value= result.getValue(); 581 if (isConditionSuspendOnTrue()) { 582 if (value instanceof IJavaPrimitiveValue) { 583 IJavaPrimitiveValue javaValue= (IJavaPrimitiveValue)value; 585 if (isConditionSuspendOnTrue()) { 586 if (javaValue.getJavaType().getName().equals("boolean") && javaValue.getBooleanValue()) { suspendForCondition(event, thread); 588 return; 589 } 590 } 591 } 592 } else { 593 IDebugTarget debugTarget= thread.getDebugTarget(); 594 IValue lastValue= (IValue)fConditionValues.get(debugTarget); 595 fConditionValues.put(debugTarget, value); 596 if (!value.equals(lastValue)) { 597 suspendForCondition(event, thread); 598 return; 599 } 600 } 601 int suspendPolicy= SUSPEND_THREAD; 602 try { 603 suspendPolicy= getSuspendPolicy(); 604 } catch (CoreException e) { 605 } 606 if (suspendPolicy == SUSPEND_VM) { 607 ((JDIDebugTarget)thread.getDebugTarget()).resumeQuiet(); 608 } else { 609 thread.resumeQuiet(); 610 } 611 return; 612 } catch (DebugException e) { 613 JDIDebugPlugin.log(e); 614 } 615 suspendForEvent(event, thread); 617 } 618 } 619 620 private void fireConditionHasRuntimeErrors(DebugException exception) { 621 JDIDebugPlugin.getDefault().fireBreakpointHasRuntimeException(this, exception); 622 } 623 624 628 private void fireConditionHasErrors(ICompiledExpression expression) { 629 JDIDebugPlugin.getDefault().fireBreakpointHasCompilationErrors(this, getMessages(expression)); 630 } 631 632 636 private Message[] getMessages(ICompiledExpression expression) { 637 String [] errorMessages= expression.getErrorMessages(); 638 Message[] messages= new Message[errorMessages.length]; 639 for (int i= 0; i < messages.length; i++) { 640 messages[i]= new Message(errorMessages[i], -1); 641 } 642 return messages; 643 } 644 645 649 public boolean conditionHasErrors(ICompiledExpression expression) { 650 return expression.hasErrors(); 651 } 652 653 657 public IAstEvaluationEngine getEvaluationEngine(IJavaDebugTarget vm, IJavaProject project) { 658 return ((JDIDebugTarget)vm).getEvaluationEngine(project); 659 } 660 661 664 public boolean supportsCondition() { 665 return true; 666 } 667 668 671 public String getCondition() throws CoreException { 672 return ensureMarker().getAttribute(CONDITION, null); 673 } 674 675 678 public void setCondition(String condition) throws CoreException { 679 fCompiledExpressions.clear(); 681 fConditionValues.clear(); 682 fSuspendEvents.clear(); 683 if (condition != null && condition.trim().length() == 0) { 684 condition = null; 685 } 686 setAttributes(new String []{CONDITION}, new Object []{condition}); 687 recreate(); 688 } 689 690 protected String getMarkerMessage(boolean conditionEnabled, String condition, int hitCount, int suspendPolicy, int lineNumber) { 691 StringBuffer message= new StringBuffer (super.getMarkerMessage(hitCount, suspendPolicy)); 692 if (lineNumber != -1) { 693 message.append(MessageFormat.format(JDIDebugBreakpointMessages.JavaLineBreakpoint___line___0___1, new Object []{Integer.toString(lineNumber)})); 694 } 695 if (conditionEnabled && condition != null) { 696 message.append(MessageFormat.format(JDIDebugBreakpointMessages.JavaLineBreakpoint___Condition___0___2, new Object []{condition})); 697 } 698 699 return message.toString(); 700 } 701 702 705 public boolean isConditionEnabled() throws CoreException { 706 return ensureMarker().getAttribute(CONDITION_ENABLED, false); 707 } 708 709 712 public void setConditionEnabled(boolean conditionEnabled) throws CoreException { 713 setAttributes(new String []{CONDITION_ENABLED}, new Object []{Boolean.valueOf(conditionEnabled)}); 714 recreate(); 715 } 716 717 720 protected void cleanupForThreadTermination(JDIThread thread) { 721 fSuspendEvents.remove(thread); 722 fCompiledExpressions.remove(thread); 723 super.cleanupForThreadTermination(thread); 724 } 725 726 729 protected void addInstanceFilter(EventRequest request,ObjectReference object) { 730 if (request instanceof BreakpointRequest) { 731 ((BreakpointRequest)request).addInstanceFilter(object); 732 } 733 } 734 735 738 public boolean isConditionSuspendOnTrue() throws DebugException { 739 return ensureMarker().getAttribute(CONDITION_SUSPEND_ON_TRUE, true); 740 } 741 742 745 public void setConditionSuspendOnTrue(boolean suspendOnTrue) throws CoreException { 746 if (isConditionSuspendOnTrue() != suspendOnTrue) { 747 setAttributes(new String []{CONDITION_SUSPEND_ON_TRUE}, new Object []{Boolean.valueOf(suspendOnTrue)}); 748 fConditionValues.clear(); 749 recreate(); 750 } 751 } 752 753 } 754 | Popular Tags |