Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ final class JarFileUrlKey {
this.runtimeRef = "runtime".equals(url.getRef());
}

JarFileUrlKey(String protocol, String host, int port, String file, boolean runtimeRef) {
this.protocol = protocol;
this.host = host;
this.port = port;
this.file = file;
this.runtimeRef = runtimeRef;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
* @author Phillip Webb
* @author Andy Wilkinson
* @author Rostyslav Dudka
* @author Sharan Bharmshetty
*/
final class JarUrlConnection extends java.net.JarURLConnection {

Expand Down Expand Up @@ -335,15 +336,12 @@ static JarUrlConnection open(URL url) throws IOException {
String spec = url.getFile();
if (spec.startsWith("nested:")) {
int separator = spec.indexOf("!/");
boolean specHasEntry = (separator != -1) && (separator + 2 != spec.length());
if (specHasEntry) {
URL jarFileUrl = new URL(spec.substring(0, separator));
if ("runtime".equals(url.getRef())) {
jarFileUrl = new URL(jarFileUrl, "#runtime");
}
boolean specHasJarEntry = (separator != -1) && (separator + 2 != spec.length());
if (specHasJarEntry) {
String jarFileSpec = spec.substring(0, separator);
boolean runtimeRef = "runtime".equals(url.getRef());
JarFile jarFile = jarFiles.getOrCreateAndCache(jarFileSpec, runtimeRef);
String entryName = UrlDecoder.decode(spec.substring(separator + 2));
JarFile jarFile = jarFiles.getOrCreate(true, jarFileUrl);
jarFiles.cacheIfAbsent(true, jarFileUrl, jarFile);
if (!hasEntry(jarFile, entryName)) {
return notFoundConnection(jarFile.getName(), entryName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
* instances.
*
* @author Phillip Webb
* @author Sharan Bharmshetty
*/
class UrlJarFiles {

Expand All @@ -53,6 +54,20 @@ class UrlJarFiles {
this.factory = factory;
}

JarFile getOrCreateAndCache(String jarFileSpec, boolean runtimeRef) throws IOException {
JarFileUrlKey jarFileUrlKey = new JarFileUrlKey("jar", "", -1, jarFileSpec, runtimeRef);
JarFile jarFile = this.cache.get(jarFileUrlKey);
if (jarFile == null) {
URL jarFileUrl = new URL(jarFileSpec);
if (runtimeRef) {
jarFileUrl = new URL(jarFileUrl, "#runtime");
}
jarFile = this.factory.createJarFile(jarFileUrl, this::onClose);
this.cache.putIfAbsent(jarFileUrlKey, jarFile, jarFileUrl);
}
return jarFile;
}

/**
* Get an existing {@link JarFile} instance from the cache, or create a new
* {@link JarFile} instance that can be {@link #cacheIfAbsent(boolean, URL, JarFile)
Expand Down Expand Up @@ -154,9 +169,17 @@ private static final class Cache {
* @return the cached {@link JarFile} or {@code null}
*/
JarFile get(URL jarFileUrl) {
JarFileUrlKey urlKey = new JarFileUrlKey(jarFileUrl);
return get(new JarFileUrlKey(jarFileUrl));
}

/**
* Get a {@link JarFile} from the cache given a jar file URL key.
* @param jarFileUrlKey the jar file URL key
* @return the cached {@link JarFile} or {@code null}
*/
JarFile get(JarFileUrlKey jarFileUrlKey) {
synchronized (this) {
return this.jarFileUrlToJarFile.get(urlKey);
return this.jarFileUrlToJarFile.get(jarFileUrlKey);
}
}

Expand All @@ -180,11 +203,23 @@ URL get(JarFile jarFile) {
* they were already there
*/
boolean putIfAbsent(URL jarFileUrl, JarFile jarFile) {
JarFileUrlKey urlKey = new JarFileUrlKey(jarFileUrl);
return putIfAbsent(new JarFileUrlKey(jarFileUrl), jarFile, jarFileUrl);
}

/**
* Put the given jar file URL and jar file into the cache if they aren't already
* there.
* @param jarFileUrlKey the jar file URL key
* @param jarFileUrl the jar file URL
* @param jarFile the jar file
* @return {@code true} if the items were added to the cache or {@code false} if
* they were already there
*/
boolean putIfAbsent(JarFileUrlKey jarFileUrlKey, JarFile jarFile, URL jarFileUrl) {
synchronized (this) {
JarFile cached = this.jarFileUrlToJarFile.get(urlKey);
JarFile cached = this.jarFileUrlToJarFile.get(jarFileUrlKey);
if (cached == null) {
this.jarFileUrlToJarFile.put(urlKey, jarFile);
this.jarFileUrlToJarFile.put(jarFileUrlKey, jarFile);
this.jarFileToJarFileUrl.put(jarFile, jarFileUrl);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
* Tests for {@link JarFileUrlKey}.
*
* @author Phillip Webb
* @author Sharan Bharmshetty
*/
class JarFileUrlKeyTests {

Expand Down Expand Up @@ -101,4 +102,27 @@ private JarFileUrlKey key(String spec) throws MalformedURLException {
return new JarFileUrlKey(new URL(spec));
}

@Test
void directKeyEqualsUrlKey() throws Exception {
JarFileUrlKey fromUrl = key("jar:nested:/my.jar/!mynested.jar!/my/path");
JarFileUrlKey direct = new JarFileUrlKey("jar", "", -1, "nested:/my.jar/!mynested.jar!/my/path", false);
assertThat(direct).isEqualTo(fromUrl);
assertThat(direct.hashCode()).isEqualTo(fromUrl.hashCode());
}

@Test
void directKeyWithRuntimeRefEqualsUrlKey() throws Exception {
JarFileUrlKey fromUrl = key("jar:nested:/my.jar/!mynested.jar!/my/path#runtime");
JarFileUrlKey direct = new JarFileUrlKey("jar", "", -1, "nested:/my.jar/!mynested.jar!/my/path", true);
assertThat(direct).isEqualTo(fromUrl);
assertThat(direct.hashCode()).isEqualTo(fromUrl.hashCode());
}

@Test
void directKeyWithRuntimeRefNotEqualToKeyWithout() {
JarFileUrlKey k1 = new JarFileUrlKey("jar", "", -1, "nested:/my.jar/!mynested.jar!/my/path", true);
JarFileUrlKey k2 = new JarFileUrlKey("jar", "", -1, "nested:/my.jar/!mynested.jar!/my/path", false);
assertThat(k1).isNotEqualTo(k2);
}

}