Simplify ResourceLoaders.

Remove the ability to create a ResourceLoader from an arbitrary
ClassLoader and provide instead a ResourceLoader associated with
the current context ClassLoader, which is the way this class
was actually used anyway.

Change-Id: Ic1b873d524f0c194d18ee68b8fbbd26574100161
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
index 94c5c60..5a819cd 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
@@ -437,7 +437,7 @@
     ZipFileClassPathEntry.clearCache();
     ResourceOracleImpl.clearCache();
 
-    ResourceLoader resources = ResourceLoaders.forClassLoader(Thread.currentThread());
+    ResourceLoader resources = ResourceLoaders.fromContextClassLoader();
     resources = ResourceLoaders.forPathAndFallback(options.getSourcePath(), resources);
     this.resourceLoader.set(resources);
 
diff --git a/dev/core/src/com/google/gwt/dev/Link.java b/dev/core/src/com/google/gwt/dev/Link.java
index 2bff2ee..d7d0062 100644
--- a/dev/core/src/com/google/gwt/dev/Link.java
+++ b/dev/core/src/com/google/gwt/dev/Link.java
@@ -418,7 +418,7 @@
     if (saveSources) {
       // Assume that all source code is available in the compiler's classpath.
       // (This will have to be adjusted to work with Super Dev Mode.)
-      ResourceLoader loader = ResourceLoaders.forClassLoader(Thread.currentThread());
+      ResourceLoader loader = ResourceLoaders.fromContextClassLoader();
       SourceSaver.save(logger, artifacts, loader, options, destPrefix, extraFileSet);
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
index 0418c03..9b91b3b 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -178,7 +178,7 @@
   private Map<String, String> gwtXmlPathByModuleName = Maps.newHashMap();
 
   public ModuleDef(String name) {
-    this(name, ResourceLoaders.forClassLoader(Thread.currentThread()));
+    this(name, ResourceLoaders.fromContextClassLoader());
   }
 
   public ModuleDef(String name, ResourceLoader resources) {
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
index cd5acbe..2f049a3 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
@@ -84,7 +84,7 @@
       return moduleDef;
     }
 
-    ResourceLoader resources = ResourceLoaders.forClassLoader(Thread.currentThread());
+    ResourceLoader resources = ResourceLoaders.fromContextClassLoader();
 
     ModuleDefLoader loader = new ModuleDefLoader(resources) {
       @Override
@@ -122,7 +122,7 @@
    */
   public static ModuleDef loadFromClassPath(TreeLogger logger, String moduleName, boolean refresh)
       throws UnableToCompleteException {
-    ResourceLoader resources = ResourceLoaders.forClassLoader(Thread.currentThread());
+    ResourceLoader resources = ResourceLoaders.fromContextClassLoader();
     return loadFromResources(logger, moduleName, resources, refresh);
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ResourceLoaders.java b/dev/core/src/com/google/gwt/dev/cfg/ResourceLoaders.java
index 987e1d9..fef35d7 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ResourceLoaders.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ResourceLoaders.java
@@ -18,12 +18,14 @@
 import static com.google.gwt.thirdparty.guava.common.base.StandardSystemProperty.JAVA_CLASS_PATH;
 
 import com.google.gwt.thirdparty.guava.common.base.Splitter;
+import com.google.gwt.thirdparty.guava.common.collect.Sets;
 
 import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 import java.util.List;
 
 /**
@@ -31,22 +33,20 @@
  */
 public class ResourceLoaders {
 
-  private static class ClassLoaderAdapter implements ResourceLoader {
-    private final ClassLoader wrapped;
+  private static class ContextClassLoaderAdapter implements ResourceLoader {
+    private final ClassLoader contextClassLoader;
 
-    public ClassLoaderAdapter(ClassLoader wrapped) {
-      // TODO(rluble): Maybe stop wrapping arbitrary class loaders here and always use the
-      // system ClassLoader.
-      this.wrapped = wrapped;
+    public ContextClassLoaderAdapter() {
+      this.contextClassLoader = Thread.currentThread().getContextClassLoader();
     }
 
     @Override
     public boolean equals(Object other) {
-      if (!(other instanceof ClassLoaderAdapter)) {
+      if (!(other instanceof ContextClassLoaderAdapter)) {
         return false;
       }
-      ClassLoaderAdapter otherAdapter = (ClassLoaderAdapter) other;
-      return wrapped.equals(otherAdapter.wrapped);
+      ContextClassLoaderAdapter otherAdapter = (ContextClassLoaderAdapter) other;
+      return contextClassLoader.equals(otherAdapter.contextClassLoader);
     }
 
     /**
@@ -54,8 +54,10 @@
      */
     @Override
     public List<URL> getClassPath() {
-      List<URL> result = new ArrayList<URL>();
-      for (String entry : Splitter.on(File.pathSeparatorChar).split(JAVA_CLASS_PATH.value())) {
+      List<URL> result = new ArrayList<>();
+      LinkedHashSet<String> uniqueClassPathEntries =
+          Sets.newLinkedHashSet(Splitter.on(File.pathSeparatorChar).split(JAVA_CLASS_PATH.value()));
+      for (String entry : uniqueClassPathEntries) {
         try {
           result.add(Paths.get(entry).toUri().toURL());
         } catch (MalformedURLException e) {
@@ -66,12 +68,12 @@
 
     @Override
     public URL getResource(String resourceName) {
-      return wrapped.getResource(resourceName);
+      return contextClassLoader.getResource(resourceName);
     }
 
     @Override
     public int hashCode() {
-      return wrapped.hashCode();
+      return contextClassLoader.hashCode();
     }
   }
 
@@ -137,8 +139,8 @@
   /**
    * Creates a ResourceLoader that loads from the given thread's class loader.
    */
-  public static ResourceLoader forClassLoader(Thread thread) {
-    return wrap(thread.getContextClassLoader());
+  public static ResourceLoader fromContextClassLoader() {
+    return new ContextClassLoaderAdapter();
   }
 
   /**
@@ -149,15 +151,6 @@
     return new PrefixLoader(path, fallback);
   }
 
-  /**
-   * Adapts a ClassLoader to work as a ResourceLoader.
-   * (Caveat: any ClassLoader in the chain that isn't a URLClassLoader won't contribute to the
-   * results of {@link  ResourceLoader#getClassPath}.)
-   */
-  public static ResourceLoader wrap(ClassLoader loader) {
-    return new ClassLoaderAdapter(loader);
-  }
-
   private ResourceLoaders() {
   }
 }
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 d9f25ed..0790601 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
@@ -204,14 +204,7 @@
    * Preinitializes the classpath from the thread default {@link ClassLoader}.
    */
   public static void preload(TreeLogger logger) {
-    preload(logger, Thread.currentThread().getContextClassLoader());
-  }
-
-  /**
-   * Preinitializes the classpath for a given {@link ClassLoader}.
-   */
-  public static void preload(TreeLogger logger, ClassLoader classLoader) {
-    preload(logger, ResourceLoaders.wrap(classLoader));
+    preload(logger, ResourceLoaders.fromContextClassLoader());
   }
 
   /**
@@ -387,17 +380,7 @@
    * {@link ClassLoader}.
    */
   public ResourceOracleImpl(TreeLogger logger) {
-    this(logger, Thread.currentThread().getContextClassLoader());
-  }
-
-  /**
-   * Constructs a {@link ResourceOracleImpl} from a {@link ClassLoader}. The
-   * specified {@link ClassLoader} and all of its parents which are instances of
-   * {@link java.net.URLClassLoader} will have their class path entries added to this
-   * instances underlying class path.
-   */
-  public ResourceOracleImpl(TreeLogger logger, ClassLoader classLoader) {
-    this(logger, ResourceLoaders.wrap(classLoader));
+    this(logger, ResourceLoaders.fromContextClassLoader());
   }
 
   public ResourceOracleImpl(TreeLogger logger, ResourceLoader resources) {
diff --git a/dev/core/test/com/google/gwt/dev/CompilerTest.java b/dev/core/test/com/google/gwt/dev/CompilerTest.java
index bb342f2..2ecf9e4 100644
--- a/dev/core/test/com/google/gwt/dev/CompilerTest.java
+++ b/dev/core/test/com/google/gwt/dev/CompilerTest.java
@@ -2504,7 +2504,7 @@
 
       // Fake out the resource loader to read resources both from the normal classpath as well as
       // this new application directory.
-      ResourceLoader resourceLoader = ResourceLoaders.forClassLoader(Thread.currentThread());
+      ResourceLoader resourceLoader = ResourceLoaders.fromContextClassLoader();
       resourceLoader =
           ResourceLoaders.forPathAndFallback(ImmutableList.of(applicationDir), resourceLoader);
 
@@ -2688,7 +2688,7 @@
 
     // Fake out the resource loader to read resources both from the normal classpath as well as this
     // new application directory.
-    ResourceLoader resourceLoader = ResourceLoaders.forClassLoader(Thread.currentThread());
+    ResourceLoader resourceLoader = ResourceLoaders.fromContextClassLoader();
     resourceLoader =
         ResourceLoaders.forPathAndFallback(ImmutableList.of(applicationDir), resourceLoader);
 
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 f53fa75..9ea0c21 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
@@ -27,7 +27,6 @@
 import java.io.InputStreamReader;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -335,25 +334,18 @@
   }
 
   /**
-   * Verify that duplicate entries are removed from the classpath, and that
-   * multiple ResourceOracleImpls created from the same classloader return the
-   * same list of ClassPathEntries.
+   * Verify ResourceOracleImpls created from the same state return the same list of
+   * ClassPathEntries.
    */
-  public void testRemoveDuplicates() {
+  public void testSameClassPathEntries() {
     TreeLogger logger = createTestTreeLogger();
-    URL cpe1 = findUrl("com/google/gwt/dev/resource/impl/testdata/cpe1.jar");
-    URL cpe2 = findUrl("com/google/gwt/dev/resource/impl/testdata/cpe2.zip");
-    URLClassLoader classLoader = new URLClassLoader(new URL[]{
-        cpe1, cpe2, cpe2, cpe1, cpe2,}, null);
-    ResourceOracleImpl oracle = new ResourceOracleImpl(logger, classLoader);
+    ResourceOracleImpl oracle = new ResourceOracleImpl(logger);
     List<ClassPathEntry> classPathEntries = oracle.getClassPathEntries();
-    assertEquals(2, classPathEntries.size());
-    assertJarEntry(classPathEntries.get(0), "cpe1.jar");
-    assertJarEntry(classPathEntries.get(1), "cpe2.zip");
-    oracle = new ResourceOracleImpl(logger, classLoader);
+
+    oracle = new ResourceOracleImpl(logger);
     List<ClassPathEntry> classPathEntries2 = oracle.getClassPathEntries();
-    assertEquals(2, classPathEntries2.size());
-    for (int i = 0; i < 2; ++i) {
+    assertEquals(classPathEntries.size(), classPathEntries2.size());
+    for (int i = 0; i < classPathEntries2.size(); ++i) {
       assertSame(classPathEntries.get(i), classPathEntries2.get(i));
     }
   }