1 11 package org.eclipse.jdt.internal.corext.util; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.Collection ; 16 import java.util.Comparator ; 17 import java.util.HashSet ; 18 import java.util.Set ; 19 20 import org.eclipse.core.runtime.IProgressMonitor; 21 import org.eclipse.core.runtime.NullProgressMonitor; 22 import org.eclipse.core.runtime.OperationCanceledException; 23 import org.eclipse.core.runtime.Platform; 24 import org.eclipse.core.runtime.SubProgressMonitor; 25 26 import org.eclipse.core.resources.ResourcesPlugin; 27 28 import org.eclipse.swt.widgets.Display; 29 30 import org.eclipse.jdt.core.ElementChangedEvent; 31 import org.eclipse.jdt.core.ICompilationUnit; 32 import org.eclipse.jdt.core.IElementChangedListener; 33 import org.eclipse.jdt.core.IJavaElement; 34 import org.eclipse.jdt.core.IJavaElementDelta; 35 import org.eclipse.jdt.core.JavaCore; 36 import org.eclipse.jdt.core.JavaModelException; 37 import org.eclipse.jdt.core.search.IJavaSearchConstants; 38 import org.eclipse.jdt.core.search.IJavaSearchScope; 39 import org.eclipse.jdt.core.search.ITypeNameRequestor; 40 import org.eclipse.jdt.core.search.SearchEngine; 41 import org.eclipse.jdt.core.search.SearchPattern; 42 43 import org.eclipse.jdt.internal.corext.CorextMessages; 44 45 import org.eclipse.jdt.internal.ui.JavaPlugin; 46 47 61 public class AllTypesCache { 62 63 private static final int INITIAL_DELAY= 4000; 64 private static final int TIMEOUT= 3000; 65 private static final int INITIAL_SIZE= 2000; 66 private static final int CANCEL_POLL_INTERVAL= 300; 67 68 static class DelegatedProgressMonitor implements IProgressMonitor { 69 private IProgressMonitor fDelegate; 70 private String fTaskName; 71 private int fTotalWork= IProgressMonitor.UNKNOWN; 73 private double fWorked; 74 75 public synchronized void beginTask(String name, int totalWork) { 76 fTaskName= name; 77 fTotalWork= totalWork; 78 if (fDelegate != null) 79 fDelegate.beginTask(name, totalWork); 80 } 81 public void done() { 82 } 83 public synchronized void internalWorked(double work) { 84 fWorked+= work; 85 if (fDelegate != null) 86 fDelegate.internalWorked(work); 87 } 88 public boolean isCanceled() { 89 return false; 90 } 91 public void setCanceled(boolean value) { 92 } 93 public synchronized void setTaskName(String name) { 94 fTaskName= name; 95 if (fDelegate != null) 96 fDelegate.setTaskName(name); 97 } 98 public synchronized void subTask(String name) { 99 if (fDelegate != null) 101 fDelegate.subTask(name); 102 } 103 public void worked(int work) { 104 internalWorked(work); 105 } 106 synchronized void setDelegate(IProgressMonitor delegate) { 107 fDelegate= delegate; 108 if (fDelegate != null) { 109 if (fTaskName != null) { 110 fDelegate.beginTask(fTaskName, fTotalWork); 111 fDelegate.internalWorked(fWorked); 112 } 113 } else { 114 fTaskName= null; 115 fTotalWork= IProgressMonitor.UNKNOWN; 116 fWorked= 0.0; 117 } 118 } 119 } 120 121 122 private static final boolean TRACING; 123 static { 124 String value= Platform.getDebugOption("org.eclipse.jdt.ui/debug/allTypesCache"); TRACING= value != null && value.equalsIgnoreCase("true"); } 127 128 static class TypeCacher extends Thread { 129 130 private int fDelay; 131 private int fSizeHint; 132 private volatile boolean fRestart; 133 private volatile boolean fAbort; 134 135 TypeCacher(int sizeHint, int delay) { 136 super("All Types Caching"); fSizeHint= sizeHint; 138 fDelay= delay; 139 setPriority(Thread.NORM_PRIORITY - 1); 140 } 141 142 void restart() { 143 fRestart= true; 144 interrupt(); 145 } 146 147 public void abort() { 148 fRestart= fAbort= true; 149 interrupt(); 150 } 151 152 public void run() { 153 while (!fAbort) { 155 if (fDelay > 0) { 156 try { 157 Thread.sleep(fDelay); 158 } catch (InterruptedException e) { 159 if (fAbort) 160 break; 161 continue; } 163 } 164 165 fRestart= false; 166 Collection searchResult= doSearchTypes(); 167 if (searchResult != null) { 168 if (!fAbort && !fRestart) { 169 TypeInfo[] result= (TypeInfo[]) searchResult.toArray(new TypeInfo[searchResult.size()]); 170 Arrays.sort(result, fgTypeNameComparator); 171 setCache(result); 172 } 173 if (!fRestart) 174 break; 175 } 176 } 177 } 178 179 private Collection doSearchTypes() { 180 181 if (ResourcesPlugin.getWorkspace() == null) 182 return null; 183 184 final ArrayList typesFound= new ArrayList (fSizeHint); 185 186 class RequestorAbort extends RuntimeException { } 187 188 ITypeNameRequestor requestor= new TypeInfoRequestor(typesFound) { 189 protected boolean inScope(char[] packageName) { 190 if (fRestart) 191 throw new RequestorAbort(); 192 return super.inScope(packageName); 193 } 194 }; 195 196 try { 197 if (! search(requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, null)) 198 return null; 199 } catch (RequestorAbort e) { 200 return null; 202 } 203 return typesFound; 204 } 205 } 206 207 210 private static Object fgLock= new Object (); 211 private volatile static boolean fgIsLocked; 212 private volatile static TypeCacher fgTypeCacherThread; 213 private static TypeInfo[] fgTypeCache; 214 private static int fgSizeHint= INITIAL_SIZE; 215 private volatile static boolean fgTerminated; 216 private volatile static boolean fgAsyncMode; 218 219 private static int fgNumberOfCacheFlushes; 220 private static DelegatedProgressMonitor fDelegatedProgressMonitor= new DelegatedProgressMonitor(); 221 private static TypeCacheDeltaListener fgDeltaListener; 222 223 226 private static Comparator fgTypeNameComparator= new Comparator () { 227 public int compare(Object o1, Object o2) { 228 return ((TypeInfo)o1).getTypeName().compareTo(((TypeInfo)o2).getTypeName()); 229 } 230 }; 231 232 238 public static void getTypes(IJavaSearchScope scope, int kind, IProgressMonitor monitor, Collection typesFound) { 239 240 TypeInfo[] allTypes= getAllTypes(monitor); 241 242 boolean isWorkspaceScope= scope.equals(SearchEngine.createWorkspaceScope()); 243 boolean isBoth= (kind == IJavaSearchConstants.TYPE); 244 boolean isInterface= (kind == IJavaSearchConstants.INTERFACE); 245 246 for (int i= 0; i < allTypes.length; i++) { 247 TypeInfo info= fgTypeCache[i]; 248 if (isWorkspaceScope || info.isEnclosed(scope)) { 249 if (isBoth || (isInterface == info.isInterface())) { 250 typesFound.add(info); 251 } 252 } 253 } 254 } 255 256 private static void setCache(TypeInfo[] cache) { 257 synchronized(fgLock) { 258 fgTypeCache= cache; 259 if (fgTypeCache != null) 260 fgSizeHint= fgTypeCache.length; 261 fgTypeCacherThread= null; 262 fgLock.notifyAll(); 263 } 264 } 265 266 270 public static TypeInfo[] getAllTypes(IProgressMonitor monitor) { 271 if (monitor == null) 272 monitor= new NullProgressMonitor(); 273 monitor.beginTask("", 10); SubProgressMonitor checkingMonitor = new SubProgressMonitor(monitor, 1); 275 SubProgressMonitor searchingMonitor= new SubProgressMonitor(monitor, 9); 276 forceDeltaComplete(checkingMonitor); 277 searchingMonitor.setTaskName(CorextMessages.getString("AllTypesCache.searching")); 279 synchronized(fgLock) { 280 try { 281 if (fgTypeCache == null) { 282 284 if (fgTypeCacherThread == null) { 285 ArrayList searchResult= new ArrayList (fgSizeHint); 287 try { 288 fgIsLocked= true; 289 if (search(new TypeInfoRequestor(searchResult), IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, searchingMonitor)) { 290 TypeInfo[] result= (TypeInfo[]) searchResult.toArray(new TypeInfo[searchResult.size()]); 291 Arrays.sort(result, fgTypeNameComparator); 292 fgTypeCache= result; 293 fgSizeHint= result.length; 294 } 295 } finally { 296 fgIsLocked= false; 297 } 298 } else { 299 fDelegatedProgressMonitor.setDelegate(searchingMonitor); 300 try { 302 while (fgTypeCache == null) { 303 fgLock.wait(CANCEL_POLL_INTERVAL); if (searchingMonitor.isCanceled()) 305 throw new OperationCanceledException(); 306 } 307 } catch (InterruptedException e) { 308 JavaPlugin.log(e); 309 } finally { 310 fDelegatedProgressMonitor.setDelegate(null); 311 } 312 } 313 } 314 315 } finally { 316 monitor.done(); 317 } 318 return fgTypeCache; 319 } 320 } 321 322 325 public static boolean isCacheUpToDate(IProgressMonitor pm) { 326 forceDeltaComplete(pm); 327 return fgTypeCache != null; 328 } 329 330 private static void forceDeltaComplete(IProgressMonitor pm) { 331 if (pm == null) 332 pm= new NullProgressMonitor(); 333 334 ICompilationUnit[] primaryWorkingCopies= JavaCore.getWorkingCopies(null); 335 pm.beginTask("", primaryWorkingCopies.length); pm.setTaskName(CorextMessages.getString("AllTypesCache.checking_type_cache")); for (int i= 0; i < primaryWorkingCopies.length; i++) { 338 ICompilationUnit curr= primaryWorkingCopies[i]; 339 try { 340 JavaModelUtil.reconcile(curr); 341 } catch (JavaModelException e) { 342 JavaPlugin.log(e); 343 } 344 pm.worked(1); 345 if (pm.isCanceled()) 346 throw new OperationCanceledException(); 347 } 348 pm.done(); 349 } 350 351 354 public static int getNumberOfAllTypesHint() { 355 return fgSizeHint; 356 } 357 358 359 public static void forceCacheFlush() { 360 if (fgTerminated) 361 return; 362 if (TRACING) { 363 System.out.println("All Types Cache -- cache flushed."); } 365 366 synchronized(fgLock) { 367 fgTypeCache= null; 368 fgNumberOfCacheFlushes++; 369 370 if (fgTypeCacherThread != null) { 371 fgTypeCacherThread.restart(); 373 } else { 374 if (fgAsyncMode) { fgTypeCacherThread= new TypeCacher(fgSizeHint, TIMEOUT); 376 fgTypeCacherThread.start(); 377 } 378 } 379 } 380 } 381 382 383 private static class TypeCacheDeltaListener implements IElementChangedListener { 384 385 388 public void elementChanged(ElementChangedEvent event) { 389 if (fgTerminated) 390 return; 391 boolean needsFlushing= processDelta(event.getDelta()); 392 if (needsFlushing) { 393 forceCacheFlush(); 394 } 395 } 396 397 400 private boolean processDelta(IJavaElementDelta delta) { 401 IJavaElement elem= delta.getElement(); 402 boolean isAddedOrRemoved= (delta.getKind() != IJavaElementDelta.CHANGED) 403 || (delta.getFlags() & (IJavaElementDelta.F_ADDED_TO_CLASSPATH | IJavaElementDelta.F_REMOVED_FROM_CLASSPATH)) != 0; 404 405 switch (elem.getElementType()) { 406 case IJavaElement.JAVA_MODEL: 407 case IJavaElement.JAVA_PROJECT: 408 case IJavaElement.PACKAGE_FRAGMENT_ROOT: 409 case IJavaElement.PACKAGE_FRAGMENT: 410 case IJavaElement.CLASS_FILE: 411 case IJavaElement.TYPE: if (isAddedOrRemoved) { 413 return true; 414 } 415 return processChildrenDelta(delta); 416 case IJavaElement.COMPILATION_UNIT: if (!JavaModelUtil.isPrimary((ICompilationUnit) elem)) { 418 return false; 419 } 420 421 if (isAddedOrRemoved || isPossibleStructuralChange(delta.getFlags())) { 422 return true; 423 } 424 return processChildrenDelta(delta); 425 default: 426 return false; 428 } 429 } 430 431 private boolean isPossibleStructuralChange(int flags) { 432 return (flags & (IJavaElementDelta.F_CONTENT | IJavaElementDelta.F_FINE_GRAINED)) == IJavaElementDelta.F_CONTENT; 433 } 434 435 private boolean processChildrenDelta(IJavaElementDelta delta) { 436 IJavaElementDelta[] children= delta.getAffectedChildren(); 437 for (int i= 0; i < children.length; i++) { 438 if (processDelta(children[i])) { 439 return true; 440 } 441 } 442 return false; 443 } 444 } 445 446 447 451 public static int getNumberOfCacheFlushes() { 452 return fgNumberOfCacheFlushes; 453 } 454 455 458 public static TypeInfo[] getTypesForName(String simpleTypeName, IJavaSearchScope searchScope, IProgressMonitor monitor) { 459 Collection result= new ArrayList (); 460 Set namesFound= new HashSet (); 461 TypeInfo[] allTypes= AllTypesCache.getAllTypes(monitor); TypeInfo key= new UnresolvableTypeInfo("", simpleTypeName, null, true, null); int index= Arrays.binarySearch(allTypes, key, fgTypeNameComparator); 464 if (index >= 0 && index < allTypes.length) { 465 for (int i= index - 1; i>= 0; i--) { 466 TypeInfo curr= allTypes[i]; 467 if (simpleTypeName.equals(curr.getTypeName())) { 468 if (!namesFound.contains(curr.getFullyQualifiedName()) && curr.isEnclosed(searchScope)) { 469 result.add(curr); 470 namesFound.add(curr.getFullyQualifiedName()); 471 } 472 } else { 473 break; 474 } 475 } 476 477 for (int i= index; i < allTypes.length; i++) { 478 TypeInfo curr= allTypes[i]; 479 if (simpleTypeName.equals(curr.getTypeName())) { 480 if (!namesFound.contains(curr.getFullyQualifiedName()) && curr.isEnclosed(searchScope)) { 481 result.add(curr); 482 namesFound.add(curr.getFullyQualifiedName()); 483 } 484 } else { 485 break; 486 } 487 } 488 } 489 return (TypeInfo[]) result.toArray(new TypeInfo[result.size()]); 490 } 491 492 495 public static boolean isIndexUpToDate() { 496 class TypeFoundException extends RuntimeException { 497 } 498 ITypeNameRequestor requestor= new ITypeNameRequestor() { 499 public void acceptClass(char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path) { 500 throw new TypeFoundException(); 501 } 502 public void acceptInterface(char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path) { 503 throw new TypeFoundException(); 504 } 505 }; 506 try { 507 if (! search(requestor, IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH, null)) 508 return false; 509 } catch (OperationCanceledException e) { 510 return false; 511 } catch (TypeFoundException e) { 512 } 513 return true; 514 } 515 516 520 static boolean search(ITypeNameRequestor requestor, int waitingPolicy, IProgressMonitor monitor) { 521 long start= System.currentTimeMillis(); 522 try { 523 if (monitor == null) 524 monitor= fDelegatedProgressMonitor; 525 526 new SearchEngine().searchAllTypeNames( 527 null, 528 null, 529 SearchPattern.R_PATTERN_MATCH, IJavaSearchConstants.TYPE, 531 SearchEngine.createWorkspaceScope(), 532 requestor, 533 waitingPolicy, 534 monitor); 535 } catch (JavaModelException e) { 536 JavaPlugin.log(e); 537 if (TRACING) { 538 System.out.println("All Types Cache -- building cache failed"); } 540 return false; 541 } 542 if (TRACING) { 543 System.out.println("All Types Cache"); System.out.println("\t cache populated in thread: " + Thread.currentThread().getName()); System.out.println("\t time needed to perform search: " + (System.currentTimeMillis() - start) + "ms"); } 547 return true; 548 } 549 550 553 public static void initialize() { 554 555 fgDeltaListener= new TypeCacheDeltaListener(); 556 JavaCore.addElementChangedListener(fgDeltaListener); 557 558 Display d= Display.getDefault(); 559 if (d != null) 560 d.asyncExec( 561 new Runnable () { 562 public void run() { 563 startBackgroundMode(); 564 } 565 } 566 ); 567 } 568 569 private static void startBackgroundMode() { 570 571 long start= System.currentTimeMillis(); 572 573 575 if (fgIsLocked) { 576 fgAsyncMode= true; 577 if (TRACING) { 578 System.out.println("All Types Cache -- Background Mode started. Time needed " + (System.currentTimeMillis() - start) + "ms."); } 580 return; 581 } 582 583 synchronized(fgLock) { 584 if (fgTypeCacherThread != null) { 585 if (fgTerminated) { 587 if (fgTypeCacherThread != null) 588 fgTypeCacherThread.abort(); 589 } else { 590 } 593 } else { 594 if (fgTerminated) { 595 } else { 597 fgAsyncMode= true; 598 if (fgTypeCache != null) { 599 } else { 601 fgTypeCacherThread= new TypeCacher(fgSizeHint, INITIAL_DELAY); 602 fgTypeCacherThread.start(); 603 } 604 } 605 } 606 } 607 if (TRACING) { 608 System.out.println("All Types Cache -- Background Mode started. Time needed: " + (System.currentTimeMillis() - start) + "ms"); } 610 } 611 612 615 public static void terminate() { 616 617 if (fgDeltaListener != null) 618 JavaCore.removeElementChangedListener(fgDeltaListener); 619 fgDeltaListener= null; 620 621 synchronized(fgLock) { 622 fgTerminated= true; 623 fgAsyncMode= false; 624 625 if (fDelegatedProgressMonitor != null && !fDelegatedProgressMonitor.isCanceled()) 626 fDelegatedProgressMonitor.setCanceled(true); 627 628 if (fgTypeCacherThread != null) { 629 fgTypeCacherThread.abort(); 630 try { 631 fgTypeCacherThread.join(1000); 632 } catch (InterruptedException e) { 633 JavaPlugin.log(e); 634 } 635 fgTypeCacherThread= null; 636 } 637 } 638 } 639 } 640 | Popular Tags |