Support jars and zips on the classpath.
Suggested by: tobyr
Review by: tobyr (TBR)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2860 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 7bd1d93..70bef30 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
@@ -36,6 +36,7 @@
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
+import java.util.zip.ZipFile;
/**
* The normal implementation of {@link ResourceOracle}.
@@ -120,13 +121,16 @@
if (url.getProtocol().equals("file")) {
URI uri = new URI(urlString);
File f = new File(uri);
+ String lowerCaseFileName = f.getName().toLowerCase();
if (f.isDirectory()) {
return new DirectoryClassPathEntry(f);
- } else if (f.isFile() && f.getName().endsWith(".jar")) {
- return new JarFileClassPathEntry(new JarFile(f));
+ } else if (f.isFile() && lowerCaseFileName.endsWith(".jar")) {
+ return new ZipFileClassPathEntry(new JarFile(f));
+ } else if (f.isFile() && lowerCaseFileName.endsWith(".zip")) {
+ return new ZipFileClassPathEntry(new ZipFile(f));
} else {
logger.log(TreeLogger.TRACE, "Unexpected entry in classpath; " + f
- + " is neither a directory nor a jar");
+ + " is neither a directory nor an archive (.jar or .zip)");
return null;
}
} else {
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/JarFileClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
similarity index 67%
rename from dev/core/src/com/google/gwt/dev/resource/impl/JarFileClassPathEntry.java
rename to dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
index 7e7de4b..666b1e6 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/JarFileClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
@@ -22,20 +22,20 @@
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
/**
- * A classpath entry that is a jar file.
+ * A classpath entry that is a jar or zip file.
*/
-public class JarFileClassPathEntry extends ClassPathEntry {
+public class ZipFileClassPathEntry extends ClassPathEntry {
/**
* Logger messages related to this class.
*/
private static class Messages {
static final Message1String BUILDING_INDEX = new Message1String(
- TreeLogger.TRACE, "Indexing jar file: $0");
+ TreeLogger.TRACE, "Indexing zip file: $0");
static final Message1String EXCLUDING_RESOURCE = new Message1String(
TreeLogger.DEBUG, "Excluding $0");
@@ -46,28 +46,28 @@
static final Message1String INCLUDING_RESOURCE = new Message1String(
TreeLogger.DEBUG, "Including $0");
- static final Message1String READ_JAR_ENTRY = new Message1String(
+ static final Message1String READ_ZIP_ENTRY = new Message1String(
TreeLogger.DEBUG, "$0");
}
- private Set<JarFileResource> allJarFileResources;
+ private Set<ZipFileResource> allZipFileResources;
private Set<AbstractResource> cachedAnswers;
- private final JarFile jarFile;
private PathPrefixSet lastPrefixSet;
+ private final ZipFile zipFile;
- public JarFileClassPathEntry(JarFile jarFile) {
- this.jarFile = jarFile;
+ public ZipFileClassPathEntry(ZipFile zipFile) {
+ this.zipFile = zipFile;
}
/**
- * Indexes the jar file on-demand, and only once over the life of the process.
+ * Indexes the zip file on-demand, and only once over the life of the process.
*/
@Override
public Set<AbstractResource> findApplicableResources(TreeLogger logger,
PathPrefixSet pathPrefixSet) {
// Never re-index.
- if (allJarFileResources == null) {
- allJarFileResources = buildIndex(logger);
+ if (allZipFileResources == null) {
+ allZipFileResources = buildIndex(logger);
}
if (cachedAnswers == null || lastPrefixSet != pathPrefixSet
@@ -78,33 +78,33 @@
return cachedAnswers;
}
- public JarFile getJarFile() {
- return jarFile;
- }
-
@Override
public String getLocation() {
- return new File(jarFile.getName()).toURI().toString();
+ return new File(zipFile.getName()).toURI().toString();
}
- private Set<JarFileResource> buildIndex(TreeLogger logger) {
- logger = Messages.BUILDING_INDEX.branch(logger, jarFile.getName(), null);
+ public ZipFile getZipFile() {
+ return zipFile;
+ }
- HashSet<JarFileResource> results = new HashSet<JarFileResource>();
- Enumeration<JarEntry> e = jarFile.entries();
+ private Set<ZipFileResource> buildIndex(TreeLogger logger) {
+ logger = Messages.BUILDING_INDEX.branch(logger, zipFile.getName(), null);
+
+ HashSet<ZipFileResource> results = new HashSet<ZipFileResource>();
+ Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
- JarEntry jarEntry = e.nextElement();
- if (jarEntry.isDirectory()) {
+ ZipEntry zipEntry = e.nextElement();
+ if (zipEntry.isDirectory()) {
// Skip directories.
continue;
}
- if (jarEntry.getName().startsWith("META-INF/")) {
+ if (zipEntry.getName().startsWith("META-INF/")) {
// Skip META-INF since classloaders normally make this invisible.
continue;
}
- JarFileResource jarResource = new JarFileResource(this, jarEntry);
- results.add(jarResource);
- Messages.READ_JAR_ENTRY.log(logger, jarEntry.getName(), null);
+ ZipFileResource zipResource = new ZipFileResource(this, zipEntry);
+ results.add(zipResource);
+ Messages.READ_ZIP_ENTRY.log(logger, zipEntry.getName(), null);
}
return results;
}
@@ -112,10 +112,10 @@
private Set<AbstractResource> computeApplicableResources(TreeLogger logger,
PathPrefixSet pathPrefixSet) {
logger = Messages.FINDING_INCLUDED_RESOURCES.branch(logger,
- jarFile.getName(), null);
+ zipFile.getName(), null);
Set<AbstractResource> results = new HashSet<AbstractResource>();
- for (JarFileResource r : allJarFileResources) {
+ for (ZipFileResource r : allZipFileResources) {
String path = r.getPath();
if (pathPrefixSet.includesResource(path)) {
Messages.INCLUDING_RESOURCE.log(logger, path, null);
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/JarFileResource.java b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileResource.java
similarity index 66%
rename from dev/core/src/com/google/gwt/dev/resource/impl/JarFileResource.java
rename to dev/core/src/com/google/gwt/dev/resource/impl/ZipFileResource.java
index 650d053..87df4fd 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/JarFileResource.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileResource.java
@@ -20,37 +20,35 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.jar.JarEntry;
+import java.util.zip.ZipEntry;
/**
- * Represents a resource contained in a jar file.
+ * Represents a resource contained in a jar or zip file.
*/
-public class JarFileResource extends AbstractResource {
+public class ZipFileResource extends AbstractResource {
- private final JarFileClassPathEntry classPathEntry;
- private final JarEntry jarEntry;
+ private final ZipFileClassPathEntry classPathEntry;
+ private final ZipEntry zipEntry;
- public JarFileResource(JarFileClassPathEntry classPathEntry, JarEntry jarEntry) {
+ public ZipFileResource(ZipFileClassPathEntry classPathEntry, ZipEntry zipEntry) {
this.classPathEntry = classPathEntry;
- this.jarEntry = jarEntry;
+ this.zipEntry = zipEntry;
}
@Override
- public JarFileClassPathEntry getClassPathEntry() {
+ public ZipFileClassPathEntry getClassPathEntry() {
return classPathEntry;
}
- public JarEntry getJarEntry() {
- return jarEntry;
- }
-
@Override
public String getLocation() {
- return "jar:" + classPathEntry.getLocation() + "!/" + getPath();
+ String proto = zipEntry instanceof JarEntry ? "jar:" : "zip:";
+ return proto + classPathEntry.getLocation() + "!/" + getPath();
}
@Override
public String getPath() {
- return jarEntry.getName();
+ return zipEntry.getName();
}
@Override
@@ -62,8 +60,12 @@
}
}
+ public ZipEntry getZipEntry() {
+ return zipEntry;
+ }
+
/**
- * Since we don't dynamically reload jars during a run, jar-based resources
+ * Since we don't dynamically reload zips during a run, zip-based resources
* cannot become stale.
*/
@Override
@@ -74,7 +76,7 @@
@Override
public InputStream openContents() {
try {
- return classPathEntry.getJarFile().getInputStream(jarEntry);
+ return classPathEntry.getZipFile().getInputStream(zipEntry);
} catch (IOException e) {
// The spec for this method says it can return null.
return null;
diff --git a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
index 723a431..8ee3cd6 100644
--- a/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
+++ b/dev/core/src/com/google/gwt/dev/shell/tomcat/EmbeddedTomcatServer.java
@@ -365,7 +365,12 @@
String prefix = "";
String urlString = url.toString();
if (urlString.startsWith("jar:")) {
- assert urlString.contains(".jar!/" + tomcatEtcDir);
+ assert urlString.toLowerCase().contains(".jar!/" + tomcatEtcDir);
+ urlString = urlString.substring(4, urlString.indexOf('!'));
+ url = new URL(urlString);
+ prefix = tomcatEtcDir;
+ } else if (urlString.startsWith("zip:")) {
+ assert urlString.toLowerCase().contains(".zip!/" + tomcatEtcDir);
urlString = urlString.substring(4, urlString.indexOf('!'));
url = new URL(urlString);
prefix = tomcatEtcDir;
diff --git a/dev/core/src/com/google/gwt/dev/util/Util.java b/dev/core/src/com/google/gwt/dev/util/Util.java
index 237a3c3..b2047f7 100644
--- a/dev/core/src/com/google/gwt/dev/util/Util.java
+++ b/dev/core/src/com/google/gwt/dev/util/Util.java
@@ -53,7 +53,6 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
-import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@@ -63,7 +62,6 @@
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.jar.JarEntry;
/**
* A smattering of useful methods. Methods in this class are candidates for
@@ -255,38 +253,6 @@
return escaped;
}
- /**
- * Converts a URL "jar:file:aaa.jar!bbb" to the filename "aaa.jar". This also
- * does URLDecoding if needed.
- *
- * @param location the URL pointing at a jar location
- * @return the path to the jar file
- */
- public static String findFileName(String location) {
- String newLocation = location;
- if ((location.startsWith("zip:file:"))
- || (location.startsWith("jar:file:"))) {
- int lastIndexOfExclam = newLocation.lastIndexOf('!');
- // This file lives in a jar or zipfile
- // we pretend the location is the jar or zip file
- if (lastIndexOfExclam != -1) {
- newLocation = newLocation.substring(0, lastIndexOfExclam);
- }
- newLocation = newLocation.substring(9);
- // If the file does not exist that may be because the path is
- // URLEncoded. Therefore, decode it.
- if (!new File(newLocation).exists()) {
- try {
- newLocation = URLDecoder.decode(newLocation, DEFAULT_ENCODING);
- } catch (UnsupportedEncodingException e) {
- // An unsupported encoding indicates confusion; do nothing.
- return location;
- }
- }
- }
- return newLocation;
- }
-
public static URL findSourceInClassPath(ClassLoader cl, String sourceTypeName) {
String toTry = sourceTypeName.replace('.', '/') + ".java";
URL foundURL = cl.getResource(toTry);
@@ -389,7 +355,8 @@
URL url = new URL(loc);
String s = url.toExternalForm();
- if (s.startsWith("file:") || s.startsWith("jar:")) {
+ if (s.startsWith("file:") || s.startsWith("jar:file:")
+ || s.startsWith("zip:file:")) {
return true;
}
} catch (MalformedURLException e) {
@@ -858,18 +825,6 @@
}
}
- public static URL toURL(URL jarUrl, JarEntry jarEntry) {
- return toURL(jarUrl, jarEntry.toString());
- }
-
- public static URL toURL(URL jarUrl, String path) {
- try {
- return new URL("jar" + ":" + jarUrl.toString() + "!/" + path);
- } catch (MalformedURLException e) {
- throw new RuntimeException("Failed to convert a jar path to a URL", e);
- }
- }
-
public static String toXml(Document doc) {
Throwable caught = null;
try {
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 6d5e3ee..5871c12 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
@@ -181,7 +181,7 @@
protected ClassPathEntry getClassPathEntry1AsJar() throws IOException,
URISyntaxException {
File file = findJarFile("com/google/gwt/dev/resource/impl/testdata/cpe1.jar");
- return new ExcludeSvnClassPathEntry(new JarFileClassPathEntry(new JarFile(
+ return new ExcludeSvnClassPathEntry(new ZipFileClassPathEntry(new JarFile(
file)));
}
@@ -198,7 +198,7 @@
protected ClassPathEntry getClassPathEntry2AsJar() throws URISyntaxException,
IOException {
File file = findJarFile("com/google/gwt/dev/resource/impl/testdata/cpe2.jar");
- return new ExcludeSvnClassPathEntry(new JarFileClassPathEntry(new JarFile(
+ return new ExcludeSvnClassPathEntry(new ZipFileClassPathEntry(new JarFile(
file)));
}