1 19 20 package org.netbeans.modules.java.source.usages; 21 22 import com.sun.source.tree.CompilationUnitTree; 23 import com.sun.source.tree.Tree; 24 import com.sun.source.util.TaskEvent; 25 import com.sun.source.util.TaskListener; 26 import com.sun.tools.javac.api.JavacTaskImpl; 27 import com.sun.tools.javac.api.JavacTaskImpl.Filter; 28 import com.sun.tools.javac.code.Symbol; 29 import com.sun.tools.javac.code.Symbol.ClassSymbol; 30 import com.sun.tools.javac.comp.AttrContext; 31 import com.sun.tools.javac.comp.Env; 32 import com.sun.tools.javac.main.JavaCompiler; 33 import com.sun.tools.javac.tree.JCTree; 34 import com.sun.tools.javac.util.Log; 35 import com.sun.tools.javac.util.Abort; 36 import com.sun.tools.javac.util.CouplingAbort; 37 import java.beans.PropertyChangeEvent ; 38 import java.beans.PropertyChangeListener ; 39 import java.io.BufferedReader ; 40 import java.io.File ; 41 import java.io.FileOutputStream ; 42 import java.io.FileReader ; 43 import java.io.IOException ; 44 import java.io.OutputStream ; 45 import java.io.OutputStreamWriter ; 46 import java.io.PrintWriter ; 47 import java.net.URI ; 48 import java.net.URL ; 49 import java.util.ArrayList ; 50 import java.util.Collections ; 51 import java.util.HashMap ; 52 import java.util.HashSet ; 53 import java.util.Iterator ; 54 import java.util.LinkedList ; 55 import java.util.List ; 56 import java.util.Map ; 57 import java.util.Set ; 58 import java.util.Stack ; 59 import java.util.StringTokenizer ; 60 import java.util.Timer ; 61 import java.util.TimerTask ; 62 import java.util.TooManyListenersException ; 63 import java.util.concurrent.CountDownLatch ; 64 import java.util.concurrent.atomic.AtomicBoolean ; 65 import java.util.logging.Level ; 66 import java.util.logging.Logger ; 67 import javax.lang.model.element.TypeElement; 68 import javax.lang.model.type.ErrorType; 69 import javax.swing.event.ChangeEvent ; 70 import javax.swing.event.ChangeListener ; 71 import javax.tools.DiagnosticListener; 72 import javax.tools.Diagnostic; 73 import javax.tools.JavaFileManager; 74 import javax.tools.JavaFileObject; 75 import javax.tools.StandardLocation; 76 import org.netbeans.api.java.classpath.ClassPath; 77 import org.netbeans.api.java.queries.SourceLevelQuery; 78 import org.netbeans.api.java.source.CancellableTask; 79 import org.netbeans.api.java.source.ClasspathInfo; 80 import org.netbeans.api.java.source.CompilationInfo; 81 import org.netbeans.api.java.source.JavaSource; 82 import org.netbeans.api.progress.ProgressHandle; 83 import org.netbeans.api.progress.ProgressHandleFactory; 84 import org.netbeans.api.queries.VisibilityQuery; 85 import org.netbeans.modules.java.JavaDataLoader; 86 import org.netbeans.modules.java.source.*; 87 import org.netbeans.modules.java.source.JavaFileFilterQuery; 88 import org.netbeans.modules.java.source.classpath.CacheClassPath; 89 import org.netbeans.modules.java.source.classpath.GlobalSourcePath; 90 import org.netbeans.modules.java.source.parsing.*; 91 import org.netbeans.modules.java.source.parsing.FileObjects; 92 import org.netbeans.modules.java.preprocessorbridge.spi.JavaFileFilterImplementation; 93 import org.netbeans.modules.java.source.util.LowMemoryEvent; 94 import org.netbeans.modules.java.source.util.LowMemoryListener; 95 import org.netbeans.modules.java.source.util.LowMemoryNotifier; 96 import org.netbeans.spi.java.classpath.ClassPathFactory; 97 import org.openide.filesystems.FileAttributeEvent; 98 import org.openide.filesystems.FileChangeListener; 99 import org.openide.filesystems.FileEvent; 100 import org.openide.filesystems.FileObject; 101 import org.openide.filesystems.FileRenameEvent; 102 import org.openide.filesystems.FileStateInvalidException; 103 import org.openide.filesystems.FileSystem; 104 import org.openide.filesystems.FileUtil; 105 import org.openide.filesystems.URLMapper; 106 import org.openide.util.Exceptions; 107 import org.openide.util.NbBundle; 108 import org.openide.util.TopologicalSortException; 109 import org.openide.util.Utilities; 110 111 115 public class RepositoryUpdater implements PropertyChangeListener , FileChangeListener { 116 117 private static final Logger LOGGER = Logger.getLogger(RepositoryUpdater.class.getName()); 118 private static final Set <String > ignoredDirectories = parseSet("org.netbeans.javacore.ignoreDirectories", "SCCS CVS .svn"); private static final boolean noscan = Boolean.getBoolean("netbeans.javacore.noscan"); public static final boolean PERF_TEST = Boolean.getBoolean("perf.refactoring.test"); 121 private static final String PACKAGE_INFO = "package-info.java"; 123 private static final int DELAY = Utilities.isWindows() ? 2000 : 1000; 124 125 private static RepositoryUpdater instance; 126 127 private final GlobalSourcePath cpImpl; 128 private final ClassPath cp; 129 private final ClassPath ucp; 130 private final ClassPath binCp; 131 private Set <URL > scannedRoots; 132 private Set <URL > scannedBinaries; 133 private Delay delay; 134 private Work currentWork; 135 private boolean dirty; 136 private int noSubmited; 137 138 private final Map <URL , JavaFileFilterImplementation> filters = Collections.synchronizedMap(new HashMap <URL , JavaFileFilterImplementation>()); 140 private final FilterListener filterListener = new FilterListener (); 141 142 143 private RepositoryUpdater() { 144 try { 145 this.scannedRoots = Collections.synchronizedSet(new HashSet <URL >()); 146 this.scannedBinaries = Collections.synchronizedSet(new HashSet <URL >()); 147 this.delay = new Delay(); 148 this.cpImpl = GlobalSourcePath.getDefault(); 149 this.cpImpl.setExcludesListener (this); 150 this.cp = ClassPathFactory.createClassPath (this.cpImpl.getSourcePath()); 151 this.cp.addPropertyChangeListener(this); 152 this.ucp = ClassPathFactory.createClassPath (this.cpImpl.getUnknownSourcePath()); 153 this.binCp = ClassPathFactory.createClassPath(this.cpImpl.getBinaryPath()); 154 this.registerFileSystemListener(); 155 submitBatch(); 156 } catch (TooManyListenersException e) { 157 throw new IllegalStateException (); 158 } 159 } 160 161 public ClassPath getScannedSources () { 162 return this.cp; 163 } 164 165 public ClassPath getScannedBinaries() { 166 return this.binCp; 167 } 168 169 public void close () { 170 this.cp.removePropertyChangeListener(this); 171 this.unregisterFileSystemListener(); 172 this.delay.cancel(); 173 } 174 175 public void propertyChange(PropertyChangeEvent evt) { 176 if (ClassPath.PROP_ROOTS.equals(evt.getPropertyName())) { 177 submitBatch(); 178 } 179 else if (GlobalSourcePath.PROP_INCLUDES.equals(evt.getPropertyName())) { 180 ClassPath changedCp = (ClassPath) evt.getNewValue(); 181 assert changedCp != null; 182 for (ClassPath.Entry e : changedCp.entries()) { 183 URL root = e.getURL(); 184 scheduleCompilation(root,root, true); 185 } 186 } 187 } 188 189 private synchronized void submitBatch () { 190 if (this.currentWork == null) { 191 this.currentWork = Work.batch(); 192 submit (this.currentWork); 193 } 194 else { 195 this.dirty = true; 196 } 197 } 198 199 public synchronized boolean isScanInProgress() { 200 return this.noSubmited > 0; 201 } 202 203 public synchronized void waitScanFinished () throws InterruptedException { 204 while (this.noSubmited > 0 ) { 205 this.wait(); 206 } 207 } 208 209 210 private synchronized boolean isDirty () { 211 if (this.dirty) { 212 this.dirty = false; 213 return true; 214 } 215 else { 216 this.currentWork = null; 217 return false; 218 } 219 } 220 221 private synchronized void resetDirty () { 222 this.dirty = false; 223 this.currentWork = null; 224 } 225 226 227 public void fileRenamed(FileRenameEvent fe) { 228 final FileObject fo = fe.getFile(); 229 try { 230 if ((isJava (fo) || fo.isFolder()) && VisibilityQuery.getDefault().isVisible(fo)) { 231 final URL root = getOwningSourceRoot(fo); 232 if (root != null) { 233 String originalName = fe.getName(); 234 final String originalExt = fe.getExt(); 235 if (originalExt.length()>0) { 236 originalName = originalName+'.'+originalExt; } 238 final File parentFile = FileUtil.toFile(fo.getParent()); 239 if (parentFile != null) { 240 final URL original = new File (parentFile,originalName).toURI().toURL(); 241 submit(Work.delete(original,root,fo.isFolder())); 242 delay.post(Work.compile (fo,root)); 243 } 244 } 245 } 246 else if (isBinary(fo) && VisibilityQuery.getDefault().isVisible(fo)) { 247 final URL root = getOwningBinaryRoot(fo); 248 if (root != null) { 249 String originalName = fe.getName(); 250 final String originalExt = fe.getExt(); 251 if (originalExt.length()>0) { 252 originalName = originalName+'.'+originalExt; } 254 final File parentFile = FileUtil.toFile(fo.getParent()); 255 if (parentFile != null) { 256 final URL original = new File (parentFile,originalName).toURI().toURL(); 257 submit(Work.binary(original, root, fo.isFolder())); 258 submit(Work.binary(fo, root)); 259 } 260 } 261 } 262 } catch (IOException ioe) { 263 Exceptions.printStackTrace(ioe); 264 } 265 } 266 267 public void fileAttributeChanged(FileAttributeEvent fe) { 268 } 270 271 public void fileFolderCreated(FileEvent fe) { 272 final FileObject fo = fe.getFile(); 276 try { 277 final URL root = getOwningSourceRoot(fo); 278 if ( root != null && VisibilityQuery.getDefault().isVisible(fo)) { 279 scheduleCompilation(fo,root); 280 } 281 } catch (IOException ioe) { 282 Exceptions.printStackTrace(ioe); 283 } 284 } 285 286 public void fileDeleted(FileEvent fe) { 287 final FileObject fo = fe.getFile(); 288 final boolean isFolder = fo.isFolder(); 289 try { 290 if ((isJava(fo) || isFolder) && VisibilityQuery.getDefault().isVisible(fo)) { 291 final URL root = getOwningSourceRoot (fo); 292 if (root != null) { 293 submit(Work.delete(fo,root,isFolder)); 294 } 295 } 296 else if ((isBinary(fo) || isFolder) && VisibilityQuery.getDefault().isVisible(fo)) { 297 final URL root = getOwningBinaryRoot(fo); 298 if (root !=null) { 299 submit(Work.binary(fo,root)); 300 } 301 } 302 } catch (IOException ioe) { 303 Exceptions.printStackTrace(ioe); 304 } 305 } 306 307 public void fileDataCreated(FileEvent fe) { 308 final FileObject fo = fe.getFile(); 309 try { 310 if (isJava(fo) && VisibilityQuery.getDefault().isVisible(fo)) { 311 final URL root = getOwningSourceRoot (fo); 312 if (root != null) { 313 postCompilation(fo, root); 314 } 315 } 316 else if (isBinary(fo) && VisibilityQuery.getDefault().isVisible(fo)) { 317 final URL root = getOwningBinaryRoot(fo); 318 if (root != null) { 319 submit(Work.binary(fo, root)); 320 } 321 } 322 } catch (IOException ioe) { 323 Exceptions.printStackTrace(ioe); 324 } 325 } 326 327 public void fileChanged(FileEvent fe) { 328 final FileObject fo = fe.getFile(); 329 try { 330 if (isJava(fo) && VisibilityQuery.getDefault().isVisible(fo)) { 331 final URL root = getOwningSourceRoot (fo); 332 if (root != null) { 333 postCompilation(fo, root); 334 } 335 } 336 else if (isBinary(fo) && VisibilityQuery.getDefault().isVisible(fo)) { 337 final URL root = getOwningBinaryRoot(fo); 338 if (root != null) { 339 submit(Work.binary(fo, root)); 340 } 341 } 342 } catch (IOException ioe) { 343 Exceptions.printStackTrace(ioe); 344 } 345 } 346 347 348 public final void scheduleCompilation (final FileObject fo, final FileObject root) throws IOException { 349 URL foURL = fo.getURL(); 350 URL rootURL = root.getURL(); 351 assert "file".equals(foURL.getProtocol()) && "file".equals(rootURL.getProtocol()); 352 scheduleCompilation (foURL,rootURL,fo.isFolder()); 353 } 354 355 private final void scheduleCompilation (final FileObject fo, final URL root) throws IOException { 356 scheduleCompilation (fo.getURL(),root,fo.isFolder()); 357 } 358 359 private final void scheduleCompilation (final URL file, final URL root, boolean isFolder) { 360 submit(Work.compile (file,root, isFolder)); 361 } 362 363 private final void postCompilation (final FileObject file, final URL root) throws FileStateInvalidException { 364 delay.post (Work.compile (file,root)); 365 } 366 367 368 377 public final CountDownLatch scheduleCompilationAndWait (final FileObject folder, final FileObject root) throws IOException { 378 CountDownLatch [] latch = new CountDownLatch [1]; 379 submit(Work.compile (folder,root.getURL(),latch)); 380 return latch[0]; 381 } 382 383 private void submit (final Work work) { 384 if (!noscan) { 385 synchronized (this) { 386 this.noSubmited++; 387 } 388 final CompileWorker cw = new CompileWorker (work); 389 JavaSourceAccessor.INSTANCE.runSpecialTask (cw,JavaSource.Priority.MAX); 390 } 391 } 392 393 394 private void registerFileSystemListener () { 395 final File [] roots = File.listRoots(); 396 final Set <FileSystem> fss = new HashSet <FileSystem> (); 397 for (File root : roots) { 398 final FileObject fo = FileUtil.toFileObject (root); 399 if (fo != null) { 400 try { 401 final FileSystem fs = fo.getFileSystem(); 402 if (!fss.contains(fs)) { 403 fs.addFileChangeListener (this); 404 fss.add(fs); 405 } 406 } catch (FileStateInvalidException e) { 407 Exceptions.printStackTrace(e); 408 } 409 } 410 } 411 } 412 413 private void unregisterFileSystemListener () { 414 final File [] roots = File.listRoots(); 415 final Set <FileSystem> fss = new HashSet <FileSystem> (); 416 for (File root : roots) { 417 final FileObject fo = FileUtil.toFileObject (root); 418 if (fo != null) { 419 try { 420 final FileSystem fs = fo.getFileSystem(); 421 if (!fss.contains(fs)) { 422 fs.removeFileChangeListener (this); 423 fss.add(fs); 424 } 425 } catch (FileStateInvalidException e) { 426 Exceptions.printStackTrace(e); 427 } 428 } 429 } 430 } 431 432 private URL getOwningSourceRoot (final FileObject fo) { 433 if (fo == null) { 434 return null; 435 } 436 synchronized (this.scannedRoots) { 437 for (URL root : this.scannedRoots) { 438 FileObject rootFo = URLMapper.findFileObject(root); 439 if (rootFo != null && FileUtil.isParentOf(rootFo,fo)) { 440 return root; 441 } 442 } 443 } 444 return null; 445 } 446 447 private URL getOwningBinaryRoot (final FileObject fo){ 448 if (fo == null) { 449 return null; 450 } 451 try { 452 synchronized (this.scannedBinaries) { 453 URL foURL = fo.getURL(); 454 for (URL root : this.scannedBinaries) { 455 URL fileURL = FileUtil.getArchiveFile(root); 456 boolean archive = true; 457 if (fileURL == null) { 458 fileURL = root; 459 archive = false; 460 } 461 String filePath = fileURL.getPath(); 462 String foPath = foURL.getPath(); 463 if (filePath.equals(foPath)) { 464 return root; 465 } 466 if (!archive && foPath.startsWith(filePath)) { 467 return root; 468 } 469 } 470 } 471 } catch (FileStateInvalidException fsi) { 472 Exceptions.printStackTrace(fsi); 473 } 474 return null; 475 } 476 477 481 private static boolean isJava (final FileObject fo) { 482 if (fo.isFolder()) { 483 return false; 484 } 485 else if (JavaDataLoader.JAVA_EXTENSION.equals(fo.getExt().toLowerCase())) { 486 return true; 487 } 488 else { 489 return JavaDataLoader.JAVA_MIME_TYPE.equals(fo.getMIMEType()); 490 } 491 } 492 493 private static boolean isBinary (final FileObject fo) { 494 if (fo.isFolder()) { 495 return false; 496 } 497 String ext = fo.getExt().toLowerCase(); 498 if (FileObjects.CLASS.equals(ext) || 499 FileObjects.JAR.equals(ext) || 500 FileObjects.ZIP.equals(ext)) { 501 return true; 502 } 503 return false; 504 } 505 506 private static enum WorkType { 507 COMPILE_BATCH, COMPILE_CONT, COMPILE, DELETE, UPDATE_BINARY, FILTER_CHANGED 508 }; 509 510 511 private static class Work { 512 private final WorkType workType; 513 private final CountDownLatch latch; 514 515 protected Work (WorkType workType, CountDownLatch latch) { 516 assert workType != null; 517 this.workType = workType; 518 this.latch = latch; 519 } 520 521 public WorkType getType () { 522 return this.workType; 523 } 524 525 public void finished () { 526 if (this.latch != null) { 527 this.latch.countDown(); 528 } 529 } 530 531 532 public static Work batch () { 533 return new Work (WorkType.COMPILE_BATCH, null); 534 } 535 536 public static Work compile (final FileObject file, final URL root) throws FileStateInvalidException { 537 return compile (file.getURL(), root, file.isFolder()); 538 } 539 540 public static Work compile (final URL file, final URL root, boolean isFolder) { 541 assert file != null && root != null; 542 return new SingleRootWork (WorkType.COMPILE, file, root, isFolder, null); 543 } 544 545 public static Work compile (final FileObject file, final URL root, CountDownLatch [] latch) throws FileStateInvalidException { 546 assert file != null && root != null; 547 assert latch != null && latch.length == 1 && latch[0] == null; 548 latch[0] = new CountDownLatch (1); 549 return new SingleRootWork (WorkType.COMPILE, file.getURL(), root, file.isFolder(),latch[0]); 550 } 551 552 public static Work delete (final FileObject file, final URL root, final boolean isFolder) throws FileStateInvalidException { 553 return delete (file.getURL(), root,file.isFolder()); 554 } 555 556 public static Work delete (final URL file, final URL root, final boolean isFolder) { 557 assert file != null && root != null; 558 return new SingleRootWork (WorkType.DELETE, file, root, isFolder,null); 559 } 560 561 public static Work binary (final FileObject file, final URL root) throws FileStateInvalidException { 562 return binary (file.getURL(), root, file.isFolder()); 563 } 564 565 public static Work binary (final URL file, final URL root, boolean isFolder) { 566 assert file != null && root != null; 567 return new SingleRootWork (WorkType.UPDATE_BINARY, file, root, isFolder, null); 568 } 569 570 public static Work filterChange (final List <URL > roots) { 571 assert roots != null; 572 return new MultiRootsWork (WorkType.FILTER_CHANGED, roots, null); 573 } 574 575 } 576 577 private static class SingleRootWork extends Work { 578 579 private URL file; 580 private URL root; 581 private boolean isFolder; 582 583 584 public SingleRootWork (WorkType type, URL file, URL root, boolean isFolder, CountDownLatch latch) { 585 super (type, latch); 586 this.file = file; 587 this.root = root; 588 this.isFolder = isFolder; 589 } 590 591 public URL getFile () { 592 return this.file; 593 } 594 595 public URL getRoot () { 596 return this.root; 597 } 598 599 public boolean isFolder () { 600 return this.isFolder; 601 } 602 603 } 604 605 private static class MultiRootsWork extends Work { 606 private List <URL > roots; 607 608 public MultiRootsWork (WorkType type, List <URL > roots, CountDownLatch latch) { 609 super (type, latch); 610 this.roots = roots; 611 } 612 613 public List <URL > getRoots () { 614 return roots; 615 } 616 } 617 618 private final class CompileWorker implements CancellableTask<CompilationInfo> { 619 620 private Work work; 621 private List <URL > state; 622 private Set <URL > oldRoots; 623 private Set <URL > oldBinaries; 624 private Set <URL > newBinaries; 625 private ProgressHandle handle; 626 private final Set <URI > dirtyCrossFiles; 627 private final Set <URL > ignoreExcludes; 628 private final AtomicBoolean canceled; 629 630 public CompileWorker (Work work ) { 631 assert work != null; 632 this.work = work; 633 this.canceled = new AtomicBoolean (false); 634 this.dirtyCrossFiles = new HashSet <URI >(); 635 this.ignoreExcludes = new HashSet <URL >(); 636 } 637 638 public void cancel () { 639 this.canceled.set(true); 640 } 641 642 public void run (final CompilationInfo nullInfo) throws IOException { 643 ClassIndexManager.getDefault().writeLock (new ClassIndexManager.ExceptionAction<Void > () { 644 645 @SuppressWarnings ("fallthrough") 646 public Void run () throws IOException { 647 boolean continuation = false; 648 try { 649 final WorkType type = work.getType(); 650 switch (type) { 651 case FILTER_CHANGED: 652 try { 653 final MultiRootsWork mw = (MultiRootsWork) work; 654 final List <URL > roots = mw.getRoots(); 655 final Map <URL ,List <URL >> depGraph = new HashMap <URL ,List <URL >> (); 656 for (URL root: roots) { 657 findDependencies (root, new Stack <URL >(), depGraph, null, false); 658 } 659 state = Utilities.topologicalSort(roots, depGraph); 660 for (java.util.ListIterator <URL > it = state.listIterator(state.size()); it.hasPrevious(); ) { 661 final URL rootURL = it.previous(); 662 it.remove(); 663 updateFolder (rootURL,rootURL, true, handle); 664 } 665 } catch (final TopologicalSortException tse) { 666 final IllegalStateException ise = new IllegalStateException (); 667 throw (IllegalStateException ) ise.initCause(tse); 668 } 669 break; 670 case COMPILE_BATCH: 671 { 672 assert handle == null; 673 handle = ProgressHandleFactory.createHandle(NbBundle.getMessage(RepositoryUpdater.class,"MSG_BackgroundCompileStart")); 674 handle.start(); 675 boolean completed = false; 676 try { 677 oldRoots = new HashSet <URL > (scannedRoots); 678 oldBinaries = new HashSet <URL > (scannedBinaries); 679 final List <ClassPath.Entry> entries = new LinkedList <ClassPath.Entry>(); 680 entries.addAll (cp.entries()); 681 entries.addAll (ucp.entries()); 682 final List <ClassPath.Entry> binaryEntries = binCp.entries(); 683 newBinaries = new HashSet <URL > (); 684 for (ClassPath.Entry entry : binaryEntries) { 685 URL binRoot = entry.getURL(); 686 if (!oldBinaries.remove(binRoot)) { 687 newBinaries.add (binRoot); 688 } 689 } 690 final Map <URL ,List <URL >> depGraph = new HashMap <URL ,List <URL >> (); 691 for (ClassPath.Entry entry : entries) { 692 final URL rootURL = entry.getURL(); 693 findDependencies (rootURL, new Stack <URL >(), depGraph, newBinaries, true); 694 } 695 CompileWorker.this.state = Utilities.topologicalSort(depGraph.keySet(), depGraph); 696 completed = true; 697 } catch (final TopologicalSortException tse) { 698 final IllegalStateException ise = new IllegalStateException (); 699 throw (IllegalStateException ) ise.initCause(tse); 700 } finally { 701 if (!completed) { 702 resetDirty(); 703 } 704 } 705 } 706 case COMPILE_CONT: 707 boolean completed = false; 708 try { 709 if (!scanRoots()) { 710 CompileWorker.this.work = new Work (WorkType.COMPILE_CONT,null); 711 JavaSourceAccessor.INSTANCE.runSpecialTask (CompileWorker.this,JavaSource.Priority.MAX); 712 continuation = true; 713 return null; 714 } 715 while (isDirty()) { 716 assert CompileWorker.this.state.isEmpty(); 717 final List <ClassPath.Entry> entries = new LinkedList <ClassPath.Entry>(); 718 entries.addAll (cp.entries()); 719 entries.addAll (ucp.entries()); 720 final List <ClassPath.Entry> binaryEntries = binCp.entries(); 721 newBinaries = new HashSet <URL > (); 722 for (ClassPath.Entry entry : binaryEntries) { 723 URL binRoot = entry.getURL(); 724 if (!scannedBinaries.contains(binRoot)) { 725 newBinaries.add(binRoot); 726 } 727 else { 728 oldBinaries.remove(binRoot); 729 } 730 } 731 final Map <URL ,List <URL >> depGraph = new HashMap <URL ,List <URL >> (); 732 for (ClassPath.Entry entry : entries) { 733 final URL rootURL = entry.getURL(); 734 findDependencies (rootURL, new Stack <URL >(), depGraph, newBinaries, true); 735 } 736 try { 737 CompileWorker.this.state = Utilities.topologicalSort(depGraph.keySet(), depGraph); 738 } catch (final TopologicalSortException tse) { 739 final IllegalStateException ise = new IllegalStateException (); 740 throw (IllegalStateException ) ise.initCause(tse); 741 } 742 if (!scanRoots ()) { 743 CompileWorker.this.work = new Work (WorkType.COMPILE_CONT,null); 744 JavaSourceAccessor.INSTANCE.runSpecialTask (CompileWorker.this,JavaSource.Priority.MAX); 745 continuation = true; 746 return null; 747 } 748 } 749 completed = true; 750 } finally { 751 if (!completed && !continuation) { 752 resetDirty (); 753 } 754 } 755 final ClassIndexManager cim = ClassIndexManager.getDefault(); 756 scannedRoots.removeAll(oldRoots); 757 for (URL oldRoot : oldRoots) { 758 cim.removeRoot(oldRoot); 759 JavaFileFilterImplementation filter = filters.remove(oldRoot); 760 if (filter != null && !filters.values().contains(filter)) { 761 filter.removeChangeListener(filterListener); 762 } 763 } 764 scannedBinaries.removeAll (oldBinaries); 765 final CachingArchiveProvider cap = CachingArchiveProvider.getDefault(); 766 for (URL oldRoot : oldBinaries) { 767 cim.removeRoot(oldRoot); 768 cap.removeArchive(oldRoot); 769 } 770 break; 771 case COMPILE: 772 { 773 try { 774 final SingleRootWork sw = (SingleRootWork) work; 775 final URL file = sw.getFile(); 776 final URL root = sw.getRoot (); 777 if (sw.isFolder()) { 778 handle = ProgressHandleFactory.createHandle(NbBundle.getMessage(RepositoryUpdater.class,"MSG_Updating")); 779 handle.start(); 780 try { 781 updateFolder (file, root, false, handle); 782 } finally { 783 handle.finish(); 784 } 785 } 786 else { 787 updateFile (file,root); 788 } 789 } catch (Abort abort) { 790 } 792 break; 793 } 794 case DELETE: 795 { 796 final SingleRootWork sw = (SingleRootWork) work; 797 final URL file = sw.getFile(); 798 final URL root = sw.getRoot (); 799 delete (file, root, sw.isFolder()); 800 break; 801 } 802 case UPDATE_BINARY: 803 { 804 SingleRootWork sw = (SingleRootWork) work; 805 final URL file = sw.getFile(); 806 final URL root = sw.getRoot(); 807 updateBinary (file, root); 808 break; 809 } 810 } 811 return null; 812 } finally { 813 if (!continuation) { 814 synchronized (RepositoryUpdater.this) { 815 RepositoryUpdater.this.noSubmited--; 816 if (RepositoryUpdater.this.noSubmited == 0) { 817 RepositoryUpdater.this.notifyAll(); 818 } 819 } 820 work.finished (); 821 if (handle != null) { 822 handle.finish (); 823 } 824 } 825 } 826 }}); 827 } 828 829 private void findDependencies (final URL rootURL, final Stack <URL > cycleDetector, final Map <URL ,List <URL >> depGraph, 830 final Set <URL > binaries, final boolean useInitialState) { 831 if (useInitialState && RepositoryUpdater.this.scannedRoots.contains(rootURL)) { 832 this.oldRoots.remove(rootURL); 833 return; 834 } 835 if (depGraph.containsKey(rootURL)) { 836 return; 837 } 838 final FileObject rootFo = URLMapper.findFileObject(rootURL); 839 if (rootFo == null) { 840 return; 841 } 842 cycleDetector.push (rootURL); 843 final ClassPath bootPath = ClassPath.getClassPath(rootFo, ClassPath.BOOT); 844 final ClassPath compilePath = ClassPath.getClassPath(rootFo, ClassPath.COMPILE); 845 final ClassPath[] pathsToResolve = new ClassPath[] {bootPath,compilePath}; 846 final List <URL > deps = new LinkedList <URL > (); 847 for (int i=0; i< pathsToResolve.length; i++) { 848 final ClassPath pathToResolve = pathsToResolve[i]; 849 if (pathToResolve != null) { 850 for (ClassPath.Entry entry : pathToResolve.entries()) { 851 final URL url = entry.getURL(); 852 final URL [] sourceRoots = RepositoryUpdater.this.cpImpl.getSourceRootForBinaryRoot(url, pathToResolve, false); 853 if (sourceRoots != null) { 854 for (URL sourceRoot : sourceRoots) { 855 if (sourceRoot.equals (rootURL)) { 856 this.ignoreExcludes.add (rootURL); 857 } 858 else if (!cycleDetector.contains(sourceRoot)) { 859 deps.add (sourceRoot); 860 findDependencies(sourceRoot, cycleDetector,depGraph, binaries, useInitialState); 861 } 862 } 863 } 864 else { 865 if (useInitialState) { 866 if (!RepositoryUpdater.this.scannedBinaries.contains(url)) { 867 binaries.add (url); 868 } 869 oldBinaries.remove(url); 870 } 871 } 872 } 873 } 874 } 875 depGraph.put(rootURL,deps); 876 cycleDetector.pop (); 877 } 878 879 private boolean scanRoots () { 880 881 for (Iterator <URL > it = this.newBinaries.iterator(); it.hasNext(); ) { 882 if (this.canceled.getAndSet(false)) { 883 return false; 884 } 885 final URL rootURL = it.next(); 886 try { 887 it.remove(); 888 final ClassIndexImpl ci = ClassIndexManager.getDefault().createUsagesQuery(rootURL,false); 889 RepositoryUpdater.this.scannedBinaries.add (rootURL); 890 long startT = System.currentTimeMillis(); 891 ci.getBinaryAnalyser().analyse(rootURL, handle); 892 long endT = System.currentTimeMillis(); 893 if (PERF_TEST) { 894 try { 895 Class c = Class.forName("org.netbeans.performance.test.utilities.LoggingScanClasspath",true,Thread.currentThread().getContextClassLoader()); java.lang.reflect.Method m = c.getMethod("reportScanOfFile", new Class [] {String .class, Long .class}); m.invoke(c.newInstance(), new Object [] {rootURL.toExternalForm(), new Long (endT - startT)}); 898 } catch (Exception e) { 899 Exceptions.printStackTrace(e); 900 } 901 } 902 } catch (Throwable e) { 903 if (e instanceof ThreadDeath ) { 904 throw (ThreadDeath ) e; 905 } 906 else { 907 Exceptions.attachMessage(e, "While scanning: " + rootURL); 908 Exceptions.printStackTrace(e); 909 } 910 } 911 } 912 for (java.util.ListIterator <URL > it = this.state.listIterator(this.state.size()); it.hasPrevious(); ) { 913 if (this.canceled.getAndSet(false)) { 914 return false; 915 } 916 try { 917 final URL rootURL = it.previous(); 918 it.remove(); 919 if (!oldRoots.remove(rootURL) && !RepositoryUpdater.this.scannedRoots.contains(rootURL)) { 920 long startT = System.currentTimeMillis(); 921 updateFolder (rootURL,rootURL, false, handle); 922 long endT = System.currentTimeMillis(); 923 if (PERF_TEST) { 924 try { 925 Class c = Class.forName("org.netbeans.performance.test.utilities.LoggingScanClasspath",true,Thread.currentThread().getContextClassLoader()); java.lang.reflect.Method m = c.getMethod("reportScanOfFile", new Class [] {String .class, Long .class}); m.invoke(c.newInstance(), new Object [] {rootURL.toExternalForm(), new Long (endT - startT)}); 928 } catch (Exception e) { 929 Exceptions.printStackTrace(e); 930 } 931 } 932 } 933 } catch (Throwable e) { 934 if (e instanceof ThreadDeath ) { 935 throw (ThreadDeath ) e; 936 } 937 else { 938 Exceptions.printStackTrace (e); 939 } 940 } 941 } 942 return true; 943 } 944 945 private void updateFolder(final URL folder, final URL root, boolean clean, final ProgressHandle handle) throws IOException { 946 final FileObject rootFo = URLMapper.findFileObject(root); 947 if (rootFo == null) { 948 return; 949 } 950 if (!rootFo.isFolder()) { 951 LOGGER.warning("Source root has to be a folder: " + FileUtil.getFileDisplayName(rootFo)); return; 953 } 954 final ClassPath sourcePath = ClassPath.getClassPath(rootFo,ClassPath.SOURCE); 955 final ClassPath bootPath = ClassPath.getClassPath(rootFo, ClassPath.BOOT); 956 final ClassPath compilePath = ClassPath.getClassPath(rootFo, ClassPath.COMPILE); 957 final boolean isInitialCompilation = folder.equals(root); 958 if (sourcePath == null || bootPath == null || compilePath == null) { 959 LOGGER.warning("Ignoring root with no ClassPath: " + FileUtil.getFileDisplayName(rootFo)); return; 961 } 962 try { 963 final File rootFile = FileUtil.toFile(rootFo); 964 final File folderFile = isInitialCompilation ? rootFile : FileUtil.normalizeFile(new File (URI.create(folder.toExternalForm()))); 965 if (handle != null) { 966 final String message = String.format (NbBundle.getMessage(RepositoryUpdater.class,"MSG_Scannig"),rootFile.getAbsolutePath()); 967 handle.setDisplayName(message); 968 } 969 JavaFileFilterImplementation filter = filters.get(root); 971 if (filter == null) { 972 filter = JavaFileFilterQuery.getFilter(rootFo); 973 if (filter != null) { 974 if (!filters.values().contains(filter)) { 975 filter.addChangeListener(filterListener); 976 } 977 filters.put(root, filter); 978 } 979 } 980 List <JavaFileObject> toCompile = new LinkedList <JavaFileObject>(); 981 final File classCache = Index.getClassFolder(rootFile); 982 final Map <String ,List <File >> resources = getAllClassFiles(classCache, FileObjects.getRelativePath(rootFile,folderFile),true); 983 final LazyFileList children = new LazyFileList(folderFile); 984 ClassIndexImpl uqImpl = ClassIndexManager.getDefault().createUsagesQuery(root, true); 985 assert uqImpl != null; 986 SourceAnalyser sa = uqImpl.getSourceAnalyser(); 987 assert sa != null; 988 boolean invalidIndex = isInitialCompilation && !sa.isValid(); 989 Set <File > rs = new HashSet <File > (); 990 ClassPath.Entry entry = null; 991 final ClasspathInfo cpInfo; 992 if (!this.ignoreExcludes.contains(root)) { 993 entry = getClassPathEntry(sourcePath, root); 994 cpInfo = ClasspathInfoAccessor.INSTANCE.create(CacheClassPath.forClassPath(bootPath),CacheClassPath.forClassPath(compilePath),sourcePath,filter,true,false); 995 } 996 else { 997 cpInfo = ClasspathInfoAccessor.INSTANCE.create(CacheClassPath.forClassPath(bootPath),CacheClassPath.forClassPath(compilePath),sourcePath,filter,true,true); 998 } 999 for (File child : children) { 1000 String offset = FileObjects.getRelativePath(rootFile,child); 1001 if (entry == null || entry.includes(offset.replace(File.separatorChar,'/'))) { 1002 if (invalidIndex || clean || dirtyCrossFiles.remove(child.toURI())) { 1003 toCompile.add (FileObjects.fileFileObject(child, rootFile, filter)); 1004 } 1005 else { 1006 final int index = offset.lastIndexOf('.'); if (index > -1) { 1008 offset = offset.substring(0,index); 1009 } 1010 List <File > files = resources.remove(offset); 1011 if (files==null) { 1012 toCompile.add(FileObjects.fileFileObject(child, rootFile, filter)); 1013 } else { 1014 boolean rsf = files.get(0).getName().endsWith(FileObjects.RS); 1015 if (files.get(0).lastModified() < child.lastModified()) { 1016 toCompile.add(FileObjects.fileFileObject(child, rootFile, filter)); 1017 for (File toDelete : files) { 1018 toDelete.delete(); 1019 if (rsf) { 1020 rsf = false; 1021 } 1022 else { 1023 String className = FileObjects.getBinaryName(toDelete,classCache); 1024 sa.delete(className); 1025 } 1026 } 1027 } 1028 else if (rsf) { 1029 files.remove(0); 1030 rs.addAll(files); 1031 } 1032 } 1033 } 1034 } 1035 } 1036 for (List <File > files : resources.values()) { 1037 for (File toDelete : files) { 1038 if (!rs.contains(toDelete)) { 1039 toDelete.delete(); 1040 if (toDelete.getName().endsWith(FileObjects.SIG)) { 1041 String className = FileObjects.getBinaryName(toDelete,classCache); 1042 sa.delete(className); 1043 } 1044 } 1045 } 1046 } 1047 if (!toCompile.isEmpty()) { 1048 if (handle != null) { 1049 final String message = String.format (NbBundle.getMessage(RepositoryUpdater.class,"MSG_BackgroundCompile"),rootFile.getAbsolutePath()); 1050 handle.setDisplayName(message); 1051 } 1052 batchCompile(toCompile, rootFo, cpInfo, sa, dirtyCrossFiles); 1053 } 1054 sa.store(); 1055 } finally { 1056 if (!clean && isInitialCompilation) { 1057 RepositoryUpdater.this.scannedRoots.add(root); 1058 } 1059 } 1060 } 1061 1062 private void updateFile (final URL file, final URL root) throws IOException { 1063 final FileObject fo = URLMapper.findFileObject(file); 1064 if (fo == null) { 1065 return; 1066 } 1067 1068 assert "file".equals(root.getProtocol()) : "Unexpected protocol of URL: " + root; final ClassIndexImpl uqImpl = ClassIndexManager.getDefault().createUsagesQuery(root, true); 1070 if (uqImpl != null) { 1071 uqImpl.setDirty(null); 1072 final JavaFileFilterImplementation filter = JavaFileFilterQuery.getFilter(fo); 1073 ClasspathInfo cpInfo = ClasspathInfoAccessor.INSTANCE.create (fo, filter, true, false); 1074 final File rootFile = FileUtil.normalizeFile(new File (URI.create(root.toExternalForm()))); 1075 final File fileFile = FileUtil.toFile(fo); 1076 final File classCache = Index.getClassFolder (rootFile); 1077 final Map <String ,List <File >> resources = getAllClassFiles (classCache, FileObjects.getRelativePath(rootFile, fileFile.getParentFile()),false); 1078 String offset = FileObjects.getRelativePath (rootFile,fileFile); 1079 final int index = offset.lastIndexOf('.'); if (index > -1) { 1081 offset = offset.substring(0,index); 1082 } 1083 List <File > files = resources.remove (offset); 1084 SourceAnalyser sa = uqImpl.getSourceAnalyser(); 1085 assert sa != null; 1086 if (files != null) { 1087 for (File toDelete : files) { 1088 toDelete.delete(); 1089 if (toDelete.getName().endsWith(FileObjects.SIG)) { 1090 String className = FileObjects.getBinaryName (toDelete,classCache); 1091 sa.delete (className); 1092 } 1093 } 1094 } 1095 else { 1096 sa.delete(FileObjects.convertFolder2Package(offset, '/')); } 1098 ClassPath.Entry entry = getClassPathEntry (cpInfo.getClassPath(ClasspathInfo.PathKind.SOURCE),root); 1099 if (entry == null || entry.includes(fo)) { 1100 String sourceLevel = SourceLevelQuery.getSourceLevel(fo); 1101 final CompilerListener listener = new CompilerListener (); 1102 final JavaFileManager fm = ClasspathInfoAccessor.INSTANCE.getFileManager(cpInfo); 1103 JavaFileObject active = FileObjects.fileFileObject(fileFile, rootFile, filter); 1104 JavacTaskImpl jt = JavaSourceAccessor.INSTANCE.createJavacTask(cpInfo, listener, sourceLevel); 1105 jt.setTaskListener(listener); 1106 Iterable <? extends CompilationUnitTree> trees = jt.parse(new JavaFileObject[] {active}); 1107 jt.enter(); 1108 jt.analyze (); 1109 dumpClasses(listener.getEnteredTypes(), fm, root.toExternalForm(), null, 1110 com.sun.tools.javac.code.Types.instance(jt.getContext()), 1111 com.sun.tools.javac.util.Name.Table.instance(jt.getContext())); 1112 sa.analyse (trees, jt, fm, active); 1113 listener.cleanDiagnostics(); 1114 sa.store(); 1115 } 1116 } 1117 } 1118 1119 private void delete (final URL file, final URL root, final boolean folder) throws IOException { 1120 assert "file".equals(root.getProtocol()) : "Unexpected protocol of URL: " + root; final File rootFile = FileUtil.normalizeFile(new File (URI.create(root.toExternalForm()))); 1122 assert "file".equals(file.getProtocol()) : "Unexpected protocol of URL: " + file; final File fileFile = FileUtil.normalizeFile(new File (URI.create(file.toExternalForm()))); 1124 final String offset = FileObjects.getRelativePath (rootFile,fileFile); 1125 assert offset != null && offset.length() > 0 : String.format("File %s not under root %s ", fileFile.getAbsolutePath(), rootFile.getAbsolutePath()); final File classCache = Index.getClassFolder (rootFile); 1127 File [] affectedFiles = null; 1128 if (folder) { 1129 final File container = new File (classCache, offset); 1130 affectedFiles = container.listFiles(); 1131 } 1132 else { 1133 int slashIndex = offset.lastIndexOf (File.separatorChar); 1134 int dotIndex = offset.lastIndexOf('.'); final File container = slashIndex == -1 ? classCache : new File (classCache,offset.substring(0,slashIndex)); 1136 final String name = offset.substring(slashIndex+1, dotIndex); 1137 final String [] patterns = new String [] { 1138 name + '.', 1139 name + '$' 1140 }; 1141 final File [] content = container.listFiles(); 1142 if (content != null) { 1143 final List <File > result = new ArrayList <File >(content.length); 1144 for (File f : content) { 1145 final String fname = f.getName(); 1146 if (fname.startsWith(patterns[0]) || fname.startsWith(patterns[1])) { 1147 result.add(f); 1148 } 1149 } 1150 affectedFiles = result.toArray(new File [result.size()]); 1151 } 1152 } 1153 if (affectedFiles != null && affectedFiles.length > 0) { 1154 final ClassIndexImpl uqImpl = ClassIndexManager.getDefault().createUsagesQuery(root, true); 1155 assert uqImpl != null; 1156 final SourceAnalyser sa = uqImpl.getSourceAnalyser(); 1157 assert sa != null; 1158 for (File f : affectedFiles) { 1159 if (f.getName().endsWith(FileObjects.RS)) { 1160 List <File > rsFiles = new LinkedList <File >(); 1161 readRSFile(f, classCache, rsFiles); 1162 for (File rsf : rsFiles) { 1163 String className = FileObjects.getBinaryName (rsf,classCache); 1164 sa.delete (className); 1165 rsf.delete(); 1166 } 1167 } 1168 else { 1169 String className = FileObjects.getBinaryName (f,classCache); 1170 sa.delete (className); 1171 } 1172 f.delete(); 1173 } 1174 sa.store(); 1175 } 1176 } 1177 1178 private void updateBinary (final URL file, final URL root) throws IOException { 1179 CachingArchiveProvider.getDefault().clearArchive(root); 1180 final BinaryAnalyser ba = ClassIndexManager.getDefault().createUsagesQuery(root, false).getBinaryAnalyser(); 1181 ba.analyse(root, handle); 1182 } 1183 } 1184 1185 static class LazyFileList implements Iterable <File > { 1186 1187 private File root; 1188 1189 public LazyFileList (final File root) { 1190 assert root != null; 1191 this.root = root; 1192 } 1193 1194 public Iterator <File > iterator() { 1195 if (!root.exists()) { 1196 return Collections.<File >emptySet().iterator(); 1197 } 1198 return new It (this.root); 1199 } 1200 1201 1202 private class It implements Iterator <File > { 1203 1204 private final List <File > toDo = new LinkedList <File > (); 1205 1206 public It (File root) { 1207 this.toDo.addAll (java.util.Arrays.asList(root.listFiles())); 1208 } 1209 1210 public boolean hasNext() { 1211 while (!toDo.isEmpty()) { 1212 File f = toDo.remove (0); 1213 final String name = f.getName(); 1214 if (f.isDirectory() && !ignoredDirectories.contains(name) && Utilities.isJavaIdentifier(name)) { 1215 File [] content = f.listFiles(); 1216 for (int i=0,j=0;i<content.length;i++) { 1217 f = content[i]; 1218 if (f.isFile()) { 1219 this.toDo.add(j++,f); 1220 } 1221 else { 1222 this.toDo.add(f); 1223 } 1224 } 1225 } 1226 else if (name.endsWith('.'+JavaDataLoader.JAVA_EXTENSION) && !PACKAGE_INFO.equals(name) && f.length()>0) { toDo.add(0,f); 1228 return true; 1229 } 1230 } 1231 return false; 1232 } 1233 1234 public File next() { 1235 return toDo.remove (0); 1236 } 1237 1238 public void remove() { 1239 throw new UnsupportedOperationException (); 1240 } 1241 1242 } 1243 } 1244 1245 1246 private final class Delay { 1247 1248 private final Timer timer; 1249 private final List <Work> tasks; 1250 1251 public Delay () { 1252 this.timer = new Timer (); 1253 this.tasks = new LinkedList <Work> (); 1254 } 1255 1256 public synchronized void post (final Work work) { 1257 assert work != null; 1258 this.tasks.add (work); 1259 this.timer.schedule(new DelayTask (work),DELAY); 1260 } 1261 1262 public void cancel () { 1263 Work[] toCancel; 1264 synchronized (this) { 1265 toCancel = this.tasks.toArray (new Work[this.tasks.size()]); 1266 } 1267 for (Work w : toCancel) { 1268 if (w.workType == WorkType.COMPILE) { 1269 w = new SingleRootWork (WorkType.DELETE,((SingleRootWork)w).file, 1270 ((SingleRootWork)w).root,((SingleRootWork)w).isFolder, 1271 w.latch); 1272 } 1273 CompileWorker cw = new CompileWorker (w); 1274 try { 1275 cw.run (null); 1276 } catch (IOException ioe) { 1277 Exceptions.printStackTrace(ioe); 1278 } 1279 } 1280 } 1281 1282 1283 private class DelayTask extends TimerTask { 1284 1285 final Work work; 1286 1287 public DelayTask (final Work work) { 1288 this.work = work; 1289 } 1290 1291 public void run() { 1292 submit(work); 1293 synchronized (Delay.this) { 1294 Delay.this.tasks.remove (work); 1295 } 1296 } 1297 1298 public @Override boolean cancel() { 1299 boolean retValue = super.cancel(); 1300 if (retValue) { 1301 synchronized (Delay.this) { 1302 Delay.this.tasks.remove (work); 1303 } 1304 } 1305 return retValue; 1306 } 1307 } 1308 } 1309 1310 private static class CompilerListener implements DiagnosticListener<JavaFileObject>, LowMemoryListener, TaskListener { 1311 1312 final List <Diagnostic> errors = new LinkedList <Diagnostic> (); 1313 final List <Diagnostic> warnings = new LinkedList <Diagnostic> (); 1314 final List <ClassSymbol> justEntered = new LinkedList <ClassSymbol> (); 1315 final AtomicBoolean lowMemory = new AtomicBoolean (); 1316 1317 void cleanDiagnostics () { 1318 if (!this.errors.isEmpty()) { 1319 if (LOGGER.isLoggable(Level.FINE)) { 1320 for (Diagnostic msg : this.errors) { 1321 LOGGER.fine(msg.toString()); } 1323 } 1324 this.errors.clear(); 1325 } 1326 if (!this.warnings.isEmpty()) { 1327 if (LOGGER.isLoggable(Level.FINE)) { 1328 for (Diagnostic msg: this.warnings) { 1329 LOGGER.fine(msg.toString()); } 1331 } 1332 this.warnings.clear(); 1333 } 1334 this.justEntered.clear(); 1335 } 1336 1337 List <? extends ClassSymbol> getEnteredTypes () { 1338 List <ClassSymbol> result = new ArrayList <ClassSymbol>(this.justEntered); 1339 this.justEntered.clear(); 1340 return result; 1341 } 1342 1343 1344 1345 public void report(final Diagnostic diagnosticMessage) { 1346 Diagnostic.Kind kind = diagnosticMessage.getKind(); 1347 if ( kind == Diagnostic.Kind.ERROR) { 1348 this.errors.add (diagnosticMessage); 1349 } 1350 else if (kind == Diagnostic.Kind.WARNING 1351 ||kind == Diagnostic.Kind.MANDATORY_WARNING) { 1352 this.warnings.add (diagnosticMessage); 1353 } 1354 } 1355 1356 public void started(TaskEvent event) { 1357 } 1358 1359 public void finished(final TaskEvent event) { 1360 if (event.getKind() == TaskEvent.Kind.ENTER) { 1361 final CompilationUnitTree unit = event.getCompilationUnit(); 1362 for (Tree typeTree : unit.getTypeDecls()) { 1363 if (typeTree instanceof JCTree.JCClassDecl) { ClassSymbol sym = ((JCTree.JCClassDecl)typeTree).sym; 1365 if (sym != null) { 1366 if (sym.sourcefile == null) { 1367 sym.sourcefile = event.getSourceFile(); 1368 } 1369 if (!(sym.sourcefile instanceof FileObjects.ZipFileBase)) { 1370 this.justEntered.add(sym); 1371 } 1372 } 1373 } 1374 } 1375 } 1376 } 1377 1378 public void lowMemory (final LowMemoryEvent event) { 1379 this.lowMemory.set(true); 1380 } 1381 } 1382 1383 public static void batchCompile (final List <JavaFileObject> toCompile, final FileObject rootFo, final ClasspathInfo cpInfo, final SourceAnalyser sa, final Set <URI > dirtyFiles) throws IOException { 1384 assert toCompile != null; 1385 assert rootFo != null; 1386 assert cpInfo != null; 1387 JavaFileObject active = null; 1388 final JavaFileFilterImplementation filter = JavaFileFilterQuery.getFilter(rootFo); 1389 final JavaFileManager fileManager = ClasspathInfoAccessor.INSTANCE.getFileManager(cpInfo); 1390 final CompilerListener listener = new CompilerListener (); 1391 LowMemoryNotifier.getDefault().addLowMemoryListener(listener); 1392 try { 1393 JavacTaskImpl jt = null; 1394 try { 1395 List <JavaFileObject> bigFiles = new LinkedList <JavaFileObject>(); 1396 int state = 0; 1397 boolean isBigFile = false; 1398 final String sourceLevel = SourceLevelQuery.getSourceLevel(rootFo); 1399 while (!toCompile.isEmpty() || !bigFiles.isEmpty() || active != null) { 1400 try { 1401 if (listener.lowMemory.getAndSet(false)) { 1402 if (jt != null) { 1403 jt.finish(); 1404 } 1405 jt = null; 1406 if (state == 1) { 1407 break; 1408 } else { 1409 state = 1; 1410 } 1411 System.gc(); 1412 continue; 1413 } 1414 if (active == null) { 1415 if (!toCompile.isEmpty()) { 1416 active = toCompile.remove(0); 1417 isBigFile = false; 1418 } else { 1419 active = bigFiles.remove(0); 1420 isBigFile = true; 1421 } 1422 } 1423 if (jt == null) { 1424 jt = JavaSourceAccessor.INSTANCE.createJavacTask(cpInfo, listener, sourceLevel); 1425 jt.setTaskListener(listener); 1426 LOGGER.fine("Created new JavacTask for: " + FileUtil.getFileDisplayName(rootFo)); } 1428 Iterable <? extends CompilationUnitTree> trees = jt.parse(new JavaFileObject[] {active}); 1429 if (listener.lowMemory.getAndSet(false)) { 1430 jt.finish(); 1431 jt = null; 1432 listener.cleanDiagnostics(); 1433 trees = null; 1434 if (state == 1) { 1435 if (isBigFile) { 1436 break; 1437 } else { 1438 bigFiles.add(active); 1439 active = null; 1440 state = 0; 1441 } 1442 } else { 1443 state = 1; 1444 } 1445 System.gc(); 1446 continue; 1447 } 1448 Iterable <? extends TypeElement> types = jt.enterTrees(trees); 1449 dumpClasses (listener.getEnteredTypes(),fileManager, 1450 rootFo.getURL().toExternalForm(), dirtyFiles, 1451 com.sun.tools.javac.code.Types.instance(jt.getContext()), 1452 com.sun.tools.javac.util.Name.Table.instance(jt.getContext())); 1453 if (listener.lowMemory.getAndSet(false)) { 1454 jt.finish(); 1455 jt = null; 1456 listener.cleanDiagnostics(); 1457 trees = null; 1458 types = null; 1459 if (state == 1) { 1460 if (isBigFile) { 1461 break; 1462 } else { 1463 bigFiles.add(active); 1464 active = null; 1465 state = 0; 1466 } 1467 } else { 1468 state = 1; 1469 } 1470 System.gc(); 1471 continue; 1472 } 1473 final JavaCompiler jc = JavaCompiler.instance(jt.getContext()); 1474 final JavaFileObject finalActive = active; 1475 Filter f = new Filter() { 1476 public void process(Env<AttrContext> env) { 1477 try { 1478 jc.attribute(env); 1479 } catch (Throwable t) { 1480 if (finalActive.toUri().getPath().contains("org/openide/loaders/OpenSupport.java")) { 1481 Exceptions.printStackTrace(t); 1482 } 1483 } 1484 } 1485 }; 1486 f.run(jc.todo, types); 1487 dumpClasses (listener.getEnteredTypes(), fileManager, 1488 rootFo.getURL().toExternalForm(), dirtyFiles, 1489 com.sun.tools.javac.code.Types.instance(jt.getContext()), 1490 com.sun.tools.javac.util.Name.Table.instance(jt.getContext())); 1491 if (listener.lowMemory.getAndSet(false)) { 1492 jt.finish(); 1493 jt = null; 1494 listener.cleanDiagnostics(); 1495 trees = null; 1496 types = null; 1497 if (state == 1) { 1498 if (isBigFile) { 1499 break; 1500 } else { 1501 bigFiles.add(active); 1502 active = null; 1503 state = 0; 1504 } 1505 } else { 1506 state = 1; 1507 } 1508 System.gc(); 1509 continue; 1510 } 1511 if (sa != null) { 1512 sa.analyse(trees,jt, ClasspathInfoAccessor.INSTANCE.getFileManager(cpInfo), active); 1513 } 1514 if (!listener.errors.isEmpty()) { 1515 Log.instance(jt.getContext()).nerrors = 0; 1516 listener.cleanDiagnostics(); 1517 } 1518 active = null; 1519 state = 0; 1520 } catch (CouplingAbort a) { 1521 couplingAbort(a, active); 1524 if (jt != null) { 1525 jt.finish(); 1526 } 1527 jt = null; 1528 listener.cleanDiagnostics(); 1529 state = 0; 1530 } catch (Throwable t) { 1531 if (t instanceof ThreadDeath ) { 1532 throw (ThreadDeath ) t; 1533 } 1534 else { 1535 if (jt != null) { 1536 jt.finish(); 1537 } 1538 final URI activeURI = active.toUri(); 1539 jt = null; 1540 active = null; 1541 listener.cleanDiagnostics(); 1542 if (!(t instanceof Abort)) { 1543 final ClassPath bootPath = cpInfo.getClassPath(ClasspathInfo.PathKind.BOOT); 1544 final ClassPath classPath = cpInfo.getClassPath(ClasspathInfo.PathKind.COMPILE); 1545 final ClassPath sourcePath = cpInfo.getClassPath(ClasspathInfo.PathKind.SOURCE); 1546 t = Exceptions.attachMessage(t,String.format("Root: %s File: %s Bootpath: %s Classpath: %s Sourcepath: %s", 1547 FileUtil.getFileDisplayName(rootFo), 1548 activeURI.toString(), 1549 bootPath == null ? null : bootPath.toString(), 1550 classPath == null ? null : classPath.toString(), 1551 sourcePath == null ? null : sourcePath.toString() 1552 )); 1553 Exceptions.printStackTrace(t); 1554 } 1555 } 1556 } 1557 } 1558 if (state == 1) { 1559 LOGGER.warning("Not enough memory to compile folder: " + FileUtil.getFileDisplayName(rootFo)); } 1561 } finally { 1562 if (jt != null) { 1563 jt.finish(); 1564 } 1565 } 1566 } finally { 1567 LowMemoryNotifier.getDefault().removeLowMemoryListener(listener); 1568 } 1569 } 1570 1571 1572 private static void dumpClasses (final List <? extends ClassSymbol> entered, final JavaFileManager fileManager, 1573 final String currentRoot, final Set <URI > dirtyFiles, final com.sun.tools.javac.code.Types javacTypes, 1574 final com.sun.tools.javac.util.Name.Table nameTable) throws IOException { 1575 for (ClassSymbol classSym : entered) { 1576 JavaFileObject source = classSym.sourcefile; 1577 dumpTopLevel(classSym, fileManager, source, currentRoot, dirtyFiles, javacTypes, nameTable); 1578 } 1579 } 1580 1581 private static void dumpTopLevel (final ClassSymbol classSym, final JavaFileManager fileManager, 1582 final JavaFileObject source, final String currentRootURL, final Set <URI > dirtyFiles, 1583 final com.sun.tools.javac.code.Types types, 1584 final com.sun.tools.javac.util.Name.Table nameTable) throws IOException { 1585 assert source != null; 1586 if (classSym.getSimpleName() != nameTable.error) { 1587 URI uri = source.toUri(); 1588 if (dirtyFiles != null && !uri.toURL().toExternalForm().startsWith(currentRootURL)) { 1589 dirtyFiles.add (uri); 1590 } 1591 final String sourceName = fileManager.inferBinaryName(StandardLocation.SOURCE_PATH, source); 1592 final StringBuilder classNameBuilder = new StringBuilder (); 1593 ClassFileUtil.encodeClassName(classSym, classNameBuilder, '.'); final String binaryName = classNameBuilder.toString(); 1595 Set <String > rsList = null; 1596 if (!sourceName.equals(binaryName)) { 1597 rsList = new HashSet <String >(); 1598 } 1599 final JavaFileObject fobj = fileManager.getJavaFileForOutput(StandardLocation.CLASS_OUTPUT, binaryName, JavaFileObject.Kind.CLASS, source); 1600 if ((classSym.asType() instanceof ErrorType) && ((FileObjects.FileBase)fobj).getFile().exists()) { 1601 return; 1602 } 1603 final PrintWriter out = new PrintWriter (new OutputStreamWriter (fobj.openOutputStream())); 1604 try { 1605 SymbolDumper.dump(out,types,classSym,null); 1606 } finally { 1607 out.close(); 1608 } 1609 if (rsList != null) { 1610 rsList.add(binaryName); 1611 } 1612 final List <Symbol> enclosedElements = classSym.getEnclosedElements(); 1613 for (Symbol ee : enclosedElements) { 1614 if (ee.getKind().isClass() || ee.getKind().isInterface()) { 1615 dumpClass ((ClassSymbol)ee,fileManager, source, types, nameTable, rsList); 1616 } 1617 } 1618 if (rsList != null) { 1619 final int index = sourceName.lastIndexOf('.'); final String pkg = index == -1 ? "" : sourceName.substring(0,index); final String rsName = (index == -1 ? sourceName : sourceName.substring(index+1)) + '.' + FileObjects.RS; javax.tools.FileObject fo = fileManager.getFileForOutput(StandardLocation.CLASS_OUTPUT, pkg, rsName, source); 1623 assert fo != null; 1624 PrintWriter rsOut = new PrintWriter (fo.openWriter()); 1625 try { 1626 for (String sig : rsList) { 1627 rsOut.println(sig); 1628 } 1629 } finally { 1630 rsOut.close(); 1631 } 1632 } 1633 } 1634 } 1635 1636 private static void dumpClass (final ClassSymbol classSym, final JavaFileManager fileManager, final JavaFileObject source, final com.sun.tools.javac.code.Types types, 1637 final com.sun.tools.javac.util.Name.Table nameTable, final Set <? super String > rsList) throws IOException { 1638 if (classSym.getSimpleName() != nameTable.error) { 1639 final StringBuilder classNameBuilder = new StringBuilder (); 1640 ClassFileUtil.encodeClassName(classSym, classNameBuilder, '.'); final String binaryName = classNameBuilder.toString(); 1642 final JavaFileObject fobj = fileManager.getJavaFileForOutput(StandardLocation.CLASS_OUTPUT, binaryName, JavaFileObject.Kind.CLASS, source); 1643 final PrintWriter out = new PrintWriter (new OutputStreamWriter (fobj.openOutputStream())); 1644 try { 1645 SymbolDumper.dump(out,types,classSym,null); 1646 } finally { 1647 out.close(); 1648 } 1649 if (rsList != null) { 1650 rsList.add(binaryName); 1651 } 1652 final List <Symbol> enclosedElements = classSym.getEnclosedElements(); 1653 for (Symbol ee : enclosedElements) { 1654 if (ee.getKind().isClass() || ee.getKind().isInterface()) { 1655 dumpClass ((ClassSymbol)ee,fileManager, source, types, nameTable, rsList); 1656 } 1657 } 1658 } 1659 } 1660 1661 private static Set <String > parseSet(String propertyName, String defaultValue) { 1662 StringTokenizer st = new StringTokenizer (System.getProperty(propertyName, defaultValue), " \t\n\r\f,-:+!"); 1663 Set <String > result = new HashSet <String >(); 1664 while (st.hasMoreTokens()) { 1665 result.add(st.nextToken()); 1666 } 1667 return result; 1668 } 1669 1670 1671 public static Map <String ,List <File >> getAllClassFiles (final File root, final String offset, boolean recursive) { 1672 assert root != null; 1673 Map <String ,List <File >> result = new HashMap <String ,List <File >> (); 1674 String rootName = root.getAbsolutePath(); 1675 int len = rootName.length(); 1676 if (rootName.charAt(len-1)!=File.separatorChar) { 1677 len++; 1678 } 1679 File folder = root; 1680 if (offset.length() > 0) { 1681 folder = new File (folder,offset); if (!folder.exists() || !folder.isDirectory()) { 1683 return result; 1684 } 1685 } 1686 getAllClassFilesImpl (folder, root,len,result, recursive); 1687 return result; 1688 } 1689 1690 private static void getAllClassFilesImpl (final File folder, final File root, final int oi, final Map <String ,List <File >> result, final boolean recursive) { 1691 final File [] content = folder.listFiles(); 1692 if (content == null) { 1693 LOGGER.info("IO error while listing folder: " + folder.getAbsolutePath() +" isDirectory: " + folder.isDirectory() +" canRead: " + folder.canRead()); return; 1695 } 1696 for (File f: content) { 1697 if (f.isDirectory() && recursive) { 1698 getAllClassFilesImpl(f, root, oi,result, recursive); 1699 } 1700 else { 1701 String path = f.getAbsolutePath(); 1702 int extIndex = path.lastIndexOf('.'); if (extIndex+1+FileObjects.RS.length() == path.length() && path.endsWith(FileObjects.RS)) { 1704 path = path.substring (oi,extIndex); 1705 List <File > files = result.get (path); 1706 if (files == null) { 1707 files = new LinkedList <File >(); 1708 result.put (path,files); 1709 } 1710 files.add(0,f); try { 1712 readRSFile (f,root, files); 1713 } catch (IOException ioe) { 1714 Exceptions.printStackTrace(ioe); 1716 } 1717 } 1718 else if (extIndex+1+FileObjects.SIG.length() == path.length() && path.endsWith(FileObjects.SIG)) { 1719 int index = path.indexOf('$',oi); if (index == -1) { 1721 path = path.substring (oi,extIndex); 1722 } 1723 else { 1724 path = path.substring (oi,index); 1725 } 1726 List <File > files = result.get (path); 1727 if (files == null) { 1728 files = new LinkedList <File >(); 1729 result.put (path,files); 1730 } 1731 files.add (f); 1732 } 1733 } 1734 } 1735 } 1736 1737 private static void readRSFile (final File f, final File root, final List <? super File > files) throws IOException { 1738 BufferedReader in = new BufferedReader (new FileReader (f)); 1739 try { 1740 String binaryName; 1741 while ((binaryName=in.readLine())!=null) { 1742 File sf = new File (root, FileObjects.convertPackage2Folder(binaryName)+'.'+FileObjects.SIG); 1743 files.add(sf); 1744 } 1745 } finally { 1746 in.close(); 1747 } 1748 } 1749 1750 1751 private static ClassPath.Entry getClassPathEntry (final ClassPath cp, final URL root) { 1752 assert cp != null; 1753 assert root != null; 1754 for (ClassPath.Entry e : cp.entries()) { 1755 if (root.equals(e.getURL())) { 1756 return e; 1757 } 1758 } 1759 return null; 1760 } 1761 1762 1763 private class FilterListener implements ChangeListener { 1764 1765 public void stateChanged(ChangeEvent event) { 1766 Object source = event.getSource(); 1767 if (source instanceof JavaFileFilterImplementation) { 1768 List <URL > dirtyRoots = new LinkedList <URL > (); 1769 synchronized (filters) { 1770 for (Map.Entry <URL ,JavaFileFilterImplementation> e : filters.entrySet()) { 1771 if (e.getValue() == source) { 1772 dirtyRoots.add(e.getKey()); 1773 } 1774 } 1775 } 1776 submit(Work.filterChange(dirtyRoots)); 1777 } 1778 } 1779 } 1780 1781 public static synchronized RepositoryUpdater getDefault () { 1782 if (instance == null) { 1783 instance = new RepositoryUpdater (); 1784 } 1785 return instance; 1786 } 1787 1788 private static final int MAX_DUMPS = 255; 1789 1790 1797 public static void couplingAbort(CouplingAbort a, JavaFileObject source) { 1798 String dumpDir = System.getProperty("netbeans.user") + "/var/log/"; JavaFileObject classSource = a.getClassFile(); 1800 String uri = classSource != null ? classSource.toUri().toASCIIString() : "<unknown>"; 1801 String origName = classSource != null ? classSource.getName() : "unknown"; 1802 File f = new File (dumpDir + origName + ".dump"); boolean dumpSucceeded = false; 1804 int i = 1; 1805 while (i < MAX_DUMPS) { 1806 if (!f.exists()) 1807 break; 1808 f = new File (dumpDir + origName + '_' + i + ".dump"); i++; 1810 } 1811 if (!f.exists()) { 1812 try { 1813 OutputStream os = new FileOutputStream (f); 1814 PrintWriter writer = new PrintWriter (new OutputStreamWriter (os, "UTF-8")); try { 1816 writer.println(String.format("Coupling error: class file %s, source file %s", uri, source.toUri().toASCIIString())); 1817 writer.println("----- Sig file content: -------------------------------------------"); if (classSource == null) { 1819 writer.println("no content"); } else { 1821 if (classSource.getName().toLowerCase().endsWith(".sig")) { writer.println(classSource.getCharContent(true)); 1823 } else { 1824 writer.println("not a sig file"); } 1826 } 1827 writer.println("----- Source file content: ----------------------------------------"); writer.println(source.getCharContent(true)); 1829 writer.println("----- Tree: -------------------------------------------------------"); writer.println(a.getTree().toString()); 1831 writer.println("----- Coupling Error: ---------------------------------------------"); a.printStackTrace(writer); 1833 } finally { 1834 writer.close(); 1835 dumpSucceeded = true; 1836 } 1837 } catch (IOException ioe) { 1838 LOGGER.log(Level.INFO, "Error when writing coupling dump file!", ioe); } 1840 } 1841 if (dumpSucceeded) { 1842 LOGGER.log(Level.SEVERE, "Coupling error: class file {0}, source file {1}", new Object [] {uri, source.toUri().toASCIIString()}); 1843 } else { 1844 LOGGER.log(Level.WARNING, 1845 "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."); } 1850 } 1851 1852} 1853 | Popular Tags |