This patch fixes the caching logic so that Gwt no longer re-reads and
re-processes all jars on the classpath on every refresh.

Patch by: amitmanjhi
Review by: jat (desk review)



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4830 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
index f7a0420..96f37c9 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
@@ -20,6 +20,7 @@
 
 import java.io.File;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Map;
@@ -52,11 +53,21 @@
         TreeLogger.DEBUG, "$0");
   }
 
+  private static class ZipFileSnapshot {
+    private final int prefixSetSize;
+    private final Map<AbstractResource, PathPrefix> cachedAnswers;
+
+    ZipFileSnapshot(int prefixSetSize,
+        Map<AbstractResource, PathPrefix> cachedAnswers) {
+      this.prefixSetSize = prefixSetSize;
+      this.cachedAnswers = cachedAnswers;
+    }
+  }
+
   private Set<ZipFileResource> allZipFileResources;
-  private Map<AbstractResource, PathPrefix> cachedAnswers;
+  private final Map<PathPrefixSet, ZipFileSnapshot> cachedSnapshots = new HashMap<PathPrefixSet, ZipFileSnapshot>(
+      2); // currently gwt has just 2 ResourceOracles.
   private String cachedLocation;
-  private PathPrefixSet lastPrefixSet;
-  private int lastPrefixSetSize;
   private final ZipFile zipFile;
 
   public ZipFileClassPathEntry(ZipFile zipFile) {
@@ -74,13 +85,13 @@
       allZipFileResources = buildIndex(logger);
     }
 
-    if (cachedAnswers == null || lastPrefixSet != pathPrefixSet
-        || lastPrefixSetSize != pathPrefixSet.getSize()) {
-      cachedAnswers = computeApplicableResources(logger, pathPrefixSet);
-      lastPrefixSet = pathPrefixSet;
-      lastPrefixSetSize = pathPrefixSet.getSize();
+    ZipFileSnapshot snapshot = cachedSnapshots.get(pathPrefixSet);
+    if (snapshot == null || snapshot.prefixSetSize != pathPrefixSet.getSize()) {
+      snapshot = new ZipFileSnapshot(pathPrefixSet.getSize(),
+          computeApplicableResources(logger, pathPrefixSet));
+      cachedSnapshots.put(pathPrefixSet, snapshot);
     }
-    return cachedAnswers;
+    return snapshot.cachedAnswers;
   }
 
   @Override
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
index 560ed05..788449a 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
@@ -15,6 +15,10 @@
  */
 package com.google.gwt.dev.resource.impl;
 
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.util.tools.Utility;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -28,10 +32,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.dev.resource.Resource;
-import com.google.gwt.util.tools.Utility;
+import java.util.jar.JarFile;
 
 /**
  * Tests {@link ResourceOracleImpl}.
@@ -131,6 +132,37 @@
     }
   }
 
+  public void testCachingOfJarResources() throws IOException,
+      URISyntaxException {
+    TreeLogger logger = createTestTreeLogger();
+    ClassPathEntry cpe1jar = new ZipFileClassPathEntry(new JarFile(
+        findJarFile("com/google/gwt/dev/resource/impl/testdata/cpe1.jar")));
+
+    // test basic caching
+    PathPrefixSet pps1 = new PathPrefixSet();
+    pps1.add(new PathPrefix("com/google/gwt", null, false));
+    Map<AbstractResource, PathPrefix> resourceMap1 = cpe1jar.findApplicableResources(
+        logger, pps1);
+    assertSame(resourceMap1, cpe1jar.findApplicableResources(logger, pps1));
+
+    // test that cache is invalidated if PathPrefixSet is modified.
+    pps1.add(new PathPrefix("com/google/gwt/user", null, false));
+    Map<AbstractResource, PathPrefix> resourceMap2 = cpe1jar.findApplicableResources(
+        logger, pps1);
+    assertNotSame(resourceMap1, resourceMap2);
+
+    PathPrefixSet pps2 = new PathPrefixSet();
+    pps2.add(new PathPrefix("org/example/bar", null, false));
+    Map<AbstractResource, PathPrefix> resourceMap3 = cpe1jar.findApplicableResources(
+        logger, pps2);
+    // check that the entry did go in the cache
+    assertSame(resourceMap3, cpe1jar.findApplicableResources(logger, pps2));
+
+    // check that the cache does not thrash
+    assertSame(resourceMap2, cpe1jar.findApplicableResources(logger, pps1));
+    assertSame(resourceMap3, cpe1jar.findApplicableResources(logger, pps2));
+  }
+
   /**
    * Test that ResourceOracleImpl preserves the order in which the same logical
    * resource is occurs in multiple ClassPathEntries.