Skip to content

Commit

Permalink
util: Add support for GraalVM Native-Image resource:-URIs and Paths
Browse files Browse the repository at this point in the history
GraalVM Native-Image makes its classpath resources accessible through an
opaque resource: URL scheme.

Add support for this scheme in URIUtil and PathResource.

Automatically create the NativeImageResourceFileSystem when necessary.
Also add a workaround where converting such Native-Image Paths back to
URI would yield the wrong URI (potentially a bug in GraalVM).

jetty#9116
oracle/graal#5720
  • Loading branch information
kohlschuetter committed Jan 7, 2023
1 parent 99b7c11 commit ef0e481
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -54,6 +57,7 @@ public final class URIUtil
.with("file:")
.with("jrt:")
.with("jar:")
.with("resource:")
.build();

// From https://www.rfc-editor.org/rfc/rfc3986
Expand Down Expand Up @@ -211,6 +215,8 @@ public final class URIUtil

private static final boolean[] ENCODE_PATH_NEEDS_ENCODING;

private static final String URI_BAD_RESOURCE_PREFIX = "file:///resources!";

private URIUtil()
{
}
Expand Down Expand Up @@ -1735,6 +1741,54 @@ public static String addQueries(String query1, String query2)
return query1 + '&' + query2;
}

/**
* Corrects any bad {@code resource} based URIs, such as those starting with {@code resource:file:///resources!}.
*
* @param uri
* The URI to correct.
* @return the corrected URI, or the original URI.
* @see <a href="https://github.com/oracle/graal/issues/5720">Graal issue 5720</a>
*/
public static URI correctResourceURI(URI uri)
{
if (uri == null || !"resource".equals(uri.getScheme()))
return uri;

String ssp = uri.getSchemeSpecificPart();
if (ssp.startsWith(URI_BAD_RESOURCE_PREFIX))
{
return URI.create("resource:" + ssp.substring(URI_BAD_RESOURCE_PREFIX.length()));
}
else
{
return uri;
}
}

/**
* A wrapper for {@link Paths#get(URI)} and {@link Path#of(URI)}.
*
* It automatically handles custom file systems, such as ZipFileSystem and NativeImageResourceFileSystem.
*
* @param uri
* The URI.
* @return The path.
* @throws IOException
* on error.
*/
public static Path getPath(URI uri) throws IOException
{
try
{
return Path.of(uri);
}
catch (FileSystemNotFoundException e)
{
FileSystems.newFileSystem(uri, Collections.emptyMap());
return Path.of(uri);
}
}

/**
* <p>
* Corrects any bad {@code file} based URIs (even within a {@code jar:file:} based URIs) from the bad out-of-spec
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class PathResource extends Resource
.caseSensitive(false)
.with("file")
.with("jrt")
.with("resource")
.build();

// The path object represented by this instance
Expand Down Expand Up @@ -141,15 +142,16 @@ public static boolean isSameName(Path pathA, Path pathB)
* Must be an absolute URI using the <code>file</code> scheme.
*
* @param uri the URI to build this PathResource from.
* @throws IOException if the path could not be resolved.
*/
PathResource(URI uri)
PathResource(URI uri) throws IOException
{
this(uri, false);
}

PathResource(URI uri, boolean bypassAllowedSchemeCheck)
PathResource(URI uri, boolean bypassAllowedSchemeCheck) throws IOException
{
this(Paths.get(uri), uri, bypassAllowedSchemeCheck);
this(URIUtil.getPath(URIUtil.correctResourceURI(uri)), uri, bypassAllowedSchemeCheck);
}

PathResource(Path path)
Expand All @@ -166,6 +168,7 @@ public static boolean isSameName(Path pathA, Path pathB)
*/
PathResource(Path path, URI uri, boolean bypassAllowedSchemeCheck)
{
uri = URIUtil.correctResourceURI(uri);
if (!uri.isAbsolute())
throw new IllegalArgumentException("not an absolute uri: " + uri);
if (!bypassAllowedSchemeCheck && !SUPPORTED_SCHEMES.contains(uri.getScheme()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class ResourceFactoryInternals
PathResourceFactory pathResourceFactory = new PathResourceFactory();
RESOURCE_FACTORIES.put("file", pathResourceFactory);
RESOURCE_FACTORIES.put("jrt", pathResourceFactory);
RESOURCE_FACTORIES.put("resource", pathResourceFactory); // GraalVM native-image resource
}

static ResourceFactory ROOT = new CompositeResourceFactory()
Expand Down

0 comments on commit ef0e481

Please sign in to comment.