|
|
|
@ -19,6 +19,7 @@ package org.springframework.boot.loader.jar; |
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
|
import java.io.FileNotFoundException; |
|
|
|
import java.io.FileNotFoundException; |
|
|
|
import java.io.FilePermission; |
|
|
|
import java.io.FilePermission; |
|
|
|
|
|
|
|
import java.io.FilterInputStream; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.InputStream; |
|
|
|
import java.io.InputStream; |
|
|
|
import java.io.UnsupportedEncodingException; |
|
|
|
import java.io.UnsupportedEncodingException; |
|
|
|
@ -80,14 +81,18 @@ final class JarURLConnection extends java.net.JarURLConnection { |
|
|
|
|
|
|
|
|
|
|
|
private final JarEntryName jarEntryName; |
|
|
|
private final JarEntryName jarEntryName; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final CloseAction closeAction; |
|
|
|
|
|
|
|
|
|
|
|
private JarEntry jarEntry; |
|
|
|
private JarEntry jarEntry; |
|
|
|
|
|
|
|
|
|
|
|
private JarURLConnection(URL url, JarFile jarFile, JarEntryName jarEntryName) throws IOException { |
|
|
|
private JarURLConnection(URL url, JarFile jarFile, JarEntryName jarEntryName, CloseAction closeAction) |
|
|
|
|
|
|
|
throws IOException { |
|
|
|
// What we pass to super is ultimately ignored
|
|
|
|
// What we pass to super is ultimately ignored
|
|
|
|
super(EMPTY_JAR_URL); |
|
|
|
super(EMPTY_JAR_URL); |
|
|
|
this.url = url; |
|
|
|
this.url = url; |
|
|
|
this.jarFile = jarFile; |
|
|
|
this.jarFile = jarFile; |
|
|
|
this.jarEntryName = jarEntryName; |
|
|
|
this.jarEntryName = jarEntryName; |
|
|
|
|
|
|
|
this.closeAction = closeAction; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@ -168,7 +173,17 @@ final class JarURLConnection extends java.net.JarURLConnection { |
|
|
|
if (inputStream == null) { |
|
|
|
if (inputStream == null) { |
|
|
|
throwFileNotFound(this.jarEntryName, this.jarFile); |
|
|
|
throwFileNotFound(this.jarEntryName, this.jarFile); |
|
|
|
} |
|
|
|
} |
|
|
|
return inputStream; |
|
|
|
return new FilterInputStream(inputStream) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public void close() throws IOException { |
|
|
|
|
|
|
|
super.close(); |
|
|
|
|
|
|
|
if (JarURLConnection.this.closeAction != null) { |
|
|
|
|
|
|
|
JarURLConnection.this.closeAction.perform(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void throwFileNotFound(Object entry, JarFile jarFile) throws FileNotFoundException { |
|
|
|
private void throwFileNotFound(Object entry, JarFile jarFile) throws FileNotFoundException { |
|
|
|
@ -249,24 +264,30 @@ final class JarURLConnection extends java.net.JarURLConnection { |
|
|
|
int index = indexOfRootSpec(spec, jarFile.getPathFromRoot()); |
|
|
|
int index = indexOfRootSpec(spec, jarFile.getPathFromRoot()); |
|
|
|
if (index == -1) { |
|
|
|
if (index == -1) { |
|
|
|
return (Boolean.TRUE.equals(useFastExceptions.get()) ? NOT_FOUND_CONNECTION |
|
|
|
return (Boolean.TRUE.equals(useFastExceptions.get()) ? NOT_FOUND_CONNECTION |
|
|
|
: new JarURLConnection(url, null, EMPTY_JAR_ENTRY_NAME)); |
|
|
|
: new JarURLConnection(url, null, EMPTY_JAR_ENTRY_NAME, null)); |
|
|
|
} |
|
|
|
} |
|
|
|
int separator; |
|
|
|
int separator; |
|
|
|
|
|
|
|
JarFile connectionJarFile = jarFile; |
|
|
|
while ((separator = spec.indexOf(SEPARATOR, index)) > 0) { |
|
|
|
while ((separator = spec.indexOf(SEPARATOR, index)) > 0) { |
|
|
|
JarEntryName entryName = JarEntryName.get(spec.subSequence(index, separator)); |
|
|
|
JarEntryName entryName = JarEntryName.get(spec.subSequence(index, separator)); |
|
|
|
JarEntry jarEntry = jarFile.getJarEntry(entryName.toCharSequence()); |
|
|
|
JarEntry jarEntry = jarFile.getJarEntry(entryName.toCharSequence()); |
|
|
|
if (jarEntry == null) { |
|
|
|
if (jarEntry == null) { |
|
|
|
return JarURLConnection.notFound(jarFile, entryName); |
|
|
|
return JarURLConnection.notFound(connectionJarFile, entryName, |
|
|
|
|
|
|
|
(connectionJarFile != jarFile) ? connectionJarFile::close : null); |
|
|
|
} |
|
|
|
} |
|
|
|
jarFile = jarFile.getNestedJarFile(jarEntry); |
|
|
|
connectionJarFile = connectionJarFile.getNestedJarFile(jarEntry); |
|
|
|
index = separator + SEPARATOR.length(); |
|
|
|
index = separator + SEPARATOR.length(); |
|
|
|
} |
|
|
|
} |
|
|
|
JarEntryName jarEntryName = JarEntryName.get(spec, index); |
|
|
|
JarEntryName jarEntryName = JarEntryName.get(spec, index); |
|
|
|
if (Boolean.TRUE.equals(useFastExceptions.get()) && !jarEntryName.isEmpty() |
|
|
|
if (Boolean.TRUE.equals(useFastExceptions.get()) && !jarEntryName.isEmpty() |
|
|
|
&& !jarFile.containsEntry(jarEntryName.toString())) { |
|
|
|
&& !connectionJarFile.containsEntry(jarEntryName.toString())) { |
|
|
|
|
|
|
|
if (connectionJarFile != jarFile) { |
|
|
|
|
|
|
|
connectionJarFile.close(); |
|
|
|
|
|
|
|
} |
|
|
|
return NOT_FOUND_CONNECTION; |
|
|
|
return NOT_FOUND_CONNECTION; |
|
|
|
} |
|
|
|
} |
|
|
|
return new JarURLConnection(url, jarFile, jarEntryName); |
|
|
|
return new JarURLConnection(url, connectionJarFile, jarEntryName, |
|
|
|
|
|
|
|
(connectionJarFile != jarFile) ? connectionJarFile::close : null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static int indexOfRootSpec(StringSequence file, String pathFromRoot) { |
|
|
|
private static int indexOfRootSpec(StringSequence file, String pathFromRoot) { |
|
|
|
@ -279,18 +300,22 @@ final class JarURLConnection extends java.net.JarURLConnection { |
|
|
|
|
|
|
|
|
|
|
|
private static JarURLConnection notFound() { |
|
|
|
private static JarURLConnection notFound() { |
|
|
|
try { |
|
|
|
try { |
|
|
|
return notFound(null, null); |
|
|
|
return notFound(null, null, null); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (IOException ex) { |
|
|
|
catch (IOException ex) { |
|
|
|
throw new IllegalStateException(ex); |
|
|
|
throw new IllegalStateException(ex); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static JarURLConnection notFound(JarFile jarFile, JarEntryName jarEntryName) throws IOException { |
|
|
|
private static JarURLConnection notFound(JarFile jarFile, JarEntryName jarEntryName, CloseAction closeAction) |
|
|
|
|
|
|
|
throws IOException { |
|
|
|
if (Boolean.TRUE.equals(useFastExceptions.get())) { |
|
|
|
if (Boolean.TRUE.equals(useFastExceptions.get())) { |
|
|
|
|
|
|
|
if (closeAction != null) { |
|
|
|
|
|
|
|
closeAction.perform(); |
|
|
|
|
|
|
|
} |
|
|
|
return NOT_FOUND_CONNECTION; |
|
|
|
return NOT_FOUND_CONNECTION; |
|
|
|
} |
|
|
|
} |
|
|
|
return new JarURLConnection(null, jarFile, jarEntryName); |
|
|
|
return new JarURLConnection(null, jarFile, jarEntryName, closeAction); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -393,4 +418,15 @@ final class JarURLConnection extends java.net.JarURLConnection { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* An action to be taken when the connection is being "closed" and its underlying |
|
|
|
|
|
|
|
* resources are no longer needed. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@FunctionalInterface |
|
|
|
|
|
|
|
private interface CloseAction { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void perform() throws IOException; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|