1 11 package org.eclipse.jdt.internal.debug.core.hcr; 12 13 14 import java.util.ArrayList ; 15 import java.util.Arrays ; 16 import java.util.Collections ; 17 import java.util.Date ; 18 import java.util.HashMap ; 19 import java.util.Iterator ; 20 import java.util.List ; 21 import java.util.Map ; 22 23 import org.eclipse.core.resources.IFile; 24 import org.eclipse.core.resources.IMarker; 25 import org.eclipse.core.resources.IProject; 26 import org.eclipse.core.resources.IResource; 27 import org.eclipse.core.resources.IResourceChangeEvent; 28 import org.eclipse.core.resources.IResourceChangeListener; 29 import org.eclipse.core.resources.IResourceDelta; 30 import org.eclipse.core.resources.IResourceDeltaVisitor; 31 import org.eclipse.core.resources.IWorkspace; 32 import org.eclipse.core.resources.IncrementalProjectBuilder; 33 import org.eclipse.core.resources.ResourcesPlugin; 34 import org.eclipse.core.runtime.CoreException; 35 import org.eclipse.core.runtime.IAdaptable; 36 import org.eclipse.core.runtime.IPath; 37 import org.eclipse.core.runtime.IStatus; 38 import org.eclipse.core.runtime.ListenerList; 39 import org.eclipse.core.runtime.MultiStatus; 40 import org.eclipse.core.runtime.Path; 41 import org.eclipse.core.runtime.Status; 42 import org.eclipse.debug.core.DebugEvent; 43 import org.eclipse.debug.core.DebugException; 44 import org.eclipse.debug.core.DebugPlugin; 45 import org.eclipse.debug.core.IDebugEventSetListener; 46 import org.eclipse.debug.core.ILaunch; 47 import org.eclipse.debug.core.ILaunchListener; 48 import org.eclipse.debug.core.ILaunchManager; 49 import org.eclipse.debug.core.model.IDebugTarget; 50 import org.eclipse.debug.core.model.ISourceLocator; 51 import org.eclipse.debug.core.model.IThread; 52 import org.eclipse.jdt.core.ICompilationUnit; 53 import org.eclipse.jdt.core.IJavaElement; 54 import org.eclipse.jdt.core.IJavaModelMarker; 55 import org.eclipse.jdt.core.IJavaProject; 56 import org.eclipse.jdt.core.IMethod; 57 import org.eclipse.jdt.core.IType; 58 import org.eclipse.jdt.core.JavaCore; 59 import org.eclipse.jdt.core.JavaModelException; 60 import org.eclipse.jdt.core.Signature; 61 import org.eclipse.jdt.core.ToolFactory; 62 import org.eclipse.jdt.core.util.IClassFileReader; 63 import org.eclipse.jdt.core.util.ISourceAttribute; 64 import org.eclipse.jdt.debug.core.IJavaDebugTarget; 65 import org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener; 66 import org.eclipse.jdt.debug.core.IJavaStackFrame; 67 import org.eclipse.jdt.debug.core.IJavaThread; 68 import org.eclipse.jdt.debug.core.JDIDebugModel; 69 import org.eclipse.jdt.internal.core.util.Util; 70 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; 71 import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; 72 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; 73 import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame; 74 import org.eclipse.jdt.internal.debug.core.model.JDIThread; 75 76 import com.ibm.icu.text.MessageFormat; 77 import com.sun.jdi.IncompatibleThreadStateException; 78 import com.sun.jdi.ReferenceType; 79 import com.sun.jdi.VirtualMachine; 80 81 87 public class JavaHotCodeReplaceManager implements IResourceChangeListener, ILaunchListener, IDebugEventSetListener { 88 91 private static JavaHotCodeReplaceManager fgInstance= null; 92 95 private static final String CLASS_FILE_EXTENSION= "class"; 97 101 private ListenerList fHotCodeReplaceListeners= new ListenerList(); 102 103 106 private ArrayList fHotSwapTargets= new ArrayList (1); 107 private ArrayList fNoHotSwapTargets= new ArrayList (1); 108 109 116 private Map fProjectBuildTimes= new HashMap (); 117 private static Date fStartupDate= new Date (); 118 119 122 private Map fDeltaCache = new HashMap (); 123 124 134 class ProjectBuildTime { 135 private Date fCurrentDate= new Date (); 136 private Date fPreviousDate= new Date (); 137 138 public void setCurrentBuildDate(Date date) { 139 fPreviousDate= fCurrentDate; 140 fCurrentDate= date; 141 } 142 143 public void setLastBuildDate(Date date) { 144 fPreviousDate= date; 145 if (fPreviousDate.getTime() > fCurrentDate.getTime()) { 146 fCurrentDate= fPreviousDate; 149 } 150 } 151 152 155 public Date getLastBuildDate() { 156 return fPreviousDate; 157 } 158 } 159 160 163 protected ChangedClassFilesVisitor fClassfileVisitor = new ChangedClassFilesVisitor(); 164 165 168 private JavaHotCodeReplaceManager() { 169 } 170 173 public static synchronized JavaHotCodeReplaceManager getDefault() { 174 if (fgInstance == null) { 175 fgInstance= new JavaHotCodeReplaceManager(); 176 } 177 return fgInstance; 178 } 179 183 public void startup() { 184 DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); 185 DebugPlugin.getDefault().addDebugEventListener(this); 186 } 187 188 193 public void shutdown() { 194 DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); 195 DebugPlugin.getDefault().removeDebugEventListener(this); 196 getWorkspace().removeResourceChangeListener(this); 197 fHotCodeReplaceListeners = new ListenerList(); 198 fHotSwapTargets= null; 199 fNoHotSwapTargets= null; 200 } 201 204 protected IWorkspace getWorkspace() { 205 return ResourcesPlugin.getWorkspace(); 206 } 207 208 211 protected ILaunchManager getLaunchManager() { 212 return DebugPlugin.getDefault().getLaunchManager(); 213 } 214 217 public void resourceChanged(IResourceChangeEvent event) { 218 List projects= getBuiltProjects(event); 219 if (!projects.isEmpty()) { 220 updateProjectBuildTime(projects); 221 } 222 if (fHotSwapTargets.isEmpty() && fNoHotSwapTargets.isEmpty()) { 223 return; 225 } 226 ChangedClassFilesVisitor visitor = getChangedClassFiles(event); 227 if (visitor != null) { 228 List resources = visitor.getChangedClassFiles(); 229 List names = visitor.getQualifiedNamesList(); 230 if (!resources.isEmpty()) { 231 notifyTargets(resources, names); 232 } 233 } 234 } 235 236 239 protected List getBuiltProjects(IResourceChangeEvent event) { 240 IResourceDelta delta= event.getDelta(); 241 if (event.getType() != IResourceChangeEvent.POST_BUILD || delta == null || event.getBuildKind() == 0) { 242 return Collections.EMPTY_LIST; 243 } 244 if (event.getBuildKind() == IncrementalProjectBuilder.AUTO_BUILD && !ResourcesPlugin.getWorkspace().isAutoBuilding()) { 245 return Collections.EMPTY_LIST; 248 } 249 Object source = event.getSource(); 250 if (source instanceof IProject) { 251 List list= new ArrayList (); 252 list.add(source); 253 return list; 254 } else if (source instanceof IWorkspace){ 255 IProject[] allProjects = ((IWorkspace) source).getRoot().getProjects(); 256 return Arrays.asList(allProjects); 257 } 258 return Collections.EMPTY_LIST; 259 } 260 261 265 private void updateProjectBuildTime(List projects) { 266 Iterator iter= projects.iterator(); 267 IProject project= null; 268 Date currentDate= new Date (); 269 ProjectBuildTime buildTime= null; 270 while (iter.hasNext()) { 271 project= (IProject) iter.next(); 272 buildTime= (ProjectBuildTime)fProjectBuildTimes.get(project); 273 if (buildTime == null) { 274 buildTime= new ProjectBuildTime(); 275 fProjectBuildTimes.put(project, buildTime); 276 } 277 buildTime.setCurrentBuildDate(currentDate); 278 } 279 } 280 281 287 protected long getLastProjectBuildTime(IProject project) { 288 ProjectBuildTime time= (ProjectBuildTime)fProjectBuildTimes.get(project); 289 if (time == null) { 290 time= new ProjectBuildTime(); 291 time.setLastBuildDate(fStartupDate); 292 fProjectBuildTimes.put(project, time); 293 } 294 return time.getLastBuildDate().getTime(); 295 } 296 297 300 private void notifyTargets(final List resources, final List qualifiedNames) { 301 final List hotSwapTargets= getHotSwapTargets(); 302 final List noHotSwapTargets= getNoHotSwapTargets(); 303 if (!hotSwapTargets.isEmpty()) { 304 Runnable runnable= new Runnable () { 305 public void run() { 306 doHotCodeReplace(hotSwapTargets, resources, qualifiedNames); 307 } 308 }; 309 DebugPlugin.getDefault().asyncExec(runnable); 310 } 311 if (!noHotSwapTargets.isEmpty()) { 312 Runnable runnable= new Runnable () { 313 public void run() { 314 notifyUnsupportedHCR(noHotSwapTargets, resources, qualifiedNames); 315 } 316 }; 317 DebugPlugin.getDefault().asyncExec(runnable); 318 } 319 } 320 321 331 private void filterUnloadedTypes(JDIDebugTarget target, List resources, List qualifiedNames) { 332 for (int i= 0, numElements= qualifiedNames.size(); i < numElements; i++) { 333 String name= (String ) qualifiedNames.get(i); 334 List list = target.jdiClassesByName(name); 335 if (list.isEmpty()) { 336 qualifiedNames.remove(i); 339 resources.remove(i); 340 i--; 342 numElements--; 343 } 344 } 345 } 346 350 protected void notifyUnsupportedHCR(List targets, List resources, List qualifiedNames) { 351 Iterator iter= targets.iterator(); 352 JDIDebugTarget target= null; 353 while (iter.hasNext()) { 354 target= (JDIDebugTarget) iter.next(); 355 if (target.isAvailable()) { 356 List resourcesToReplace= new ArrayList (resources); 359 List qualifiedNamesToReplace= new ArrayList (qualifiedNames); 360 filterUnloadedTypes(target, resourcesToReplace, qualifiedNamesToReplace); 361 362 if (!qualifiedNamesToReplace.isEmpty()) { 363 fireHCRFailed(target, null); 365 notifyFailedHCR(target, qualifiedNamesToReplace); 366 } 367 } else { 368 deregisterTarget(target); 371 } 372 } 373 } 374 375 protected void notifyFailedHCR(JDIDebugTarget target, List qualifiedNames) { 376 if (target.isAvailable()) { 377 target.addOutOfSynchTypes(qualifiedNames); 378 target.fireChangeEvent(DebugEvent.STATE); 379 } 380 } 381 382 386 protected List getHotSwapTargets() { 387 return (List ) fHotSwapTargets.clone(); 388 } 389 390 394 protected List getNoHotSwapTargets() { 395 return (List ) fNoHotSwapTargets.clone(); 396 } 397 398 417 private void doHotCodeReplace(List targets, List resources, List qualifiedNames) { 418 MultiStatus ms= new MultiStatus(JDIDebugPlugin.getUniqueIdentifier(), DebugException.TARGET_REQUEST_FAILED, "At least one target failed to drop to frame after successful hot code replace.", null); Iterator iter= targets.iterator(); 420 while (iter.hasNext()) { 421 JDIDebugTarget target= (JDIDebugTarget) iter.next(); 422 if (!target.isAvailable()) { 423 deregisterTarget(target); 424 continue; 425 } 426 List resourcesToReplace= new ArrayList (resources); 429 List qualifiedNamesToReplace= new ArrayList (qualifiedNames); 430 filterUnloadedTypes(target, resourcesToReplace, qualifiedNamesToReplace); 431 if (qualifiedNamesToReplace.isEmpty()) { 432 continue; 434 } 435 436 List poppedThreads= new ArrayList (); 437 target.setIsPerformingHotCodeReplace(true); 438 try { 439 boolean framesPopped= false; 440 if (target.canPopFrames()) { 441 try { 447 attemptPopFrames(target, resourcesToReplace, qualifiedNamesToReplace, poppedThreads); 448 framesPopped= true; } catch (DebugException de) { 450 if (shouldLogHCRException(de)) { 451 ms.merge(de.getStatus()); 452 } 453 } 454 } 455 target.removeOutOfSynchTypes(qualifiedNamesToReplace); 456 if (target.supportsJDKHotCodeReplace()) { 457 redefineTypesJDK(target, resourcesToReplace, qualifiedNamesToReplace); 458 } else if (target.supportsJ9HotCodeReplace()) { 459 redefineTypesJ9(target, qualifiedNamesToReplace); 460 } 461 if (containsObsoleteMethods(target)) { 462 fireObsoleteMethods(target); 463 } 464 try { 465 if (target.canPopFrames() && framesPopped) { 466 target.setIsPerformingHotCodeReplace(false); 472 attemptStepIn(poppedThreads); 473 } else { 474 attemptDropToFrame(target, resourcesToReplace, qualifiedNamesToReplace); 477 } 478 } catch (DebugException de) { 479 if (shouldLogHCRException(de)) { 480 ms.merge(de.getStatus()); 481 } 482 } 483 fireHCRSucceeded(target); 484 } catch (DebugException de) { 485 fireHCRFailed(target, de); 487 } 488 target.setIsPerformingHotCodeReplace(false); 490 target.fireChangeEvent(DebugEvent.CONTENT); 491 } 492 if (!ms.isOK()) { 493 JDIDebugPlugin.log(ms); 494 } 495 fDeltaCache.clear(); 496 } 497 498 504 private boolean shouldLogHCRException(DebugException exception) { 505 return !(exception.getStatus().getException() instanceof IncompatibleThreadStateException || 506 exception.getStatus().getCode() == IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE || 507 exception.getStatus().getCode() == IJavaThread.ERR_THREAD_NOT_SUSPENDED); 508 } 509 510 526 private void redefineTypesJ9(JDIDebugTarget target, List qualifiedNames) throws DebugException { 527 String [] typeNames = (String []) qualifiedNames.toArray(new String [qualifiedNames.size()]); 528 if (target.supportsJ9HotCodeReplace()) { 529 target.setHCROccurred(true); 530 org.eclipse.jdi.hcr.VirtualMachine vm= (org.eclipse.jdi.hcr.VirtualMachine) target.getVM(); 531 if (vm == null) { 532 target.requestFailed(JDIDebugHCRMessages.JavaHotCodeReplaceManager_Hot_code_replace_failed___VM_disconnected__1, null); 533 } 534 int result= org.eclipse.jdi.hcr.VirtualMachine.RELOAD_FAILURE; 535 try { 536 result= vm.classesHaveChanged(typeNames); 537 } catch (RuntimeException e) { 538 target.targetRequestFailed(MessageFormat.format(JDIDebugHCRMessages.JavaHotCodeReplaceManager_exception_replacing_types, new String [] {e.toString()}), e); 539 } 540 switch (result) { 541 case org.eclipse.jdi.hcr.VirtualMachine.RELOAD_SUCCESS: 542 break; 543 case org.eclipse.jdi.hcr.VirtualMachine.RELOAD_IGNORED: 544 target.targetRequestFailed(JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_ignored, null); 545 break; 546 case org.eclipse.jdi.hcr.VirtualMachine.RELOAD_FAILURE: 547 target.targetRequestFailed(JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_failed, null); 548 target.addOutOfSynchTypes(qualifiedNames); 549 break; 550 } 551 } else { 552 target.notSupported(JDIDebugHCRMessages.JavaHotCodeReplaceManager_does_not_support_hcr); 553 target.addOutOfSynchTypes(qualifiedNames); 554 } 555 } 556 557 562 private void redefineTypesJDK(JDIDebugTarget target, List resources, List qualifiedNames) throws DebugException { 563 if (target.supportsJDKHotCodeReplace()) { 564 target.setHCROccurred(true); 565 Map typesToBytes= getTypesToBytes(target, resources, qualifiedNames); 566 try { 567 VirtualMachine vm = target.getVM(); 568 if (vm == null) { 569 target.requestFailed(JDIDebugHCRMessages.JavaHotCodeReplaceManager_Hot_code_replace_failed___VM_disconnected__2, null); 570 } 571 vm.redefineClasses(typesToBytes); 572 } catch (UnsupportedOperationException exception) { 573 String detail= exception.getMessage(); 574 if (detail != null) { 575 redefineTypesFailedJDK(target, qualifiedNames, MessageFormat.format(JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_unsupported_operation, new String [] {detail}), exception); 576 } else { 577 redefineTypesFailedJDK(target, qualifiedNames, JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_unsupported_redefinition, exception); 578 } 579 } catch (NoClassDefFoundError exception) { 580 redefineTypesFailedJDK(target, qualifiedNames, JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_bad_bytes, exception); 581 } catch (VerifyError exception) { 582 redefineTypesFailedJDK(target, qualifiedNames, JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_verify_error, exception); 583 } catch (UnsupportedClassVersionError exception) { 584 redefineTypesFailedJDK(target, qualifiedNames, JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_unsupported_class_version, exception); 585 } catch (ClassFormatError exception) { 586 redefineTypesFailedJDK(target, qualifiedNames, JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_class_format_error, exception); 587 } catch (ClassCircularityError exception) { 588 redefineTypesFailedJDK(target, qualifiedNames, JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_class_circularity_error, exception); 589 } catch (RuntimeException exception) { 590 redefineTypesFailedJDK(target, qualifiedNames, JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_failed, exception); 591 } 592 target.reinstallBreakpointsIn(resources, qualifiedNames); 593 } else { 594 target.notSupported(JDIDebugHCRMessages.JavaHotCodeReplaceManager_does_not_support_hcr); 595 } 596 } 597 598 604 private void redefineTypesFailedJDK(JDIDebugTarget target, List qualifiedNames, String message, Throwable exception) throws DebugException { 605 target.addOutOfSynchTypes(qualifiedNames); 606 target.jdiRequestFailed(message, exception); 607 } 608 609 622 private Map getTypesToBytes(JDIDebugTarget target, List resources, List qualifiedNames) { 623 Map typesToBytes= new HashMap (resources.size()); 624 Iterator resourceIter= resources.iterator(); 625 Iterator nameIter= qualifiedNames.iterator(); 626 IResource resource; 627 String name; 628 while (resourceIter.hasNext()) { 629 resource= (IResource) resourceIter.next(); 630 name= (String ) nameIter.next(); 631 List classes= target.jdiClassesByName(name); 632 byte[] bytes= null; 633 try { 634 bytes= Util.getResourceContentsAsByteArray((IFile) resource); 635 } catch (JavaModelException jme) { 636 continue; 637 } 638 Iterator classIter= classes.iterator(); 639 while (classIter.hasNext()) { 640 ReferenceType type= (ReferenceType) classIter.next(); 641 typesToBytes.put(type, bytes); 642 } 643 } 644 return typesToBytes; 645 } 646 647 650 private void fireHCRSucceeded(IJavaDebugTarget target) { 651 Object [] listeners= fHotCodeReplaceListeners.getListeners(); 652 for (int i=0; i<listeners.length; i++) { 653 ((IJavaHotCodeReplaceListener)listeners[i]).hotCodeReplaceSucceeded(target); 654 } 655 } 656 657 660 private void fireHCRFailed(JDIDebugTarget target, DebugException exception) { 661 Object [] listeners= fHotCodeReplaceListeners.getListeners(); 662 for (int i=0; i<listeners.length; i++) { 663 ((IJavaHotCodeReplaceListener)listeners[i]).hotCodeReplaceFailed(target, exception); 664 } 665 } 666 667 670 private void fireObsoleteMethods(JDIDebugTarget target) { 671 Object [] listeners= fHotCodeReplaceListeners.getListeners(); 672 for (int i=0; i<listeners.length; i++) { 673 ((IJavaHotCodeReplaceListener)listeners[i]).obsoleteMethods(target); 674 } 675 } 676 677 685 protected void attemptDropToFrame(JDIDebugTarget target, List resources, List replacedClassNames) throws DebugException { 686 List dropFrames= getAffectedFrames(target.getThreads(), resources, replacedClassNames); 687 688 JDIStackFrame dropFrame= null; 690 Iterator iter= dropFrames.iterator(); 691 while (iter.hasNext()) { 692 try { 693 dropFrame= ((JDIStackFrame)iter.next()); 694 dropFrame.dropToFrame(); 695 } catch (DebugException de) { 696 notifyFailedDrop(((JDIThread)dropFrame.getThread()).computeStackFrames(), replacedClassNames); 697 } 698 } 699 } 700 701 711 protected void attemptPopFrames(JDIDebugTarget target, List resources, List replacedClassNames, List poppedThreads) throws DebugException { 712 List popFrames= getAffectedFrames(target.getThreads(), resources, replacedClassNames); 713 714 JDIStackFrame popFrame= null; 716 Iterator iter= popFrames.iterator(); 717 while (iter.hasNext()) { 718 try { 719 popFrame= ((JDIStackFrame)iter.next()); 720 popFrame.popFrame(); 721 poppedThreads.add(popFrame.getThread()); 722 } catch (DebugException de) { 723 poppedThreads.remove(popFrame.getThread()); 724 notifyFailedDrop(((JDIThread)popFrame.getThread()).computeStackFrames(), replacedClassNames); 725 } 726 } 727 } 728 729 733 protected boolean containsObsoleteMethods(JDIDebugTarget target) throws DebugException { 734 IThread[] threads=target.getThreads(); 735 List frames= null; 736 Iterator iter= null; 737 for (int i= 0, numThreads= threads.length; i < numThreads; i++) { 738 frames= ((JDIThread)threads[i]).computeNewStackFrames(); 739 iter= frames.iterator(); 740 while (iter.hasNext()) { 741 if (((JDIStackFrame)iter.next()).isObsolete()) { 742 return true; 743 } 744 } 745 } 746 return false; 747 } 748 749 752 protected List getAffectedFrames(IThread[] threads, List resourceList, List replacedClassNames) throws DebugException { 753 JDIThread thread= null; 754 JDIStackFrame affectedFrame= null; 755 List popFrames= new ArrayList (); 756 int numThreads= threads.length; 757 IResource[] resources= new IResource[resourceList.size()]; 758 resourceList.toArray(resources); 759 for (int i = 0; i < numThreads; i++) { 760 thread= (JDIThread) threads[i]; 761 if (thread.isSuspended()) { 762 affectedFrame= getAffectedFrame(thread, replacedClassNames); 763 if (affectedFrame == null) { 764 continue; 766 } 767 if (affectedFrame.supportsDropToFrame()) { 768 popFrames.add(affectedFrame); 769 } else { 770 for (int j= 0; j < numThreads; j++) { 773 notifyFailedDrop(((JDIThread)threads[i]).computeStackFrames(), replacedClassNames); 774 } 775 throw new DebugException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), 776 DebugException.NOT_SUPPORTED, JDIDebugHCRMessages.JavaHotCodeReplaceManager_Drop_to_frame_not_supported, null)); 777 } 778 } 779 } 780 return popFrames; 781 } 782 783 791 protected JDIStackFrame getAffectedFrame(JDIThread thread, List replacedClassNames) throws DebugException { 792 List frames= thread.computeStackFrames(); 793 JDIStackFrame affectedFrame= null; 794 JDIStackFrame frame= null; 795 ICompilationUnit compilationUnit= null; 796 CompilationUnitDelta delta= null; 797 IProject project= null; 798 for (int j= frames.size() - 1; j >= 0; j--) { 799 frame= (JDIStackFrame) frames.get(j); 800 if (containsChangedType(frame, replacedClassNames)) { 801 compilationUnit= getCompilationUnit(frame); 803 if (compilationUnit != null) { 805 try { 806 project= compilationUnit.getCorrespondingResource().getProject(); 807 delta = getDelta(compilationUnit, getLastProjectBuildTime(project)); 808 if (!delta.hasChanged(frame.getName(), frame.getSignature())) { 809 continue; 810 } 811 } catch (CoreException exception) { 812 } 814 } 815 816 if (frame.supportsDropToFrame()) { 817 affectedFrame= frame; 818 break; 819 } 820 while (j > 0) { 824 j--; 825 frame= (JDIStackFrame) frames.get(j); 826 if (frame.supportsDropToFrame()) { 827 affectedFrame= frame; 828 break; 829 } 830 } 831 break; 832 } 833 } 834 return affectedFrame; 835 } 836 837 844 private CompilationUnitDelta getDelta(ICompilationUnit cu, long time) throws CoreException { 845 CompilationUnitDelta delta = (CompilationUnitDelta) fDeltaCache.get(cu); 846 if (delta == null) { 847 delta= new CompilationUnitDelta(cu, time); 848 fDeltaCache.put(cu, delta); 849 } 850 return delta; 851 } 852 853 857 protected boolean containsChangedType(JDIStackFrame frame, List replacedClassNames) throws DebugException { 858 String declaringTypeName= frame.getDeclaringTypeName(); 859 if (replacedClassNames.contains(declaringTypeName)) { 861 return true; 862 } 863 Iterator iter= replacedClassNames.iterator(); 865 int index; 866 String className= null; 867 while (iter.hasNext()) { 868 className= (String ) iter.next(); 869 index= className.indexOf('$'); 870 if (index > -1 && declaringTypeName.equals(className.substring(0, index))) { 871 return true; 872 } 873 } 874 return false; 875 } 876 877 880 protected void attemptStepIn(List threads) throws DebugException { 881 Iterator iter= threads.iterator(); 882 while (iter.hasNext()) { 883 ((JDIThread) iter.next()).stepInto(); 884 } 885 } 886 887 892 protected ICompilationUnit getCompilationUnit(IJavaStackFrame frame) { 893 ILaunch launch= frame.getLaunch(); 894 if (launch == null) { 895 return null; 896 } 897 ISourceLocator locator= launch.getSourceLocator(); 898 if (locator == null) { 899 return null; 900 } 901 IJavaDebugTarget target = (IJavaDebugTarget) frame.getDebugTarget(); 902 String def = target.getDefaultStratum(); 903 target.setDefaultStratum("Java"); Object sourceElement= locator.getSourceElement(frame); 905 target.setDefaultStratum(def); 906 if (!(sourceElement instanceof IJavaElement) && sourceElement instanceof IAdaptable) { 907 sourceElement = ((IAdaptable)sourceElement).getAdapter(IJavaElement.class); 908 } 909 if (sourceElement instanceof IType) { 910 return ((IType)sourceElement).getCompilationUnit(); 911 } 912 if (sourceElement instanceof ICompilationUnit) { 913 return (ICompilationUnit)sourceElement; 914 } 915 return null; 916 } 917 918 922 public IMethod getMethod(JDIStackFrame frame, ICompilationUnit unit) throws CoreException { 923 String declaringTypeName= frame.getDeclaringTypeName(); 924 String methodName= frame.getMethodName(); 925 String [] arguments= null; 926 try { 927 arguments= Signature.getParameterTypes(frame.getSignature()); 928 } catch (IllegalArgumentException exception) { 929 return null; 932 } 933 String typeName = getUnqualifiedName(declaringTypeName); 934 int index = typeName.indexOf('$'); 935 IType type = null; 936 if (index > 0) { 937 String remaining = typeName.substring(index + 1); 938 typeName = typeName.substring(0, index); 939 type = unit.getType(typeName); 940 while (remaining != null) { 941 index = remaining.indexOf('$'); 942 if (index > 0) { 943 typeName = remaining.substring(0, index); 944 remaining = remaining.substring(index + 1); 945 } else { 946 typeName = remaining; 947 remaining = null; 948 } 949 type = type.getType(typeName); 950 } 951 } else { 952 type = unit.getType(typeName); 953 } 954 if (type != null) { 955 return type.getMethod(methodName, arguments); 956 } 957 return null; 958 } 959 960 963 protected String getUnqualifiedName(String qualifiedName) { 964 int index= qualifiedName.lastIndexOf('.'); 965 return qualifiedName.substring(index + 1); 966 } 967 968 972 private void notifyFailedDrop(List frames, List replacedClassNames) throws DebugException { 973 JDIStackFrame frame; 974 Iterator iter= frames.iterator(); 975 while (iter.hasNext()) { 976 frame= (JDIStackFrame) iter.next(); 977 if (replacedClassNames.contains(frame.getDeclaringTypeName())) { 978 frame.setOutOfSynch(true); 979 } 980 } 981 } 982 988 protected ChangedClassFilesVisitor getChangedClassFiles(IResourceChangeEvent event) { 989 IResourceDelta delta= event.getDelta(); 990 if (event.getType() != IResourceChangeEvent.POST_BUILD || delta == null) { 991 return null; 992 } 993 fClassfileVisitor.reset(); 994 try { 995 delta.accept(fClassfileVisitor); 996 } catch (CoreException e) { 997 JDIDebugPlugin.log(e); 998 return null; } 1000 return fClassfileVisitor; 1001 } 1002 1003 1006 class ChangedClassFilesVisitor implements IResourceDeltaVisitor { 1007 1010 protected List fFiles= null; 1011 1012 1015 protected List fNames= null; 1016 1017 1023 public boolean visit(IResourceDelta delta) { 1024 if (delta == null || 0 == (delta.getKind() & IResourceDelta.CHANGED)) { 1025 return false; 1026 } 1027 IResource resource= delta.getResource(); 1028 if (resource != null) { 1029 switch (resource.getType()) { 1030 case IResource.FILE : 1031 if (0 == (delta.getFlags() & IResourceDelta.CONTENT)) 1032 return false; 1033 if (CLASS_FILE_EXTENSION.equals(resource.getFullPath().getFileExtension())) { 1034 IPath localLocation = resource.getLocation(); 1035 if (localLocation != null) { 1036 String path = localLocation.toOSString(); 1037 IClassFileReader reader = ToolFactory.createDefaultClassFileReader(path, IClassFileReader.CLASSFILE_ATTRIBUTES); 1038 if (reader != null) { 1039 String qualifiedName = new String (reader.getClassName()); 1041 boolean hasBlockingErrors= false; 1042 try { 1043 if (!JDIDebugModel.getPreferences().getBoolean(JDIDebugModel.PREF_HCR_WITH_COMPILATION_ERRORS)) { 1044 IJavaProject pro = JavaCore.create(resource.getProject()); 1048 ISourceAttribute sourceAttribute = reader.getSourceFileAttribute(); 1049 String sourceName = null; 1050 if (sourceAttribute != null) { 1051 sourceName = new String (sourceAttribute.getSourceFileName()); 1052 } 1053 IResource sourceFile= getSourceFile(pro, qualifiedName, sourceName); 1054 if (sourceFile != null) { 1055 IMarker[] problemMarkers= null; 1056 problemMarkers= sourceFile.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); 1057 for (int i= 0; i < problemMarkers.length; i++) { 1058 if (problemMarkers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR) { 1059 hasBlockingErrors= true; 1060 break; 1061 } 1062 } 1063 } 1064 } 1065 } catch (CoreException e) { 1066 JDIDebugPlugin.log(e); 1067 } 1068 if (!hasBlockingErrors) { 1069 fFiles.add(resource); 1070 fNames.add(qualifiedName.replace('/','.')); 1072 } 1073 } 1074 } 1075 } 1076 return false; 1077 1078 default : 1079 return true; 1080 } 1081 } 1082 return true; 1083 } 1084 1087 public void reset() { 1088 fFiles = new ArrayList (); 1089 fNames = new ArrayList (); 1090 } 1091 1092 1095 public List getChangedClassFiles() { 1096 return fFiles; 1097 } 1098 1099 1105 public List getQualifiedNamesList() { 1106 return fNames; 1107 } 1108 1109 1119 private IResource getSourceFile(IJavaProject project, String qualifiedName, String sourceAttribute) { 1120 String name = null; 1121 IJavaElement element = null; 1122 try { 1123 if (sourceAttribute == null) { 1124 element = JavaDebugUtils.findElement(qualifiedName, project); 1125 } else { 1126 int i = qualifiedName.lastIndexOf('/'); 1127 if (i > 0) { 1128 name = qualifiedName.substring(0, i + 1); 1129 name = name + sourceAttribute; 1130 } else { 1131 name = sourceAttribute; 1132 } 1133 element = project.findElement(new Path(name)); 1134 } 1135 if (element instanceof ICompilationUnit) { 1136 ICompilationUnit cu = (ICompilationUnit) element; 1137 return cu.getCorrespondingResource(); 1138 } 1139 } catch (CoreException e) { 1140 } 1141 return null; 1142 } 1143 } 1144 1145 1146 1150 public void addHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) { 1151 fHotCodeReplaceListeners.add(listener); 1152 } 1153 1154 1159 public void removeHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) { 1160 fHotCodeReplaceListeners.remove(listener); 1161 } 1162 1163 1166 public void launchRemoved(ILaunch launch) { 1167 IDebugTarget[] debugTargets= launch.getDebugTargets(); 1168 for (int i = 0; i < debugTargets.length; i++) { 1169 IJavaDebugTarget jt = (IJavaDebugTarget)debugTargets[i].getAdapter(IJavaDebugTarget.class); 1170 if (jt != null) { 1171 deregisterTarget((JDIDebugTarget)jt); 1172 } 1173 } 1174 } 1175 1176 1182 public void launchAdded(ILaunch launch) { 1183 IDebugTarget[] debugTargets= launch.getDebugTargets(); 1184 for (int i = 0; i < debugTargets.length; i++) { 1185 IJavaDebugTarget jt = (IJavaDebugTarget)debugTargets[i].getAdapter(IJavaDebugTarget.class); 1186 if (jt != null) { 1187 JDIDebugTarget target = (JDIDebugTarget)jt; 1188 if (target.supportsHotCodeReplace()) { 1189 addHotSwapTarget(target); 1190 } else if (target.isAvailable()){ 1191 addNonHotSwapTarget(target); 1192 } 1193 } 1194 } 1195 if (!fHotSwapTargets.isEmpty() || !fNoHotSwapTargets.isEmpty()) { 1196 getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_BUILD); 1197 } 1198 } 1199 1200 1206 public void launchChanged(ILaunch launch) { 1207 launchAdded(launch); 1208 } 1209 1210 1213 public void handleDebugEvents(DebugEvent[] events) { 1214 for (int i = 0; i < events.length; i++) { 1215 DebugEvent event = events[i]; 1216 if (event.getKind() == DebugEvent.TERMINATE) { 1217 Object source = event.getSource(); 1218 if (source instanceof IAdaptable && source instanceof IDebugTarget) { 1219 IJavaDebugTarget jt = (IJavaDebugTarget)((IAdaptable)source).getAdapter(IJavaDebugTarget.class); 1220 if (jt != null) { 1221 deregisterTarget((JDIDebugTarget)jt); 1222 } 1223 } 1224 } 1225 } 1226 } 1227 1228 protected void deregisterTarget(JDIDebugTarget target) { 1229 if (!fHotSwapTargets.remove(target)) { 1231 fNoHotSwapTargets.remove(target); 1232 } 1233 ILaunch[] launches= DebugPlugin.getDefault().getLaunchManager().getLaunches(); 1234 for (int i= 0; i < launches.length; i++) { 1237 IDebugTarget[] targets = launches[i].getDebugTargets(); 1238 for (int j = 0; j < targets.length; j++) { 1239 IDebugTarget debugTarget = targets[j]; 1240 IJavaDebugTarget jt = (IJavaDebugTarget)debugTarget.getAdapter(IJavaDebugTarget.class); 1241 if (jt != null) { 1242 if (((JDIDebugTarget)jt).isAvailable()) { 1243 return; 1244 } 1245 } 1246 } 1247 } 1248 } 1249 1250 1256 protected void addHotSwapTarget(JDIDebugTarget target) { 1257 if (!fHotSwapTargets.contains(target)) { 1258 fHotSwapTargets.add(target); 1259 } 1260 } 1261 1262 1268 protected void addNonHotSwapTarget(JDIDebugTarget target) { 1269 if (!fNoHotSwapTargets.contains(target)) { 1270 fNoHotSwapTargets.add(target); 1271 } 1272 } 1273 1274} 1275 1276 | Popular Tags |