410 lines
19 KiB
Java
410 lines
19 KiB
Java
/*
|
|
* Copyright (c) 2007, 2013, 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. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* 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 java.nio.file;
|
|
|
|
import java.nio.file.spi.FileSystemProvider;
|
|
import java.net.URI;
|
|
import java.io.IOException;
|
|
import java.security.AccessController;
|
|
import java.security.PrivilegedAction;
|
|
import java.util.*;
|
|
import java.lang.reflect.Constructor;
|
|
|
|
/**
|
|
* Factory methods for file systems. This class defines the {@link #getDefault
|
|
* getDefault} method to get the default file system and factory methods to
|
|
* construct other types of file systems.
|
|
*
|
|
* <p> The first invocation of any of the methods defined by this class causes
|
|
* the default {@link FileSystemProvider provider} to be loaded. The default
|
|
* provider, identified by the URI scheme "file", creates the {@link FileSystem}
|
|
* that provides access to the file systems accessible to the Java virtual
|
|
* machine. If the process of loading or initializing the default provider fails
|
|
* then an unspecified error is thrown.
|
|
*
|
|
* <p> The first invocation of the {@link FileSystemProvider#installedProviders
|
|
* installedProviders} method, by way of invoking any of the {@code
|
|
* newFileSystem} methods defined by this class, locates and loads all
|
|
* installed file system providers. Installed providers are loaded using the
|
|
* service-provider loading facility defined by the {@link ServiceLoader} class.
|
|
* Installed providers are loaded using the system class loader. If the
|
|
* system class loader cannot be found then the extension class loader is used;
|
|
* if there is no extension class loader then the bootstrap class loader is used.
|
|
* Providers are typically installed by placing them in a JAR file on the
|
|
* application class path or in the extension directory, the JAR file contains a
|
|
* provider-configuration file named {@code java.nio.file.spi.FileSystemProvider}
|
|
* in the resource directory {@code META-INF/services}, and the file lists one or
|
|
* more fully-qualified names of concrete subclass of {@link FileSystemProvider}
|
|
* that have a zero argument constructor.
|
|
* The ordering that installed providers are located is implementation specific.
|
|
* If a provider is instantiated and its {@link FileSystemProvider#getScheme()
|
|
* getScheme} returns the same URI scheme of a provider that was previously
|
|
* instantiated then the most recently instantiated duplicate is discarded. URI
|
|
* schemes are compared without regard to case. During construction a provider
|
|
* may safely access files associated with the default provider but care needs
|
|
* to be taken to avoid circular loading of other installed providers. If
|
|
* circular loading of installed providers is detected then an unspecified error
|
|
* is thrown.
|
|
*
|
|
* <p> This class also defines factory methods that allow a {@link ClassLoader}
|
|
* to be specified when locating a provider. As with installed providers, the
|
|
* provider classes are identified by placing the provider configuration file
|
|
* in the resource directory {@code META-INF/services}.
|
|
*
|
|
* <p> If a thread initiates the loading of the installed file system providers
|
|
* and another thread invokes a method that also attempts to load the providers
|
|
* then the method will block until the loading completes.
|
|
*
|
|
* @since 1.7
|
|
*/
|
|
|
|
public final class FileSystems {
|
|
private FileSystems() {
|
|
}
|
|
|
|
// lazy initialization of default file system
|
|
private static class DefaultFileSystemHolder {
|
|
static final FileSystem defaultFileSystem = defaultFileSystem();
|
|
|
|
// returns default file system
|
|
private static FileSystem defaultFileSystem() {
|
|
// load default provider
|
|
FileSystemProvider provider = AccessController
|
|
.doPrivileged(new PrivilegedAction<FileSystemProvider>() {
|
|
public FileSystemProvider run() {
|
|
return getDefaultProvider();
|
|
}
|
|
});
|
|
|
|
// return file system
|
|
return provider.getFileSystem(URI.create("file:///"));
|
|
}
|
|
|
|
// returns default provider
|
|
private static FileSystemProvider getDefaultProvider() {
|
|
FileSystemProvider provider = sun.nio.fs.DefaultFileSystemProvider.create();
|
|
|
|
// 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");
|
|
if (propValue != null) {
|
|
for (String cn: propValue.split(",")) {
|
|
try {
|
|
Class<?> c = Class
|
|
.forName(cn, true, ClassLoader.getSystemClassLoader());
|
|
Constructor<?> ctor = c
|
|
.getDeclaredConstructor(FileSystemProvider.class);
|
|
provider = (FileSystemProvider)ctor.newInstance(provider);
|
|
|
|
// must be "file"
|
|
if (!provider.getScheme().equals("file"))
|
|
throw new Error("Default provider must use scheme 'file'");
|
|
|
|
} catch (Exception x) {
|
|
throw new Error(x);
|
|
}
|
|
}
|
|
}
|
|
return provider;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the default {@code FileSystem}. The default file system creates
|
|
* objects that provide access to the file systems accessible to the Java
|
|
* virtual machine. The <em>working directory</em> of the file system is
|
|
* the current user directory, named by the system property {@code user.dir}.
|
|
* This allows for interoperability with the {@link java.io.File java.io.File}
|
|
* class.
|
|
*
|
|
* <p> The first invocation of any of the methods defined by this class
|
|
* locates the default {@link FileSystemProvider provider} object. Where the
|
|
* system property {@code java.nio.file.spi.DefaultFileSystemProvider} is
|
|
* not defined then the default provider is a system-default provider that
|
|
* is invoked to create the default file system.
|
|
*
|
|
* <p> If the system property {@code java.nio.file.spi.DefaultFileSystemProvider}
|
|
* is defined then it is taken to be a list of one or more fully-qualified
|
|
* names of concrete provider classes identified by the URI scheme
|
|
* {@code "file"}. Where the property is a list of more than one name then
|
|
* the names are separated by a comma. Each class is loaded, using the system
|
|
* class loader, and instantiated by invoking a one argument constructor
|
|
* whose formal parameter type is {@code FileSystemProvider}. The providers
|
|
* are loaded and instantiated in the order they are listed in the property.
|
|
* If this process fails or a provider's scheme is not equal to {@code "file"}
|
|
* then an unspecified error is thrown. URI schemes are normally compared
|
|
* without regard to case but for the default provider, the scheme is
|
|
* required to be {@code "file"}. The first provider class is instantiated
|
|
* by invoking it with a reference to the system-default provider.
|
|
* The second provider class is instantiated by invoking it with a reference
|
|
* to the first provider instance. The third provider class is instantiated
|
|
* by invoking it with a reference to the second instance, and so on. The
|
|
* last provider to be instantiated becomes the default provider; its {@code
|
|
* getFileSystem} method is invoked with the URI {@code "file:///"} to
|
|
* get a reference to the default file system.
|
|
*
|
|
* <p> Subsequent invocations of this method return the file system that was
|
|
* returned by the first invocation.
|
|
*
|
|
* @return the default file system
|
|
*/
|
|
public static FileSystem getDefault() {
|
|
return DefaultFileSystemHolder.defaultFileSystem;
|
|
}
|
|
|
|
/**
|
|
* Returns a reference to an existing {@code FileSystem}.
|
|
*
|
|
* <p> This method iterates over the {@link FileSystemProvider#installedProviders()
|
|
* installed} providers to locate the provider that is identified by the URI
|
|
* {@link URI#getScheme scheme} of the given URI. URI schemes are compared
|
|
* without regard to case. The exact form of the URI is highly provider
|
|
* dependent. If found, the provider's {@link FileSystemProvider#getFileSystem
|
|
* getFileSystem} method is invoked to obtain a reference to the {@code
|
|
* FileSystem}.
|
|
*
|
|
* <p> Once a file system created by this provider is {@link FileSystem#close
|
|
* closed} it is provider-dependent if this method returns a reference to
|
|
* the closed file system or throws {@link FileSystemNotFoundException}.
|
|
* If the provider allows a new file system to be created with the same URI
|
|
* as a file system it previously created then this method throws the
|
|
* exception if invoked after the file system is closed (and before a new
|
|
* instance is created by the {@link #newFileSystem newFileSystem} method).
|
|
*
|
|
* <p> If a security manager is installed then a provider implementation
|
|
* may require to check a permission before returning a reference to an
|
|
* existing file system. In the case of the {@link FileSystems#getDefault
|
|
* default} file system, no permission check is required.
|
|
*
|
|
* @param uri the URI to locate the file system
|
|
*
|
|
* @return the reference to the file system
|
|
*
|
|
* @throws IllegalArgumentException
|
|
* if the pre-conditions for the {@code uri} parameter are not met
|
|
* @throws FileSystemNotFoundException
|
|
* if the file system, identified by the URI, does not exist
|
|
* @throws ProviderNotFoundException
|
|
* if a provider supporting the URI scheme is not installed
|
|
* @throws SecurityException
|
|
* if a security manager is installed and it denies an unspecified
|
|
* permission
|
|
*/
|
|
public static FileSystem getFileSystem(URI uri) {
|
|
String scheme = uri.getScheme();
|
|
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
|
|
if (scheme.equalsIgnoreCase(provider.getScheme())) {
|
|
return provider.getFileSystem(uri);
|
|
}
|
|
}
|
|
throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
|
|
}
|
|
|
|
/**
|
|
* Constructs a new file system that is identified by a {@link URI}
|
|
*
|
|
* <p> This method iterates over the {@link FileSystemProvider#installedProviders()
|
|
* installed} providers to locate the provider that is identified by the URI
|
|
* {@link URI#getScheme scheme} of the given URI. URI schemes are compared
|
|
* without regard to case. The exact form of the URI is highly provider
|
|
* dependent. If found, the provider's {@link FileSystemProvider#newFileSystem(URI,Map)
|
|
* newFileSystem(URI,Map)} method is invoked to construct the new file system.
|
|
*
|
|
* <p> Once a file system is {@link FileSystem#close closed} it is
|
|
* provider-dependent if the provider allows a new file system to be created
|
|
* with the same URI as a file system it previously created.
|
|
*
|
|
* <p> <b>Usage Example:</b>
|
|
* Suppose there is a provider identified by the scheme {@code "memory"}
|
|
* installed:
|
|
* <pre>
|
|
* Map<String,String> env = new HashMap<>();
|
|
* env.put("capacity", "16G");
|
|
* env.put("blockSize", "4k");
|
|
* FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
|
|
* </pre>
|
|
*
|
|
* @param uri
|
|
* the URI identifying the file system
|
|
* @param env
|
|
* a map of provider specific properties to configure the file system;
|
|
* may be empty
|
|
*
|
|
* @return a new file system
|
|
*
|
|
* @throws IllegalArgumentException
|
|
* if the pre-conditions for the {@code uri} parameter are not met,
|
|
* or the {@code env} parameter does not contain properties required
|
|
* by the provider, or a property value is invalid
|
|
* @throws FileSystemAlreadyExistsException
|
|
* if the file system has already been created
|
|
* @throws ProviderNotFoundException
|
|
* if a provider supporting the URI scheme is not installed
|
|
* @throws IOException
|
|
* if an I/O error occurs creating the file system
|
|
* @throws SecurityException
|
|
* if a security manager is installed and it denies an unspecified
|
|
* permission required by the file system provider implementation
|
|
*/
|
|
public static FileSystem newFileSystem(URI uri, Map<String,?> env)
|
|
throws IOException
|
|
{
|
|
return newFileSystem(uri, env, null);
|
|
}
|
|
|
|
/**
|
|
* Constructs a new file system that is identified by a {@link URI}
|
|
*
|
|
* <p> This method first attempts to locate an installed provider in exactly
|
|
* the same manner as the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)}
|
|
* method. If none of the installed providers support the URI scheme then an
|
|
* attempt is made to locate the provider using the given class loader. If a
|
|
* provider supporting the URI scheme is located then its {@link
|
|
* FileSystemProvider#newFileSystem(URI,Map) newFileSystem(URI,Map)} is
|
|
* invoked to construct the new file system.
|
|
*
|
|
* @param uri
|
|
* the URI identifying the file system
|
|
* @param env
|
|
* a map of provider specific properties to configure the file system;
|
|
* may be empty
|
|
* @param loader
|
|
* the class loader to locate the provider or {@code null} to only
|
|
* attempt to locate an installed provider
|
|
*
|
|
* @return a new file system
|
|
*
|
|
* @throws IllegalArgumentException
|
|
* if the pre-conditions for the {@code uri} parameter are not met,
|
|
* or the {@code env} parameter does not contain properties required
|
|
* by the provider, or a property value is invalid
|
|
* @throws FileSystemAlreadyExistsException
|
|
* if the URI scheme identifies an installed provider and the file
|
|
* system has already been created
|
|
* @throws ProviderNotFoundException
|
|
* if a provider supporting the URI scheme is not found
|
|
* @throws ServiceConfigurationError
|
|
* when an error occurs while loading a service provider
|
|
* @throws IOException
|
|
* an I/O error occurs creating the file system
|
|
* @throws SecurityException
|
|
* if a security manager is installed and it denies an unspecified
|
|
* permission required by the file system provider implementation
|
|
*/
|
|
public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader)
|
|
throws IOException
|
|
{
|
|
String scheme = uri.getScheme();
|
|
|
|
// check installed providers
|
|
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
|
|
if (scheme.equalsIgnoreCase(provider.getScheme())) {
|
|
return provider.newFileSystem(uri, env);
|
|
}
|
|
}
|
|
|
|
// if not found, use service-provider loading facility
|
|
if (loader != null) {
|
|
ServiceLoader<FileSystemProvider> sl = ServiceLoader
|
|
.load(FileSystemProvider.class, loader);
|
|
for (FileSystemProvider provider: sl) {
|
|
if (scheme.equalsIgnoreCase(provider.getScheme())) {
|
|
return provider.newFileSystem(uri, env);
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
|
|
}
|
|
|
|
/**
|
|
* Constructs a new {@code FileSystem} to access the contents of a file as a
|
|
* file system.
|
|
*
|
|
* <p> This method makes use of specialized providers that create pseudo file
|
|
* systems where the contents of one or more files is treated as a file
|
|
* system.
|
|
*
|
|
* <p> This method iterates over the {@link FileSystemProvider#installedProviders()
|
|
* installed} providers. It invokes, in turn, each provider's {@link
|
|
* FileSystemProvider#newFileSystem(Path,Map) newFileSystem(Path,Map)} method
|
|
* with an empty map. If a provider returns a file system then the iteration
|
|
* terminates and the file system is returned. If none of the installed
|
|
* providers return a {@code FileSystem} then an attempt is made to locate
|
|
* the provider using the given class loader. If a provider returns a file
|
|
* system then the lookup terminates and the file system is returned.
|
|
*
|
|
* @param path
|
|
* the path to the file
|
|
* @param loader
|
|
* the class loader to locate the provider or {@code null} to only
|
|
* attempt to locate an installed provider
|
|
*
|
|
* @return a new file system
|
|
*
|
|
* @throws ProviderNotFoundException
|
|
* if a provider supporting this file type cannot be located
|
|
* @throws ServiceConfigurationError
|
|
* when an error occurs while loading a service provider
|
|
* @throws IOException
|
|
* if an I/O error occurs
|
|
* @throws SecurityException
|
|
* if a security manager is installed and it denies an unspecified
|
|
* permission
|
|
*/
|
|
public static FileSystem newFileSystem(Path path,
|
|
ClassLoader loader)
|
|
throws IOException
|
|
{
|
|
if (path == null)
|
|
throw new NullPointerException();
|
|
Map<String,?> env = Collections.emptyMap();
|
|
|
|
// check installed providers
|
|
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
|
|
try {
|
|
return provider.newFileSystem(path, env);
|
|
} catch (UnsupportedOperationException uoe) {
|
|
}
|
|
}
|
|
|
|
// if not found, use service-provider loading facility
|
|
if (loader != null) {
|
|
ServiceLoader<FileSystemProvider> sl = ServiceLoader
|
|
.load(FileSystemProvider.class, loader);
|
|
for (FileSystemProvider provider: sl) {
|
|
try {
|
|
return provider.newFileSystem(path, env);
|
|
} catch (UnsupportedOperationException uoe) {
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new ProviderNotFoundException("Provider not found");
|
|
}
|
|
}
|