Fixes issue #3078; when the same logical resource occurs in more than one classpath entry, the classpath order must be honored. Adds a test to verify this behavior. Some minor cleanup, too.
Patch by: amitmanjhi
Review by: me
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4481 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
index 0245008..502e634 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
@@ -31,6 +31,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -246,7 +247,6 @@
* Rescans the associated paths to recompute the available resources.
*
* @param logger status and error details are written here
- * @throws UnableToCompleteException
*/
public void refresh(TreeLogger logger) {
TreeLogger refreshBranch = Messages.REFRESHING_RESOURCES.branch(logger,
@@ -254,9 +254,10 @@
/*
* Allocate fresh data structures in anticipation of needing to honor the
- * "new identity for the collections if anything changes" guarantee.
+ * "new identity for the collections if anything changes" guarantee. Use a
+ * LinkedHashMap because we do not want the order to change.
*/
- final Map<String, AbstractResource> newInternalMap = new HashMap<String, AbstractResource>();
+ final Map<String, AbstractResource> newInternalMap = new LinkedHashMap<String, AbstractResource>();
/*
* Walk across path roots (i.e. classpath entries) in priority order. This
@@ -348,6 +349,12 @@
assert (path.startsWith(pathPrefix.getPrefix()));
if (pathPrefix.shouldReroot()) {
String rerootedPath = pathPrefix.getRerootedPath(path);
+ if (externalMap.get(rerootedPath) instanceof ResourceWrapper) {
+ // A rerooted resource blocks any other resource at this path.
+ ++hitCount;
+ break;
+ }
+
// Try to reuse the same wrapper.
Resource exposed = exposedResourceMap.get(rerootedPath);
if (exposed instanceof ResourceWrapper) {
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
index 5871c12..489e571 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
@@ -132,12 +132,14 @@
}
protected void assertPathIncluded(Set<AbstractResource> resources, String path) {
- assertNotNull(findResourceWithPath(resources, path));
+ assertNotNull("path = " + path + " should have been found in resources = "
+ + resources, findResourceWithPath(resources, path));
}
protected void assertPathNotIncluded(Set<AbstractResource> resources,
String path) {
- assertNull(findResourceWithPath(resources, path));
+ assertNull("path = " + path + " should not have been found in resources = "
+ + resources, findResourceWithPath(resources, path));
}
protected File findJarDirectory(String name) throws URISyntaxException {
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 c6fe7e0..46e166d 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
@@ -25,6 +25,7 @@
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -59,9 +60,9 @@
}
private static class ResourceOracleSnapshot {
- private final Set<Resource> resources;
- private final Map<String, Resource> resourceMap;
private final Set<String> pathNames;
+ private final Map<String, Resource> resourceMap;
+ private final Set<Resource> resources;
public ResourceOracleSnapshot(ResourceOracleImpl oracle) {
resources = oracle.getResources();
@@ -127,6 +128,34 @@
}
}
+ /**
+ * Test that ResourceOracleImpl preserves the order in which the same logical
+ * resource is occurs in multiple ClassPathEntries.
+ *
+ * @throws URISyntaxException
+ * @throws IOException
+ */
+ public void testClassPathOrderIsHonored() throws IOException,
+ URISyntaxException {
+ TreeLogger logger = createTestTreeLogger();
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+
+ ClassPathEntry[] cp12 = new ClassPathEntry[] {cpe1jar, cpe2jar};
+ ClassPathEntry[] cp21 = new ClassPathEntry[] {cpe2jar, cpe1jar};
+ String resKeyNormal = "org/example/bar/client/BarClient2.txt";
+ String resKeyReroot = "/BarClient2.txt";
+ PathPrefix pathPrefixNormal = new PathPrefix("org/example/bar/client",
+ null, false);
+ PathPrefix pathPrefixReroot = new PathPrefix("org/example/bar/client",
+ null, true);
+
+ testClassPathOrderIsHonored(logger, resKeyNormal, cp12, pathPrefixNormal);
+ testClassPathOrderIsHonored(logger, resKeyReroot, cp12, pathPrefixReroot);
+ testClassPathOrderIsHonored(logger, resKeyNormal, cp21, pathPrefixNormal);
+ testClassPathOrderIsHonored(logger, resKeyReroot, cp21, pathPrefixReroot);
+ }
+
public void testNoClassPathEntries() {
TreeLogger logger = createTestTreeLogger();
ResourceOracleImpl oracle = createResourceOracle(new MOCK_CPE0());
@@ -139,7 +168,6 @@
*
* @throws URISyntaxException
* @throws IOException
- * @throws UnableToCompleteException
*/
public void testReadingResource() throws IOException, URISyntaxException {
ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
@@ -229,9 +257,6 @@
/**
* Creates an array of class path entries, setting up each one with a
* well-known set of client prefixes.
- *
- * @param entries
- * @return
*/
private ResourceOracleImpl createResourceOracle(ClassPathEntry... entries) {
PathPrefixSet pps = new PathPrefixSet();
@@ -255,14 +280,22 @@
return new ResourceOracleSnapshot(oracle);
}
+ private void testClassPathOrderIsHonored(TreeLogger logger,
+ String resourceKey, ClassPathEntry[] classPath, PathPrefix pathPrefix) {
+ PathPrefixSet pps = new PathPrefixSet();
+ pps.add(pathPrefix);
+ ResourceOracleImpl oracle = new ResourceOracleImpl(Arrays.asList(classPath));
+ oracle.setPathPrefixes(pps);
+ ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
+ s.assertPathIncluded(resourceKey, classPath[0]);
+ }
+
private void testReadingResource(ClassPathEntry cpe1, ClassPathEntry cpe2)
throws IOException {
TreeLogger logger = createTestTreeLogger();
ResourceOracleImpl oracle = createResourceOracle(cpe1, cpe2);
-
- oracle.refresh(logger);
- ResourceOracleSnapshot s = new ResourceOracleSnapshot(oracle);
+ ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
s.assertCollectionsConsistent(9);
s.assertPathIncluded("com/google/gwt/user/client/Command.java", cpe1);
s.assertPathIncluded("com/google/gwt/i18n/client/Messages.java", cpe2);
@@ -440,8 +473,7 @@
/*
* Baseline assumptions about the set of resources present by default.
*/
- oracle.refresh(logger);
- ResourceOracleSnapshot s = new ResourceOracleSnapshot(oracle);
+ ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
s.assertPathIncluded("com/google/gwt/user/client/Command.java", cpe1);
s.assertPathIncluded("com/google/gwt/user/client/Timer.java", cpe1);
}
@@ -454,8 +486,7 @@
/*
* Ensure that the dups have the effect we expect.
*/
- oracle.refresh(logger);
- ResourceOracleSnapshot s = new ResourceOracleSnapshot(oracle);
+ ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
s.assertPathIncluded("com/google/gwt/user/client/Command.java", cpe0);
s.assertPathIncluded("com/google/gwt/user/client/Timer.java", cpe1);
}