From 47bdd8d80da1f359bf924b4852e56529e47ddee7 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Tue, 10 Jan 2023 09:58:51 -0600 Subject: [PATCH 1/2] Add tests in util/resource for alternate FileSystem implementations --- jetty-core/jetty-util/pom.xml | 6 + .../java/org/eclipse/jetty/util/URIUtil.java | 6 - .../resource/ResourceFactoryInternals.java | 10 +- .../AlternateFileSystemResourceTest.java | 112 ++++++++++++++++++ 4 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AlternateFileSystemResourceTest.java diff --git a/jetty-core/jetty-util/pom.xml b/jetty-core/jetty-util/pom.xml index 24e2ef48da9b..ced2ad214a01 100644 --- a/jetty-core/jetty-util/pom.xml +++ b/jetty-core/jetty-util/pom.xml @@ -70,6 +70,12 @@ org.slf4j slf4j-api + + com.google.jimfs + jimfs + 1.2 + test + org.awaitility awaitility diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java index 88cecb426dfa..a7fc6c328501 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java @@ -49,12 +49,6 @@ public final class URIUtil { private static final Logger LOG = LoggerFactory.getLogger(URIUtil.class); - private static final Index KNOWN_SCHEMES = new Index.Builder() - .caseSensitive(false) - .with("file:") - .with("jrt:") - .with("jar:") - .build(); // From https://www.rfc-editor.org/rfc/rfc3986 private static final String UNRESERVED = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-._~"; diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceFactoryInternals.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceFactoryInternals.java index 5f3406e24cd1..d564f99155e2 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceFactoryInternals.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceFactoryInternals.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; import java.nio.file.Path; import java.nio.file.ProviderNotFoundException; import java.util.List; @@ -48,10 +49,17 @@ class ResourceFactoryInternals CURRENT_WORKING_DIR = Path.of(System.getProperty("user.dir")); // The default resource factories - RESOURCE_FACTORIES.put("jar", new MountedPathResourceFactory()); + MountedPathResourceFactory mountedPathResourceFactory = new MountedPathResourceFactory(); + RESOURCE_FACTORIES.put("jar", mountedPathResourceFactory); PathResourceFactory pathResourceFactory = new PathResourceFactory(); RESOURCE_FACTORIES.put("file", pathResourceFactory); RESOURCE_FACTORIES.put("jrt", pathResourceFactory); + + URL url = ResourceFactoryInternals.class.getResource("/org/eclipse/jetty/version/build.properties"); + if ((url != null) && !RESOURCE_FACTORIES.contains(url.getProtocol())) + { + RESOURCE_FACTORIES.put(url.getProtocol(), mountedPathResourceFactory); + } } static ResourceFactory ROOT = new CompositeResourceFactory() diff --git a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AlternateFileSystemResourceTest.java b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AlternateFileSystemResourceTest.java new file mode 100644 index 000000000000..fa11540b22ec --- /dev/null +++ b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AlternateFileSystemResourceTest.java @@ -0,0 +1,112 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.util.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.util.Optional; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import org.eclipse.jetty.util.IO; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Test to ensure that Alternate FileSystem providers work as expected. + * + *

+ * Uses the google/jimfs In-Memory FileSystem provider + * to have a FileSystem based on scheme `jimfs` (with an authority) + *

+ */ +public class AlternateFileSystemResourceTest +{ + private static final Logger LOG = LoggerFactory.getLogger(AlternateFileSystemResourceTest.class); + private FileSystem jimfs; + private URI fsBaseURI; + + @BeforeEach + public void initInMemoryFileSystem(TestInfo testInfo) + { + Optional testMethod = testInfo.getTestMethod(); + String testMethodName = testMethod.map(Method::getName).orElseGet(AlternateFileSystemResourceTest.class::getSimpleName); + jimfs = Jimfs.newFileSystem(testMethodName, Configuration.unix()); + fsBaseURI = jimfs.getPath("/").toUri(); + + ResourceFactory.registerResourceFactory(fsBaseURI.getScheme(), new MountedPathResourceFactory()); + } + + @AfterEach + public void closeInMemoryFileSystem() + { + IO.close(jimfs); + } + + @Test + public void testNewResource() throws IOException + { + // Create some content to reference + Files.writeString(jimfs.getPath("/foo.txt"), "Hello Foo", StandardCharsets.UTF_8); + + // Reference it via Resource object + Resource resource = ResourceFactory.root().newResource(fsBaseURI.resolve("/foo.txt")); + assertTrue(Resources.isReadable(resource)); + + LOG.info("resource = {}", resource); + + try (InputStream in = resource.newInputStream()) + { + String contents = IO.toString(in, StandardCharsets.UTF_8); + assertThat(contents, is("Hello Foo")); + } + } + + @Test + public void testNavigateResource() throws IOException + { + // Create some content to reference + Files.createDirectories(jimfs.getPath("/zed")); + Files.writeString(jimfs.getPath("/zed/bar.txt"), "Hello Bar", StandardCharsets.UTF_8); + + // Reference it via Resource object + Resource resourceRoot = ResourceFactory.root().newResource(fsBaseURI.resolve("/")); + assertTrue(Resources.isDirectory(resourceRoot)); + + Resource resourceZedDir = resourceRoot.resolve("zed"); + assertTrue(Resources.isDirectory(resourceZedDir)); + + Resource resourceBarText = resourceZedDir.resolve("bar.txt"); + LOG.info("resource = {}", resourceBarText); + + try (InputStream in = resourceBarText.newInputStream()) + { + String contents = IO.toString(in, StandardCharsets.UTF_8); + assertThat(contents, is("Hello Bar")); + } + } +} From 05c09e734b2697d8326547d99a4f5c7c6b7d1691 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Tue, 10 Jan 2023 11:17:04 -0600 Subject: [PATCH 2/2] Changes per review --- .../util/resource/ResourceFactoryInternals.java | 6 ++++++ .../resource/AlternateFileSystemResourceTest.java | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceFactoryInternals.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceFactoryInternals.java index d564f99155e2..d810e1853d61 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceFactoryInternals.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceFactoryInternals.java @@ -55,6 +55,12 @@ class ResourceFactoryInternals RESOURCE_FACTORIES.put("file", pathResourceFactory); RESOURCE_FACTORIES.put("jrt", pathResourceFactory); + /* Best effort attempt to detect that an alternate FileSystem type that is in use. + * We don't attempt to look up a Class, as not all runtimes and environments have the classes anymore + * (eg: they were compiled into native code) + * The build.properties is present in the jetty-util jar, so it's reasonably safe to look for that + * as a resource + */ URL url = ResourceFactoryInternals.class.getResource("/org/eclipse/jetty/version/build.properties"); if ((url != null) && !RESOURCE_FACTORIES.contains(url.getProtocol())) { diff --git a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AlternateFileSystemResourceTest.java b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AlternateFileSystemResourceTest.java index fa11540b22ec..90594b456ca0 100644 --- a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AlternateFileSystemResourceTest.java +++ b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AlternateFileSystemResourceTest.java @@ -54,8 +54,19 @@ public class AlternateFileSystemResourceTest public void initInMemoryFileSystem(TestInfo testInfo) { Optional testMethod = testInfo.getTestMethod(); - String testMethodName = testMethod.map(Method::getName).orElseGet(AlternateFileSystemResourceTest.class::getSimpleName); - jimfs = Jimfs.newFileSystem(testMethodName, Configuration.unix()); + if (testMethod.isPresent()) + { + String testMethodName = testMethod.get().getName(); + // Create a jimfs that has the testMethodName as its authority + // eg: jimfs:/// + jimfs = Jimfs.newFileSystem(testMethodName, Configuration.unix()); + } + else + { + // Let jimfs establish a unique name on its own + // eg: jimfs://a3cc0bda-1238-4847-864f-22fae7614146/ + jimfs = Jimfs.newFileSystem(Configuration.unix()); + } fsBaseURI = jimfs.getPath("/").toUri(); ResourceFactory.registerResourceFactory(fsBaseURI.getScheme(), new MountedPathResourceFactory());