1 19 20 package org.netbeans.modules.javacore; 21 22 import java.io.BufferedInputStream ; 23 import java.io.BufferedOutputStream ; 24 import java.io.File ; 25 import java.io.FileInputStream ; 26 import java.io.FileOutputStream ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.io.OutputStream ; 30 import java.io.StringReader ; 31 import java.util.AbstractSet ; 32 import java.util.ArrayList ; 33 import java.util.Arrays ; 34 import java.util.Collection ; 35 import java.util.Collections ; 36 import java.util.Comparator ; 37 import java.util.ConcurrentModificationException ; 38 import java.util.HashMap ; 39 import java.util.HashSet ; 40 import java.util.Iterator ; 41 import java.util.List ; 42 import java.util.Map ; 43 import java.util.NoSuchElementException ; 44 import java.util.Set ; 45 import java.util.SortedMap ; 46 import java.util.TreeMap ; 47 import org.netbeans.api.java.classpath.ClassPath; 48 import org.netbeans.api.java.queries.SourceLevelQuery; 49 import org.netbeans.api.mdr.MDRepository; 50 import org.netbeans.jmi.javamodel.JavaClass; 51 import org.netbeans.jmi.javamodel.JavaModelPackage; 52 import org.netbeans.jmi.javamodel.Resource; 53 import org.netbeans.jmi.javamodel.ResourceClass; 54 import org.netbeans.lib.java.parser.Factory; 55 import org.netbeans.lib.java.parser.JScanner; 56 import org.netbeans.lib.java.parser.ParserTokens; 57 import org.netbeans.mdr.NBMDRepositoryImpl; 58 import org.netbeans.mdr.handlers.BaseObjectHandler; 59 import org.netbeans.mdr.persistence.MOFID; 60 import org.netbeans.mdr.util.IOUtils; 61 import org.netbeans.modules.javacore.ClassIndexStorage.QueryItem; 62 import org.netbeans.modules.javacore.internalapi.JavaMetamodel; 63 import org.netbeans.modules.javacore.jmiimpl.javamodel.JavaClassImpl; 64 import org.netbeans.spi.java.classpath.support.ClassPathSupport; 65 import org.openide.ErrorManager; 66 import org.openide.filesystems.FileObject; 67 import org.openide.filesystems.FileStateInvalidException; 68 import org.openide.filesystems.JarFileSystem; 69 70 74 public class ClassIndex { 75 private static final boolean DEBUG = false; 76 77 private static final Map codebaseIndexes = Collections.synchronizedMap(new HashMap ()); 78 private static boolean shutdownListenerRegistered = false; 79 private static final ShutdownL shutdownListener = new ShutdownL(); 80 81 private final ClassIndexStorage storage; 82 private final String storageId; 83 private final NBMDRepositoryImpl rep; 84 85 private long lastSaved; 86 87 private HashMap changeLogSN; 88 private HashMap changeLogFQN; 89 private HashMap changeLogI; 90 91 92 private ClassIndex(String file, String storageId) { 93 this.storageId = storageId; 94 rep = (NBMDRepositoryImpl) JavaMetamodel.getDefaultRepository(); 95 storage = new CISImpl(file); 96 97 if (!shutdownListenerRegistered) { 99 synchronized (shutdownListener) { 100 if (!shutdownListenerRegistered) { 101 ((NBMDRepositoryImpl) JavaMetamodel.getDefaultRepository()).addShutdownListener(shutdownListener); 102 shutdownListenerRegistered = true; 103 } 104 } 105 } 106 } 107 108 static void commit() { 109 for (Iterator it = codebaseIndexes.values().iterator(); it.hasNext();) { 110 ((ClassIndex) it.next()).commitChanges(); 111 } 112 } 113 114 static void rollback() { 115 for (Iterator it = codebaseIndexes.values().iterator(); it.hasNext();) { 116 ((ClassIndex) it.next()).rollbackChanges(); 117 } 118 } 119 120 private void commitChanges() { 121 changeLogSN = null; 122 changeLogFQN = null; 123 changeLogI = null; 124 } 125 126 private void rollbackChanges() { 127 if (changeLogSN != null) { 128 for (Iterator it = changeLogSN.entrySet().iterator(); it.hasNext();) { 129 Map.Entry entry = (Map.Entry ) it.next(); 130 it.remove(); 131 long mofId = ((Long ) entry.getKey()).longValue(); 132 if (entry.getValue() == null) { 133 JavaClass cls = (JavaClass) rep.getByMofId(makeMofId(mofId)); 134 if (cls != null) { 135 addClass(cls, cls.getName(), cls.getSimpleName()); 136 } 137 } else { 138 removeFromIndex(true, (String ) entry.getValue(), mofId); 139 } 142 } 143 } 144 145 if (changeLogFQN != null) { 146 for (Iterator it = changeLogFQN.entrySet().iterator(); it.hasNext();) { 147 Map.Entry entry = (Map.Entry ) it.next(); 148 it.remove(); 149 long mofId = ((Long ) entry.getKey()).longValue(); 150 JavaClass cls = (JavaClass) rep.getByMofId(makeMofId(mofId)); 151 if (entry.getValue() != null) { 152 removeFromIndex(false, (String ) entry.getValue(), mofId); 153 } 154 if (cls != null) { 155 addClass(cls, cls.getName(), cls.getSimpleName()); 156 } 157 } 158 } 159 160 if (changeLogI != null) { 161 for (Iterator it = changeLogI.entrySet().iterator(); it.hasNext();) { 162 Map.Entry entry = (Map.Entry ) it.next(); 163 it.remove(); 164 storage.setIdentifiers(((Long ) entry.getKey()).longValue(), (int[]) entry.getValue()); 165 } 166 } 167 } 168 169 public static ClassIndex getIndex(JavaModelPackage mofPackage) { 170 return (ClassIndex)codebaseIndexes.get(mofPackage); 171 } 172 173 private static void saveAllIndexes() { 174 MDRepository rep = JavaMetamodel.getDefaultRepository(); 175 176 rep.beginTrans(false); 177 try { 178 synchronized (codebaseIndexes) { 179 Iterator indexIt = codebaseIndexes.values().iterator(); 180 181 while (indexIt.hasNext()) { 182 ClassIndex index = (ClassIndex) indexIt.next(); 183 index.storage.unmount(); 184 } 185 } 186 } finally { 187 rep.endTrans(); 188 } 189 } 190 191 static void removeIndex(JavaModelPackage mofPackage) { 193 ClassIndex index = (ClassIndex) codebaseIndexes.remove(mofPackage); 194 index.storage.unmount(); 195 } 196 197 static ClassIndex addIndex(JavaModelPackage mofPackage, String filename) { 199 ClassIndex index = new ClassIndex(filename, ((BaseObjectHandler) mofPackage)._getDelegate().getMofId().getStorageID()); 200 codebaseIndexes.put(mofPackage, index); 201 return index; 202 } 203 204 static boolean loadIndex(String filename, JavaModelPackage mofPackage) { 206 ClassIndex index = addIndex(mofPackage, filename); 207 return index.storage.mount(); 208 } 209 210 public void renameClass(JavaClass jcls, String newName) { 211 long mofId = getMofId(jcls); 212 String name = jcls.getName(); 213 String simpleName = jcls.getSimpleName(); 214 String newSimpleName = JavaClassImpl.getSimpleName(newName); 215 216 if (JMManager.INCONSISTENCY_DEBUG) System.err.println("ClassIndex: Renaming class: " + name + " to: " + newName + " MOFID: " + jcls.refMofId()); 217 219 removeFromIndex(false, name, mofId); 220 221 Long objMofId = new Long (mofId); 222 logFQNChange(objMofId, newName); 223 if (!simpleName.equals(newSimpleName)) { 224 removeFromIndex(true, simpleName, mofId); 225 logSNChange(objMofId, newSimpleName); 226 } 227 addClass(jcls, newName, newSimpleName); 228 } 229 230 private static HashMap logChange(HashMap map, Long mofId, Object value) { 231 if (map == null) { 232 map = new HashMap (); 233 } 234 map.put(mofId, value); 235 return map; 236 } 237 238 private void logFQNChange(Long mofId, String name) { 239 changeLogFQN = logChange(changeLogFQN, mofId, name); 240 } 241 242 private void logSNChange(Long mofId, String name) { 243 changeLogSN = logChange(changeLogSN, mofId, name); 244 } 245 246 public void addClass(JavaClass jcls,String fqn,String simpleName) { 247 if (JMManager.INCONSISTENCY_DEBUG) System.err.println("ClassIndex: Adding class " + fqn + " MOFID: " + jcls.refMofId()); 248 long mofId = getMofId(jcls); 249 250 addToIndex(true, simpleName, mofId); 251 addToIndex(false, fqn, mofId); 252 } 253 254 public long getTimestamp() { 255 return lastSaved; 256 } 257 258 public void setTimestamp() { 259 lastSaved = System.currentTimeMillis(); 260 } 261 262 public Set getClassesByFqn(String fqn) { 264 Set result = new HashSet (); 265 long[] classes = storage.getIDsForName(fqn, false); 266 if (classes != null) { 267 JavaClass cls = null; 268 int j = 0; 269 for (int i = 0; i < classes.length; i++) { 270 JavaClass temp = (JavaClass) rep.getByMofId(makeMofId(classes[i])); 271 if (temp == null) { 272 logFQNChange(new Long (classes[i]), null); 273 } else { 274 classes[j] = classes[i]; 275 j++; 276 result.add(temp); 277 } 278 } 279 if (j == 0) { 280 storage.setIDsForName(fqn, false, null); 281 } else if (j < classes.length) { 282 long[] newValue = new long[j]; 283 System.arraycopy(classes, 0, newValue, 0, j); 284 storage.setIDsForName(fqn, false, newValue); 285 } 286 } 287 return result; 288 } 289 290 public JavaClass getClassByFqn(String fqn) { 292 JavaClass cls = null; 293 JavaClass oldCls; 294 do { 295 oldCls = cls; 296 cls = tryToGetClassByFqn(fqn); 297 } while (cls != null && !cls.isValid() && oldCls != cls); 298 if (cls != null && oldCls == cls) { 299 try { 300 JMManager.getLog().notify(ErrorManager.INFORMATIONAL, new RuntimeException ("Class was not cleaned from index: " + cls.getName())); } catch (javax.jmi.reflect.InvalidObjectException e) { 302 JMManager.getLog().notify(ErrorManager.INFORMATIONAL, e); 303 } 304 cls = null; 305 } 306 return cls; 307 } 308 309 private JavaClass tryToGetClassByFqn(String fqn) { 310 long[] classes = storage.getIDsForName(fqn, false); 311 if (classes != null) { 312 JavaClass result = null; 313 JavaClass sureResult = null; 314 int j = 0; 315 for (int i = 0; i < classes.length; i++) { 316 JavaClass temp = (JavaClass) rep.getByMofId(makeMofId(classes[i])); 317 if (temp == null) { 318 logFQNChange(new Long (classes[i]), null); 319 } else { 320 classes[j] = classes[i]; 321 j++; 322 result = temp; 323 } 333 } 334 if (j == 0) { 335 storage.setIDsForName(fqn, false, null); 336 } else if (j < classes.length) { 337 long[] newValue = new long[j]; 338 System.arraycopy(classes, 0, newValue, 0, j); 339 storage.setIDsForName(fqn, false, newValue); 340 } 341 return sureResult == null ? result : sureResult; 342 } 343 return null; 344 } 345 346 public LazyImmutableList getClassesByFQNPrefix(String fqnPrefix) { 348 return new LazyImmutableList(new ClassesByFQNPrefixIterator(storage.getFirstForNamePrefix(fqnPrefix, false))); 349 } 350 351 public LazyImmutableList getClassesByFQNPrefix(String fqnPrefix, boolean caseSensitive) { 352 if (caseSensitive) return getClassesByFQNPrefix(fqnPrefix); 353 354 int dot = fqnPrefix.lastIndexOf('.'); 355 String packagePart = fqnPrefix.substring(0, dot + 1); 356 return new LazyImmutableList(new ClassesByFQNPrefixCIIterator(storage.getFirstForNamePrefix(packagePart, false), fqnPrefix)); 357 } 358 359 367 public LazyImmutableList getClassesBySNPrefix(String snPrefix) { 368 return getClassesBySNPrefix(snPrefix, true); 369 } 370 371 379 public LazyImmutableList getClassesBySNPrefix(String snPrefix, boolean caseSensitive) { 380 ClassIndexStorage.QueryItem query; 381 boolean camelCase; 382 if (snPrefix.length() > 1 && snPrefix.equals(snPrefix.toUpperCase())) { 383 query = storage.getFirstForNamePrefix(snPrefix.substring(0,1), true); 384 camelCase = true; 385 } else { 386 query = storage.getFirstForNamePrefix(snPrefix.toUpperCase(), true); 387 camelCase = false; 388 } 389 return new LazyImmutableList(new ClassesBySNPrefixIterator(query, snPrefix, caseSensitive, camelCase)); 390 } 391 392 private abstract class ClassesByPrefixIterator extends LazyImmutableList.LazyIterator { 393 private int maxSize = -1; 394 private int currentSize = 0; 395 396 protected ClassIndexStorage.QueryItem currentItem; 397 398 private Object next; 399 private boolean hasNext = true; 400 private Iterator inner = Collections.EMPTY_LIST.iterator(); 401 402 ClassesByPrefixIterator(ClassIndexStorage.QueryItem item) { 403 this.currentItem = item; 404 } 405 406 public final Object next() { 407 if (next == null) { 408 findNext(); 409 } 410 Object result = next; 411 next = null; 412 return result; 413 } 414 415 public final boolean hasNext() { 416 findNext(); 417 return hasNext; 418 } 419 420 protected final int maxEstimatedSize() { 421 if (maxSize == -1) { 422 computeSize(); 423 } 424 return maxSize; 425 } 426 427 private void computeSize() { 428 maxSize = currentSize; 429 ClassIndexStorage.QueryItem item = currentItem; 430 while (item != null) { 431 maxSize += item.getIDs().length; 432 item = item.getNext(); 433 } 434 } 435 436 private void findNext() { 437 if (!hasNext) { 438 throw new NoSuchElementException (); 439 } 440 while (next == null && hasNext == true) { 441 if (inner.hasNext()) { 442 next = inner.next(); 443 } else { 444 while ((currentItem != null) && (!accept(currentItem))) { 445 currentItem = currentItem.getNext(); 446 } 447 if (currentItem != null) { 448 inner = getClassesByPrefix().iterator(); 449 } else { 450 hasNext=false; 451 } 452 } 453 } 454 } 455 456 private Collection getClassesByPrefix() { 457 Collection result = new ArrayList (); 458 459 long[] value = currentItem.getIDs(); 460 currentSize += value.length; 461 462 int j = 0; 463 for (int i = 0; i < value.length; i++) { 464 JavaClass cls = (JavaClass) rep.getByMofId(makeMofId(value[i])); 465 j += evaluateItem(value, i, j, cls, result); 466 } 467 if (j == 0) { 468 currentItem.setIDs(null); 469 } else if (j < value.length) { 470 long[] newValue = new long[j]; 471 System.arraycopy(value, 0, newValue, 0, j); 472 currentItem.setIDs(newValue); 473 } 474 475 currentItem = currentItem.getNext(); 476 return result; 477 } 478 479 protected boolean accept(ClassIndexStorage.QueryItem item) { 480 return true; 481 } 482 483 protected abstract int evaluateItem(long[] value, int i, int j, JavaClass cls, Collection result); 484 } 485 486 private class ClassesBySNPrefixIterator extends ClassesByPrefixIterator { 487 private final String prefix; 488 private final boolean matchName; 489 private final boolean camelCase; 490 491 ClassesBySNPrefixIterator(ClassIndexStorage.QueryItem item, String prefix, boolean caseSensitive, boolean camelCase) { 492 super(item); 493 this.prefix = prefix; 494 this.matchName = caseSensitive && prefix.length() > 0; 495 this.camelCase = camelCase; 496 } 497 498 protected boolean accept(ClassIndexStorage.QueryItem item) { 499 return !camelCase || item.getName().startsWith(prefix) || matchIndexEntry(item.getName()); 500 } 501 502 private boolean matchIndexEntry(String indexEntryName) { 503 int index = -1; 504 for (int i = 0; i < prefix.length(); i++) { 505 index = indexEntryName.indexOf(prefix.charAt(i), index + 1); 506 if (index < 0) { 507 return false; 508 } 509 } 510 return true; 511 } 512 513 private boolean matchName(String simpleName) { 514 if (!matchName && simpleName.toUpperCase().startsWith(prefix)) return true; 515 516 int sni, pi; 517 for (pi = 0, sni = 0; sni < simpleName.length() && pi < prefix.length(); sni++) { 518 char ch = simpleName.charAt(sni); 519 if (Character.isUpperCase(ch)) { 520 if (ch != prefix.charAt(pi++)) { 521 return false; 522 } 523 } 524 } 525 return pi == prefix.length(); 526 } 527 528 protected int evaluateItem(long[] value, int i, int j, JavaClass cls, Collection result) { 529 if (cls == null) { 530 logSNChange(new Long (value[i]), null); 531 return 0; 532 } else { 533 value[j] = value[i]; 534 if ((!matchName && !camelCase) || (matchName && cls.getSimpleName().startsWith(prefix)) || (camelCase && matchName(cls.getSimpleName()))) { 535 if (((JavaClassImpl) cls).hasComposite()) { 536 result.add(cls); 537 } else { 538 JMManager.getTransactionMutex().invalidateAtCommit(cls); 539 } 540 } 541 return 1; 542 } 543 } 544 } 545 546 private class ClassesByFQNPrefixIterator extends ClassesByPrefixIterator { 547 ClassesByFQNPrefixIterator(ClassIndexStorage.QueryItem item) { 548 super(item); 549 } 550 551 protected int evaluateItem(long[] value, int i, int j, JavaClass cls, Collection result) { 552 if (cls == null) { 553 logFQNChange(new Long (value[i]), null); 554 return 0; 555 } else { 556 if (((JavaClassImpl) cls).hasComposite()) { 557 result.add(cls); 558 } else { 559 JMManager.getTransactionMutex().invalidateAtCommit(cls); 560 } 561 value[j] = value[i]; 562 return 1; 563 } 564 } 565 } 566 567 private class ClassesByFQNPrefixCIIterator extends ClassesByFQNPrefixIterator { 568 private final String namePrefix; 569 570 ClassesByFQNPrefixCIIterator(ClassIndexStorage.QueryItem item, String namePrefix) { 571 super(item); 572 this.namePrefix = namePrefix.toUpperCase(); 573 } 574 575 protected boolean accept(ClassIndexStorage.QueryItem item) { 576 return (namePrefix.length() == 0) || item.getName().toUpperCase().startsWith(namePrefix); 577 } 578 } 579 580 public boolean doesnotExist(String fqn) { 581 return !storage.existsFQN(fqn); 582 } 583 584 public boolean hasClass(String fqn) { 585 return getClassByFqn(fqn) != null; 586 } 587 588 595 public Collection getClassesBySimpleName(String simpleName) { 596 return getClassesBySimpleName(simpleName, true); 597 } 598 599 607 public Collection getClassesBySimpleName(String simpleName, boolean caseSensitive) { 608 String simpleUpper = simpleName.toUpperCase(); 609 long[] value = (long[]) storage.getIDsForName(simpleUpper, true); 610 611 List res = new ArrayList (); 612 613 if (value != null) { 614 int j = 0; 615 for (int i = 0; i < value.length; i++) { 616 JavaClass cls = (JavaClass) rep.getByMofId(makeMofId(value[i])); 617 if (cls == null) { 618 logSNChange(new Long (value[i]), null); 619 } else { 620 value[j] = value[i]; 621 j++; 622 if (!caseSensitive || simpleName.equals(cls.getSimpleName())) { 623 res.add(cls); 624 } 625 } 626 } 627 if (j == 0) { 628 storage.setIDsForName(simpleUpper, true, null); 629 } else if (j < value.length) { 630 long[] newValue = new long[j]; 631 System.arraycopy(value, 0, newValue, 0, j); 632 storage.setIDsForName(simpleUpper, true, newValue); 633 } 634 } 635 return res; 636 } 637 638 public static boolean hasClass(String fqn,ClassPath classPath) { 639 FileObject[] roots = classPath.getRoots(); 640 for (int i = 0; i < roots.length; i++) { 642 JavaModelPackage mofPackage = JavaMetamodel.getManager().getJavaExtent(roots[i]); 643 if (mofPackage!=null && ClassIndex.getIndex(mofPackage).hasClass(fqn)) 649 return true; 650 } 651 return false; 652 } 653 654 public static JavaClass getClassByFqn(String fqn, ClassPath classPath) { 655 FileObject[] roots = classPath.getRoots(); 656 for (int i = 0; i < roots.length; i++) { 657 JavaModelPackage mofPackage = org.netbeans.modules.javacore.internalapi.JavaMetamodel.getManager().getJavaExtent(roots[i]); 658 if (mofPackage != null) { 659 ClassIndex index = ClassIndex.getIndex(mofPackage); 660 if (index != null) { 661 JavaClass cls = index.getClassByFqn(fqn); 662 if (cls != null) { 663 return cls; 664 } 665 } 666 } 667 } 668 return null; 669 } 670 671 public void setIdentifiers(Resource rsc,int identifiers[]) { 672 Arrays.sort(identifiers); 673 storage.setIdentifiers(getMofId(rsc), identifiers); 674 } 675 676 private long getMofId(Object obj) { 677 return ((BaseObjectHandler) obj)._getMofId().getSerialNumber(); 678 } 679 680 private MOFID makeMofId(long mofId) { 681 return new MOFID(mofId, storageId); 682 } 683 684 public void removeResource(Resource rsc) { 685 long mofId = getMofId(rsc); 686 int[] o = storage.removeIdentifiers(mofId); 687 changeLogI = logChange(changeLogI, new Long (mofId), o); 688 } 689 690 void updateIdentifiersInResource(Resource rsc,String sourceText) { 691 FileObject file=JavaMetamodel.getManager().getFileObject(rsc); 692 String sourceLevel=SourceLevelQuery.getSourceLevel(file); 693 JScanner scanner=Factory.getDefault().getScanner(new StringReader (sourceText),sourceLevel); 694 int token; 695 int identifiers[] = storage.getIdentifiers(getMofId(rsc)); 696 List newIds=new ArrayList (10); 697 int newIdSize; 698 699 try { 700 while((token=scanner.yylex())!=0) { 701 if (token==ParserTokens.IDENTIFIER) { 702 String text=scanner.yytext(); 703 int hash=text.hashCode(); 704 705 if (Arrays.binarySearch(identifiers,hash)<0) { 706 newIds.add(text); 707 } 708 } 709 } 710 } 711 catch (IOException ex) { 712 ErrorManager.getDefault().notify(ex); 713 } 714 newIdSize=newIds.size(); 715 if (newIdSize>0) { 716 int ids[]=new int[identifiers.length+newIdSize]; 717 String newIdArr[]=(String [])newIds.toArray(new String [newIdSize]); 718 int i; 719 720 for (i=0;i<newIdSize;i++) { 721 ids[i]=newIdArr[i].hashCode(); 722 } 723 System.arraycopy(identifiers, 0, ids, newIdSize, identifiers.length); 724 setIdentifiers(rsc,ids); 725 } 726 } 727 728 public Collection findResourcesForIdent(String identifier) { 730 long[] ids = storage.getIDsForIdentifier(identifier.hashCode()); 731 Collection res = new ArrayList (ids.length); 732 for (int i = 0; i < ids.length; i++) { 733 Object obj = rep.getByMofId(makeMofId(ids[i])); 734 if (obj == null) { 735 storage.removeIdentifiers(ids[i]); 736 } else { 737 res.add(obj); 738 } 739 } 740 return res; 741 } 742 743 public static Resource[] findResourcesForIdentifier(String identifier,boolean includeLibraries) { 744 FileObject[] roots; 745 List cp = ((JMManager) JavaMetamodel.getManager()).getTransactionMutex().getSearchScope(); 746 if (cp == null) { 747 roots = JavaMetamodel.getManager().getClassPath().getRoots(); 748 } else { 749 if (cp.size() == 1) { 750 roots = ((ClassPath) cp.get(0)).getRoots(); 751 } else { 752 roots = ClassPathSupport.createProxyClassPath((ClassPath[]) cp.toArray(new ClassPath[cp.size()])).getRoots(); 753 } 754 } 755 Collection resources=new ArrayList (); 757 HashSet visitedRoots = new HashSet ((int) (roots.length / .7)); 758 org.netbeans.modules.javacore.internalapi.JavaMetamodel manager=org.netbeans.modules.javacore.internalapi.JavaMetamodel.getManager(); 759 boolean isJavaDocTag = identifier.startsWith("@"); 761 for (int i = 0; i < roots.length; i++) { 762 FileObject root = roots[i]; 763 if (!visitedRoots.add(root)) continue; 764 try { 765 if (includeLibraries || !(root.getFileSystem() instanceof JarFileSystem)) { 766 JavaModelPackage mofPackage = manager.getJavaExtent(root); 767 769 if (mofPackage != null) { 770 if (isJavaDocTag) { 771 ResourceClass resourceClass = mofPackage.getResource(); 772 resources.addAll(resourceClass.refAllOfClass()); 773 } 774 else { 775 resources.addAll(ClassIndex.getIndex(mofPackage).findResourcesForIdent(identifier)); 776 } 777 } 778 } 779 } catch (FileStateInvalidException ex) { 780 ErrorManager.getDefault().notify(ex); 781 } 782 } 783 return (Resource[])resources.toArray(new Resource[resources.size()]); 784 } 785 786 public static Resource[] findResourcesForIdentifier(String identifier) { 787 return findResourcesForIdentifier(identifier,false); 788 } 789 790 public static void updateIdentifiers(Resource rsc,String sourceText) { 791 JavaModelPackage mofPackage=(JavaModelPackage)rsc.refOutermostPackage(); 792 ClassIndex.getIndex(mofPackage).updateIdentifiersInResource(rsc, sourceText); 793 } 794 795 public static boolean containsIdentifier(Resource rsc, int identifier) { 796 JavaModelPackage mofPackage=(JavaModelPackage)rsc.refOutermostPackage(); 797 ClassIndex index = ClassIndex.getIndex(mofPackage); 798 int[] idents = (int[]) index.storage.getIdentifiers(index.getMofId(rsc)); 799 800 if (idents==null) { 801 JMManager.getLog().log("ids is null for "+rsc.getName()); 802 return false; 803 } 804 return Arrays.binarySearch(idents, identifier) >= 0; 805 } 806 807 private void addToIndex(boolean isSimpleName, String name, long value) { 808 if (isSimpleName) { 809 name = name.toUpperCase(); 810 } 811 long[] temp = storage.getIDsForName(name, isSimpleName); 812 long[] newValue; 813 int len; 814 if (temp == null) { 815 len = 0; 816 newValue = new long[len + 1]; 817 } else { 818 long[] oldValue = temp; 819 len = oldValue.length; 820 newValue = new long[len + 1]; 821 for (int i = 0; i < len; i++) { 822 if (oldValue[i] == value) { 823 newValue = oldValue; 824 break; 825 } 826 newValue[i] = oldValue[i]; 827 } 828 } 829 if (newValue != temp) { 830 newValue[len] = value; 831 storage.setIDsForName(name, isSimpleName, newValue); 832 } 833 } 834 835 private void removeFromIndex(boolean isSimpleName, String name, long value) { 836 if (isSimpleName) { 837 name = name.toUpperCase(); 838 } 839 Object temp = storage.getIDsForName(name, isSimpleName); 840 if (temp != null) { 841 long[] oldValue = (long[]) temp; 842 int len = oldValue.length; 843 long[] newValue = new long[len - 1]; 844 int i = 0, j = 0; 845 for (; i < len && j < len - 1; i++) { 846 if (oldValue[i] != value) { 847 newValue[j++] = oldValue[i]; 848 } 849 } 850 851 if (i < len && oldValue[i] != value) { 852 if (j < len - 1) { 853 newValue[j] = oldValue[i]; 854 } else { 855 newValue = oldValue; 856 } 857 } 858 859 if (oldValue != newValue) { 860 if (newValue.length == 0) { 861 newValue = null; 862 } 863 storage.setIDsForName(name, isSimpleName, newValue); 864 } 865 } 866 } 867 868 870 private static class ShutdownL implements NBMDRepositoryImpl.ShutdownListener { 871 872 public void shutdown() { 873 saveAllIndexes(); 875 } 876 877 public void stepFinished() { 878 } 879 } 880 881 private class CISImpl implements ClassIndexStorage { 882 private static final int VERSION = 2; 883 private static final String INDEX_SUFFIX=".cdx"; 885 private final SortedMap fqnMap; 886 private final SortedMap simpleMap; 887 private Map identifiersMap; 888 private final String filename; 889 890 private transient boolean isDirty; 891 892 CISImpl(String filename) { 893 this.filename = filename; 894 fqnMap = new TreeMap (); 895 simpleMap = new TreeMap (); 896 identifiersMap = new HashMap (); 897 isDirty = true; 898 } 899 900 private QueryItem createNextCIIImpl(Iterator it, int length) throws ConcurrentModificationException { 901 while (it.hasNext()) { 902 Map.Entry entry = (Map.Entry ) it.next(); 903 if (((String ) entry.getKey()).lastIndexOf('.') < length) { 904 return new CIIImpl(it, entry, length); 905 } 906 } 907 return null; 908 } 909 910 public QueryItem createNextCIISNImpl(Iterator it) throws ConcurrentModificationException { 911 if (it.hasNext()) { 912 Map.Entry entry = (Map.Entry ) it.next(); 913 return new CIISNImpl(it, entry); 914 } 915 return null; 916 } 917 918 private abstract class AbstractCIIImpl implements QueryItem { 919 private Iterator it; 920 private final Map.Entry entry; 921 private QueryItem next ; 922 923 AbstractCIIImpl(Iterator it, Map.Entry entry) { 924 this.it = it; 925 this.entry = entry; 926 } 927 928 public final void setIDs(long[] ids) throws ConcurrentModificationException { 929 isDirty=true; 930 entry.setValue(ids); 931 if (ids == null) { 932 if (it == null) { 933 QueryItem item = getNext(); 934 while (item != null) item = item.getNext(); 935 remove(); 936 } else { 937 it.remove(); 938 } 939 } 940 } 941 942 public final String getName() { 943 return (String ) entry.getKey(); 944 } 945 946 public final long[] getIDs() { 947 return (long[]) entry.getValue(); 948 } 949 950 public final QueryItem getNext() throws ConcurrentModificationException { 951 if (it != null) { 952 next = createNext(it); 953 it = null; 954 } 955 return next; 956 } 957 958 protected abstract QueryItem createNext(Iterator it) throws ConcurrentModificationException ; 959 protected abstract void remove(); 960 } 961 962 private class CIIImpl extends AbstractCIIImpl { 963 private final int length; 964 965 CIIImpl(Iterator it, Map.Entry entry, int length) { 966 super(it, entry); 967 this.length = length; 968 } 969 970 protected QueryItem createNext(Iterator it) throws ConcurrentModificationException { 971 return createNextCIIImpl(it, length); 972 } 973 974 protected void remove() { 975 setIDsForName(getName(), false, null); 976 } 977 } 978 979 private class CIISNImpl extends AbstractCIIImpl { 980 CIISNImpl(Iterator it, Map.Entry entry) { 981 super(it, entry); 982 } 983 984 protected QueryItem createNext(Iterator it) throws ConcurrentModificationException { 985 return createNextCIISNImpl(it); 986 } 987 988 protected void remove() { 989 setIDsForName(getName(), true, null); 990 } 991 } 992 993 public QueryItem getFirstForNamePrefix(String prefix, boolean isSimpleName) { 994 SortedMap map; 995 if (prefix == null || prefix.length() == 0) { 996 map = isSimpleName ? simpleMap : fqnMap; 997 } else { 998 map = (isSimpleName ? simpleMap : fqnMap).subMap(prefix, prefix + '\uffff'); 999 } 1000 if (isSimpleName) { 1001 return createNextCIISNImpl(map.entrySet().iterator()); 1002 } else { 1003 int length = prefix.length(); 1004 return createNextCIIImpl(map.entrySet().iterator(), length); 1005 } 1006 } 1007 1008 public boolean existsFQN(String fqn) { 1009 return fqnMap.get(fqn) != null; 1010 } 1011 1012 public void setIdentifiers(long resourceId, int[] hashCodes) { 1013 assert hashCodes != null; 1014 isDirty=true; 1015 identifiersMap.put(new Long (resourceId), hashCodes); 1016 } 1017 1018 public boolean mount() { 1019 long t = 0; 1020 try { 1021 if (JMManager.PERF_DEBUG) { 1022 t = System.currentTimeMillis(); 1023 } 1024 1025 File indexFile = new File (filename.concat(INDEX_SUFFIX)); 1026 if (!indexFile.isFile()) { 1027 JMManager.getLog().log(ErrorManager.WARNING, "Index file missing: " + indexFile); 1028 return false; 1029 } 1030 InputStream indexStream = new BufferedInputStream (new FileInputStream (indexFile), 65536); 1031 1032 try { 1033 read(indexStream); 1034 } finally { 1035 indexStream.close(); 1036 } 1037 isDirty=false; 1038 return true; 1039 } catch (Exception ex) { 1040 JMManager.getLog().notify(ErrorManager.INFORMATIONAL, ex); 1041 return false; 1042 } finally { 1043 if (JMManager.PERF_DEBUG) { 1044 System.err.println("loading index " + filename + " took: " + (System.currentTimeMillis() - t) + "ms"); 1045 } 1046 } 1047 } 1048 1049 public void unmount() { 1050 if (!isDirty) return; 1051 1052 if (JMManager.PERF_DEBUG) { 1053 System.err.println("saving index " + filename); 1054 } 1055 1056 rep.beginTrans(false); 1057 try { 1058 FileOutputStream fos=new FileOutputStream (filename.concat(INDEX_SUFFIX)); 1059 BufferedOutputStream indexStream=new BufferedOutputStream (fos, 65536); 1060 try { 1061 write(indexStream); 1062 } finally { 1063 indexStream.close(); 1064 } 1065 isDirty=false; 1066 } catch (Exception ex) { 1067 JMManager.getLog().notify(ErrorManager.INFORMATIONAL, ex); 1068 } finally { 1069 rep.endTrans(); 1070 } 1071 } 1072 1073 private void read(InputStream indexStream) throws IOException { 1074 if (VERSION != IOUtils.readInt(indexStream)) return; 1075 if (!storageId.equals(IOUtils.readString(indexStream))) return; 1076 readMap(indexStream, fqnMap); 1077 readMap(indexStream, simpleMap); 1078 1079 int count = IOUtils.readInt(indexStream); 1080 identifiersMap = new HashMap (count * 4 / 3 + 1); 1081 for (int i = 0; i < count; i++) { 1082 Long key = new Long (IOUtils.readLong(indexStream)); 1083 int count2 = IOUtils.readInt(indexStream); 1084 int[] value = new int[count2]; 1085 for (int j = 0; j < count2; j++) { 1086 value[j] = IOUtils.readInt(indexStream); 1087 } 1088 identifiersMap.put(key, value); 1089 } 1090 lastSaved = IOUtils.readLong(indexStream); 1091 } 1092 1093 private void write(OutputStream indexStream) throws IOException { 1094 if (JMManager.PERF_DEBUG) System.err.println("fqnMap: " + fqnMap.size() + " records; identifiersMap: " + identifiersMap.size() + "records"); 1095 IOUtils.writeInt(indexStream, VERSION); 1096 IOUtils.writeString(indexStream, storageId); 1097 writeMap(indexStream, fqnMap); 1098 writeMap(indexStream, simpleMap); 1099 1100 IOUtils.writeInt(indexStream, identifiersMap.size()); 1101 for (Iterator it = identifiersMap.entrySet().iterator(); it.hasNext();) { 1102 Map.Entry entry = (Map.Entry ) it.next(); 1103 IOUtils.writeLong(indexStream, ((Long ) entry.getKey()).longValue()); 1104 1105 int[] array = (int[]) entry.getValue(); 1106 IOUtils.writeInt(indexStream, array.length); 1107 for (int i = 0; i < array.length; i++) { 1108 IOUtils.writeInt(indexStream, array[i]); 1109 } 1110 } 1111 1112 IOUtils.writeLong(indexStream, System.currentTimeMillis()); 1113 } 1114 1115 private void readMap(InputStream indexStream, Map map) throws IOException { 1116 map.putAll(new StreamBasedSortedMap(indexStream)); 1117 } 1118 1119 private void writeMap(OutputStream indexStream, Map map) throws IOException { 1120 IOUtils.writeInt(indexStream, map.size()); 1121 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 1122 Map.Entry entry = (Map.Entry ) it.next(); 1123 IOUtils.writeString(indexStream, (String ) entry.getKey()); 1124 1125 long[] array = (long[]) entry.getValue(); 1126 IOUtils.writeInt(indexStream, array.length); 1127 for (int i = 0; i < array.length; i++) { 1128 IOUtils.writeLong(indexStream, array[i]); 1129 } 1130 } 1131 } 1132 1133 public long[] getIDsForName(String name, boolean isSimpleName) { 1134 return (long[]) (isSimpleName ? simpleMap : fqnMap).get(name); 1135 } 1136 1137 public long[] getIDsForIdentifier(int hashCode) { 1138 Iterator it = identifiersMap.entrySet().iterator(); 1139 Collection result = new ArrayList (50); 1140 while(it.hasNext()) { 1141 Map.Entry en = (Map.Entry ) it.next(); 1142 int ids[] = (int[]) en.getValue(); 1143 if (ids == null) { 1144 isDirty = true; 1145 it.remove(); 1146 } else if (Arrays.binarySearch(ids, hashCode) >= 0) { 1147 result.add(en.getKey()); 1148 } 1149 } 1150 long[] res = new long[result.size()]; 1151 it = result.iterator(); 1152 for (int i = 0; it.hasNext(); i++) { 1153 res[i] = ((Long ) it.next()).longValue(); 1154 } 1155 return res; 1156 } 1157 1158 public void setIDsForName(String name, boolean isSimpleName, long[] classIDs) { 1159 isDirty=true; 1160 Map map = isSimpleName ? simpleMap : fqnMap; 1161 if (classIDs == null || classIDs.length == 0) { 1162 map.remove(name); 1163 } else { 1164 map.put(name, classIDs); 1165 } 1166 } 1167 1168 public int[] getIdentifiers(long resourceId) { 1169 return (int[]) identifiersMap.get(new Long (resourceId)); 1170 } 1171 1172 public int[] removeIdentifiers(long resourceId) { 1173 isDirty=true; 1174 return (int[]) identifiersMap.remove(new Long (resourceId)); 1175 } 1176 } 1177 1178 1182 private class StreamBasedSortedMap implements SortedMap { 1183 private int size; 1184 InputStream stream; 1185 1186 private StreamBasedSortedMap(InputStream indexStream) throws IOException { 1187 stream = indexStream; 1188 size = IOUtils.readInt(stream); 1189 } 1190 1191 public Comparator comparator() { 1192 return null; 1193 } 1194 1195 public SortedMap subMap(Object fromKey, Object toKey) { 1196 throw new UnsupportedOperationException (); 1197 } 1198 1199 public SortedMap headMap(Object toKey) { 1200 throw new UnsupportedOperationException (); 1201 } 1202 1203 public SortedMap tailMap(Object fromKey) { 1204 throw new UnsupportedOperationException (); 1205 } 1206 1207 public Object firstKey() { 1208 throw new UnsupportedOperationException (); 1209 } 1210 1211 public Object lastKey() { 1212 throw new UnsupportedOperationException (); 1213 } 1214 1215 public int size() { 1216 return size; 1217 } 1218 1219 public boolean isEmpty() { 1220 return size == 0; 1221 } 1222 1223 public boolean containsKey(Object key) { 1224 throw new UnsupportedOperationException (); 1225 } 1226 1227 public boolean containsValue(Object value) { 1228 throw new UnsupportedOperationException (); 1229 } 1230 1231 public Object get(Object key) { 1232 throw new UnsupportedOperationException (); 1233 } 1234 1235 public Object put(Object key, Object value) { 1236 throw new UnsupportedOperationException (); 1237 } 1238 1239 public Object remove(Object key) { 1240 throw new UnsupportedOperationException (); 1241 } 1242 1243 public void putAll(Map t) { 1244 throw new UnsupportedOperationException (); 1245 } 1246 1247 public void clear() { 1248 throw new UnsupportedOperationException (); 1249 } 1250 1251 public Set keySet() { 1252 throw new UnsupportedOperationException (); 1253 } 1254 1255 public Collection values() { 1256 throw new UnsupportedOperationException (); 1257 } 1258 1259 public Set entrySet() { 1260 return new EntrySet(); 1261 } 1262 1263 private class EntrySet extends AbstractSet { 1264 public Iterator iterator() { 1265 return new EntrySetIterator(); 1266 } 1267 1268 public int size() { 1269 return size; 1270 } 1271 1272 private class EntrySetIterator implements Iterator , Map.Entry { 1273 private int index; 1274 private String key; 1275 private long[] value; 1276 1277 public boolean hasNext() { 1278 return index<size; 1279 } 1280 1281 public Object next() { 1282 try { 1283 key = IOUtils.readString(stream); 1284 int count = IOUtils.readInt(stream); 1285 value = new long[count]; 1286 for (int j = 0; j < count; j++) { 1287 value[j] = IOUtils.readLong(stream); 1288 } 1289 index++; 1290 } catch (IOException ex) { 1291 ex.printStackTrace(); 1292 index = size; 1293 } 1294 return this; 1295 } 1296 1297 public void remove() { 1298 throw new UnsupportedOperationException (); 1299 } 1300 1301 public Object getKey() { 1302 return key; 1303 } 1304 1305 public Object getValue() { 1306 return value; 1307 } 1308 1309 public Object setValue(Object value) { 1310 throw new UnsupportedOperationException (); 1311 } 1312 1313 } 1314 } 1315 } 1316} 1317 | Popular Tags |