1 19 package org.netbeans.modules.debugger.jpda.ui; 20 21 import com.sun.jdi.AbsentInformationException; 22 import com.sun.jdi.StackFrame; 23 import java.beans.PropertyChangeListener ; 24 import java.io.File ; 25 import java.util.ArrayList ; 26 import java.util.Arrays ; 27 import java.util.Collections ; 28 import java.util.HashSet ; 29 import java.util.Iterator ; 30 import java.util.WeakHashMap ; 31 import java.util.List ; 32 import java.util.Set ; 33 import org.netbeans.api.debugger.Properties; 34 import org.netbeans.spi.debugger.ContextProvider; 35 36 import org.netbeans.api.debugger.DebuggerManager; 37 import org.netbeans.api.debugger.Session; 38 import org.netbeans.api.debugger.jpda.CallStackFrame; 39 import org.netbeans.api.debugger.jpda.Field; 40 import org.netbeans.api.debugger.jpda.JPDADebugger; 41 import org.netbeans.api.debugger.jpda.JPDAThread; 42 import org.netbeans.api.debugger.jpda.LineBreakpoint; 43 import org.netbeans.api.debugger.jpda.LocalVariable; 44 import org.netbeans.api.debugger.jpda.Variable; 45 import org.netbeans.spi.debugger.jpda.EditorContext; 46 import org.netbeans.spi.debugger.jpda.EditorContext.Operation; 47 import org.netbeans.spi.debugger.jpda.SourcePathProvider; 48 import org.openide.ErrorManager; 49 50 57 public class SourcePath { 58 59 private ContextProvider contextProvider; 60 private SourcePathProvider sourcePathProvider; 61 private JPDADebugger debugger; 62 63 64 public SourcePath (ContextProvider contextProvider) { 65 this.contextProvider = contextProvider; 66 debugger = (JPDADebugger) contextProvider.lookupFirst 67 (null, JPDADebugger.class); 68 } 69 70 private SourcePathProvider getContext () { 71 if (sourcePathProvider == null) { 72 List l = contextProvider.lookup (null, SourcePathProvider.class); 73 sourcePathProvider = (SourcePathProvider) l.get (0); 74 int i, k = l.size (); 75 for (i = 1; i < k; i++) { 76 sourcePathProvider = new CompoundContextProvider ( 77 (SourcePathProvider) l.get (i), 78 sourcePathProvider 79 ); 80 } 81 initSourcePaths (); 82 } 83 return sourcePathProvider; 84 } 85 86 87 89 99 public String getRelativePath ( 100 String url, 101 char directorySeparator, 102 boolean includeExtension 103 ) { 104 return getContext ().getRelativePath 105 (url, directorySeparator, includeExtension); 106 } 107 108 117 public String getURL (String relativePath, boolean global) { 118 return getContext ().getURL (relativePath, global); 119 } 120 121 public String getURL ( 122 StackFrame sf, 123 String stratumn 124 ) { 125 try { 126 return getURL ( 127 convertSlash (sf.location ().sourcePath (stratumn)), 128 true 129 ); 130 } catch (AbsentInformationException e) { 131 return getURL ( 132 convertClassNameToRelativePath ( 133 sf.location ().declaringType ().name () 134 ), 135 true 136 ); 137 } 138 } 139 140 143 public String [] getSourceRoots () { 144 return getContext ().getSourceRoots (); 145 } 146 147 152 public void setSourceRoots (String [] sourceRoots) { 153 getContext ().setSourceRoots (sourceRoots); 154 } 155 156 161 public String [] getOriginalSourceRoots () { 162 return getContext ().getOriginalSourceRoots (); 163 } 164 165 170 public void addPropertyChangeListener (PropertyChangeListener l) { 171 getContext ().addPropertyChangeListener (l); 172 } 173 174 179 public void removePropertyChangeListener ( 180 PropertyChangeListener l 181 ) { 182 getContext ().removePropertyChangeListener (l); 183 } 184 185 186 188 public boolean sourceAvailable ( 189 String relativePath, 190 boolean global 191 ) { 192 return getURL (relativePath, global) != null; 193 } 194 195 public boolean sourceAvailable ( 196 JPDAThread t, 197 String stratumn, 198 boolean global 199 ) { 200 try { 201 return sourceAvailable ( 202 convertSlash (t.getSourcePath (stratumn)), global 203 ); 204 } catch (AbsentInformationException e) { 205 return sourceAvailable ( 206 convertClassNameToRelativePath (t.getClassName ()), global 207 ); 208 } 209 } 210 211 public boolean sourceAvailable ( 212 Field f 213 ) { 214 String className = f.getClassName (); 215 return sourceAvailable (className, true); 216 } 217 218 public boolean sourceAvailable ( 219 CallStackFrame csf, 220 String stratumn 221 ) { 222 try { 223 return sourceAvailable ( 224 convertSlash (csf.getSourcePath (stratumn)), true 225 ); 226 } catch (AbsentInformationException e) { 227 return sourceAvailable ( 228 convertClassNameToRelativePath (csf.getClassName ()), true 229 ); 230 } 231 } 232 233 public String getURL ( 234 CallStackFrame csf, 235 String stratumn 236 ) { 237 try { 238 return getURL (convertSlash (csf.getSourcePath (stratumn)), true); 239 } catch (AbsentInformationException e) { 240 return getURL ( 241 convertClassNameToRelativePath (csf.getClassName ()), true 242 ); 243 } 244 } 245 246 public boolean showSource ( 247 JPDAThread t, 248 String stratumn 249 ) { 250 int lineNumber = t.getLineNumber (stratumn); 251 if (lineNumber < 1) lineNumber = 1; 252 try { 253 return EditorContextBridge.showSource ( 254 getURL (convertSlash (t.getSourcePath (stratumn)), true), 255 lineNumber, 256 debugger 257 ); 258 } catch (AbsentInformationException e) { 259 return EditorContextBridge.showSource ( 260 getURL ( 261 convertClassNameToRelativePath (t.getClassName ()), true 262 ), 263 lineNumber, 264 debugger 265 ); 266 } 267 } 268 269 public boolean showSource (CallStackFrame csf, String stratumn) { 270 try { 271 String url = getURL ( 272 convertSlash (csf.getSourcePath (stratumn)), true 273 ); 274 if (url == null) { 275 stratumn = csf.getDefaultStratum (); 276 url = getURL ( 277 convertSlash (csf.getSourcePath (stratumn)), true 278 ); 279 } 280 if (url == null) { 281 ErrorManager.getDefault().log(ErrorManager.WARNING, 282 "Show Source: No URL for source path "+csf.getSourcePath (stratumn)+ 283 "\nThe reason is likely no opened project for this source file."); 284 return false; 285 } 286 int lineNumber = csf.getLineNumber (stratumn); 287 if (lineNumber < 1) lineNumber = 1; 288 return EditorContextBridge.showSource ( 289 url, 290 lineNumber, 291 debugger 292 ); 293 } catch (AbsentInformationException e) { 294 String url = getURL ( 295 convertClassNameToRelativePath (csf.getClassName ()), true 296 ); 297 if (url == null) { 298 ErrorManager.getDefault().log(ErrorManager.WARNING, 299 "Show Source: No source URL for class "+csf.getClassName()+ 300 "\nThe reason is likely no opened project for the source file."); 301 return false; 302 } 303 return EditorContextBridge.showSource ( 304 url, 305 1, 306 debugger 307 ); 308 } 309 } 310 311 public boolean showSource (Field v) { 312 String fieldName = ((Field) v).getName (); 313 String className = className = ((Field) v).getClassName (); 314 String url = getURL ( 315 EditorContextBridge.getRelativePath (className), true 316 ); 317 if (url == null) return false; 318 int lineNumber = lineNumber = EditorContextBridge.getFieldLineNumber ( 319 url, 320 className, 321 fieldName 322 ); 323 if (lineNumber < 1) lineNumber = 1; 324 return EditorContextBridge.showSource ( 325 url, 326 lineNumber, 327 debugger 328 ); 329 } 330 331 private static String convertSlash (String original) { 332 return original.replace (File.separatorChar, '/'); 333 } 334 335 public static String convertClassNameToRelativePath ( 336 String className 337 ) { 338 int i = className.indexOf ('$'); 339 if (i > 0) className = className.substring (0, i); 340 String sourceName = className.replace 341 ('.', '/') + ".java"; 342 return sourceName; 343 } 344 345 public Object annotate ( 346 JPDAThread t, 347 String stratumn 348 ) { 349 int lineNumber = t.getLineNumber (stratumn); 350 if (lineNumber < 1) return null; 351 Operation operation = t.getCurrentOperation(); 353 String url; 354 try { 355 url = getURL (convertSlash (t.getSourcePath (stratumn)), true); 356 } catch (AbsentInformationException e) { 357 url = getURL (convertClassNameToRelativePath (t.getClassName ()), true); 358 } 359 List operationsAnn = annotateOperations(debugger, url, operation, t.getLastOperations(), lineNumber); 360 if (operation == null) { 361 if (operationsAnn.size() == 0) { 362 return EditorContextBridge.annotate ( 363 url, 364 lineNumber, 365 EditorContext.CURRENT_LINE_ANNOTATION_TYPE, 366 debugger 367 ); 368 } else { 369 377 } 378 } 379 return operationsAnn; 380 } 381 382 public Object annotate ( 383 CallStackFrame csf, 384 String stratumn 385 ) { 386 int lineNumber = csf.getLineNumber (stratumn); 387 if (lineNumber < 1) return null; 388 Operation operation = csf.getCurrentOperation(stratumn); 389 try { 390 if (operation != null) { 391 int startOffset; 392 int endOffset; 393 if (operation.getMethodName() != null) { 394 startOffset = operation.getMethodStartPosition().getOffset(); 395 endOffset = operation.getMethodEndPosition().getOffset(); 396 } else { 397 startOffset = operation.getStartPosition().getOffset(); 398 endOffset = operation.getEndPosition().getOffset(); 399 } 400 return EditorContextBridge.annotate ( 401 getURL (convertSlash (csf.getSourcePath (stratumn)), true), 402 startOffset, 403 endOffset, 404 EditorContext.CALL_STACK_FRAME_ANNOTATION_TYPE, 405 debugger 406 ); 407 } else { 408 return EditorContextBridge.annotate ( 409 getURL (convertSlash (csf.getSourcePath (stratumn)), true), 410 lineNumber, 411 EditorContext.CALL_STACK_FRAME_ANNOTATION_TYPE, 412 debugger 413 ); 414 } 415 } catch (AbsentInformationException e) { 416 return EditorContextBridge.annotate ( 417 getURL ( 418 convertClassNameToRelativePath (csf.getClassName ()), true 419 ), 420 lineNumber, 421 EditorContext.CALL_STACK_FRAME_ANNOTATION_TYPE, 422 debugger 423 ); 424 } 425 } 426 427 private static List annotateOperations(JPDADebugger debugger, String url, 428 Operation currentOperation, List lastOperations, 429 int locLineNumber) { 430 List annotations = null; 431 if (currentOperation != null) { 432 annotations = new ArrayList (); 433 annotations.add(createAnnotation(debugger, url, currentOperation, 434 EditorContext.CURRENT_LINE_ANNOTATION_TYPE, 435 true)); 436 int lineNumber; 437 if (currentOperation.getMethodName() != null) { 438 lineNumber = currentOperation.getMethodStartPosition().getLine(); 439 } else { 440 lineNumber = currentOperation.getStartPosition().getLine(); 441 } 442 annotations.add(EditorContextBridge.annotate ( 443 url, 444 lineNumber, 445 EditorContext.CURRENT_EXPRESSION_CURRENT_LINE_ANNOTATION_TYPE, 446 debugger 447 )); 448 } 449 boolean isNewLineExp = false; 450 if (lastOperations != null && lastOperations.size() > 0) { 451 if (annotations == null) { 452 annotations = new ArrayList (); 453 } 454 isNewLineExp = currentOperation == null; 455 for (int i = 0; i < lastOperations.size(); i++) { 456 Operation lastOperation = (Operation) lastOperations.get(i); 457 if (currentOperation == lastOperation && i == lastOperations.size() - 1) { 458 annotations.add(createAnnotation(debugger, url, 459 lastOperation, 460 EditorContext.CURRENT_OUT_OPERATION_ANNOTATION_TYPE, 461 false)); 462 int lineNumber = lastOperation.getEndPosition().getLine(); 463 annotations.add(EditorContextBridge.annotate ( 464 url, 465 lineNumber, 466 EditorContext.CURRENT_EXPRESSION_CURRENT_LINE_ANNOTATION_TYPE, 467 debugger 468 )); 469 isNewLineExp = false; 470 } else { 471 annotations.add(createAnnotation(debugger, url, 472 lastOperation, 473 EditorContext.CURRENT_LAST_OPERATION_ANNOTATION_TYPE, 474 true)); 475 } 476 } 477 } 478 if (isNewLineExp) { 479 annotations.add(EditorContextBridge.annotate ( 480 url, 481 locLineNumber, 482 EditorContext.CURRENT_LINE_ANNOTATION_TYPE, 483 debugger 484 )); 485 } 486 if (annotations != null) { 487 return annotations; 488 } else { 489 return Collections.EMPTY_LIST; 490 } 491 } 492 493 private static Object createAnnotation(JPDADebugger debugger, String url, 494 Operation operation, String type, 495 boolean method) { 496 int startOffset; 497 int endOffset; 498 if (method && operation.getMethodName() != null) { 499 startOffset = operation.getMethodStartPosition().getOffset(); 500 endOffset = operation.getMethodEndPosition().getOffset(); 501 } else { 502 startOffset = operation.getStartPosition().getOffset(); 503 endOffset = operation.getEndPosition().getOffset(); 504 } 505 return EditorContextBridge.annotate ( 506 url, 507 startOffset, 508 endOffset, 509 type, 510 debugger 511 ); 512 } 513 514 515 517 private static class CompoundContextProvider extends SourcePathProvider { 518 519 private SourcePathProvider cp1, cp2; 520 521 CompoundContextProvider ( 522 SourcePathProvider cp1, 523 SourcePathProvider cp2 524 ) { 525 this.cp1 = cp1; 526 this.cp2 = cp2; 527 } 528 529 public String getURL (String relativePath, boolean global) { 530 String p1 = cp1.getURL (relativePath, global); 531 if (p1 != null) return p1; 532 return cp2.getURL (relativePath, global); 533 } 534 535 public String getRelativePath ( 536 String url, 537 char directorySeparator, 538 boolean includeExtension 539 ) { 540 String p1 = cp1.getRelativePath ( 541 url, 542 directorySeparator, 543 includeExtension 544 ); 545 if (p1 != null) return p1; 546 return cp2.getRelativePath ( 547 url, 548 directorySeparator, 549 includeExtension 550 ); 551 } 552 553 public String [] getSourceRoots () { 554 String [] fs1 = cp1.getSourceRoots (); 555 String [] fs2 = cp2.getSourceRoots (); 556 String [] fs = new String [fs1.length + fs2.length]; 557 System.arraycopy (fs1, 0, fs, 0, fs1.length); 558 System.arraycopy (fs2, 0, fs, fs1.length, fs2.length); 559 return fs; 560 } 561 562 public String [] getOriginalSourceRoots () { 563 String [] fs1 = cp1.getOriginalSourceRoots (); 564 String [] fs2 = cp2.getOriginalSourceRoots (); 565 String [] fs = new String [fs1.length + fs2.length]; 566 System.arraycopy (fs1, 0, fs, 0, fs1.length); 567 System.arraycopy (fs2, 0, fs, fs1.length, fs2.length); 568 return fs; 569 } 570 571 public void setSourceRoots (String [] sourceRoots) { 572 cp1.setSourceRoots (sourceRoots); 573 cp2.setSourceRoots (sourceRoots); 574 } 575 576 public void addPropertyChangeListener (PropertyChangeListener l) { 577 cp1.addPropertyChangeListener (l); 578 cp2.addPropertyChangeListener (l); 579 } 580 581 public void removePropertyChangeListener (PropertyChangeListener l) { 582 cp1.removePropertyChangeListener (l); 583 cp2.removePropertyChangeListener (l); 584 } 585 } 586 587 private void initSourcePaths () { 588 Properties properties = Properties.getDefault (). 589 getProperties ("debugger").getProperties ("sources"); 590 Set originalSourceRoots = new HashSet (Arrays.asList ( 591 sourcePathProvider.getOriginalSourceRoots () 592 )); 593 Set sourceRoots = new HashSet (Arrays.asList ( 594 sourcePathProvider.getSourceRoots () 595 )); 596 597 Iterator enabledSourceRoots = properties.getProperties ("source_roots"). 598 getCollection ("enabled", Collections.EMPTY_SET).iterator (); 599 while (enabledSourceRoots.hasNext ()) { 600 String root = (String ) enabledSourceRoots.next (); 601 if (originalSourceRoots.contains (root)) 602 sourceRoots.add (root); 603 } 604 Iterator disabledSourceRoots = properties.getProperties ("source_roots"). 605 getCollection ("disabled", Collections.EMPTY_SET).iterator (); 606 while (disabledSourceRoots.hasNext ()) { 607 String root = (String ) disabledSourceRoots.next (); 608 sourceRoots.remove (root); 609 } 610 String [] ss = new String [sourceRoots.size ()]; 611 sourcePathProvider.setSourceRoots ((String []) sourceRoots.toArray (ss)); 612 } 613 614 private static class CompoundAnnotation { 615 Object annotation1; 616 Object annotation2; 617 } 618 } 619 620 | Popular Tags |