changeset 19559:aa0e5a215c2d

Override default file system provider does not work with module path or patching
author alanb
date Sun, 23 Apr 2017 11:35:33 +0100
parents b38f70bbe88d
children 3cd57b38881e
files src/java.base/share/classes/java/nio/file/FileSystems.java src/java.base/share/classes/jdk/internal/module/ModulePatcher.java src/java.base/share/classes/jdk/internal/module/ModuleReferences.java src/java.base/share/classes/jdk/internal/module/Resources.java test/java/nio/file/spi/SetDefaultProvider.java test/java/nio/file/spi/TestProvider.java test/java/nio/file/spi/m/module-info.java test/java/nio/file/spi/m/p/Main.java
diffstat 8 files changed, 245 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/nio/file/FileSystems.java	Fri Apr 21 20:12:04 2017 +0100
+++ b/src/java.base/share/classes/java/nio/file/FileSystems.java	Sun Apr 23 11:35:33 2017 +0100
@@ -36,6 +36,8 @@
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 
+import jdk.internal.misc.VM;
+
 /**
  * Factory methods for file systems. This class defines the {@link #getDefault
  * getDefault} method to get the default file system and factory methods to
@@ -120,8 +122,8 @@
 
             // if the property java.nio.file.spi.DefaultFileSystemProvider is
             // set then its value is the name of the default provider (or a list)
-            String propValue = System
-                .getProperty("java.nio.file.spi.DefaultFileSystemProvider");
+            String prop = "java.nio.file.spi.DefaultFileSystemProvider";
+            String propValue = VM.getSavedProperty(prop);
             if (propValue != null) {
                 for (String cn: propValue.split(",")) {
                     try {
@@ -184,7 +186,7 @@
      * @return  the default file system
      */
     public static FileSystem getDefault() {
-        if (jdk.internal.misc.VM.isBooted()) {
+        if (VM.isModuleSystemInited()) {
             return DefaultFileSystemHolder.defaultFileSystem;
         } else {
             return BuiltinFileSystemHolder.builtinFileSystem;
--- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Fri Apr 21 20:12:04 2017 +0100
+++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Sun Apr 23 11:35:33 2017 +0100
@@ -120,7 +120,7 @@
 
                     // JAR file - do not open as a multi-release JAR as this
                     // is not supported by the boot class loader
-                    try (JarFile jf = new JarFile(file.toFile())) {
+                    try (JarFile jf = new JarFile(file.toString())) {
                         jf.stream()
                           .filter(e -> !e.isDirectory()
                                   && (!isAutomatic || e.getName().endsWith(".class")))
@@ -431,7 +431,7 @@
         private final URL csURL;
 
         JarResourceFinder(Path path) throws IOException {
-            this.jf = new JarFile(path.toFile());
+            this.jf = new JarFile(path.toString());
             this.csURL = path.toUri().toURL();
         }
 
--- a/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	Fri Apr 21 20:12:04 2017 +0100
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	Sun Apr 23 11:35:33 2017 +0100
@@ -25,6 +25,7 @@
 
 package jdk.internal.module;
 
+import java.io.File;
 import java.io.IOError;
 import java.io.IOException;
 import java.io.InputStream;
@@ -226,8 +227,8 @@
 
         static JarFile newJarFile(Path path) {
             try {
-                return new JarFile(path.toFile(),
-                                   true,               // verify
+                return new JarFile(new File(path.toString()),
+                                   true,                       // verify
                                    ZipFile.OPEN_READ,
                                    JarFile.runtimeVersion());
             } catch (IOException ioe) {
--- a/src/java.base/share/classes/jdk/internal/module/Resources.java	Fri Apr 21 20:12:04 2017 +0100
+++ b/src/java.base/share/classes/jdk/internal/module/Resources.java	Sun Apr 23 11:35:33 2017 +0100
@@ -26,10 +26,10 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.FileSystem;
 import java.nio.file.Files;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.nio.file.attribute.BasicFileAttributes;
 
 /**
@@ -94,7 +94,7 @@
         if (expectDirectory) {
             name = name.substring(0, name.length() - 1);  // drop trailing "/"
         }
-        Path path = toSafeFilePath(name);
+        Path path = toSafeFilePath(dir.getFileSystem(), name);
         if (path != null) {
             Path file = dir.resolve(path);
             try {
@@ -116,7 +116,7 @@
      * are rejected, as are resource names that translates to a file path
      * with a root component.
      */
-    private static Path toSafeFilePath(String name) {
+    private static Path toSafeFilePath(FileSystem fs, String name) {
         // scan elements of resource name
         int next;
         int off = 0;
@@ -135,12 +135,12 @@
         // convert to file path
         Path path;
         if (File.separatorChar == '/') {
-            path = Paths.get(name);
+            path = fs.getPath(name);
         } else {
             // not allowed to embed file separators
             if (name.contains(File.separator))
                 return null;
-            path = Paths.get(name.replace('/', File.separatorChar));
+            path = fs.getPath(name.replace('/', File.separatorChar));
         }
 
         // file path not allowed to have root component
--- a/test/java/nio/file/spi/SetDefaultProvider.java	Fri Apr 21 20:12:04 2017 +0100
+++ b/test/java/nio/file/spi/SetDefaultProvider.java	Sun Apr 23 11:35:33 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,23 +21,141 @@
  * questions.
  */
 
-/* @test
- * @bug 4313887 7006126
- * @summary Unit test for java.nio.file.spi.FileSystemProvider
- * @build TestProvider SetDefaultProvider
- * @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider SetDefaultProvider
+/**
+ * @test
+ * @modules jdk.jartool
+ * @library /lib/testlibrary
+ * @build SetDefaultProvider TestProvider m/* jdk.testlibrary.ProcessTools
+ * @run testng/othervm SetDefaultProvider
+ * @summary Runs tests with -Djava.nio.file.spi.DefaultFileSystemProvider set on
+ *          the command line to override the default file system provider
  */
 
-import java.nio.file.*;
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.spi.ToolProvider;
 
+import jdk.testlibrary.ProcessTools;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
 public class SetDefaultProvider {
-    public static void main(String[] args) throws Exception {
-        Class<?> c = FileSystems.getDefault().provider().getClass();
 
-        Class<?> expected = Class.forName("TestProvider", false,
-            ClassLoader.getSystemClassLoader());
+    private static String SET_DEFAULT_FSP =
+        "-Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider";
 
-        if (c != expected)
-            throw new RuntimeException();
+    private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
+        .orElseThrow(() ->
+            new RuntimeException("jar tool not found")
+        );
+
+    /**
+     * Test override of default FileSystemProvider with the main application
+     * on the class path.
+     */
+    public void testClassPath() throws Exception {
+        String moduleClasses = moduleClasses();
+        String testClasses = System.getProperty("test.classes");
+        String classpath = moduleClasses + File.pathSeparator + testClasses;
+        int exitValue = exec(SET_DEFAULT_FSP, "-cp", classpath, "p.Main");
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Test override of default FileSystemProvider with the main application
+     * on the module path as an exploded module.
+     */
+    public void testExplodedModule() throws Exception {
+        String modulePath = System.getProperty("jdk.module.path");
+        int exitValue = exec(SET_DEFAULT_FSP, "-p", modulePath, "-m", "m/p.Main");
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Test override of default FileSystemProvider with the main application
+     * on the module path as a modular JAR.
+     */
+    public void testModularJar() throws Exception {
+        String jarFile = createModularJar();
+        int exitValue = exec(SET_DEFAULT_FSP, "-p", jarFile, "-m", "m/p.Main");
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Test override of default FileSystemProvider where the main application
+     * is a module that is patched by an exploded patch.
+     */
+    public void testExplodedModuleWithExplodedPatch() throws Exception {
+        Path patchdir = Files.createTempDirectory("patch");
+        String modulePath = System.getProperty("jdk.module.path");
+        int exitValue = exec(SET_DEFAULT_FSP,
+                             "--patch-module", "m=" + patchdir,
+                             "-p", modulePath,
+                             "-m", "m/p.Main");
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Test override of default FileSystemProvider where the main application
+     * is a module that is patched by an exploded patch.
+     */
+    public void testExplodedModuleWithJarPatch() throws Exception {
+        Path patchdir = Files.createTempDirectory("patch");
+        Files.createDirectory(patchdir.resolve("m.properties"));
+        Path patch = createJarFile(patchdir);
+        String modulePath = System.getProperty("jdk.module.path");
+        int exitValue = exec(SET_DEFAULT_FSP,
+                             "--patch-module", "m=" + patch,
+                             "-p", modulePath,
+                             "-m", "m/p.Main");
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Returns the directory containing the classes for module "m".
+     */
+    private String moduleClasses() {
+        String mp = System.getProperty("jdk.module.path");
+        for (String dir : mp.split(File.pathSeparator)) {
+            Path m = Paths.get(dir, "m");
+            if (Files.exists(m)) return m.toString();
+        }
+        assertFalse(true);
+        return null;
+    }
+
+    /**
+     * Creates a modular JAR containing module "m".
+     */
+    private String createModularJar() throws Exception {
+        Path dir = Paths.get(moduleClasses());
+        Path jar = createJarFile(dir);
+        return jar.toString();
+    }
+
+    /**
+     * Creates a JAR file containing the entries in the given file tree.
+     */
+    private Path createJarFile(Path dir) throws Exception {
+        Path jar = Files.createTempDirectory("tmp").resolve("m.jar");
+        String[] args = { "--create", "--file=" + jar, "-C", dir.toString(), "." };
+        int ret = JAR_TOOL.run(System.out, System.out, args);
+        assertTrue(ret == 0);
+        return jar;
+    }
+
+    /**
+     * Invokes the java launcher with the given arguments, returning the exit code.
+     */
+    private int exec(String... args) throws Exception {
+       return ProcessTools.executeTestJava(args)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
     }
 }
--- a/test/java/nio/file/spi/TestProvider.java	Fri Apr 21 20:12:04 2017 +0100
+++ b/test/java/nio/file/spi/TestProvider.java	Sun Apr 23 11:35:33 2017 +0100
@@ -77,7 +77,7 @@
                              LinkOption... options)
         throws IOException
     {
-        throw new ReadOnlyFileSystemException();
+        throw new RuntimeException("not implemented");
     }
 
     @Override
@@ -110,19 +110,20 @@
 
     @Override
     public void delete(Path file) throws IOException {
-        throw new ReadOnlyFileSystemException();
+        Path delegate = theFileSystem.unwrap(file);
+        defaultProvider.delete(delegate);
     }
 
     @Override
     public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
         throws IOException
     {
-        throw new ReadOnlyFileSystemException();
+        throw new RuntimeException("not implemented");
     }
 
     @Override
     public void createLink(Path link, Path existing) throws IOException {
-        throw new ReadOnlyFileSystemException();
+        throw new RuntimeException("not implemented");
     }
 
     @Override
@@ -136,14 +137,14 @@
     public void copy(Path source, Path target, CopyOption... options)
         throws IOException
     {
-        throw new ReadOnlyFileSystemException();
+        throw new RuntimeException("not implemented");
     }
 
     @Override
     public void move(Path source, Path target, CopyOption... options)
         throws IOException
     {
-        throw new ReadOnlyFileSystemException();
+        throw new RuntimeException("not implemented");
     }
 
     @Override
@@ -158,7 +159,8 @@
     public void createDirectory(Path dir, FileAttribute<?>... attrs)
         throws IOException
     {
-        throw new ReadOnlyFileSystemException();
+        Path delegate = theFileSystem.unwrap(dir);
+        defaultProvider.createDirectory(delegate, attrs);
     }
 
     @Override
@@ -167,13 +169,8 @@
                                               FileAttribute<?>... attrs)
         throws IOException
     {
-        if (options.contains(StandardOpenOption.READ) && options.size() == 1) {
-            Path delegate = theFileSystem.unwrap(file);
-            options = Collections.singleton(StandardOpenOption.READ);
-            return defaultProvider.newByteChannel(delegate, options, attrs);
-        }
-
-        throw new RuntimeException("not implemented");
+        Path delegate = theFileSystem.unwrap(file);
+        return defaultProvider.newByteChannel(delegate, options, attrs);
     }
 
     @Override
@@ -236,7 +233,7 @@
 
         @Override
         public boolean isReadOnly() {
-            return true;
+            return false;
         }
 
         @Override
@@ -419,7 +416,7 @@
 
         @Override
         public File toFile() {
-            return delegate.toFile();
+            return new File(toString());
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/file/spi/m/module-info.java	Sun Apr 23 11:35:33 2017 +0100
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+module m {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/file/spi/m/p/Main.java	Sun Apr 23 11:35:33 2017 +0100
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+import java.io.File;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * Launched by SetDefaultProvider to test startup with the default file system
+ * provider overridden.
+ */
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        FileSystem fs = FileSystems.getDefault();
+        if (fs.getClass().getModule() == Object.class.getModule())
+            throw new RuntimeException("FileSystemProvider not overridden");
+
+        // exercise the file system
+        Path dir = Files.createTempDirectory("tmp");
+        if (dir.getFileSystem() != fs)
+            throw new RuntimeException("'dir' not in default file system");
+        System.out.println("created: " + dir);
+
+        Path foo = Files.createFile(dir.resolve("foo"));
+        if (foo.getFileSystem() != fs)
+            throw new RuntimeException("'foo' not in default file system");
+        System.out.println("created: " + foo);
+
+        // exercise interop with java.io.File
+        File file = foo.toFile();
+        Path path = file.toPath();
+        if (path.getFileSystem() != fs)
+            throw new RuntimeException("'path' not in default file system");
+        if (!path.equals(foo))
+            throw new RuntimeException(path + " not equal to " + foo);
+    }
+}