1 19 20 package org.netbeans.api.java.source; 21 22 import com.sun.source.tree.CompilationUnitTree; 23 import com.sun.tools.javac.api.JavacTaskImpl; 24 import com.sun.tools.javac.code.Source; 25 import com.sun.tools.javac.code.Source; 26 import com.sun.tools.javac.comp.Enter; 27 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 28 import com.sun.tools.javac.util.Abort; 29 import com.sun.tools.javac.util.Context; 30 import com.sun.tools.javac.util.CouplingAbort; 31 import com.sun.tools.javac.util.Log; 32 import com.sun.tools.javadoc.JavadocEnter; 33 import com.sun.tools.javadoc.JavadocMemberEnter; 34 import com.sun.tools.javadoc.Messager; 35 import java.beans.PropertyChangeEvent ; 36 import java.beans.PropertyChangeListener ; 37 import java.io.File ; 38 import java.io.FileOutputStream ; 39 import java.io.IOException ; 40 import java.io.OutputStream ; 41 import java.io.OutputStreamWriter ; 42 import java.io.PrintWriter ; 43 import java.lang.ref.Reference ; 44 import java.lang.ref.WeakReference ; 45 import java.lang.reflect.Method ; 46 import java.util.ArrayList ; 47 import java.util.Arrays ; 48 import java.util.Collection ; 49 import java.util.Collections ; 50 import java.util.Comparator ; 51 import java.util.HashMap ; 52 import java.util.Iterator ; 53 import java.util.LinkedList ; 54 import java.util.List ; 55 import java.util.Map ; 56 import java.util.WeakHashMap ; 57 import java.util.concurrent.Executors ; 58 import java.util.concurrent.PriorityBlockingQueue ; 59 import java.util.concurrent.ThreadFactory ; 60 import java.util.concurrent.TimeUnit ; 61 import java.util.concurrent.atomic.AtomicBoolean ; 62 import java.util.concurrent.locks.ReentrantLock ; 63 import java.util.logging.Level ; 64 import java.util.logging.Logger ; 65 import javax.swing.event.CaretEvent ; 66 import javax.swing.event.CaretListener ; 67 import javax.swing.event.ChangeEvent ; 68 import javax.swing.event.ChangeListener ; 69 import javax.swing.event.ChangeListener ; 70 import javax.swing.event.DocumentEvent ; 71 import javax.swing.event.DocumentListener ; 72 import javax.swing.text.AbstractDocument ; 73 import javax.swing.text.Document ; 74 import javax.swing.text.JTextComponent ; 75 import javax.swing.text.StyledDocument ; 76 import javax.tools.DiagnosticListener; 77 import javax.tools.JavaCompiler; 78 import javax.tools.JavaFileObject; 79 import javax.tools.ToolProvider; 80 import org.netbeans.api.java.classpath.ClassPath; 81 import org.netbeans.api.java.platform.JavaPlatformManager; 82 import org.netbeans.api.java.queries.SourceLevelQuery; 83 import org.netbeans.api.java.source.ClasspathInfo.PathKind; 84 import org.netbeans.api.java.source.ModificationResult.Difference; 85 import org.netbeans.api.timers.TimesCollector; 86 import org.netbeans.editor.Registry; 87 import org.netbeans.api.java.source.query.QueryEnvironment; 88 import org.netbeans.modules.java.source.JavaFileFilterQuery; 89 import org.netbeans.modules.java.source.builder.ASTService; 90 import org.netbeans.modules.java.source.builder.Scanner; 91 import org.netbeans.modules.java.source.JavaSourceAccessor; 92 import org.netbeans.modules.java.source.JavadocEnv; 93 import org.netbeans.modules.java.source.engine.ReattributionException; 94 import org.netbeans.modules.java.source.engine.RootTree; 95 import org.netbeans.modules.java.source.parsing.FileObjects; 96 import org.netbeans.modules.java.preprocessorbridge.spi.JavaFileFilterImplementation; 97 import org.netbeans.modules.java.source.builder.UndoListService; 98 import org.netbeans.modules.java.source.usages.ClassIndexImpl; 99 import org.netbeans.modules.java.source.usages.ClassIndexManager; 100 import org.netbeans.modules.java.source.usages.RepositoryUpdater; 101 import org.netbeans.modules.java.source.util.LowMemoryEvent; 102 import org.netbeans.modules.java.source.util.LowMemoryListener; 103 import org.netbeans.modules.java.source.util.LowMemoryNotifier; 104 import org.netbeans.modules.java.source.usages.SymbolClassReader; 105 import org.openide.cookies.EditorCookie; 106 import org.openide.filesystems.FileChangeAdapter; 107 import org.openide.filesystems.FileChangeListener; 108 import org.openide.filesystems.FileEvent; 109 import org.openide.filesystems.FileObject; 110 import org.openide.filesystems.FileRenameEvent; 111 import org.openide.filesystems.FileUtil; 112 import org.openide.filesystems.FileUtil; 113 import org.openide.loaders.DataObject; 114 import org.openide.loaders.DataObjectNotFoundException; 115 import org.openide.modules.SpecificationVersion; 116 import org.openide.util.Exceptions; 117 import org.openide.util.NbBundle; 118 import org.openide.util.RequestProcessor; 119 import org.openide.util.WeakListeners; 120 121 125 public final class JavaSource { 126 127 128 public static enum Phase { 129 MODIFIED, 130 131 PARSED, 132 133 ELEMENTS_RESOLVED, 134 135 RESOLVED, 136 137 UP_TO_DATE; 138 139 }; 140 141 public static enum Priority { 142 MAX, 143 HIGH, 144 ABOVE_NORMAL, 145 NORMAL, 146 BELOW_NORMAL, 147 LOW, 148 MIN 149 }; 150 151 152 153 158 public static final class InsufficientMemoryException extends IOException { 159 160 private FileObject fo; 161 162 private InsufficientMemoryException (final String message, final FileObject fo) { 163 super (message); 164 this.fo = fo; 165 } 166 167 private InsufficientMemoryException (FileObject fo) { 168 this (NbBundle.getMessage(JavaSource.class, "MSG_UnsufficientMemoryException", FileUtil.getFileDisplayName (fo)),fo); 169 } 170 171 172 176 public FileObject getFile () { 177 return this.fo; 178 } 179 } 180 181 182 private static final int INVALID = 1; 183 private static final int CHANGE_EXPECTED = INVALID<<1; 184 private static final int RESCHEDULE_FINISHED_TASKS = CHANGE_EXPECTED<<1; 185 private static final int UPDATE_INDEX = RESCHEDULE_FINISHED_TASKS<<1; 186 187 188 private static final boolean reportSlowTasks = Boolean.getBoolean("org.netbeans.api.java.source.JavaSource.reportSlowTasks"); 190 private static final int SLOW_TASK_LIMIT = 250; 191 private static final int SLOW_CANCEL_LIMIT = 50; 192 193 194 static int REPARSE_DELAY = 500; 195 196 197 static JavaFileObjectProvider jfoProvider = new DefaultJavaFileObjectProvider (); 198 199 203 private static Map <Phase, String > phase2Key = new HashMap <Phase,String > (); 204 private static Map <Phase, String > phase2Message = new HashMap <Phase,String > (); 205 206 209 static { 210 JavaSourceAccessor.INSTANCE = new JavaSourceAccessorImpl (); 211 phase2Key.put(Phase.PARSED,"parsed"); phase2Message.put (Phase.PARSED,"Parsed"); 214 phase2Key.put(Phase.ELEMENTS_RESOLVED,"sig-attributed"); phase2Message.put (Phase.ELEMENTS_RESOLVED,"Signatures Attributed"); 217 phase2Key.put(Phase.RESOLVED, "attributed"); phase2Message.put (Phase.RESOLVED, "Attributed"); 220 } 221 222 private final static PriorityBlockingQueue <Request> requests = new PriorityBlockingQueue <Request> (10, new RequestComparator()); 223 private final static Map <JavaSource,Collection <Request>> finishedRequests = new WeakHashMap <JavaSource,Collection <Request>>(); 224 private final static Map <JavaSource,Collection <Request>> waitingRequests = new WeakHashMap <JavaSource,Collection <Request>>(); 225 private final static Collection <CancellableTask> toRemove = new LinkedList <CancellableTask> (); 226 private final static SingleThreadFactory factory = new SingleThreadFactory (); 227 private final static CurrentRequestReference currentRequest = new CurrentRequestReference (); 228 private final static EditorRegistryListener editorRegistryListener = new EditorRegistryListener (); 229 private final static ReentrantLock javacLock = new ReentrantLock (true); 231 232 private final Collection <FileObject> files; 233 private final FileObject rootFo; 234 private final FileChangeListener fileChangeListener; 235 private DocListener listener; 236 private DataObjectListener dataObjectListener; 237 238 private final ClasspathInfo classpathInfo; 239 private CompilationInfo currentInfo; 240 private java.util.Stack <CompilationInfo> infoStack = new java.util.Stack <CompilationInfo> (); 241 242 private int flags = 0; 243 244 private FilterListener filterListener; 246 247 248 static { 249 Executors.newSingleThreadExecutor(factory).submit (new CompilationJob()); 250 } 251 252 253 261 public static JavaSource create(final ClasspathInfo cpInfo, final Collection <? extends FileObject> files) throws IllegalArgumentException { 262 if (files == null || cpInfo == null) { 263 throw new IllegalArgumentException (); 264 } 265 try { 266 return new JavaSource(cpInfo, files); 267 } catch (DataObjectNotFoundException donf) { 268 Logger.getLogger("global").warning("Ignoring non existent file: " + FileUtil.getFileDisplayName(donf.getFileObject())); } catch (IOException ex) { 270 Exceptions.printStackTrace(ex); 271 } 272 return null; 273 } 274 275 276 284 public static JavaSource create(final ClasspathInfo cpInfo, final FileObject... files) throws IllegalArgumentException { 285 if (files == null || cpInfo == null) { 286 throw new IllegalArgumentException (); 287 } 288 return create(cpInfo, Arrays.asList(files)); 289 } 290 291 private static Map <FileObject, Reference <JavaSource>> file2JavaSource = new WeakHashMap <FileObject, Reference <JavaSource>>(); 292 293 300 public static JavaSource forFileObject(FileObject fileObject) throws IllegalArgumentException { 301 if (fileObject == null) { 302 throw new IllegalArgumentException ("fileObject == null"); } 304 if (!fileObject.isValid()) { 305 return null; 306 } 307 if (!"text/x-java".equals(FileUtil.getMIMEType(fileObject)) && !"java".equals(fileObject.getExt())) { return null; 310 } 311 312 Reference <JavaSource> ref = file2JavaSource.get(fileObject); 313 JavaSource js = ref != null ? ref.get() : null; 314 315 if (js == null) { 316 file2JavaSource.put(fileObject, new WeakReference <JavaSource>(js = create(ClasspathInfo.create(fileObject), fileObject))); 317 } 318 319 return js; 320 } 321 322 330 public static JavaSource forDocument(Document doc) throws IllegalArgumentException { 331 if (doc == null) { 332 throw new IllegalArgumentException ("doc == null"); } 334 Reference <?> ref = (Reference <?>) doc.getProperty(JavaSource.class); 335 JavaSource js = ref != null ? (JavaSource) ref.get() : null; 336 if (js == null) { 337 DataObject dObj = (DataObject)doc.getProperty(Document.StreamDescriptionProperty); 338 if (dObj != null) 339 js = forFileObject(dObj.getPrimaryFile()); 340 } 341 return js; 342 } 343 344 349 private JavaSource (ClasspathInfo cpInfo, Collection <? extends FileObject> files) throws IOException { 350 this.files = Collections.unmodifiableList(new ArrayList <FileObject>(files)); this.fileChangeListener = new FileChangeListenerImpl (); 352 boolean multipleSources = this.files.size() > 1, filterAssigned = false; 353 for (Iterator <? extends FileObject> it = this.files.iterator(); it.hasNext();) { 354 FileObject file = it.next(); 355 try { 356 TimesCollector.getDefault().reportReference( file, JavaSource.class.toString(), "[M] JavaSource", this ); if (!multipleSources) { 358 file.addFileChangeListener(FileUtil.weakFileChangeListener(this.fileChangeListener,file)); 359 this.assignDocumentListener(file); 360 this.dataObjectListener = new DataObjectListener(file); 361 } 362 if (!filterAssigned) { 363 filterAssigned = true; 364 JavaFileFilterImplementation filter = JavaFileFilterQuery.getFilter(file); 365 if (filter != null) { 366 this.filterListener = new FilterListener (filter); 367 } 368 } 369 } catch (DataObjectNotFoundException donf) { 370 if (multipleSources) { 371 Logger.getLogger("global").warning("Ignoring non existent file: " + FileUtil.getFileDisplayName(file)); it.remove(); 373 } 374 else { 375 throw donf; 376 } 377 } 378 } 379 this.classpathInfo = cpInfo; 380 if (this.files.size() == 1) { 381 this.rootFo = classpathInfo.getClassPath(PathKind.SOURCE).findOwnerRoot(this.files.iterator().next()); 382 } 383 else { 384 this.rootFo = null; 385 } 386 this.classpathInfo.addChangeListener(WeakListeners.change(this.listener, this.classpathInfo)); 387 } 388 389 400 public void runUserActionTask( final CancellableTask<CompilationController> task, final boolean shared) throws IOException { 401 if (task == null) { 402 throw new IllegalArgumentException ("Task cannot be null"); } 404 405 assert !holdsDocumentWriteLock(files) : "JavaSource.runCompileControlTask called under Document write lock."; 407 if (this.files.size()<=1) { 408 CompilationInfo currentInfo = null; 409 synchronized (this) { 410 if (this.currentInfo != null && (this.flags & INVALID)==0) { 411 currentInfo = this.currentInfo; 412 } 413 if (!shared) { 414 this.flags|=INVALID; 415 } 416 } 417 if (currentInfo == null) { 418 currentInfo = createCurrentInfo(this,this.files.isEmpty() ? null : this.files.iterator().next(), filterListener, null); 419 if (shared) { 420 synchronized (this) { 421 if (this.currentInfo == null || (this.flags & INVALID) != 0) { 422 this.currentInfo = currentInfo; 423 this.flags&=~INVALID; 424 } 425 else { 426 currentInfo = this.currentInfo; 427 } 428 } 429 } 430 } 431 assert currentInfo != null; 432 final JavaSource.Request request = currentRequest.getTaskToCancel(); 433 try { 434 if (request != null) { 435 request.task.cancel(); 436 } 437 this.javacLock.lock(); 438 try { 439 if (shared) { 440 if (!infoStack.isEmpty()) { 441 currentInfo = infoStack.peek(); 442 } 443 } 444 else { 445 infoStack.push (currentInfo); 446 } 447 try { 448 task.run (new CompilationController (currentInfo)); 449 } finally { 450 if (!shared) { 451 infoStack.pop (); 452 } 453 } 454 } catch (Exception e) { 455 IOException ioe = new IOException (); 456 ioe.initCause(e); 457 throw ioe; 458 } finally { 459 this.javacLock.unlock(); 460 } 461 } finally { 462 currentRequest.cancelCompleted (request); 463 } 464 } 465 else { 466 final JavaSource.Request request = currentRequest.getTaskToCancel(); 467 try { 468 if (request != null) { 469 request.task.cancel(); 470 } 471 this.javacLock.lock(); 472 try { 473 JavacTaskImpl jt = null; 474 FileObject activeFile = null; 475 Iterator <FileObject> files = this.files.iterator(); 476 while (files.hasNext() || activeFile != null) { 477 boolean restarted; 478 if (activeFile == null) { 479 activeFile = files.next(); 480 restarted = false; 481 } 482 else { 483 restarted = true; 484 } 485 CompilationInfo ci = createCurrentInfo(this,activeFile,filterListener,jt); 486 task.run(new CompilationController(ci)); 487 if (!ci.needsRestart) { 488 jt = ci.getJavacTask(); 489 Log.instance(jt.getContext()).nerrors = 0; 490 activeFile = null; 491 } 492 else { 493 jt = null; 494 ci = null; 495 System.gc(); 496 if (restarted) { 497 throw new InsufficientMemoryException (activeFile); 498 } 499 } 500 } 501 } catch (Exception e) { 502 IOException ioe = new IOException (); 503 ioe.initCause(e); 504 throw ioe; 505 } finally { 506 this.javacLock.unlock(); 507 } 508 } finally { 509 currentRequest.cancelCompleted(request); 510 } 511 } 512 } 513 514 520 public ModificationResult runModificationTask(CancellableTask<WorkingCopy> task) throws IOException { 521 if (task == null) { 522 throw new IllegalArgumentException ("Task cannot be null"); } 524 525 assert !holdsDocumentWriteLock(files) : "JavaSource.runModificationTask called under Document write lock."; 527 ModificationResult result = new ModificationResult(this); 528 if (this.files.size()<=1) { 529 long start = System.currentTimeMillis(); 530 CompilationInfo currentInfo = null; 531 synchronized (this) { 532 if (this.currentInfo != null && (this.flags & INVALID) == 0) { 533 currentInfo = this.currentInfo; 534 } 535 } 536 if (currentInfo == null) { 537 currentInfo = createCurrentInfo(this,this.files.isEmpty() ? null : this.files.iterator().next(), filterListener, null); 538 synchronized (this) { 539 if (this.currentInfo == null || (this.flags & INVALID) != 0) { 540 this.currentInfo = currentInfo; 541 this.flags&=~INVALID; 542 } 543 else { 544 currentInfo = this.currentInfo; 545 } 546 } 547 } 548 assert currentInfo != null; 549 final JavaSource.Request request = currentRequest.getTaskToCancel(); 550 try { 551 if (request != null) { 552 request.task.cancel(); 553 } 554 this.javacLock.lock(); 555 try { 556 WorkingCopy copy = new WorkingCopy (currentInfo); 557 task.run (copy); 558 List <Difference> diffs = copy.getChanges(); 559 if (diffs != null && diffs.size() > 0) 560 result.diffs.put(currentInfo.getFileObject(), diffs); 561 } catch (Exception e) { 562 IOException ioe = new IOException (); 563 ioe.initCause(e); 564 throw ioe; 565 } finally { 566 this.javacLock.unlock(); 567 } 568 } finally { 569 currentRequest.cancelCompleted (request); 570 } 571 TimesCollector.getDefault().reportTime(currentInfo.getFileObject(), "java-source-modification-task", "Modification Task", System.currentTimeMillis() - start); } 574 else { 575 final JavaSource.Request request = currentRequest.getTaskToCancel(); 576 try { 577 if (request != null) { 578 request.task.cancel(); 579 } 580 this.javacLock.lock(); 581 try { 582 JavacTaskImpl jt = null; 583 FileObject activeFile = null; 584 Iterator <FileObject> files = this.files.iterator(); 585 while (files.hasNext() || activeFile != null) { 586 boolean restarted; 587 if (activeFile == null) { 588 activeFile = files.next(); 589 restarted = false; 590 } 591 else { 592 restarted = true; 593 } 594 CompilationInfo ci = createCurrentInfo(this,activeFile, filterListener, jt); 595 WorkingCopy copy = new WorkingCopy(ci); 596 task.run(copy); 597 if (!ci.needsRestart) { 598 jt = ci.getJavacTask(); 599 Log.instance(jt.getContext()).nerrors = 0; 600 List <Difference> diffs = copy.getChanges(); 601 if (diffs != null && diffs.size() > 0) 602 result.diffs.put(ci.getFileObject(), diffs); 603 activeFile = null; 604 } 605 else { 606 jt = null; 607 ci = null; 608 System.gc(); 609 if (restarted) { 610 throw new InsufficientMemoryException (activeFile); 611 } 612 } 613 } 614 } catch (Exception e) { 615 IOException ioe = new IOException (); 616 ioe.initCause(e); 617 throw ioe; 618 } finally { 619 this.javacLock.unlock(); 620 } 621 } finally { 622 currentRequest.cancelCompleted(request); 623 } 624 } 625 synchronized (this) { 626 this.flags|=INVALID; 627 } 628 return result; 629 } 630 631 638 void addPhaseCompletionTask( CancellableTask<CompilationInfo> task, Phase phase, Priority priority ) throws IOException { 639 if (task == null) { 640 throw new IllegalArgumentException ("Task cannot be null"); } 642 if (phase == null || phase == Phase.MODIFIED) { 643 throw new IllegalArgumentException (String.format("The %s is not a legal value of phase",phase)); } 645 if (priority == null) { 646 throw new IllegalArgumentException ("The priority cannot be null"); } 648 CompilationInfo currentInfo; 649 synchronized (this) { 650 currentInfo = this.currentInfo; 651 } 652 if (currentInfo == null) { 653 currentInfo = createCurrentInfo (this, this.files.isEmpty() ? null : this.files.iterator().next(), filterListener, null); 654 } 655 synchronized (this) { 656 if (this.currentInfo == null) { 657 this.currentInfo = currentInfo; 658 } 659 } 660 handleAddRequest (new Request (task, this, phase, priority, true)); 661 } 662 663 666 void removePhaseCompletionTask( CancellableTask<CompilationInfo> task ) { 667 synchronized (JavaSource.class) { 668 toRemove.add (task); 669 } 670 } 671 672 676 void rescheduleTask(CancellableTask<CompilationInfo> task) { 677 synchronized (JavaSource.class) { 678 JavaSource.Request request = this.currentRequest.getTaskToCancel (task); 679 if ( request == null) { 680 out: for (Iterator <Collection <Request>> it = finishedRequests.values().iterator(); it.hasNext();) { 681 Collection <Request> cr = it.next (); 682 for (Iterator <Request> it2 = cr.iterator(); it2.hasNext();) { 683 Request fr = it2.next(); 684 if (task == fr.task) { 685 it2.remove(); 686 JavaSource.requests.add(fr); 687 if (cr.size()==0) { 688 it.remove(); 689 } 690 break out; 691 } 692 } 693 } 694 } 695 else { 696 currentRequest.cancelCompleted(request); 697 } 698 } 699 } 700 701 708 void revalidate () { 709 this.resetState(true, false); 710 } 711 712 717 public ClasspathInfo getClasspathInfo() { 718 return classpathInfo; 719 } 720 721 725 public Collection <FileObject> getFileObjects() { 726 return files; 727 } 728 729 JavacTaskImpl createJavacTask(final DiagnosticListener<? super JavaFileObject> diagnosticListener) { 730 String sourceLevel = null; 731 if (!this.files.isEmpty()) { 732 sourceLevel = SourceLevelQuery.getSourceLevel(files.iterator().next()); 733 } 734 if (sourceLevel == null) { 735 sourceLevel = JavaPlatformManager.getDefault().getDefaultPlatform().getSpecification().getVersion().toString(); 736 } 737 JavacTaskImpl javacTask = createJavacTask(getClasspathInfo(), diagnosticListener, sourceLevel, false); 738 Context context = javacTask.getContext(); 739 Messager.preRegister(context, null); 740 ErrorHandlingJavadocEnter.preRegister(context); 741 JavadocMemberEnter.preRegister(context); 742 JavadocEnv.preRegister(context, getClasspathInfo()); 743 Scanner.Factory.instance(context); 744 com.sun.tools.javac.main.JavaCompiler.instance(context).keepComments = true; 746 return javacTask; 747 } 748 749 private static JavacTaskImpl createJavacTask(final ClasspathInfo cpInfo, final DiagnosticListener<? super JavaFileObject> diagnosticListener, final String sourceLevel, final boolean backgroundCompilation) { 750 ArrayList <String > options = new ArrayList <String >(); 751 if (!backgroundCompilation) { 752 if (Boolean.getBoolean("org.netbeans.api.java.source.JavaSource.USE_COMPILER_LINT")) { options.add("-Xlint"); 754 options.add("-Xlint:-serial"); 755 } 756 options.add("-Xjcov"); } else { 758 options.add("-XDbackgroundCompilation"); options.add("-XDcompilePolicy=byfile"); } 761 options.add("-g:"); options.add("-g:lines"); options.add("-g:vars"); options.add("-source"); options.add(validateSourceLevel(sourceLevel)); 766 767 ClassLoader orig = Thread.currentThread().getContextClassLoader(); 768 try { 769 Thread.currentThread().setContextClassLoader(ClasspathInfo.class.getClassLoader()); 772 JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 773 JavacTaskImpl task = (JavacTaskImpl)tool.getTask(null, cpInfo.getFileManager(), diagnosticListener, options, null, Collections.<JavaFileObject>emptySet()); 774 Context context = task.getContext(); 775 776 if (backgroundCompilation) { 777 SymbolClassReader.preRegister(context, false); 778 } else { 779 SymbolClassReader.preRegister(context, true); 780 } 781 782 return task; 783 } finally { 784 Thread.currentThread().setContextClassLoader(orig); 785 } 786 } 787 788 private static class ErrorHandlingJavadocEnter extends JavadocEnter { 789 790 private Messager messager; 791 792 public static void preRegister(final Context context) { 793 context.put(enterKey, new Context.Factory<Enter>() { 794 public Enter make() { 795 return new ErrorHandlingJavadocEnter(context); 796 } 797 }); 798 } 799 800 protected ErrorHandlingJavadocEnter(Context context) { 801 super(context); 802 messager = Messager.instance0(context); 803 } 804 805 public @Override void main(com.sun.tools.javac.util.List<JCCompilationUnit> trees) { 806 this.complete(trees, null); 809 } 810 } 811 812 816 static Phase moveToPhase (final Phase phase, final CompilationInfo currentInfo, final boolean cancellable) throws IOException { 817 Phase currentPhase = currentInfo.getPhase(); 818 final boolean isMultiFiles = currentInfo.getJavaSource().files.size()>1; 819 LowMemoryNotifier lm = null; 820 LMListener lmListener = null; 821 if (isMultiFiles) { 822 lm = LowMemoryNotifier.getDefault(); 823 assert lm != null; 824 lmListener = new LMListener (); 825 lm.addLowMemoryListener (lmListener); 826 } 827 try { 828 if (lmListener != null && lmListener.lowMemory.getAndSet(false)) { 829 currentInfo.needsRestart = true; 830 return currentPhase; 831 } 832 if (currentPhase.compareTo(Phase.PARSED)<0 && phase.compareTo(Phase.PARSED)>=0) { 833 if (cancellable && currentRequest.isCanceled()) { 834 return Phase.MODIFIED; 837 } 838 long start = System.currentTimeMillis(); 839 Iterable <? extends CompilationUnitTree> trees = currentInfo.getJavacTask().parse(new JavaFileObject[] {currentInfo.jfo}); 841 assert trees != null : "Did not parse anything"; Iterator <? extends CompilationUnitTree> it = trees.iterator(); 843 assert it.hasNext(); 844 CompilationUnitTree unit = it.next(); 845 currentInfo.setCompilationUnit(unit); 846 JCCompilationUnit tree = (JCCompilationUnit) unit; 847 ASTService s = ASTService.instance(currentInfo.getJavacTask().getContext()); 848 if (tree.endPositions != null) { 849 s.setEndPosTable(tree.sourcefile, tree.endPositions); 850 } 851 List <CompilationUnitTree> units = new ArrayList <CompilationUnitTree>(); 852 units.add(tree); 853 s.setRoot(new RootTree(units)); 854 UndoListService undoList = UndoListService.instance(currentInfo.getJavacTask().getContext()); 855 if (undoList != null) { 856 undoList.reset(); } 858 assert !it.hasNext(); 859 currentPhase = Phase.PARSED; 860 long end = System.currentTimeMillis(); 861 FileObject file = currentInfo.getFileObject(); 862 TimesCollector.getDefault().reportReference(file, "compilationUnit", "[M] Compilation Unit", unit); logTime (file,currentPhase,(end-start)); 864 } 865 if (lmListener != null && lmListener.lowMemory.getAndSet(false)) { 866 currentInfo.needsRestart = true; 867 return currentPhase; 868 } 869 if (currentPhase == Phase.PARSED && phase.compareTo(Phase.ELEMENTS_RESOLVED)>=0) { 870 if (cancellable && currentRequest.isCanceled()) { 871 return Phase.MODIFIED; 872 } 873 long start = System.currentTimeMillis(); 874 currentInfo.getJavacTask().enter(); 875 currentPhase = Phase.ELEMENTS_RESOLVED; 876 long end = System.currentTimeMillis(); 877 logTime(currentInfo.getFileObject(),currentPhase,(end-start)); 878 } 879 if (lmListener != null && lmListener.lowMemory.getAndSet(false)) { 880 currentInfo.needsRestart = true; 881 return currentPhase; 882 } 883 if (currentPhase == Phase.ELEMENTS_RESOLVED && phase.compareTo(Phase.RESOLVED)>=0) { 884 if (cancellable && currentRequest.isCanceled()) { 885 return Phase.MODIFIED; 886 } 887 long start = System.currentTimeMillis (); 888 currentInfo.getJavacTask().analyze(); 889 currentPhase = Phase.RESOLVED; 890 long end = System.currentTimeMillis (); 891 logTime(currentInfo.getFileObject(),currentPhase,(end-start)); 892 } 893 if (lmListener != null && lmListener.lowMemory.getAndSet(false)) { 894 currentInfo.needsRestart = true; 895 return currentPhase; 896 } 897 if (currentPhase == Phase.RESOLVED && phase.compareTo(Phase.UP_TO_DATE)>=0) { 898 currentPhase = Phase.UP_TO_DATE; 899 } 900 } catch (CouplingAbort a) { 901 RepositoryUpdater.couplingAbort(a, currentInfo.jfo); 902 currentInfo.needsRestart = true; 903 return currentPhase; 904 } catch (Abort abort) { 905 currentPhase = Phase.UP_TO_DATE; 906 } catch (IOException ex) { 907 dumpSource(currentInfo, ex); 908 throw ex; 909 } catch (ReattributionException ex) { 910 dumpSource(currentInfo, ex); 911 throw new RuntimeException (ex); 912 } catch (RuntimeException ex) { 913 dumpSource(currentInfo, ex); 914 throw ex; 915 } catch (Error ex) { 916 dumpSource(currentInfo, ex); 917 throw ex; 918 } 919 finally { 920 if (isMultiFiles) { 921 assert lm != null; 922 assert lmListener != null; 923 lm.removeLowMemoryListener (lmListener); 924 } 925 currentInfo.setPhase(currentPhase); 926 } 927 return currentPhase; 928 } 929 930 static void logTime (FileObject source, Phase phase, long time) { 931 assert source != null && phase != null; 932 String key = phase2Key.get(phase); 933 String message = phase2Message.get(phase); 934 assert key != null && message != null; 935 TimesCollector.getDefault().reportTime (source,key,message,time); 936 } 937 938 private static final RequestProcessor RP = new RequestProcessor ("JavaSource-event-collector",1); 940 private final RequestProcessor.Task resetTask = RP.create(new Runnable () { 941 public void run() { 942 resetStateImpl(); 943 } 944 }); 945 946 private void resetState(boolean invalidate, boolean updateIndex) { 947 boolean invalid; 948 synchronized (this) { 949 invalid = (this.flags & INVALID) != 0; 950 this.flags|=CHANGE_EXPECTED; 951 if (invalidate) { 952 this.flags|=(INVALID|RESCHEDULE_FINISHED_TASKS); 953 } 954 if (updateIndex) { 955 this.flags|=UPDATE_INDEX; 956 } 957 } 958 if (updateIndex && !invalid) { 959 updateIndex (); 961 } 962 Request r = currentRequest.getTaskToCancel (this); 963 try { 964 if (r != null) { 965 r.task.cancel(); 966 } 967 } 968 finally { 969 currentRequest.cancelCompleted(r); 970 } 971 resetTask.schedule(REPARSE_DELAY); 972 } 973 974 978 private void resetStateImpl() { 979 synchronized (JavaSource.class) { 980 boolean reschedule, updateIndex; 981 synchronized (this) { 982 reschedule = (this.flags & RESCHEDULE_FINISHED_TASKS) != 0; 983 updateIndex = (this.flags & UPDATE_INDEX) != 0; 984 this.flags&=~(RESCHEDULE_FINISHED_TASKS|CHANGE_EXPECTED|UPDATE_INDEX); 985 } 986 if (updateIndex) { 987 updateIndex (); 989 } 990 Collection <Request> cr; 991 if (reschedule) { 992 if ((cr=JavaSource.finishedRequests.remove(this)) != null && cr.size()>0) { 993 JavaSource.requests.addAll(cr); 994 } 995 } 996 if ((cr=JavaSource.waitingRequests.remove(this)) != null && cr.size()>0) { 997 JavaSource.requests.addAll(cr); 998 } 999 } 1000 } 1001 1002 private void updateIndex () { 1003 if (this.rootFo != null) { 1004 try { 1005 ClassIndexImpl ciImpl = ClassIndexManager.getDefault().getUsagesQuery(this.rootFo.getURL()); 1006 if (ciImpl != null) { 1007 ciImpl.setDirty(this); 1008 } 1009 } catch (IOException ioe) { 1010 Exceptions.printStackTrace(ioe); 1011 } 1012 } 1013 } 1014 1015 private void assignDocumentListener(FileObject fo) throws IOException { 1016 DataObject od = DataObject.find(fo); 1017 EditorCookie.Observable ec = od.getCookie(EditorCookie.Observable.class); 1018 if (ec != null) { 1019 this.listener = new DocListener (ec); 1020 } else { 1021 Logger.getLogger("global").log(Level.WARNING,String.format("File: %s has no EditorCookie.Observable", FileUtil.getFileDisplayName (fo))); } 1023 } 1024 1025 private static class Request { 1026 private final CancellableTask<? extends CompilationInfo> task; 1027 private final JavaSource javaSource; private final Phase phase; 1029 private final Priority priority; 1030 private final boolean reschedule; 1031 1032 public Request (final CancellableTask<? extends CompilationInfo> task, final JavaSource javaSource, 1033 final Phase phase, final Priority priority, final boolean reschedule) { 1034 assert task != null; 1035 this.task = task; 1036 this.javaSource = javaSource; 1037 this.phase = phase; 1038 this.priority = priority; 1039 this.reschedule = reschedule; 1040 } 1041 1042 public @Override String toString () { 1043 if (reschedule) { 1044 return String.format("Periodic request for phase: %s with priority: %s to perform: %s", phase.name(), priority, task.toString()); } 1046 else { 1047 return String.format("One time request for phase: %s with priority: %s to perform: %s", phase != null ? phase.name() : "<null>", priority, task.toString()); } 1049 } 1050 1051 public @Override int hashCode () { 1052 return this.priority.ordinal(); 1053 } 1054 1055 public @Override boolean equals (Object other) { 1056 if (other instanceof Request) { 1057 Request otherRequest = (Request) other; 1058 return priority == otherRequest.priority 1059 && reschedule == otherRequest.reschedule 1060 && phase.equals (otherRequest.phase) 1061 && task.equals(otherRequest.task); 1062 } 1063 else { 1064 return false; 1065 } 1066 } 1067 } 1068 1069 private static class RequestComparator implements Comparator <Request> { 1070 public int compare (Request r1, Request r2) { 1071 assert r1 != null && r2 != null; 1072 return r1.priority.compareTo (r2.priority); 1073 } 1074 } 1075 1076 private static class CompilationJob implements Runnable { 1077 1078 @SuppressWarnings ("unchecked") public void run () { 1080 try { 1081 while (true) { 1082 try { 1083 synchronized (JavaSource.class) { 1084 if (!toRemove.isEmpty()) { 1086 for (Iterator <Collection <Request>> it = finishedRequests.values().iterator(); it.hasNext();) { 1087 Collection <Request> cr = it.next (); 1088 for (Iterator <Request> it2 = cr.iterator(); it2.hasNext();) { 1089 Request fr = it2.next(); 1090 if (toRemove.remove(fr.task)) { 1091 it2.remove(); 1092 } 1093 } 1094 if (cr.size()==0) { 1095 it.remove(); 1096 } 1097 } 1098 } 1099 } 1100 Request r = JavaSource.requests.poll(2,TimeUnit.SECONDS); 1101 if (r != null) { 1102 currentRequest.setCurrentTask(r); 1103 try { 1104 JavaSource js = r.javaSource; 1105 if (js == null) { 1106 assert r.phase == null; 1107 assert r.reschedule == false; 1108 javacLock.lock (); 1109 try { 1110 r.task.run (null); 1111 } catch (RuntimeException re) { 1112 Exceptions.printStackTrace(re); 1113 } 1114 finally { 1115 javacLock.unlock(); 1116 } 1117 } 1118 else { 1119 assert js.files.size() <= 1; 1120 boolean jsInvalid; 1121 CompilationInfo ci; 1122 synchronized (JavaSource.class) { 1123 if (toRemove.remove(r.task)) { 1127 continue; 1128 } 1129 synchronized (js) { 1130 boolean changeExpected = (js.flags & CHANGE_EXPECTED) != 0; 1131 if (changeExpected) { 1132 Collection <Request> rc = JavaSource.waitingRequests.get (r.javaSource); 1134 if (rc == null) { 1135 rc = new LinkedList <Request> (); 1136 JavaSource.waitingRequests.put (r.javaSource, rc); 1137 } 1138 rc.add(r); 1139 continue; 1140 } 1141 jsInvalid = (js.flags & INVALID)!=0; 1142 ci = js.currentInfo; 1143 } 1144 } 1145 try { 1146 if (jsInvalid) { 1148 ci = createCurrentInfo (js,js.files.isEmpty() ? null : js.files.iterator().next(), js.filterListener, null); 1149 synchronized (js) { 1150 if ((js.flags & INVALID) != 0) { 1151 js.currentInfo = ci; 1152 js.flags &= ~INVALID; 1153 } 1154 else { 1155 ci = js.currentInfo; 1156 } 1157 } 1158 } 1159 assert ci != null; 1160 javacLock.lock(); 1161 try { 1162 final Phase phase = JavaSource.moveToPhase (r.phase, ci, true); 1163 boolean shouldCall = phase.compareTo(r.phase)>=0; 1164 if (shouldCall) { 1165 synchronized (js) { 1166 shouldCall &= (js.flags & INVALID)==0; 1167 } 1168 if (shouldCall) { 1169 try { 1171 final long startTime = System.currentTimeMillis(); 1172 ((CancellableTask<CompilationInfo>)r.task).run (ci); final long endTime = System.currentTimeMillis(); 1174 if (reportSlowTasks) { 1175 if ((endTime - startTime) > SLOW_TASK_LIMIT) { 1176 Logger.getLogger("global").log(Level.INFO,String.format("JavaSource executed a slow task: %s in %d ms.", r.task.getClass().toString(), (endTime-startTime))); 1178 } 1179 final long cancelTime = currentRequest.getCancelTime(); 1180 if (cancelTime >= startTime && (endTime - cancelTime) > SLOW_CANCEL_LIMIT) { 1181 Logger.getLogger("global").log(Level.INFO,String.format("Task: %s ignored cancel for %d ms.", r.task.getClass().toString(), (endTime-cancelTime))); 1183 } 1184 } 1185 } catch (Exception re) { 1186 Exceptions.printStackTrace (re); 1187 } 1188 } 1189 } 1190 } finally { 1191 javacLock.unlock(); 1192 } 1193 1194 if (r.reschedule) { 1195 synchronized (JavaSource.class) { 1196 boolean canceled = currentRequest.setCurrentTask(null); 1197 synchronized (js) { 1198 if ((js.flags & INVALID)!=0 || canceled) { 1199 JavaSource.requests.add(r); 1201 } 1202 else { 1203 Collection <Request> rc = JavaSource.finishedRequests.get (r.javaSource); 1205 if (rc == null) { 1206 rc = new LinkedList <Request> (); 1207 JavaSource.finishedRequests.put (r.javaSource, rc); 1208 } 1209 rc.add(r); 1210 } 1211 } 1212 } 1213 } 1214 } catch (final FileObjects.InvalidFileException invalidFile) { 1215 } 1218 } 1219 } finally { 1220 currentRequest.setCurrentTask(null); 1221 } 1222 } 1223 } catch (Throwable e) { 1224 if (e instanceof InterruptedException ) { 1225 throw (InterruptedException )e; 1226 } 1227 else if (e instanceof ThreadDeath ) { 1228 throw (ThreadDeath )e; 1229 } 1230 else { 1231 Exceptions.printStackTrace(e); 1232 } 1233 } 1234 } 1235 } catch (InterruptedException ie) { 1236 ie.printStackTrace(); 1237 } 1239 } 1240 } 1241 1242 private class DocListener implements DocumentListener , PropertyChangeListener , ChangeListener { 1243 1244 private EditorCookie.Observable ec; 1245 private DocumentListener docListener; 1246 1247 public DocListener (EditorCookie.Observable ec) { 1248 assert ec != null; 1249 this.ec = ec; 1250 this.ec.addPropertyChangeListener(WeakListeners.propertyChange(this, this.ec)); 1251 Document doc = ec.getDocument(); 1252 if (doc != null) { 1253 doc.addDocumentListener(docListener = WeakListeners.create(DocumentListener .class, this, doc)); 1254 } 1255 } 1256 1257 public void insertUpdate(DocumentEvent e) { 1258 JavaSource.this.resetState(true, true); 1262 } 1263 1264 public void removeUpdate(DocumentEvent e) { 1265 JavaSource.this.resetState(true, true); 1269 } 1270 1271 public void changedUpdate(DocumentEvent e) { 1272 } 1273 1274 public void propertyChange(PropertyChangeEvent evt) { 1275 if (EditorCookie.Observable.PROP_DOCUMENT.equals(evt.getPropertyName())) { 1276 Object old = evt.getOldValue(); 1277 if (old instanceof Document && docListener != null) { 1278 ((Document ) old).removeDocumentListener(docListener); 1279 docListener = null; 1280 } 1281 Document doc = ec.getDocument(); 1282 if (doc != null) { 1283 doc.addDocumentListener(docListener = WeakListeners.create(DocumentListener .class, this, doc)); 1284 } 1285 } 1286 } 1287 1288 public void stateChanged(ChangeEvent e) { 1289 JavaSource.this.resetState(true, false); 1290 } 1291 1292 } 1293 1294 private static class EditorRegistryListener implements ChangeListener , CaretListener { 1295 1296 private JTextComponent lastEditor; 1297 1298 public EditorRegistryListener () { 1299 Registry.addChangeListener(this); 1300 } 1301 1302 public void stateChanged(ChangeEvent event) { 1303 final JTextComponent editor = Registry.getMostActiveComponent(); 1304 if (lastEditor != editor) { 1305 if (lastEditor != null) { 1306 lastEditor.removeCaretListener(this); 1307 } 1308 lastEditor = editor; 1309 if (lastEditor != null) { 1310 lastEditor.addCaretListener(this); 1311 } 1312 } 1313 } 1314 1315 public void caretUpdate(CaretEvent event) { 1316 if (lastEditor != null) { 1317 Document doc = lastEditor.getDocument(); 1318 if (doc != null) { 1319 JavaSource js = forDocument(doc); 1320 if (js != null) { 1321 js.resetState(false, false); 1322 } 1323 } 1324 } 1325 } 1326 } 1327 1328 private class FileChangeListenerImpl extends FileChangeAdapter { 1329 1330 public @Override void fileChanged(final FileEvent fe) { 1331 JavaSource.this.resetState(true, false); 1332 } 1333 1334 public @Override void fileRenamed(FileRenameEvent fe) { 1335 JavaSource.this.resetState(true, false); 1336 } 1337 } 1338 1339 private final class DataObjectListener implements PropertyChangeListener { 1340 1341 private DataObject dobj; 1342 private final FileObject fobj; 1343 private PropertyChangeListener wlistener; 1344 1345 public DataObjectListener(FileObject fo) throws DataObjectNotFoundException { 1346 this.fobj = fo; 1347 this.dobj = DataObject.find(fo); 1348 wlistener = WeakListeners.propertyChange(this, dobj); 1349 this.dobj.addPropertyChangeListener(wlistener); 1350 } 1351 1352 public void propertyChange(PropertyChangeEvent pce) { 1353 DataObject invalidDO = (DataObject) pce.getSource(); 1354 if (invalidDO != dobj) 1355 return; 1356 if (DataObject.PROP_VALID.equals(pce.getPropertyName())) { 1357 handleInvalidDataObject(invalidDO); 1358 } else if (pce.getPropertyName() == null && !dobj.isValid()) { 1359 handleInvalidDataObject(invalidDO); 1360 } 1361 } 1362 1363 private void handleInvalidDataObject(final DataObject invalidDO) { 1364 RequestProcessor.getDefault().post(new Runnable () { 1365 public void run() { 1366 handleInvalidDataObjectImpl(invalidDO); 1367 } 1368 }); 1369 } 1370 1371 private void handleInvalidDataObjectImpl(DataObject invalidDO) { 1372 invalidDO.removePropertyChangeListener(wlistener); 1373 if (fobj.isValid()) { 1374 try { 1376 DataObject dobjNew = DataObject.find(fobj); 1377 synchronized (DataObjectListener.this) { 1378 if (dobjNew == dobj) { 1379 return; 1380 } 1381 dobj = dobjNew; 1382 dobj.addPropertyChangeListener(wlistener); 1383 } 1384 assignDocumentListener(fobj); 1385 resetState(true, true); 1386 } catch (IOException ex) { 1387 Logger.getLogger(JavaSource.class.getName()).log(Level.SEVERE, 1389 ex.getMessage(), 1390 ex); 1391 } 1392 } 1393 } 1394 1395 } 1396 1397 private final class FilterListener implements ChangeListener { 1398 1399 private final JavaFileFilterImplementation filter; 1400 1401 public FilterListener (final JavaFileFilterImplementation filter) { 1402 this.filter = filter; 1403 this.filter.addChangeListener(WeakListeners.change(this, this.filter)); 1404 } 1405 1406 public void stateChanged(ChangeEvent event) { 1407 JavaSource.this.resetState(true, false); 1408 } 1409 } 1410 1411 private static CompilationInfo createCurrentInfo (final JavaSource js, final FileObject fo, final FilterListener filterListener, final JavacTaskImpl javac) throws IOException { 1412 CompilationInfo info = new CompilationInfo (js, fo, filterListener == null ? null : filterListener.filter, javac); 1413 TimesCollector.getDefault().reportReference(fo, CompilationInfo.class.toString(), "[M] CompilationInfo", info); return info; 1415 } 1416 1417 private static void handleAddRequest (final Request nr) { 1418 assert nr != null; 1419 requests.add (nr); 1420 JavaSource.Request request = currentRequest.getTaskToCancel(nr.priority); 1421 try { 1422 if (request != null) { 1423 request.task.cancel(); 1424 } 1425 } finally { 1426 currentRequest.cancelCompleted(request); 1427 } 1428 } 1429 1430 private static class SingleThreadFactory implements ThreadFactory { 1431 1432 private Thread t; 1433 1434 public Thread newThread(Runnable r) { 1435 assert this.t == null; 1436 this.t = new Thread (r,"Java Source Worker Thread"); return this.t; 1438 } 1439 1440 public boolean isDispatchThread (Thread t) { 1441 assert t != null; 1442 return this.t == t; 1443 } 1444 } 1445 1446 private static class JavaSourceAccessorImpl extends JavaSourceAccessor { 1447 1448 protected @Override void runSpecialTaskImpl (CancellableTask<CompilationInfo> task, Priority priority) { 1449 handleAddRequest(new Request (task, null, null, priority, false)); 1450 } 1451 1452 @Override 1453 public JavacTaskImpl createJavacTask(ClasspathInfo cpInfo, DiagnosticListener<? super JavaFileObject> diagnosticListener, String sourceLevel) { 1454 if (sourceLevel == null) 1455 sourceLevel = JavaPlatformManager.getDefault().getDefaultPlatform().getSpecification().getVersion().toString(); 1456 return JavaSource.createJavacTask(cpInfo, diagnosticListener, sourceLevel, true); 1457 } 1458 1459 @Override 1460 public JavacTaskImpl getJavacTask (final CompilationInfo compilationInfo) { 1461 assert compilationInfo != null; 1462 return compilationInfo.getJavacTask(); 1463 } 1464 1465 @Override 1466 public QueryEnvironment getCommandEnvironment(WorkingCopy copy) { 1467 assert copy != null; 1468 return copy.getCommandEnvironment(); 1469 } 1470 1471 @Override 1472 public CompilationInfo getCurrentCompilationInfo (final JavaSource js, final Phase phase) throws IOException { 1473 assert js != null; 1474 assert isDispatchThread(); 1475 CompilationInfo info = null; 1476 synchronized (js) { 1477 if ((js.flags & INVALID)==0) { 1478 info = js.currentInfo; 1479 } 1480 } 1481 if (info == null) { 1482 return null; 1483 } 1484 Phase currentPhase = moveToPhase(phase, info, true); 1485 return currentPhase.compareTo(phase)<0 ? null : info; 1486 } 1487 1488 @Override 1489 public void revalidate(JavaSource js) { 1490 js.revalidate(); 1491 } 1492 1493 @Override 1494 public boolean isDispatchThread () { 1495 return factory.isDispatchThread(Thread.currentThread()); 1496 } 1497 } 1498 1499 private static class CurrentRequestReference { 1500 1501 1502 private JavaSource.Request reference; 1503 private JavaSource.Request canceledReference; 1504 private long cancelTime; 1505 private boolean canceled; 1506 1507 public CurrentRequestReference () { 1508 } 1509 1510 public boolean setCurrentTask (JavaSource.Request reference) throws InterruptedException { 1511 boolean result = false; 1512 synchronized (this) { 1513 while (this.canceledReference!=null) { 1514 this.wait(); 1515 } 1516 result = this.canceled; 1517 this.canceled = false; 1518 this.cancelTime = 0; 1519 this.reference = reference; 1520 } 1521 return result; 1522 } 1523 1524 public JavaSource.Request getTaskToCancel (final Priority priority) { 1525 JavaSource.Request request = null; 1526 if (!factory.isDispatchThread(Thread.currentThread())) { 1527 synchronized (this) { 1528 if (this.reference != null && priority.compareTo(this.reference.priority) < 0) { 1529 assert this.canceledReference == null; 1530 request = this.reference; 1531 this.canceledReference = request; 1532 this.reference = null; 1533 this.canceled = true; 1534 if (reportSlowTasks) { 1535 cancelTime = System.currentTimeMillis(); 1536 } 1537 } 1538 } 1539 } 1540 return request; 1541 } 1542 1543 public JavaSource.Request getTaskToCancel (final JavaSource js) { 1544 JavaSource.Request request = null; 1545 if (!factory.isDispatchThread(Thread.currentThread())) { 1546 synchronized (this) { 1547 if (this.reference != null && js.equals(this.reference.javaSource)) { 1548 assert this.canceledReference == null; 1549 request = this.reference; 1550 this.canceledReference = request; 1551 this.reference = null; 1552 this.canceled = true; 1553 if (reportSlowTasks) { 1554 cancelTime = System.currentTimeMillis(); 1555 } 1556 } 1557 } 1558 } 1559 return request; 1560 } 1561 1562 public JavaSource.Request getTaskToCancel (final CancellableTask task) { 1563 JavaSource.Request request = null; 1564 if (!factory.isDispatchThread(Thread.currentThread())) { 1565 synchronized (this) { 1566 if (this.reference != null && task == this.reference.task) { 1567 assert this.canceledReference == null; 1568 request = this.reference; 1569 this.canceledReference = request; 1570 this.reference = null; 1571 this.canceled = true; 1572 } 1573 } 1574 } 1575 return request; 1576 } 1577 1578 public JavaSource.Request getTaskToCancel () { 1579 JavaSource.Request request = null; 1580 if (!factory.isDispatchThread(Thread.currentThread())) { 1581 synchronized (this) { 1582 request = this.reference; 1583 if (request != null) { 1584 assert this.canceledReference == null; 1585 this.canceledReference = request; 1586 this.reference = null; 1587 this.canceled = true; 1588 if (reportSlowTasks) { 1589 cancelTime = System.currentTimeMillis(); 1590 } 1591 } 1592 } 1593 } 1594 return request; 1595 } 1596 1597 public synchronized boolean isCanceled () { 1598 return this.canceled; 1599 } 1600 1601 public synchronized long getCancelTime () { 1602 return this.cancelTime; 1603 } 1604 1605 public void cancelCompleted (final JavaSource.Request request) { 1606 if (request != null) { 1607 synchronized (this) { 1608 assert request == this.canceledReference; 1609 this.canceledReference = null; 1610 this.notify(); 1611 } 1612 } 1613 } 1614 } 1615 1616 1619 static interface JavaFileObjectProvider { 1620 public JavaFileObject createJavaFileObject (FileObject fo, JavaFileFilterImplementation filter) throws IOException ; 1621 } 1622 1623 static final class DefaultJavaFileObjectProvider implements JavaFileObjectProvider { 1624 public JavaFileObject createJavaFileObject (FileObject fo, JavaFileFilterImplementation filter) throws IOException { 1625 return FileObjects.nbFileObject(fo, filter, true); 1626 } 1627 } 1628 1629 private static class LMListener implements LowMemoryListener { 1630 private AtomicBoolean lowMemory = new AtomicBoolean (false); 1631 1632 public void lowMemory(LowMemoryEvent event) { 1633 lowMemory.set(true); 1634 } 1635 } 1636 1637 1641 private static boolean holdsDocumentWriteLock (Iterable <FileObject> files) { 1642 final Class <AbstractDocument > docClass = AbstractDocument .class; 1643 try { 1644 final Method method = docClass.getDeclaredMethod("getCurrentWriter"); method.setAccessible(true); 1646 final Thread currentThread = Thread.currentThread(); 1647 for (FileObject fo : files) { 1648 try { 1649 final DataObject dobj = DataObject.find(fo); 1650 final EditorCookie ec = dobj.getCookie(EditorCookie.class); 1651 if (ec != null) { 1652 final StyledDocument doc = ec.getDocument(); 1653 if (doc instanceof AbstractDocument ) { 1654 Object result = method.invoke(doc); 1655 if (result == currentThread) { 1656 return true; 1657 } 1658 } 1659 } 1660 } catch (Exception e) { 1661 Exceptions.printStackTrace(e); 1662 } 1663 } 1664 } catch (NoSuchMethodException e) { 1665 Exceptions.printStackTrace(e); 1666 } 1667 return false; 1668 } 1669 1670 private static String validateSourceLevel (String sourceLevel) { 1671 Source[] sources = Source.values(); 1672 if (sourceLevel == null) { 1673 return sources[sources.length-1].name; 1675 } 1676 for (Source source : sources) { 1677 if (source.name.equals(sourceLevel)) { 1678 return sourceLevel; 1679 } 1680 } 1681 SpecificationVersion specVer = new SpecificationVersion (sourceLevel); 1682 SpecificationVersion JAVA_12 = new SpecificationVersion ("1.2"); if (JAVA_12.compareTo(specVer)>0) { 1684 return sources[0].name; 1686 } 1687 else { 1688 return sources[sources.length-1].name; 1689 } 1690 } 1691 1692 private static final int MAX_DUMPS = 255; 1693 1694 1701 private static void dumpSource(CompilationInfo info, Throwable exc) { 1702 String dumpDir = System.getProperty("netbeans.user") + "/var/log/"; String src = info.getText(); 1704 FileObject file = info.getFileObject(); 1705 String fileName = FileUtil.getFileDisplayName(info.getFileObject()); 1706 String origName = file.getName(); 1707 File f = new File (dumpDir + origName + ".dump"); boolean dumpSucceeded = false; 1709 int i = 1; 1710 while (i < MAX_DUMPS) { 1711 if (!f.exists()) 1712 break; 1713 f = new File (dumpDir + origName + '_' + i + ".dump"); i++; 1715 } 1716 if (!f.exists()) { 1717 try { 1718 OutputStream os = new FileOutputStream (f); 1719 PrintWriter writer = new PrintWriter (new OutputStreamWriter (os, "UTF-8")); try { 1721 writer.println(src); 1722 writer.println("----- Classpath: ---------------------------------------------"); 1724 final ClassPath bootPath = info.getClasspathInfo().getClassPath(ClasspathInfo.PathKind.BOOT); 1725 final ClassPath classPath = info.getClasspathInfo().getClassPath(ClasspathInfo.PathKind.COMPILE); 1726 final ClassPath sourcePath = info.getClasspathInfo().getClassPath(ClasspathInfo.PathKind.SOURCE); 1727 1728 writer.println("bootPath: " + (bootPath != null ? bootPath.toString() : "null")); 1729 writer.println("classPath: " + (classPath != null ? classPath.toString() : "null")); 1730 writer.println("sourcePath: " + (sourcePath != null ? sourcePath.toString() : "null")); 1731 1732 writer.println("----- Original exception ---------------------------------------------"); exc.printStackTrace(writer); 1734 } finally { 1735 writer.close(); 1736 dumpSucceeded = true; 1737 } 1738 } catch (IOException ioe) { 1739 Logger.getLogger("global").log(Level.INFO, "Error when writing parser dump file!", ioe); } 1741 } 1742 if (dumpSucceeded) { 1743 Throwable t = Exceptions.attachMessage(exc, "An error occurred during parsing of \'" + fileName + "\'. Please report a bug against java/source and attach dump file '" + f.getAbsolutePath() + "'."); Exceptions.printStackTrace(t); 1746 } else { 1747 Logger.getLogger("global").log(Level.WARNING, 1748 "Dump could not be written. Either dump file could not " + "be created or all dump files were already used. Please " + "check that you have write permission to '" + dumpDir + "' and " + "clean all *.dump files in that directory."); } 1753 } 1754 1755} 1756 | Popular Tags |