From: Anna Koskinen Date: Fri, 6 Aug 2021 14:37:46 +0000 (+0300) Subject: fix: Reuse existing filesystem (#12346) (#12362) X-Git-Tag: 8.13.3~5 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b1036f69cf0fc8d4bb1dc33df4e7aae0296a00cd;p=vaadin-framework.git fix: Reuse existing filesystem (#12346) (#12362) Modified cherry-pick of https://github.com/vaadin/flow/pull/11428 --- diff --git a/server/src/main/java/com/vaadin/server/VaadinServlet.java b/server/src/main/java/com/vaadin/server/VaadinServlet.java index 3ddbd956e9..b418b5dd3f 100644 --- a/server/src/main/java/com/vaadin/server/VaadinServlet.java +++ b/server/src/main/java/com/vaadin/server/VaadinServlet.java @@ -39,6 +39,7 @@ import java.net.URLDecoder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; +import java.nio.file.FileSystemAlreadyExistsException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -197,8 +198,12 @@ public class VaadinServlet extends HttpServlet implements Constants { private VaadinServletService servletService; - // Mapped uri is for the jar file - static final Map openFileSystems = new HashMap<>(); + /** + * Mapped uri is for the jar file. + *

+ * FOR INTERNAL USE ONLY, may get renamed or removed. + */ + static final Map OPEN_FILE_SYSTEMS = new HashMap<>(); private static final Object fileSystemLock = new Object(); /** @@ -1364,29 +1369,41 @@ public class VaadinServlet extends HttpServlet implements Constants { + " and will determine this as not a folder"); } - Integer locks = openFileSystems.computeIfPresent(fileURI, + Integer locks = OPEN_FILE_SYSTEMS.computeIfPresent(fileURI, (key, value) -> value + 1); if (locks != null) { // Get filesystem is for the file to get the correct provider return FileSystems.getFileSystem(resourceURI); } // Opened filesystem is for the file to get the correct provider - FileSystem fileSystem = FileSystems.newFileSystem(resourceURI, - Collections.emptyMap()); - openFileSystems.put(fileURI, 1); + FileSystem fileSystem = getNewOrExistingFileSystem(resourceURI); + OPEN_FILE_SYSTEMS.put(fileURI, 1); return fileSystem; } } + private FileSystem getNewOrExistingFileSystem(URI resourceURI) + throws IOException { + try { + return FileSystems.newFileSystem(resourceURI, + Collections.emptyMap()); + } catch (FileSystemAlreadyExistsException fsaee) { + getLogger().log(Level.FINER, + "Tried to get new filesystem, but it already existed for target uri.", + fsaee); + return FileSystems.getFileSystem(resourceURI); + } + } + // Package protected for feature verification purpose void closeFileSystem(URI resourceURI) { synchronized (fileSystemLock) { try { URI fileURI = getFileURI(resourceURI); - Integer locks = openFileSystems.computeIfPresent(fileURI, + Integer locks = OPEN_FILE_SYSTEMS.computeIfPresent(fileURI, (key, value) -> value - 1); if (locks != null && locks == 0) { - openFileSystems.remove(fileURI); + OPEN_FILE_SYSTEMS.remove(fileURI); // Get filesystem is for the file to get the correct // provider FileSystems.getFileSystem(resourceURI).close(); diff --git a/server/src/test/java/com/vaadin/server/VaadinServletTest.java b/server/src/test/java/com/vaadin/server/VaadinServletTest.java index 006872b212..4eb97d4453 100644 --- a/server/src/test/java/com/vaadin/server/VaadinServletTest.java +++ b/server/src/test/java/com/vaadin/server/VaadinServletTest.java @@ -10,11 +10,13 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.FileSystem; import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -233,7 +235,7 @@ public class VaadinServletTest { public void isAllowedVAADINResource_jarWarFileScheme_detectsAsStaticResources() throws IOException, URISyntaxException, ServletException { assertTrue("Can not run concurrently with other test", - VaadinServlet.openFileSystems.isEmpty()); + VaadinServlet.OPEN_FILE_SYSTEMS.isEmpty()); VaadinServlet servlet = new VaadinServlet(); servlet.init(new MockServletConfig()); @@ -276,7 +278,7 @@ public class VaadinServletTest { public void isAllowedVAADINResource_jarInAJar_detectsAsStaticResources() throws IOException, URISyntaxException, ServletException { assertTrue("Can not run concurrently with other test", - VaadinServlet.openFileSystems.isEmpty()); + VaadinServlet.OPEN_FILE_SYSTEMS.isEmpty()); VaadinServlet servlet = new VaadinServlet(); servlet.init(new MockServletConfig()); @@ -321,11 +323,47 @@ public class VaadinServletTest { } } + @Test + public void openFileServerExistsForZip_openingNewDoesNotFail() + throws IOException, URISyntaxException { + assertTrue("Can not run concurrently with other test", + VaadinServlet.OPEN_FILE_SYSTEMS.isEmpty()); + + VaadinServlet servlet = new VaadinServlet(); + + final TemporaryFolder folder = TemporaryFolder.builder().build(); + folder.create(); + + try { + Path tempArchive = createJAR(folder).toPath(); + + final FileSystem fileSystem = FileSystems + .newFileSystem( + new URL("jar:file:///" + tempArchive.toString() + .replaceAll("\\\\", "/") + "!/").toURI(), + Collections.emptyMap()); + + final URL folderResourceURL = new URL("jar:file:///" + + tempArchive.toString().replaceAll("\\\\", "/") + + "!/VAADIN"); + + try { + servlet.getFileSystem(folderResourceURL.toURI()); + } finally { + servlet.closeFileSystem(folderResourceURL.toURI()); + fileSystem.close(); + } + } finally { + folder.delete(); + } + + } + @Test public void openingJarFileSystemForDifferentFilesInSameJar_existingFileSystemIsUsed() throws IOException, URISyntaxException, ServletException { assertTrue("Can not run concurrently with other test", - VaadinServlet.openFileSystems.isEmpty()); + VaadinServlet.OPEN_FILE_SYSTEMS.isEmpty()); VaadinServlet servlet = new VaadinServlet(); servlet.init(new MockServletConfig()); @@ -348,15 +386,15 @@ public class VaadinServletTest { servlet.getFileSystem(fileResourceURL.toURI()); assertEquals("Same file should be marked for both resources", - (Integer) 2, VaadinServlet.openFileSystems.entrySet() + (Integer) 2, VaadinServlet.OPEN_FILE_SYSTEMS.entrySet() .iterator().next().getValue()); servlet.closeFileSystem(folderResourceURL.toURI()); assertEquals("Closing resource should be removed from jar uri", - (Integer) 1, VaadinServlet.openFileSystems.entrySet() + (Integer) 1, VaadinServlet.OPEN_FILE_SYSTEMS.entrySet() .iterator().next().getValue()); servlet.closeFileSystem(fileResourceURL.toURI()); assertTrue("Closing last resource should clear marking", - VaadinServlet.openFileSystems.isEmpty()); + VaadinServlet.OPEN_FILE_SYSTEMS.isEmpty()); try { FileSystems.getFileSystem(folderResourceURL.toURI()); @@ -375,7 +413,7 @@ public class VaadinServletTest { throws IOException, InterruptedException, ExecutionException, URISyntaxException, ServletException { assertTrue("Can not run concurrently with other test", - VaadinServlet.openFileSystems.isEmpty()); + VaadinServlet.OPEN_FILE_SYSTEMS.isEmpty()); VaadinServlet servlet = new VaadinServlet(); servlet.init(new MockServletConfig()); @@ -547,7 +585,7 @@ public class VaadinServletTest { private void ensureFileSystemsCleared(URL fileResourceURL) throws URISyntaxException { assertFalse("URI should have been cleared", - VaadinServlet.openFileSystems + VaadinServlet.OPEN_FILE_SYSTEMS .containsKey(fileResourceURL.toURI())); try { FileSystems.getFileSystem(fileResourceURL.toURI());