]> source.dussan.org Git - vaadin-framework.git/commitdiff
fix: Reuse existing filesystem (#12346) (#12362)
authorAnna Koskinen <Ansku@users.noreply.github.com>
Fri, 6 Aug 2021 14:37:46 +0000 (17:37 +0300)
committerGitHub <noreply@github.com>
Fri, 6 Aug 2021 14:37:46 +0000 (17:37 +0300)
Modified cherry-pick of https://github.com/vaadin/flow/pull/11428

server/src/main/java/com/vaadin/server/VaadinServlet.java
server/src/test/java/com/vaadin/server/VaadinServletTest.java

index 3ddbd956e93cf22effbe220fe9e1fec2427d4029..b418b5dd3fee6a06bd078758a4ce2b4aa1042a8b 100644 (file)
@@ -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<URI, Integer> openFileSystems = new HashMap<>();
+    /**
+     * Mapped uri is for the jar file.
+     * <p>
+     * FOR INTERNAL USE ONLY, may get renamed or removed.
+     */
+    static final Map<URI, Integer> 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();
index 006872b2128e763548339fb122c05b2427d1aa76..4eb97d4453aa30155dc6d20d6f6b9741af0aa87b 100644 (file)
@@ -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());