diff -r de07dd2bcfef java.source/src/org/netbeans/modules/java/source/usages/RepositoryUpdater.java --- a/java.source/src/org/netbeans/modules/java/source/usages/RepositoryUpdater.java Sun Jul 20 19:29:13 2008 -0700 +++ b/java.source/src/org/netbeans/modules/java/source/usages/RepositoryUpdater.java Thu Jul 24 09:51:43 2008 +0200 @@ -59,6 +59,7 @@ import java.io.BufferedReader; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -72,6 +73,8 @@ import java.net.URISyntaxException; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -232,7 +235,7 @@ public class RepositoryUpdater implement public Map> getDependencies () { return new HashMap> (this.deps); } - + private synchronized void open () throws IllegalStateException { if (notInitialized) { try { @@ -1750,7 +1753,7 @@ public class RepositoryUpdater implement final URL rootURL = it.previous(); it.remove(); if (!oldRoots.remove(rootURL) && !RepositoryUpdater.this.scannedRoots.contains(rootURL)) { - long startT = System.currentTimeMillis(); + long startT = System.currentTimeMillis(); updateFolder (rootURL,rootURL, true, false, handle); long time = System.currentTimeMillis() - startT; if (PERF_TEST) { @@ -2164,13 +2167,18 @@ public class RepositoryUpdater implement } final File classCache = Index.getClassFolder(rootFile); final Map> misplacedSource2FQNs = new HashMap>(); - Map > resources = getAllClassFiles(classCache, FileObjects.getRelativePath(rootFile,folderFile),true); + Map > resources = Collections.>emptyMap(); final FileList children = new FileList(folderFile); + children.getJavaFiles(); Set compiledFiles = new HashSet(); - parseFiles(root, classCache, isInitialCompilation, - children.getJavaFiles(), children.getVirtualJavaFiles(), - clean, handle, filter, resources, compiledFiles, null, misplacedSource2FQNs, false); - + if (children.digestChanged()) { + resources = getAllClassFiles(classCache, FileObjects.getRelativePath(rootFile,folderFile),true); + parseFiles(root, classCache, isInitialCompilation, + children.getJavaFiles(), children.getVirtualJavaFiles(), + clean, handle, filter, resources, compiledFiles, null, misplacedSource2FQNs, false); + } else { + ClassIndexManager.getDefault().createUsagesQuery(root, true); + } if (!misplacedSource2FQNs.isEmpty()) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "misplaces classes detected"); @@ -2697,6 +2705,7 @@ public class RepositoryUpdater implement private final List javaFiles = new LinkedList(); private final List virtualJavaFiles = new LinkedList(); private boolean initialized; + private boolean digestChanged = true; public FileList (final File root) { assert root != null; @@ -2717,8 +2726,52 @@ public class RepositoryUpdater implement private synchronized void init () { if (!initialized) { collectFiles (root, javaFiles, virtualJavaFiles); + computeDigest(root, javaFiles); initialized = true; } + } + + private boolean digestChanged() { + return digestChanged; + } + + private void computeDigest(File root, final List javaFiles) { + StringBuilder sb = new StringBuilder(200); + sb.append(SourceLevelQuery.getSourceLevel(FileUtil.toFileObject(root))); + for (File f : javaFiles) { + sb.append(f.getPath()).append(f.lastModified()); + } + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + byte[] b = sb.toString().getBytes(); + byte[] digest = md5.digest(b); + URL rootUrl = root.toURI().toURL(); + Properties prop = loadProperties(rootUrl); + String data = prop.getProperty("digest"); + if (data != null) { + String newDigest = printDigest(digest); + if (data.equals(newDigest) == true) { + digestChanged = false; + } + } + prop.put("digest", printDigest(digest)); + storeProperties(rootUrl, prop); + } catch (IOException e) { + } catch (NoSuchAlgorithmException ex) { + Exceptions.printStackTrace(ex); + } + } + + private String printDigest(byte[] digest) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < digest.length; i++) { + String hex = Integer.toHexString(0xFF & digest[i]); + if (hex.length() == 1) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString(); } private static void collectFiles (final File root, final List javaFiles, diff -r de07dd2bcfef java.source/test/unit/src/org/netbeans/modules/java/source/usages/RepositoryUpdaterTest.java --- a/java.source/test/unit/src/org/netbeans/modules/java/source/usages/RepositoryUpdaterTest.java Sun Jul 20 19:29:13 2008 -0700 +++ b/java.source/test/unit/src/org/netbeans/modules/java/source/usages/RepositoryUpdaterTest.java Thu Jul 24 09:51:43 2008 +0200 @@ -42,16 +42,22 @@ package org.netbeans.modules.java.source package org.netbeans.modules.java.source.usages; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.net.URL; +import java.security.Permission; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import javax.swing.event.ChangeListener; +import junit.framework.Assert; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.classpath.GlobalPathRegistry; import org.netbeans.api.java.source.JavaSource; @@ -86,6 +92,7 @@ public class RepositoryUpdaterTest exten super(testName); } + @Override protected void setUp() throws Exception { SourceUtilsTestUtil.prepareTest(new String[0], new Object[0]); RepositoryUpdater.DELAY = 0; @@ -106,6 +113,7 @@ public class RepositoryUpdaterTest exten super.setUp(); } + @Override protected void tearDown() throws Exception { Logger.getLogger(RepositoryUpdater.class.getName()).removeHandler(handler); if (sourceCP != null) { @@ -304,6 +312,30 @@ public class RepositoryUpdaterTest exten assertTrue(TaskCache.getDefault().getErrors(fileA).toString(), TaskCache.getDefault().isInError(fileA, false)); assertFalse(TaskCache.getDefault().getErrors(fileB).toString(), TaskCache.getDefault().isInError(fileB, false)); } + + public void testFile() throws Exception { + prepareTest("package pack; public class A { B.Inner x; }", "package pack; public class B {public static class Inner {}}"); + assertFalse(TaskCache.getDefault().getErrors(fileA).toString(), TaskCache.getDefault().isInError(fileA, false)); + assertFalse(TaskCache.getDefault().getErrors(fileB).toString(), TaskCache.getDefault().isInError(fileB, false)); + + + waitScanFinished(); + CountingSecurityManager.initialize(".class"); + + File workDir = getWorkDir(); + File src = new File(workDir, "src"); + ClassPath myRoot = ClassPathSupport.createClassPath(new FileObject[] {FileUtil.toFileObject(src)}); + RepositoryUpdater.getDefault(); + Set kunda = GlobalPathRegistry.getDefault().getPaths(ClassPath.SOURCE); + ClassPath cp = kunda.iterator().next(); + GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, new ClassPath[] { cp }); + waitScanFinished(); + GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] { cp }); + waitScanFinished(); + + CountingSecurityManager.assertCounts("Expected", 0); + + } public void testFileUpdate2() throws Exception { prepareTest("package pack; public class A { B.Inner x; }", "package pack; public class B {public static class Inner {}}"); @@ -449,3 +481,68 @@ public class RepositoryUpdaterTest exten "public static void tests() {}\n" + "}\n"; } + +final class CountingSecurityManager extends SecurityManager { + private static int cnt; + private static StringWriter msgs; + private static PrintWriter pw; + private static String suffix; + + public static void initialize(String suffix) { + if (System.getSecurityManager() instanceof CountingSecurityManager) { + // ok + } else { + System.setSecurityManager(new CountingSecurityManager()); + } + cnt = 0; + msgs = new StringWriter(); + pw = new PrintWriter(msgs); + CountingSecurityManager.suffix = suffix; + } + + public static void assertCounts(String msg, int expectedCnt) { + Assert.assertEquals(msg + "\n" + msgs, expectedCnt, cnt); + cnt = 0; + msgs = new StringWriter(); + pw = new PrintWriter(msgs); + } + + @Override + public void checkRead(String file) { + if (file.endsWith(suffix)) { + cnt++; + pw.println("checkRead: " + file); + new Exception().printStackTrace(pw); + } + } + + @Override + public void checkRead(String file, Object context) { + if (file.endsWith(suffix)) { + cnt++; + pw.println("checkRead2: " + file); + } + } + + @Override + public void checkWrite(FileDescriptor fd) { + cnt++; + pw.println("Fd: " + fd); + } + + @Override + public void checkWrite(String file) { + if (file.endsWith(suffix)) { + cnt++; + pw.println("checkWrite: " + file); + } + } + + @Override + public void checkPermission(Permission perm) { + } + + @Override + public void checkPermission(Permission perm, Object context) { + } +}