FileSystems.java revision 13901:b2a69d66dc65
136285Sbrian/*
236285Sbrian * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
336285Sbrian * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
436285Sbrian *
536285Sbrian * This code is free software; you can redistribute it and/or modify it
636285Sbrian * under the terms of the GNU General Public License version 2 only, as
736285Sbrian * published by the Free Software Foundation.  Oracle designates this
836285Sbrian * particular file as subject to the "Classpath" exception as provided
936285Sbrian * by Oracle in the LICENSE file that accompanied this code.
1036285Sbrian *
1136285Sbrian * This code is distributed in the hope that it will be useful, but WITHOUT
1236285Sbrian * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1336285Sbrian * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1436285Sbrian * version 2 for more details (a copy is included in the LICENSE file that
1536285Sbrian * accompanied this code).
1636285Sbrian *
1736285Sbrian * You should have received a copy of the GNU General Public License version
1836285Sbrian * 2 along with this work; if not, write to the Free Software Foundation,
1936285Sbrian * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2036285Sbrian *
2136285Sbrian * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2236285Sbrian * or visit www.oracle.com if you need additional information or have any
2336285Sbrian * questions.
2436285Sbrian */
2536285Sbrian
2637141Sbrianpackage java.nio.file;
2736285Sbrian
2836285Sbrianimport java.nio.file.spi.FileSystemProvider;
2936285Sbrianimport java.net.URI;
3036285Sbrianimport java.io.IOException;
3136285Sbrianimport java.security.AccessController;
3236285Sbrianimport java.security.PrivilegedAction;
3336285Sbrianimport java.lang.reflect.Constructor;
3436285Sbrianimport java.util.Collections;
3536285Sbrianimport java.util.Map;
3636285Sbrianimport java.util.ServiceConfigurationError;
3736285Sbrianimport java.util.ServiceLoader;
3836285Sbrian
3936285Sbrian/**
4036285Sbrian * Factory methods for file systems. This class defines the {@link #getDefault
4136285Sbrian * getDefault} method to get the default file system and factory methods to
4236285Sbrian * construct other types of file systems.
4336285Sbrian *
4436285Sbrian * <p> The first invocation of any of the methods defined by this class causes
4536285Sbrian * the default {@link FileSystemProvider provider} to be loaded. The default
4636285Sbrian * provider, identified by the URI scheme "file", creates the {@link FileSystem}
4737009Sbrian * that provides access to the file systems accessible to the Java virtual
4836285Sbrian * machine. If the process of loading or initializing the default provider fails
4936285Sbrian * then an unspecified error is thrown.
5036285Sbrian *
5136285Sbrian * <p> The first invocation of the {@link FileSystemProvider#installedProviders
5236285Sbrian * installedProviders} method, by way of invoking any of the {@code
5336285Sbrian * newFileSystem} methods defined by this class, locates and loads all
5436285Sbrian * installed file system providers. Installed providers are loaded using the
5536285Sbrian * service-provider loading facility defined by the {@link ServiceLoader} class.
5636285Sbrian * Installed providers are loaded using the system class loader. If the
5736285Sbrian * system class loader cannot be found then the platform class loader is used.
5836285Sbrian * Providers are typically installed by placing them in a JAR file on the
5936285Sbrian * application class path, the JAR file contains a
6036285Sbrian * provider-configuration file named {@code java.nio.file.spi.FileSystemProvider}
6136285Sbrian * in the resource directory {@code META-INF/services}, and the file lists one or
6236285Sbrian * more fully-qualified names of concrete subclass of {@link FileSystemProvider}
6336285Sbrian * that have a zero argument constructor.
6436285Sbrian * The ordering that installed providers are located is implementation specific.
6536285Sbrian * If a provider is instantiated and its {@link FileSystemProvider#getScheme()
6636285Sbrian * getScheme} returns the same URI scheme of a provider that was previously
6736285Sbrian * instantiated then the most recently instantiated duplicate is discarded. URI
6836285Sbrian * schemes are compared without regard to case. During construction a provider
6936285Sbrian * may safely access files associated with the default provider but care needs
7036285Sbrian * to be taken to avoid circular loading of other installed providers. If
7136285Sbrian * circular loading of installed providers is detected then an unspecified error
7236285Sbrian * is thrown.
7336285Sbrian *
7436285Sbrian * <p> This class also defines factory methods that allow a {@link ClassLoader}
7536285Sbrian * to be specified when locating a provider. As with installed providers, the
7636285Sbrian * provider classes are identified by placing the provider configuration file
7736285Sbrian * in the resource directory {@code META-INF/services}.
7836285Sbrian *
7936285Sbrian * <p> If a thread initiates the loading of the installed file system providers
8036285Sbrian * and another thread invokes a method that also attempts to load the providers
8136285Sbrian * then the method will block until the loading completes.
8236285Sbrian *
8336285Sbrian * @since 1.7
8436285Sbrian */
8536285Sbrian
8636285Sbrianpublic final class FileSystems {
8736285Sbrian    private FileSystems() { }
8836285Sbrian
8936285Sbrian    // Built-in file system provider
9036285Sbrian    private static final FileSystemProvider builtinFileSystemProvider =
9136285Sbrian        sun.nio.fs.DefaultFileSystemProvider.create();
9236285Sbrian
9336285Sbrian    // built-in file system
9436285Sbrian    private static class BuiltinFileSystemHolder {
9536285Sbrian        static final FileSystem builtinFileSystem =
9636285Sbrian            builtinFileSystemProvider.getFileSystem(URI.create("file:///"));
9736285Sbrian    }
9836285Sbrian
9936285Sbrian    // lazy initialization of default file system
10036285Sbrian    private static class DefaultFileSystemHolder {
10136285Sbrian        static final FileSystem defaultFileSystem = defaultFileSystem();
10236285Sbrian
10336285Sbrian        // returns default file system
10436285Sbrian        private static FileSystem defaultFileSystem() {
10536285Sbrian            // load default provider
10636285Sbrian            FileSystemProvider provider = AccessController
10736285Sbrian                .doPrivileged(new PrivilegedAction<>() {
10836285Sbrian                    public FileSystemProvider run() {
10936285Sbrian                        return getDefaultProvider();
11036285Sbrian                    }
11136285Sbrian                });
11236285Sbrian
11336285Sbrian            // return file system
11436285Sbrian            return provider.getFileSystem(URI.create("file:///"));
11536285Sbrian        }
11636285Sbrian
11736285Sbrian        // returns default provider
11836285Sbrian        private static FileSystemProvider getDefaultProvider() {
11936285Sbrian            FileSystemProvider provider = builtinFileSystemProvider;
12036285Sbrian
12136285Sbrian            // if the property java.nio.file.spi.DefaultFileSystemProvider is
12236285Sbrian            // set then its value is the name of the default provider (or a list)
12336285Sbrian            String propValue = System
12436285Sbrian                .getProperty("java.nio.file.spi.DefaultFileSystemProvider");
12536285Sbrian            if (propValue != null) {
12636285Sbrian                for (String cn: propValue.split(",")) {
12736285Sbrian                    try {
12836285Sbrian                        Class<?> c = Class
12936285Sbrian                            .forName(cn, true, ClassLoader.getSystemClassLoader());
13036285Sbrian                        Constructor<?> ctor = c
13136285Sbrian                            .getDeclaredConstructor(FileSystemProvider.class);
13236285Sbrian                        provider = (FileSystemProvider)ctor.newInstance(provider);
13336285Sbrian
13436285Sbrian                        // must be "file"
13536285Sbrian                        if (!provider.getScheme().equals("file"))
13636285Sbrian                            throw new Error("Default provider must use scheme 'file'");
13736285Sbrian
13836285Sbrian                    } catch (Exception x) {
13936285Sbrian                        throw new Error(x);
14036285Sbrian                    }
14136285Sbrian                }
14236285Sbrian            }
14336285Sbrian            return provider;
14436285Sbrian        }
14536285Sbrian    }
14636285Sbrian
14736285Sbrian    /**
14836285Sbrian     * Returns the default {@code FileSystem}. The default file system creates
14936285Sbrian     * objects that provide access to the file systems accessible to the Java
15036285Sbrian     * virtual machine. The <em>working directory</em> of the file system is
15136285Sbrian     * the current user directory, named by the system property {@code user.dir}.
15236285Sbrian     * This allows for interoperability with the {@link java.io.File java.io.File}
15336285Sbrian     * class.
15436285Sbrian     *
15536285Sbrian     * <p> The first invocation of any of the methods defined by this class
15636285Sbrian     * locates the default {@link FileSystemProvider provider} object. Where the
15736285Sbrian     * system property {@code java.nio.file.spi.DefaultFileSystemProvider} is
15836285Sbrian     * not defined then the default provider is a system-default provider that
15936285Sbrian     * is invoked to create the default file system.
16036285Sbrian     *
16136285Sbrian     * <p> If the system property {@code java.nio.file.spi.DefaultFileSystemProvider}
16236285Sbrian     * is defined then it is taken to be a list of one or more fully-qualified
16336285Sbrian     * names of concrete provider classes identified by the URI scheme
16436285Sbrian     * {@code "file"}. Where the property is a list of more than one name then
16536285Sbrian     * the names are separated by a comma. Each class is loaded, using the system
16636285Sbrian     * class loader, and instantiated by invoking a one argument constructor
16736285Sbrian     * whose formal parameter type is {@code FileSystemProvider}. The providers
16836285Sbrian     * are loaded and instantiated in the order they are listed in the property.
16936285Sbrian     * If this process fails or a provider's scheme is not equal to {@code "file"}
17036285Sbrian     * then an unspecified error is thrown. URI schemes are normally compared
17136285Sbrian     * without regard to case but for the default provider, the scheme is
17236285Sbrian     * required to be {@code "file"}. The first provider class is instantiated
17336285Sbrian     * by invoking it with a reference to the system-default provider.
17436285Sbrian     * The second provider class is instantiated by invoking it with a reference
17536285Sbrian     * to the first provider instance. The third provider class is instantiated
17636285Sbrian     * by invoking it with a reference to the second instance, and so on. The
17736285Sbrian     * last provider to be instantiated becomes the default provider; its {@code
17836285Sbrian     * getFileSystem} method is invoked with the URI {@code "file:///"} to
17936285Sbrian     * get a reference to the default file system.
18036285Sbrian     *
18136285Sbrian     * <p> Subsequent invocations of this method return the file system that was
18236285Sbrian     * returned by the first invocation.
18336285Sbrian     *
18436285Sbrian     * @return  the default file system
18536285Sbrian     */
18636285Sbrian    public static FileSystem getDefault() {
18736285Sbrian        if (jdk.internal.misc.VM.isBooted()) {
18836285Sbrian            return DefaultFileSystemHolder.defaultFileSystem;
18936285Sbrian        } else {
19036285Sbrian            return BuiltinFileSystemHolder.builtinFileSystem;
19136285Sbrian        }
19236285Sbrian    }
19336285Sbrian
19436285Sbrian    /**
19536285Sbrian     * Returns a reference to an existing {@code FileSystem}.
19636285Sbrian     *
19736285Sbrian     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
19836285Sbrian     * installed} providers to locate the provider that is identified by the URI
19936285Sbrian     * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
20036285Sbrian     * without regard to case. The exact form of the URI is highly provider
20136285Sbrian     * dependent. If found, the provider's {@link FileSystemProvider#getFileSystem
20236285Sbrian     * getFileSystem} method is invoked to obtain a reference to the {@code
20336285Sbrian     * FileSystem}.
20436285Sbrian     *
20536285Sbrian     * <p> Once a file system created by this provider is {@link FileSystem#close
20636285Sbrian     * closed} it is provider-dependent if this method returns a reference to
20736285Sbrian     * the closed file system or throws {@link FileSystemNotFoundException}.
20836285Sbrian     * If the provider allows a new file system to be created with the same URI
20936285Sbrian     * as a file system it previously created then this method throws the
21036285Sbrian     * exception if invoked after the file system is closed (and before a new
21136285Sbrian     * instance is created by the {@link #newFileSystem newFileSystem} method).
21236285Sbrian     *
21336285Sbrian     * <p> If a security manager is installed then a provider implementation
21436285Sbrian     * may require to check a permission before returning a reference to an
21536285Sbrian     * existing file system. In the case of the {@link FileSystems#getDefault
21636285Sbrian     * default} file system, no permission check is required.
21736285Sbrian     *
21836285Sbrian     * @param   uri  the URI to locate the file system
21936285Sbrian     *
22036285Sbrian     * @return  the reference to the file system
22136285Sbrian     *
22236285Sbrian     * @throws  IllegalArgumentException
22336285Sbrian     *          if the pre-conditions for the {@code uri} parameter are not met
22436285Sbrian     * @throws  FileSystemNotFoundException
22536285Sbrian     *          if the file system, identified by the URI, does not exist
22636285Sbrian     * @throws  ProviderNotFoundException
22736285Sbrian     *          if a provider supporting the URI scheme is not installed
22836285Sbrian     * @throws  SecurityException
22936285Sbrian     *          if a security manager is installed and it denies an unspecified
23036285Sbrian     *          permission
23136285Sbrian     */
23236285Sbrian    public static FileSystem getFileSystem(URI uri) {
23336285Sbrian        String scheme = uri.getScheme();
23436285Sbrian        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
23536285Sbrian            if (scheme.equalsIgnoreCase(provider.getScheme())) {
23636285Sbrian                return provider.getFileSystem(uri);
23736285Sbrian            }
23836285Sbrian        }
23936285Sbrian        throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
24036285Sbrian    }
24136285Sbrian
24236285Sbrian    /**
24336285Sbrian     * Constructs a new file system that is identified by a {@link URI}
24436285Sbrian     *
24536285Sbrian     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
24636285Sbrian     * installed} providers to locate the provider that is identified by the URI
24736285Sbrian     * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
24836285Sbrian     * without regard to case. The exact form of the URI is highly provider
24936285Sbrian     * dependent. If found, the provider's {@link FileSystemProvider#newFileSystem(URI,Map)
25036285Sbrian     * newFileSystem(URI,Map)} method is invoked to construct the new file system.
25136285Sbrian     *
25236285Sbrian     * <p> Once a file system is {@link FileSystem#close closed} it is
25336285Sbrian     * provider-dependent if the provider allows a new file system to be created
25436285Sbrian     * with the same URI as a file system it previously created.
25536285Sbrian     *
25636285Sbrian     * <p> <b>Usage Example:</b>
25736285Sbrian     * Suppose there is a provider identified by the scheme {@code "memory"}
25836285Sbrian     * installed:
25936285Sbrian     * <pre>
26036285Sbrian     *   Map&lt;String,String&gt; env = new HashMap&lt;&gt;();
26136285Sbrian     *   env.put("capacity", "16G");
26236285Sbrian     *   env.put("blockSize", "4k");
26336285Sbrian     *   FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
26436285Sbrian     * </pre>
26536285Sbrian     *
26636285Sbrian     * @param   uri
26736285Sbrian     *          the URI identifying the file system
26836285Sbrian     * @param   env
26936285Sbrian     *          a map of provider specific properties to configure the file system;
27036285Sbrian     *          may be empty
27136285Sbrian     *
27236285Sbrian     * @return  a new file system
27336285Sbrian     *
27436285Sbrian     * @throws  IllegalArgumentException
27536310Sbrian     *          if the pre-conditions for the {@code uri} parameter are not met,
27636285Sbrian     *          or the {@code env} parameter does not contain properties required
27736285Sbrian     *          by the provider, or a property value is invalid
27836285Sbrian     * @throws  FileSystemAlreadyExistsException
27936285Sbrian     *          if the file system has already been created
28036285Sbrian     * @throws  ProviderNotFoundException
28136285Sbrian     *          if a provider supporting the URI scheme is not installed
28236285Sbrian     * @throws  IOException
28336285Sbrian     *          if an I/O error occurs creating the file system
28436285Sbrian     * @throws  SecurityException
28536285Sbrian     *          if a security manager is installed and it denies an unspecified
28636285Sbrian     *          permission required by the file system provider implementation
28736285Sbrian     */
28836285Sbrian    public static FileSystem newFileSystem(URI uri, Map<String,?> env)
28936285Sbrian        throws IOException
29036285Sbrian    {
29136285Sbrian        return newFileSystem(uri, env, null);
29236285Sbrian    }
29336285Sbrian
29436285Sbrian    /**
29536285Sbrian     * Constructs a new file system that is identified by a {@link URI}
29636285Sbrian     *
29737060Sbrian     * <p> This method first attempts to locate an installed provider in exactly
29836285Sbrian     * the same manner as the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)}
29936285Sbrian     * method. If none of the installed providers support the URI scheme then an
30036285Sbrian     * attempt is made to locate the provider using the given class loader. If a
30136285Sbrian     * provider supporting the URI scheme is located then its {@link
30236285Sbrian     * FileSystemProvider#newFileSystem(URI,Map) newFileSystem(URI,Map)} is
30336285Sbrian     * invoked to construct the new file system.
30436285Sbrian     *
30536285Sbrian     * @param   uri
30636285Sbrian     *          the URI identifying the file system
30736285Sbrian     * @param   env
30836285Sbrian     *          a map of provider specific properties to configure the file system;
30936285Sbrian     *          may be empty
31036285Sbrian     * @param   loader
31136285Sbrian     *          the class loader to locate the provider or {@code null} to only
31236285Sbrian     *          attempt to locate an installed provider
31336285Sbrian     *
31436285Sbrian     * @return  a new file system
31536285Sbrian     *
31636285Sbrian     * @throws  IllegalArgumentException
31736285Sbrian     *          if the pre-conditions for the {@code uri} parameter are not met,
31836285Sbrian     *          or the {@code env} parameter does not contain properties required
31936285Sbrian     *          by the provider, or a property value is invalid
32036285Sbrian     * @throws  FileSystemAlreadyExistsException
32136285Sbrian     *          if the URI scheme identifies an installed provider and the file
32236285Sbrian     *          system has already been created
32336285Sbrian     * @throws  ProviderNotFoundException
32436285Sbrian     *          if a provider supporting the URI scheme is not found
32536312Sbrian     * @throws  ServiceConfigurationError
32636312Sbrian     *          when an error occurs while loading a service provider
32736312Sbrian     * @throws  IOException
32836312Sbrian     *          an I/O error occurs creating the file system
32936312Sbrian     * @throws  SecurityException
33036312Sbrian     *          if a security manager is installed and it denies an unspecified
33136312Sbrian     *          permission required by the file system provider implementation
33236285Sbrian     */
33336285Sbrian    public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader)
33436285Sbrian        throws IOException
33536285Sbrian    {
33636312Sbrian        String scheme = uri.getScheme();
33736312Sbrian
33836312Sbrian        // check installed providers
33936312Sbrian        for (FileSystemProvider provider : FileSystemProvider.installedProviders()) {
34036312Sbrian            if (scheme.equalsIgnoreCase(provider.getScheme())) {
34136312Sbrian                try {
34236285Sbrian                    return provider.newFileSystem(uri, env);
34336285Sbrian                } catch (UnsupportedOperationException uoe) {
34436285Sbrian                }
34536285Sbrian            }
34636285Sbrian        }
34736285Sbrian
34836285Sbrian        // if not found, use service-provider loading facility
34936312Sbrian        if (loader != null) {
35036285Sbrian            ServiceLoader<FileSystemProvider> sl = ServiceLoader
35136312Sbrian                .load(FileSystemProvider.class, loader);
35236312Sbrian            for (FileSystemProvider provider : sl) {
35336312Sbrian                if (scheme.equalsIgnoreCase(provider.getScheme())) {
35436285Sbrian                    try {
35536285Sbrian                        return provider.newFileSystem(uri, env);
35636285Sbrian                    } catch (UnsupportedOperationException uoe) {
35736285Sbrian                    }
35836285Sbrian                }
35936285Sbrian            }
36036285Sbrian        }
36136285Sbrian
36236285Sbrian        throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
36336285Sbrian    }
36436285Sbrian
36536285Sbrian    /**
36636285Sbrian     * Constructs a new {@code FileSystem} to access the contents of a file as a
36736285Sbrian     * file system.
36836285Sbrian     *
36936285Sbrian     * <p> This method makes use of specialized providers that create pseudo file
37036285Sbrian     * systems where the contents of one or more files is treated as a file
37136285Sbrian     * system.
37236285Sbrian     *
37336285Sbrian     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
37436285Sbrian     * installed} providers. It invokes, in turn, each provider's {@link
37536285Sbrian     * FileSystemProvider#newFileSystem(Path,Map) newFileSystem(Path,Map)} method
37636285Sbrian     * with an empty map. If a provider returns a file system then the iteration
37736285Sbrian     * terminates and the file system is returned. If none of the installed
37836285Sbrian     * providers return a {@code FileSystem} then an attempt is made to locate
37936285Sbrian     * the provider using the given class loader. If a provider returns a file
38036285Sbrian     * system then the lookup terminates and the file system is returned.
38136285Sbrian     *
38236285Sbrian     * @param   path
38336285Sbrian     *          the path to the file
38436285Sbrian     * @param   loader
38536285Sbrian     *          the class loader to locate the provider or {@code null} to only
38636285Sbrian     *          attempt to locate an installed provider
38736285Sbrian     *
38836285Sbrian     * @return  a new file system
38936285Sbrian     *
39036285Sbrian     * @throws  ProviderNotFoundException
39136285Sbrian     *          if a provider supporting this file type cannot be located
39236285Sbrian     * @throws  ServiceConfigurationError
39336285Sbrian     *          when an error occurs while loading a service provider
39436285Sbrian     * @throws  IOException
39536285Sbrian     *          if an I/O error occurs
39636285Sbrian     * @throws  SecurityException
39736285Sbrian     *          if a security manager is installed and it denies an unspecified
39836285Sbrian     *          permission
39936285Sbrian     */
40036285Sbrian    public static FileSystem newFileSystem(Path path,
40136285Sbrian                                           ClassLoader loader)
40236285Sbrian        throws IOException
40336285Sbrian    {
40436285Sbrian        if (path == null)
40536285Sbrian            throw new NullPointerException();
40636285Sbrian        Map<String,?> env = Collections.emptyMap();
40736285Sbrian
40836285Sbrian        // check installed providers
40936285Sbrian        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
41036285Sbrian            try {
41136285Sbrian                return provider.newFileSystem(path, env);
41236285Sbrian            } catch (UnsupportedOperationException uoe) {
41336285Sbrian            }
41436285Sbrian        }
41536285Sbrian
41636285Sbrian        // if not found, use service-provider loading facility
41736285Sbrian        if (loader != null) {
41836285Sbrian            ServiceLoader<FileSystemProvider> sl = ServiceLoader
41936285Sbrian                .load(FileSystemProvider.class, loader);
42036285Sbrian            for (FileSystemProvider provider: sl) {
42136285Sbrian                try {
42236285Sbrian                    return provider.newFileSystem(path, env);
42336285Sbrian                } catch (UnsupportedOperationException uoe) {
42436285Sbrian                }
42536285Sbrian            }
42636285Sbrian        }
42736285Sbrian
42836285Sbrian        throw new ProviderNotFoundException("Provider not found");
42936285Sbrian    }
43036285Sbrian}
43136285Sbrian