1 19 20 package org.netbeans.modules.ant.debugger; 21 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.lang.StringBuffer ; 25 import java.util.Collections ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import java.util.HashSet ; 29 import java.util.LinkedList ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.Set ; 33 import java.util.Stack ; 34 import java.util.StringTokenizer ; 35 import org.apache.tools.ant.module.api.AntProjectCookie; 36 import org.apache.tools.ant.module.api.support.TargetLister; 37 import org.apache.tools.ant.module.spi.AntEvent; 38 import org.apache.tools.ant.module.spi.AntLogger; 39 import org.apache.tools.ant.module.spi.AntSession; 40 import org.apache.tools.ant.module.spi.TaskStructure; 41 import org.netbeans.api.debugger.ActionsManager; 42 import org.netbeans.api.debugger.Breakpoint; 43 import org.netbeans.api.debugger.DebuggerEngine; 44 import org.netbeans.api.debugger.DebuggerManager; 45 import org.netbeans.api.debugger.Watch; 46 import org.netbeans.modules.ant.debugger.breakpoints.AntBreakpoint; 47 import org.netbeans.modules.ant.debugger.breakpoints.BreakpointModel; 48 import org.netbeans.spi.debugger.ActionsProviderSupport; 49 import org.netbeans.spi.debugger.ContextProvider; 50 import org.netbeans.spi.debugger.DebuggerEngineProvider; 51 import org.netbeans.spi.viewmodel.TableModel; 52 import org.netbeans.spi.viewmodel.TreeModel; 53 import org.openide.execution.ExecutorTask; 54 import org.openide.filesystems.FileObject; 55 import org.openide.filesystems.FileUtil; 56 import org.openide.loaders.DataObject; 57 import org.openide.loaders.DataObjectNotFoundException; 58 import org.openide.text.Annotatable; 59 import org.openide.text.Line; 60 import org.openide.util.Lookup; 61 import org.openide.util.RequestProcessor; 62 import org.openide.util.TaskListener; 63 import org.w3c.dom.Element ; 64 65 70 public class AntDebugger extends ActionsProviderSupport { 71 72 73 74 private static RequestProcessor actionsRequestProcessor; 75 76 private AntProjectCookie antCookie; 77 private AntDebuggerEngineProvider engineProvider; 78 private ContextProvider contextProvider; 79 private ExecutorTask execTask; 80 private Object LOCK = new Object (); 81 private Object LOCK_ACTIONS = new Object (); 82 private boolean actionRunning = false; 83 private IOManager ioManager; 84 private Object currentLine; 85 private LinkedList callStackList = new LinkedList (); 86 private File currentFile; 87 private String currentTargetName; 88 private String currentTaskName; 89 private int originatingIndex = -1; 91 92 public AntDebugger ( 93 ContextProvider contextProvider 94 ) { 95 96 this.contextProvider = contextProvider; 97 98 antCookie = (AntProjectCookie) contextProvider.lookupFirst 100 (null, AntProjectCookie.class); 101 102 engineProvider = (AntDebuggerEngineProvider) contextProvider.lookupFirst 104 (null, DebuggerEngineProvider.class); 105 106 for (Iterator it = actions.iterator(); it.hasNext(); ) { 108 setEnabled (it.next(), true); 109 } 110 111 ioManager = new IOManager (antCookie.getFile ().getName ()); 112 } 113 114 void setExecutor(ExecutorTask execTask) { 115 this.execTask = execTask; 116 if (execTask != null) { 117 execTask.addTaskListener(new TaskListener() { 118 public void taskFinished(org.openide.util.Task task) { 119 finish(); 121 } 122 }); 123 } 124 } 125 126 127 129 private static final Set actions = new HashSet (); 130 static { 131 actions.add (ActionsManager.ACTION_KILL); 132 actions.add (ActionsManager.ACTION_CONTINUE); 133 actions.add (ActionsManager.ACTION_START); 134 actions.add (ActionsManager.ACTION_STEP_INTO); 135 actions.add (ActionsManager.ACTION_STEP_OVER); 136 actions.add (ActionsManager.ACTION_STEP_OUT); 137 } 138 139 public Set getActions () { 140 return actions; 141 } 142 143 public void doAction (Object action) { 144 synchronized (LOCK_ACTIONS) { 145 actionRunning = true; 146 } 147 if (action == ActionsManager.ACTION_KILL) { 148 finish (); 149 } else 150 if (action == ActionsManager.ACTION_CONTINUE) { 151 doContinue (); 152 } else 153 if (action == ActionsManager.ACTION_START) { 154 return ; 155 } else 156 if ( action == ActionsManager.ACTION_STEP_INTO || 157 action == ActionsManager.ACTION_STEP_OUT || 158 action == ActionsManager.ACTION_STEP_OVER 159 ) { 160 doStep (action); 161 } 162 synchronized (LOCK_ACTIONS) { 163 if (actionRunning) { 164 try { 165 LOCK_ACTIONS.wait(); 166 } catch (InterruptedException iex) {} 167 } 168 } 169 } 170 171 public void postAction(final Object action, final Runnable actionPerformedNotifier) { 172 for (Iterator it = actions.iterator(); it.hasNext(); ) { 173 setEnabled (it.next(), false); 174 } 175 synchronized (AntDebugger.class) { 176 if (actionsRequestProcessor == null) { 177 actionsRequestProcessor = new RequestProcessor("Ant debugger actions RP", 1); 178 } 179 } 180 actionsRequestProcessor.post(new Runnable () { 181 public void run() { 182 try { 183 doAction(action); 184 } finally { 185 actionPerformedNotifier.run(); 186 for (Iterator it = actions.iterator(); it.hasNext(); ) { 187 setEnabled (it.next(), true); 188 } 189 } 190 } 191 }); 192 } 193 194 195 197 private AntEvent lastEvent; 198 199 202 void taskStarted (AntEvent event) { 203 Object taskLine = Utils.getLine (event); 204 callStackList.addFirst( 205 new Task (event.getTaskStructure (), 206 taskLine, 207 event.getScriptLocation ())); 208 currentTaskName = event.getTaskStructure().getName(); 209 originatingIndex = 0; 210 elementStarted(event); 211 } 212 213 private void elementStarted(AntEvent event) { 214 if (!doStop) { 215 if (!onBreakpoint ()) { 216 return ; } 218 } 219 stopHere(event); 220 } 221 222 private void stopHere(AntEvent event) { 223 synchronized (this) { 224 lastEvent = event; 225 } 226 updateUI(); 227 currentFile = event.getScriptLocation(); 228 Set properties = event.getPropertyNames (); 230 variables = (String []) properties.toArray 231 (new String [properties.size ()]); 232 getVariablesModel ().fireChanges (); 233 getBreakpointModel ().fireChanges (); 234 235 synchronized (LOCK_ACTIONS) { 237 actionRunning = false; 238 LOCK_ACTIONS.notifyAll(); 239 } 240 241 synchronized (LOCK) { 243 try { 244 LOCK.wait (); 245 } catch (InterruptedException ex) { 246 ex.printStackTrace (); 247 } 248 } 249 synchronized (this) { 250 lastEvent = null; 251 } 252 } 253 254 void taskFinished (AntEvent event) { 255 callStackList.remove(0); if (taskEndToStopAt != null && 257 taskEndToStopAt.equals(event.getTaskStructure().getName()) && 258 event.getScriptLocation().equals(fileToStopAt)) { 259 260 if (targetEndToStopAt != null) { 261 if (targetEndToStopAt.equals(event.getTargetName())) { 262 targetEndToStopAt = null; 263 taskEndToStopAt = null; 264 fileToStopAt = null; 265 doStop = true; 266 } 267 } else { 268 taskEndToStopAt = null; 269 fileToStopAt = null; 270 doStop = true; 271 } 272 } 273 } 274 275 278 void buildFinished (AntEvent event) { 279 engineProvider.getDestructor ().killEngine (); 280 ioManager.closeStream (); 281 Utils.unmarkCurrent (); 282 synchronized (LOCK_ACTIONS) { 284 actionRunning = false; 285 LOCK_ACTIONS.notifyAll(); 286 } 287 } 288 289 void targetStarted(AntEvent event) { 290 String targetName = event.getTargetName(); 291 TargetLister.Target target = findTarget(targetName, event.getScriptLocation()); 293 294 List originatingTargets = null; 295 if (callStackList.size() > 0) { 296 Object topFrame = callStackList.get(0); 297 if (topFrame instanceof Task) { 298 Task t1 = (Task) topFrame; 299 String startingTargetName = t1.getTaskStructure().getAttribute("target"); 300 if (startingTargetName != null && !targetName.equals(startingTargetName)) { 301 originatingTargets = findPath(event.getScriptLocation(), startingTargetName, targetName); 302 } 303 } else if (topFrame instanceof TargetLister.Target) { 304 String start = ((TargetLister.Target) topFrame).getName(); 305 List path = findPath (event.getScriptLocation(), start, targetName); 306 if (path != null) { 307 callStackList.removeFirst(); 308 originatingTargets = path; 309 } 310 } else if (topFrame instanceof TargetOriginating) { 311 String start = ((TargetOriginating) topFrame).getOriginatingTarget().getName(); 312 if (start.equals(targetName)) { 313 callStackList.removeFirst(); 314 originatingIndex--; 315 } else { 316 List path = findPath (event.getScriptLocation(), start, targetName); 317 if (path != null) { 318 callStackList.removeFirst(); 319 originatingTargets = path; 320 } 321 } 322 } 323 } else { 324 String [] sessionOriginatingTargets = event.getSession ().getOriginatingTargets(); 325 int l = sessionOriginatingTargets.length; 326 for (int i = 0; i < l; i++) { 327 String start = sessionOriginatingTargets [i]; 328 if (start.equals(targetName)) continue; 329 List path = findPath (event.getScriptLocation(), start, targetName); 330 if (path != null) { 331 originatingTargets = path; 332 break; 333 } 334 } 336 } 337 if (originatingTargets != null) { 338 originatingIndex = originatingTargets.size(); 339 callStackList.addAll(0, originatingTargets); 340 } else { 341 originatingIndex = 0; 342 } 343 345 Object topFrame = (callStackList.size()) > 0 ? callStackList.getFirst() : null; 346 if (topFrame instanceof TargetOriginating) { 347 if (((TargetOriginating) topFrame).getOriginatingTarget().getName().equals(targetName)) { 348 callStackList.removeFirst(); 349 originatingIndex--; 350 } 351 } 352 353 callStackList.addFirst(target); 354 currentTargetName = targetName; 355 currentTaskName = null; 356 elementStarted(event); 357 } 358 359 void targetFinished(AntEvent event) { 360 callStackList.remove(0); if (targetEndToStopAt != null && targetEndToStopAt.equals(event.getTargetName()) && 362 fileToStopAt.equals(event.getScriptLocation())) { 363 targetEndToStopAt = null; 364 taskEndToStopAt = null; 365 fileToStopAt = null; 366 doStop = true; 367 } 368 currentTargetName = null; 369 } 370 371 private Object getTopFrame() { 372 Object topFrame; 373 if (originatingIndex > 0) { 374 topFrame = callStackList.get(originatingIndex); 375 } else { 376 topFrame = callStackList.get(0); 377 } 378 if (topFrame instanceof TargetOriginating) { 379 topFrame = ((TargetOriginating) topFrame).getOriginatingTarget(); 380 } 381 return topFrame; 382 } 383 384 private void updateUI () { 385 388 Object topFrame; 389 String nextTargetName = null; 390 if (originatingIndex > 0) { 391 topFrame = callStackList.get(originatingIndex); 392 } else { 393 topFrame = callStackList.get(0); 394 } 395 if (topFrame instanceof TargetOriginating) { 396 TargetLister.Target nextTarget = ((TargetOriginating) topFrame).getDependentTarget(); 397 nextTargetName = nextTarget.getName(); 398 topFrame = ((TargetOriginating) topFrame).getOriginatingTarget(); 399 } 400 currentLine = topFrame instanceof Task ? 401 ((Task) topFrame).getLine () : 402 Utils.getLine ( 403 (TargetLister.Target) topFrame, 404 nextTargetName 405 ); 406 updateOutputWindow (currentLine); 407 Utils.markCurrent (currentLine); 408 getCallStackModel ().fireChanges (); 409 } 410 411 private void updateOutputWindow (Object currentLine) { 412 Object topFrame = getTopFrame(); 413 if (topFrame instanceof Task) { 414 Task task = (Task) topFrame; 415 ioManager.println ( 416 task.getFile ().getName () + ":" + 417 (Utils.getLineNumber (currentLine) + 1) + 418 ": Task " + getStackAsString (), 419 currentLine 420 ); 421 } else { 422 TargetLister.Target target = (TargetLister.Target) topFrame; 423 ioManager.println ( 424 target.getScript ().getFile ().getName () + ":" + 425 (Utils.getLineNumber (currentLine) + 1) + 426 ": Target " + getStackAsString (), 427 currentLine 428 ); 429 } 430 } 431 432 private String getStackAsString () { 433 StringBuffer sb = new StringBuffer (); 434 int i = callStackList.size() - 1; 435 sb.append (getFrameName (callStackList.get(i--))); 436 int end = Math.max(0, originatingIndex); 437 while (i >= end) 438 sb.append ('.').append (getFrameName (callStackList.get(i--))); 439 return new String (sb); 440 } 441 442 private static String getFrameName (Object frame) { 443 if (frame instanceof TargetOriginating) { 444 frame = ((TargetOriginating) frame).getOriginatingTarget(); 445 } 446 return frame instanceof Task ? 447 ((Task) frame).getTaskStructure ().getName () : 448 ((TargetLister.Target) frame).getName (); 449 } 450 451 private Map watches = new HashMap (); 452 453 private boolean onBreakpoint () { 454 Watch[] ws = DebuggerManager.getDebuggerManager (). 456 getWatches (); 457 int j, jj = ws.length; 458 for (j = 0; j < jj; j++) { 459 Object value = getVariableValue (ws [j].getExpression ()); 460 if (value == null) value = new Integer (0); 461 if ( watches.containsKey (ws [j].getExpression ()) && 462 !watches.get (ws [j].getExpression ()).equals (value) 463 ) { 464 469 watches.put ( 470 ws [j].getExpression (), 471 value 472 ); 473 return true; 474 } else 475 watches.put ( 476 ws [j].getExpression (), 477 value 478 ); 479 } 480 481 Breakpoint[] breakpoints = DebuggerManager.getDebuggerManager (). 483 getBreakpoints (); 484 jj = callStackList.size(); 485 if (jj >= 1) { 486 Object frame = callStackList.getFirst(); 487 if (frame instanceof TargetOriginating) { 488 frame = ((TargetOriginating) frame).getOriginatingTarget(); 489 } 490 Object line = frame instanceof Task ? 491 ((Task) frame).getLine () : 492 Utils.getLine ( 493 (TargetLister.Target) frame, 494 null 495 ); 496 if (line != null) { 497 line = new Annotatable[] { ((Annotatable[]) line)[0] }; 498 } 499 int i, k = breakpoints.length; 500 for (i = 0; i < k; i++) 501 if ( breakpoints [i] instanceof AntBreakpoint && 502 breakpoints [i].isEnabled() && 503 Utils.contains ( 504 line, 505 ((AntBreakpoint) breakpoints [i]).getLine () 506 507 ) 508 ) { 509 return true; 514 } 515 } 516 return false; 517 } 518 519 public Object getCurrentLine () { 520 return currentLine; 521 } 522 523 524 526 private Object lastAction; 527 528 private String targetEndToStopAt = null; 529 private String taskEndToStopAt = null; 530 private File fileToStopAt = null; 531 private boolean doStop = true; 533 private void doContinue () { 534 Utils.unmarkCurrent (); 535 doStop = false; 537 targetEndToStopAt = null; 538 taskEndToStopAt = null; 539 fileToStopAt = null; 540 doEngineStep (); 541 } 542 543 546 private void doStep (Object action) { 547 if (action == ActionsManager.ACTION_STEP_INTO) { 548 if (originatingIndex > 0) { 549 originatingIndex--; 550 updateUI(); 551 synchronized (LOCK_ACTIONS) { 553 actionRunning = false; 554 LOCK_ACTIONS.notifyAll(); 555 } 556 return ; 557 } 558 doStop = true; 559 } else if (action == ActionsManager.ACTION_STEP_OVER) { 560 if (originatingIndex > 0) { 561 Object frame = callStackList.get(originatingIndex); 562 TargetLister.Target dep = ((TargetOriginating) frame).getDependentTarget(); 563 targetEndToStopAt = dep.getName(); 564 taskEndToStopAt = null; 565 fileToStopAt = currentFile; 566 doStop = false; 567 } else { 568 taskEndToStopAt = currentTaskName; 569 targetEndToStopAt = currentTargetName; 570 fileToStopAt = currentFile; 571 doStop = false; 572 } 573 } else if (action == ActionsManager.ACTION_STEP_OUT) { 574 if (originatingIndex > 1) { 575 Object frame = callStackList.get(originatingIndex - 1); 576 TargetLister.Target dep = ((TargetOriginating) frame).getDependentTarget(); 577 targetEndToStopAt = dep.getName(); 578 taskEndToStopAt = null; 579 fileToStopAt = currentFile; 580 doStop = false; 581 } 582 if (callStackList.size() > 1) { 583 Object frame = callStackList.get(1); 584 if (frame instanceof Task) { 585 taskEndToStopAt = ((Task) frame).getTaskStructure().getName(); 586 for (int i = 2; i < callStackList.size(); i++) { 587 frame = callStackList.get(i); 588 if (frame instanceof String ) { 589 targetEndToStopAt = ((TargetLister.Target) frame).getName(); 590 break; 591 } 592 } 593 } else { 594 if (frame instanceof TargetOriginating) { 595 targetEndToStopAt = ((TargetOriginating) frame).getOriginatingTarget().getName(); 596 } else { 597 targetEndToStopAt = ((TargetLister.Target) frame).getName(); 598 } 599 } 600 fileToStopAt = currentFile; 601 doStop = false; 602 } 603 } else { 604 throw new IllegalArgumentException (action.toString()); 605 } 606 doEngineStep(); 607 } 609 610 611 private void doEngineStep () { 612 synchronized (LOCK) { 614 LOCK.notify (); 615 } 616 } 617 618 private void finish () { 619 if (execTask != null) { 620 execTask.stop(); 621 } 622 Utils.unmarkCurrent (); 623 doStop = false; 624 taskEndToStopAt = null; 625 targetEndToStopAt = null; 626 fileToStopAt = null; 627 synchronized (LOCK) { 628 LOCK.notify (); 629 } 630 buildFinished(null); 631 } 632 633 634 636 private CallStackModel callStackModel; 637 638 private CallStackModel getCallStackModel () { 639 if (callStackModel == null) 640 callStackModel = (CallStackModel) contextProvider.lookupFirst 641 ("CallStackView", TreeModel.class); 642 return callStackModel; 643 } 644 645 646 Object [] getCallStack () { 647 Object [] callStack; 650 if (originatingIndex > 0) { 651 callStack = callStackList.subList(originatingIndex, callStackList.size()).toArray(); 652 } else { 653 callStack = callStackList.toArray(); 654 } 655 for (int i = 0; i < callStack.length; i++) { 656 if (callStack[i] instanceof TargetOriginating) { 657 callStack[i] = ((TargetOriginating) callStack[i]).getOriginatingTarget(); 658 } 659 } 660 return callStack; 661 } 662 663 private LinkedList findPath ( 664 File file, 665 String start, 666 String end 667 ) { 668 TargetLister.Target t = findTarget(start, file); 669 if (t == null) { 670 return null; } 672 if (start.equals (end)) { 673 LinkedList ll = new LinkedList (); 674 ll.addFirst (new TargetOriginating(null, t)); 675 return ll; 676 } 677 String depends = t.getElement ().getAttribute ("depends"); 678 StringTokenizer st = new StringTokenizer (depends, ","); 679 while (st.hasMoreTokens ()) { 680 String newStart = st.nextToken ().trim(); 681 LinkedList ll = findPath ( 682 file, 683 newStart, 684 end 685 ); 686 if (ll == null) continue; 687 TargetOriginating to = (TargetOriginating) ll.getLast(); 688 if (to.getOriginatingTarget() == null) { 689 to.setOriginatingTarget(findTarget(start, file)); 690 } else { 691 ll.addLast(new TargetOriginating(findTarget(start, file), to.getOriginatingTarget())); 692 } 693 return ll; 694 } 695 return null; 696 } 697 698 699 700 703 private Map nameToTargetByFiles = new HashMap (); 704 707 private Map projectNamesByFiles = new HashMap (); 708 709 private synchronized TargetLister.Target findTarget(String name, File file) { 710 Map nameToTarget = (Map ) nameToTargetByFiles.get(file); 711 if (nameToTarget == null) { 712 nameToTarget = new HashMap (); 713 FileObject fo = FileUtil.toFileObject(file); 714 DataObject dob; 715 try { 716 dob = DataObject.find (fo); 717 } catch (DataObjectNotFoundException donfex) { 718 throw new IllegalStateException (donfex.getLocalizedMessage()); 719 } 720 AntProjectCookie ant = (AntProjectCookie) dob.getCookie 721 (AntProjectCookie.class); 722 Element proj = ant.getProjectElement(); 723 if (proj != null) { 724 String projName = proj.getAttribute("name"); 725 projectNamesByFiles.put(file, projName); 726 } 727 try { 728 Set targets = TargetLister.getTargets (ant); 729 Iterator it = targets.iterator (); 730 while (it.hasNext ()) { 731 TargetLister.Target t = (TargetLister.Target) it.next (); 732 nameToTarget.put (t.getName (), t); 733 } 734 } catch (IOException ioex) { 735 } 737 nameToTargetByFiles.put(file, nameToTarget); 738 } 739 TargetLister.Target target = (TargetLister.Target) nameToTarget.get(name); 740 if (target == null) { 741 String projName = (String ) projectNamesByFiles.get(file); 742 if (name.startsWith(projName+".")) { 743 name = name.substring(projName.length() + 1); 744 target = (TargetLister.Target) nameToTarget.get(name); 745 } 746 } 747 return target; 748 } 749 750 751 753 private VariablesModel variablesModel; 754 755 private VariablesModel getVariablesModel () { 756 if (variablesModel == null) 757 variablesModel = (VariablesModel) contextProvider.lookupFirst 758 ("LocalsView", TreeModel.class); 759 return variablesModel; 760 } 761 762 private BreakpointModel breakpointModel; 763 764 private BreakpointModel getBreakpointModel () { 765 if (breakpointModel == null) { 766 Iterator it = DebuggerManager.getDebuggerManager ().lookup 767 ("BreakpointsView", TableModel.class).iterator (); 768 while (it.hasNext ()) { 769 TableModel model = (TableModel) it.next (); 770 if (model instanceof BreakpointModel) { 771 breakpointModel = (BreakpointModel) model; 772 break; 773 } 774 } 775 } 776 return breakpointModel; 777 } 778 779 String evaluate (String expression) { 780 String value = getVariableValue (expression); 781 if (value != null) return value; 782 synchronized (this) { 783 if (lastEvent == null) return null; 784 return lastEvent.evaluate (expression); 785 } 786 } 787 788 private String [] variables = new String [0]; 789 790 String [] getVariables () { 791 return variables; 792 } 793 794 String getVariableValue (String variableName) { 795 synchronized (this) { 796 if (lastEvent == null) return null; 797 return lastEvent.getProperty (variableName); 798 } 799 } 800 801 807 private static class TargetOriginating { 808 809 private TargetLister.Target target; 810 private TargetLister.Target dependent; 811 812 817 TargetOriginating ( 818 TargetLister.Target target, 819 TargetLister.Target dependent 820 ) { 821 this.target = target; 822 this.dependent = dependent; 823 } 824 825 TargetLister.Target getOriginatingTarget () { 826 return target; 827 } 828 829 void setOriginatingTarget (TargetLister.Target target) { 830 this.target = target; 831 } 832 833 TargetLister.Target getDependentTarget () { 834 return dependent; 835 } 836 837 } 838 839 } 840 | Popular Tags |