1 19 20 21 package org.netbeans.modules.tasklist.suggestions; 22 23 import org.openide.loaders.DataObject; 24 import org.openide.awt.StatusDisplayer; 25 import org.openide.util.NbBundle; 26 import org.openide.util.Lookup; 27 import org.openide.util.Cancellable; 28 import org.openide.cookies.EditorCookie; 29 import org.openide.filesystems.FileObject; 30 import org.openide.filesystems.FileUtil; 31 import org.openide.windows.WindowManager; 32 import org.openide.windows.Mode; 33 import org.openide.windows.TopComponent; 34 import org.openide.text.CloneableEditorSupport; 35 import org.openide.nodes.Node; 36 import org.openide.ErrorManager; 37 import org.netbeans.modules.tasklist.providers.SuggestionContext; 38 import org.netbeans.modules.tasklist.providers.SuggestionProvider; 39 import org.netbeans.modules.tasklist.providers.DocumentSuggestionProvider; 40 import org.netbeans.apihole.tasklist.SPIHole; 41 import org.netbeans.modules.tasklist.client.SuggestionManager; 42 import org.netbeans.api.queries.VisibilityQuery; 43 44 import javax.swing.*; 45 import java.util.*; 46 import java.lang.ref.WeakReference ; 47 import java.lang.ref.Reference ; 48 import java.lang.reflect.InvocationTargetException ; 49 50 64 public final class SuggestionsScanner implements Cancellable { 65 66 67 private ScanProgress progressMonitor; 68 69 76 private final Set scanned = new HashSet(); 77 78 79 private SuggestionList list; 80 81 private ProviderAcceptor typeFilter; 82 83 private final SuggestionManagerImpl manager; 85 86 private final SuggestionProviders registry; 87 88 private static Reference instance; 90 91 private volatile boolean interrupted; 92 private int suggestionsCounter; 93 private int usabilityLimit = 503; 94 private boolean workaround38476; 95 96 private List cummulateInList; 98 99 private SuggestionsScanner() { 100 manager = (SuggestionManagerImpl) Lookup.getDefault().lookup(SuggestionManager.class); 101 registry = SuggestionProviders.getDefault(); 102 } 103 104 public static SuggestionsScanner getDefault() { 105 if (instance == null) { 106 return createDefault(); 107 } 108 SuggestionsScanner scanner = (SuggestionsScanner) instance.get(); 109 if (scanner == null) { 110 return createDefault(); 111 } else { 112 return scanner; 113 } 114 } 115 116 private static SuggestionsScanner createDefault() { 117 SuggestionsScanner scanner = new SuggestionsScanner(); 118 instance = new WeakReference (scanner); 119 return scanner; 120 } 121 122 128 public final synchronized void scan(DataObject.Container[] folders, SuggestionList list, ScanProgress monitor) { 129 scan(folders, list, monitor, ProviderAcceptor.ALL); 130 } 131 132 139 public final synchronized void scan(DataObject.Container[] folders, SuggestionList list, ScanProgress monitor, ProviderAcceptor filter) { 140 try { 141 typeFilter = filter; 142 progressMonitor = monitor; 143 scan(folders, list, true); 144 } finally { 145 typeFilter = null; 146 progressMonitor = null; 147 if (monitor != null) monitor.scanFinished(); 148 } 149 } 150 151 160 private final synchronized void scan(DataObject.Container[] folders, SuggestionList list, 161 boolean recursive) { 162 163 lowMemoryWarning = false; 164 lowMemoryWarningCount = 0; 165 interrupted = false; 166 assureMemory(REQUIRED_PER_ITERATION, true); suggestionsCounter = 0; 168 169 170 try { 171 this.list = list; 172 173 workaround38476 = true; 176 scanPreferred(folders, recursive); 177 workaround38476 = false; 178 179 if (progressMonitor != null) { 180 int estimate = -1; 181 progressMonitor.estimate(estimate); 182 for (int i = 0; i < folders.length; i++) { 183 FileObject fo = ((DataObject)folders[i]).getPrimaryFile(); 185 estimate += countFolders(fo); 186 } 187 progressMonitor.estimate(estimate); 188 progressMonitor.scanStarted(); 189 } 190 191 for (int i = 0; i < folders.length; i++) { 192 if (shouldStop()) return; 193 DataObject.Container folder = folders[i]; 194 scanFolder(folder, recursive); 195 } 196 } finally { 197 scanned.clear(); 198 } 199 } 200 201 202 206 static TopComponent[] openedTopComponents() { 207 final Object [] wsResult = new Object [1]; 208 try { 209 210 if (SwingUtilities.isEventDispatchThread()) { 211 Mode editorMode = WindowManager.getDefault().findMode(CloneableEditorSupport.EDITOR_MODE); 212 if (editorMode == null) { 213 return new TopComponent[0]; 214 } else { 215 return editorMode.getTopComponents(); 216 } 217 } else { 218 SwingUtilities.invokeAndWait(new Runnable () { 221 public void run() { 222 Mode editorMode = WindowManager.getDefault().findMode(CloneableEditorSupport.EDITOR_MODE); 223 if (editorMode == null) { 224 wsResult[0] = new TopComponent[0]; 225 } else { 226 wsResult[0] = editorMode.getTopComponents(); 227 } 228 } 229 }); 230 return (TopComponent[]) wsResult[0]; 231 } 232 } catch (InterruptedException e) { 233 return new TopComponent[0]; 234 } catch (InvocationTargetException e) { 235 return new TopComponent[0]; 236 } 237 } 238 239 246 private void scanPreferred(DataObject.Container[] folders, boolean recursive) { 247 248 TopComponent[] views = openedTopComponents(); 249 DataObject[] roots = null; 250 for (int i = 0; i<views.length; i++) { 251 Node[] nodes = views[i].getActivatedNodes(); 252 if (nodes == null) continue; for (int n = 0; n<nodes.length; n++) { 254 DataObject dobj = (DataObject) nodes[n].getCookie(DataObject.class); 255 if (dobj != null) { 256 if (roots == null) { 257 Set allRoots = new HashSet(); 258 for (int r = 0; r<folders.length; r++) { 259 DataObject[] droots = folders[r].getChildren(); 260 for (int d = 0; d<droots.length; d++) { 261 allRoots.add(droots[d]); 262 } 263 } 264 roots = (DataObject[]) allRoots.toArray(new DataObject[allRoots.size()]); 265 } 266 scanPreferred(dobj, roots, recursive); 267 break; } 269 } 270 } 271 } 272 273 private void scanPreferred(DataObject dobj, DataObject[] roots, boolean recursive) { 274 FileObject fo = dobj.getPrimaryFile(); 275 for (int i=0; i<roots.length; i++) { 276 FileObject root = roots[i].getPrimaryFile(); 277 if (root.equals(fo) || (recursive ? FileUtil.isParentOf(root,fo) : fo.getParent().equals(root))) { 278 scanLeaf(dobj); 279 scanned.add(dobj); 280 break; } 283 } 284 } 285 286 private void scanFolder(DataObject.Container folder, boolean recursive) { 287 DataObject[] children = folder.getChildren(); 288 for (int i = 0; i < children.length; i++) { 289 290 if (shouldStop()) return; 291 292 DataObject f = children[i]; 293 if (f instanceof DataObject.Container) { 294 if (!recursive) { 295 continue; 296 } 297 298 String name = f.getPrimaryFile().getNameExt(); 300 if ("CVS".equals(name) || "SCCS".equals(name) || ".svn".equals(name)) { continue; 302 } 303 304 if (progressMonitor == null) { 305 StatusDisplayer.getDefault().setStatusText( 307 NbBundle.getMessage(SuggestionsScanner.class, 308 "ScanningFolder", f.getPrimaryFile().getNameExt())); 310 } else { 311 progressMonitor.folderEntered(f.getPrimaryFile()); 312 } 313 314 scanFolder((DataObject.Container) f, true); if (progressMonitor != null) { 316 progressMonitor.folderScanned(f.getPrimaryFile()); 317 } 318 319 } else { 320 scanLeaf(f); 321 } 322 } 323 } 324 325 326 332 final synchronized List scanTopComponent(TopComponent topComponent, ProviderAcceptor acceptor) { 333 List ret = Collections.EMPTY_LIST; 334 try { 335 336 338 cummulateInList = new LinkedList(); 339 progressMonitor = null; 340 scanned.clear(); 341 workaround38476 = topComponent.isOpened(); 342 suggestionsCounter = 0; 343 interrupted = false; 344 typeFilter = acceptor; 345 346 348 Node[] nodes = topComponent.getActivatedNodes(); 349 if (nodes == null) return ret; 350 for (int n = 0; n<nodes.length; n++) { 351 DataObject dobj = (DataObject) nodes[n].getCookie(DataObject.class); 352 if (dobj == null) return ret; 353 scanLeaf(dobj); 354 break; } 356 ret = cummulateInList; 357 } finally { 358 cummulateInList = null; 359 typeFilter = null; 360 } 361 return ret; 362 } 363 364 367 private void scanLeaf(DataObject dobj) { 368 370 if (!dobj.isValid()) return; 371 372 if (scanned.contains(dobj)) return; 373 374 final EditorCookie edit = 375 (EditorCookie) dobj.getCookie(EditorCookie.class); 376 if (edit == null) return; 377 378 FileObject fo = dobj.getPrimaryFile(); 379 if (VisibilityQuery.getDefault().isVisible(fo) == false) return; String extension = fo.getExt(); 381 boolean directAccess = "java".equals(extension) || "properties".equals(extension); final boolean isPrimed = edit.getDocument() == null && directAccess == false; 383 384 SuggestionContext env = SPIHole.createSuggestionContext(dobj); 385 386 scanLeaf(env); 387 388 if (false) { 389 try { 390 Thread.sleep(1000); } catch (InterruptedException e) { 394 } 396 } 397 398 399 Runnable r = new Runnable () { 404 public void run() { 405 if (isPrimed && edit.getOpenedPanes() == null && workaround38476 == false) { 406 edit.close(); 407 } 408 } 409 }; 410 if( SwingUtilities.isEventDispatchThread() ) { 411 r.run(); 412 } else { 413 try { 414 SwingUtilities.invokeAndWait( r ); 415 } catch( InvocationTargetException itE ) { 416 } catch( InterruptedException iE ) { 418 } 420 } 421 422 if (progressMonitor != null) { 423 progressMonitor.fileScanned(dobj.getPrimaryFile()); 424 } 425 426 } 427 428 private void scanLeaf(SuggestionContext env) { 429 List providers = registry.getProviders(); 430 ListIterator it = providers.listIterator(); 431 while (it.hasNext()) { 432 if (interrupted) return; 433 interrupted = Thread.interrupted(); 434 SuggestionProvider provider = (SuggestionProvider) it.next(); 435 436 assert typeFilter != null; 437 if (typeFilter.accept(provider) == false) continue; 438 439 if (provider instanceof DocumentSuggestionProvider) { 443 List l = null; 444 String type = null; 445 try { 446 type = provider.getType(); 447 l = ((DocumentSuggestionProvider) provider).scan(env); 448 } catch (RuntimeException e) { 449 ErrorManager.getDefault().annotate(e, "Skipping faulty provider (" + provider + ")."); ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 451 } catch (ThreadDeath e) { 452 throw e; 453 } catch (Error e) { 454 ErrorManager.getDefault().annotate(e, "Skipping faulty provider (" + provider + ")."); ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 456 } 457 if (l != null && l.size() > 0) { 458 suggestionsCounter += l.size(); 460 if (cummulateInList == null) { 461 manager.register(type, l, null, list, true); 462 } else { 463 cummulateInList.addAll(l); 464 } 465 } 466 } 467 } 468 } 469 470 472 private static boolean lowMemoryWarning = false; 473 private static int lowMemoryWarningCount = 0; 474 private static int MB = 1024 * 1024; 475 private static int REQUIRED_PER_ITERATION = 2 * MB; 476 private static int REQUIRED_PER_FULL_GC = 7 * MB; 477 478 483 private void assureMemory(int estimate, boolean tryGC) { 484 Runtime rt = Runtime.getRuntime(); 485 long total = rt.totalMemory(); 486 long max = rt.maxMemory(); long required = Math.max(total/13, estimate + REQUIRED_PER_FULL_GC); 488 if (total == max && rt.freeMemory() < required) { 489 if (tryGC) { 491 try { 492 byte[] gcProvocation = new byte[(int)required]; 493 gcProvocation[0] = 75; 494 gcProvocation = null; 495 return; 496 } catch (OutOfMemoryError e) { 497 handleNoMemory(); 498 } 499 } else { 500 lowMemoryWarning = true; 501 } 502 } else if (lowMemoryWarning) { 503 lowMemoryWarning = false; 504 lowMemoryWarningCount ++; 505 } 506 if (lowMemoryWarningCount > 7 || (total == max && rt.freeMemory() < REQUIRED_PER_FULL_GC)) { 508 handleNoMemory(); 509 } 510 511 } 512 513 private void handleNoMemory() { 514 interrupted = true; 515 if (progressMonitor != null) { 516 progressMonitor.scanTerminated(-1); 517 } 518 } 519 520 521 private boolean shouldStop() { 522 if (interrupted) return true; 523 interrupted = Thread.interrupted(); 524 if (interrupted) return true; 525 assureMemory(REQUIRED_PER_ITERATION, false); 526 if (interrupted) return true; 527 if (suggestionsCounter > getCountLimit()) { 528 interrupted = true; 529 if (progressMonitor != null) { 530 progressMonitor.scanTerminated(-3); 531 } 532 } 533 return interrupted; 534 535 } 536 537 587 588 private int getCountLimit() { 589 return usabilityLimit; 590 } 591 592 private static int countFolders(FileObject projectFolder) { 593 int count = 0; 594 if (Thread.currentThread().isInterrupted()) return count; 595 Enumeration en = projectFolder.getFolders(false); 596 while (en.hasMoreElements()) { 597 FileObject next = (FileObject) en.nextElement(); 598 String name = next.getNameExt(); 599 if ("CVS".equals(name) || "SCCS".equals(name) || ".svn".equals(name)) { continue; 601 } 602 count++; 603 count += countFolders(next); } 605 return count; 606 } 607 608 public boolean cancel() { 609 interrupted = true; 610 if (progressMonitor != null) { 611 progressMonitor.scanTerminated(-2); 612 } 613 return true; 614 } 615 616 617 public void setUsabilityLimit(int usabilityLimit) { 618 this.usabilityLimit = usabilityLimit; 619 } 620 621 627 public interface ScanProgress { 628 632 void estimate(int estimatedFolders); 633 634 void scanStarted(); 635 636 void folderEntered(FileObject folder); 637 638 void fileScanned(FileObject file); 639 640 void folderScanned(FileObject folder); 641 642 void scanFinished(); 643 644 648 void scanTerminated(int reason); 649 } 650 651 652 } 653 | Popular Tags |