Home | History | Annotate | Download | only in file
      1 /*
      2  * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package java.nio.file;
     27 
     28 import java.nio.file.spi.FileSystemProvider;
     29 import java.net.URI;
     30 import java.io.IOException;
     31 import java.security.AccessController;
     32 import java.security.PrivilegedAction;
     33 import java.util.*;
     34 import java.lang.reflect.Constructor;
     35 
     36 /**
     37  * Factory methods for file systems. This class defines the {@link #getDefault
     38  * getDefault} method to get the default file system and factory methods to
     39  * construct other types of file systems.
     40  *
     41  * <p> The first invocation of any of the methods defined by this class causes
     42  * the default {@link FileSystemProvider provider} to be loaded. The default
     43  * provider, identified by the URI scheme "file", creates the {@link FileSystem}
     44  * that provides access to the file systems accessible to the Java virtual
     45  * machine. If the process of loading or initializing the default provider fails
     46  * then an unspecified error is thrown.
     47  *
     48  * <p> The first invocation of the {@link FileSystemProvider#installedProviders
     49  * installedProviders} method, by way of invoking any of the {@code
     50  * newFileSystem} methods defined by this class, locates and loads all
     51  * installed file system providers. Installed providers are loaded using the
     52  * service-provider loading facility defined by the {@link ServiceLoader} class.
     53  * Installed providers are loaded using the system class loader. If the
     54  * system class loader cannot be found then the extension class loader is used;
     55  * if there is no extension class loader then the bootstrap class loader is used.
     56  * Providers are typically installed by placing them in a JAR file on the
     57  * application class path or in the extension directory, the JAR file contains a
     58  * provider-configuration file named {@code java.nio.file.spi.FileSystemProvider}
     59  * in the resource directory {@code META-INF/services}, and the file lists one or
     60  * more fully-qualified names of concrete subclass of {@link FileSystemProvider}
     61  * that have a zero argument constructor.
     62  * The ordering that installed providers are located is implementation specific.
     63  * If a provider is instantiated and its {@link FileSystemProvider#getScheme()
     64  * getScheme} returns the same URI scheme of a provider that was previously
     65  * instantiated then the most recently instantiated duplicate is discarded. URI
     66  * schemes are compared without regard to case. During construction a provider
     67  * may safely access files associated with the default provider but care needs
     68  * to be taken to avoid circular loading of other installed providers. If
     69  * circular loading of installed providers is detected then an unspecified error
     70  * is thrown.
     71  *
     72  * <p> This class also defines factory methods that allow a {@link ClassLoader}
     73  * to be specified when locating a provider. As with installed providers, the
     74  * provider classes are identified by placing the provider configuration file
     75  * in the resource directory {@code META-INF/services}.
     76  *
     77  * <p> If a thread initiates the loading of the installed file system providers
     78  * and another thread invokes a method that also attempts to load the providers
     79  * then the method will block until the loading completes.
     80  *
     81  * @since 1.7
     82  */
     83 
     84 public final class FileSystems {
     85     private FileSystems() {
     86     }
     87 
     88     // lazy initialization of default file system
     89     private static class DefaultFileSystemHolder {
     90         static final FileSystem defaultFileSystem = defaultFileSystem();
     91 
     92         // returns default file system
     93         private static FileSystem defaultFileSystem() {
     94             // load default provider
     95             FileSystemProvider provider = AccessController
     96                 .doPrivileged(new PrivilegedAction<FileSystemProvider>() {
     97                     public FileSystemProvider run() {
     98                         return getDefaultProvider();
     99                     }
    100                 });
    101 
    102             // return file system
    103             return provider.getFileSystem(URI.create("file:///"));
    104         }
    105 
    106         // returns default provider
    107         private static FileSystemProvider getDefaultProvider() {
    108             FileSystemProvider provider = sun.nio.fs.DefaultFileSystemProvider.create();
    109 
    110             // if the property java.nio.file.spi.DefaultFileSystemProvider is
    111             // set then its value is the name of the default provider (or a list)
    112             String propValue = System
    113                 .getProperty("java.nio.file.spi.DefaultFileSystemProvider");
    114             if (propValue != null) {
    115                 for (String cn: propValue.split(",")) {
    116                     try {
    117                         Class<?> c = Class
    118                             .forName(cn, true, ClassLoader.getSystemClassLoader());
    119                         Constructor<?> ctor = c
    120                             .getDeclaredConstructor(FileSystemProvider.class);
    121                         provider = (FileSystemProvider)ctor.newInstance(provider);
    122 
    123                         // must be "file"
    124                         if (!provider.getScheme().equals("file"))
    125                             throw new Error("Default provider must use scheme 'file'");
    126 
    127                     } catch (Exception x) {
    128                         throw new Error(x);
    129                     }
    130                 }
    131             }
    132             return provider;
    133         }
    134     }
    135 
    136     /**
    137      * Returns the default {@code FileSystem}. The default file system creates
    138      * objects that provide access to the file systems accessible to the Java
    139      * virtual machine. The <em>working directory</em> of the file system is
    140      * the current user directory, named by the system property {@code user.dir}.
    141      * This allows for interoperability with the {@link java.io.File java.io.File}
    142      * class.
    143      *
    144      * <p> The first invocation of any of the methods defined by this class
    145      * locates the default {@link FileSystemProvider provider} object. Where the
    146      * system property {@code java.nio.file.spi.DefaultFileSystemProvider} is
    147      * not defined then the default provider is a system-default provider that
    148      * is invoked to create the default file system.
    149      *
    150      * <p> If the system property {@code java.nio.file.spi.DefaultFileSystemProvider}
    151      * is defined then it is taken to be a list of one or more fully-qualified
    152      * names of concrete provider classes identified by the URI scheme
    153      * {@code "file"}. Where the property is a list of more than one name then
    154      * the names are separated by a comma. Each class is loaded, using the system
    155      * class loader, and instantiated by invoking a one argument constructor
    156      * whose formal parameter type is {@code FileSystemProvider}. The providers
    157      * are loaded and instantiated in the order they are listed in the property.
    158      * If this process fails or a provider's scheme is not equal to {@code "file"}
    159      * then an unspecified error is thrown. URI schemes are normally compared
    160      * without regard to case but for the default provider, the scheme is
    161      * required to be {@code "file"}. The first provider class is instantiated
    162      * by invoking it with a reference to the system-default provider.
    163      * The second provider class is instantiated by invoking it with a reference
    164      * to the first provider instance. The third provider class is instantiated
    165      * by invoking it with a reference to the second instance, and so on. The
    166      * last provider to be instantiated becomes the default provider; its {@code
    167      * getFileSystem} method is invoked with the URI {@code "file:///"} to
    168      * get a reference to the default file system.
    169      *
    170      * <p> Subsequent invocations of this method return the file system that was
    171      * returned by the first invocation.
    172      *
    173      * @return  the default file system
    174      */
    175     public static FileSystem getDefault() {
    176         return DefaultFileSystemHolder.defaultFileSystem;
    177     }
    178 
    179     /**
    180      * Returns a reference to an existing {@code FileSystem}.
    181      *
    182      * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
    183      * installed} providers to locate the provider that is identified by the URI
    184      * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
    185      * without regard to case. The exact form of the URI is highly provider
    186      * dependent. If found, the provider's {@link FileSystemProvider#getFileSystem
    187      * getFileSystem} method is invoked to obtain a reference to the {@code
    188      * FileSystem}.
    189      *
    190      * <p> Once a file system created by this provider is {@link FileSystem#close
    191      * closed} it is provider-dependent if this method returns a reference to
    192      * the closed file system or throws {@link FileSystemNotFoundException}.
    193      * If the provider allows a new file system to be created with the same URI
    194      * as a file system it previously created then this method throws the
    195      * exception if invoked after the file system is closed (and before a new
    196      * instance is created by the {@link #newFileSystem newFileSystem} method).
    197      *
    198      * <p> If a security manager is installed then a provider implementation
    199      * may require to check a permission before returning a reference to an
    200      * existing file system. In the case of the {@link FileSystems#getDefault
    201      * default} file system, no permission check is required.
    202      *
    203      * @param   uri  the URI to locate the file system
    204      *
    205      * @return  the reference to the file system
    206      *
    207      * @throws  IllegalArgumentException
    208      *          if the pre-conditions for the {@code uri} parameter are not met
    209      * @throws  FileSystemNotFoundException
    210      *          if the file system, identified by the URI, does not exist
    211      * @throws  ProviderNotFoundException
    212      *          if a provider supporting the URI scheme is not installed
    213      * @throws  SecurityException
    214      *          if a security manager is installed and it denies an unspecified
    215      *          permission
    216      */
    217     public static FileSystem getFileSystem(URI uri) {
    218         String scheme = uri.getScheme();
    219         for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
    220             if (scheme.equalsIgnoreCase(provider.getScheme())) {
    221                 return provider.getFileSystem(uri);
    222             }
    223         }
    224         throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
    225     }
    226 
    227     /**
    228      * Constructs a new file system that is identified by a {@link URI}
    229      *
    230      * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
    231      * installed} providers to locate the provider that is identified by the URI
    232      * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
    233      * without regard to case. The exact form of the URI is highly provider
    234      * dependent. If found, the provider's {@link FileSystemProvider#newFileSystem(URI,Map)
    235      * newFileSystem(URI,Map)} method is invoked to construct the new file system.
    236      *
    237      * <p> Once a file system is {@link FileSystem#close closed} it is
    238      * provider-dependent if the provider allows a new file system to be created
    239      * with the same URI as a file system it previously created.
    240      *
    241      * <p> <b>Usage Example:</b>
    242      * Suppose there is a provider identified by the scheme {@code "memory"}
    243      * installed:
    244      * <pre>
    245      *   Map&lt;String,String&gt; env = new HashMap&lt;&gt;();
    246      *   env.put("capacity", "16G");
    247      *   env.put("blockSize", "4k");
    248      *   FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
    249      * </pre>
    250      *
    251      * @param   uri
    252      *          the URI identifying the file system
    253      * @param   env
    254      *          a map of provider specific properties to configure the file system;
    255      *          may be empty
    256      *
    257      * @return  a new file system
    258      *
    259      * @throws  IllegalArgumentException
    260      *          if the pre-conditions for the {@code uri} parameter are not met,
    261      *          or the {@code env} parameter does not contain properties required
    262      *          by the provider, or a property value is invalid
    263      * @throws  FileSystemAlreadyExistsException
    264      *          if the file system has already been created
    265      * @throws  ProviderNotFoundException
    266      *          if a provider supporting the URI scheme is not installed
    267      * @throws  IOException
    268      *          if an I/O error occurs creating the file system
    269      * @throws  SecurityException
    270      *          if a security manager is installed and it denies an unspecified
    271      *          permission required by the file system provider implementation
    272      */
    273     public static FileSystem newFileSystem(URI uri, Map<String,?> env)
    274         throws IOException
    275     {
    276         return newFileSystem(uri, env, null);
    277     }
    278 
    279     /**
    280      * Constructs a new file system that is identified by a {@link URI}
    281      *
    282      * <p> This method first attempts to locate an installed provider in exactly
    283      * the same manner as the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)}
    284      * method. If none of the installed providers support the URI scheme then an
    285      * attempt is made to locate the provider using the given class loader. If a
    286      * provider supporting the URI scheme is located then its {@link
    287      * FileSystemProvider#newFileSystem(URI,Map) newFileSystem(URI,Map)} is
    288      * invoked to construct the new file system.
    289      *
    290      * @param   uri
    291      *          the URI identifying the file system
    292      * @param   env
    293      *          a map of provider specific properties to configure the file system;
    294      *          may be empty
    295      * @param   loader
    296      *          the class loader to locate the provider or {@code null} to only
    297      *          attempt to locate an installed provider
    298      *
    299      * @return  a new file system
    300      *
    301      * @throws  IllegalArgumentException
    302      *          if the pre-conditions for the {@code uri} parameter are not met,
    303      *          or the {@code env} parameter does not contain properties required
    304      *          by the provider, or a property value is invalid
    305      * @throws  FileSystemAlreadyExistsException
    306      *          if the URI scheme identifies an installed provider and the file
    307      *          system has already been created
    308      * @throws  ProviderNotFoundException
    309      *          if a provider supporting the URI scheme is not found
    310      * @throws  ServiceConfigurationError
    311      *          when an error occurs while loading a service provider
    312      * @throws  IOException
    313      *          an I/O error occurs creating the file system
    314      * @throws  SecurityException
    315      *          if a security manager is installed and it denies an unspecified
    316      *          permission required by the file system provider implementation
    317      */
    318     public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader)
    319         throws IOException
    320     {
    321         String scheme = uri.getScheme();
    322 
    323         // check installed providers
    324         for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
    325             if (scheme.equalsIgnoreCase(provider.getScheme())) {
    326                 return provider.newFileSystem(uri, env);
    327             }
    328         }
    329 
    330         // if not found, use service-provider loading facility
    331         if (loader != null) {
    332             ServiceLoader<FileSystemProvider> sl = ServiceLoader
    333                 .load(FileSystemProvider.class, loader);
    334             for (FileSystemProvider provider: sl) {
    335                 if (scheme.equalsIgnoreCase(provider.getScheme())) {
    336                     return provider.newFileSystem(uri, env);
    337                 }
    338             }
    339         }
    340 
    341         throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
    342     }
    343 
    344     /**
    345      * Constructs a new {@code FileSystem} to access the contents of a file as a
    346      * file system.
    347      *
    348      * <p> This method makes use of specialized providers that create pseudo file
    349      * systems where the contents of one or more files is treated as a file
    350      * system.
    351      *
    352      * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
    353      * installed} providers. It invokes, in turn, each provider's {@link
    354      * FileSystemProvider#newFileSystem(Path,Map) newFileSystem(Path,Map)} method
    355      * with an empty map. If a provider returns a file system then the iteration
    356      * terminates and the file system is returned. If none of the installed
    357      * providers return a {@code FileSystem} then an attempt is made to locate
    358      * the provider using the given class loader. If a provider returns a file
    359      * system then the lookup terminates and the file system is returned.
    360      *
    361      * @param   path
    362      *          the path to the file
    363      * @param   loader
    364      *          the class loader to locate the provider or {@code null} to only
    365      *          attempt to locate an installed provider
    366      *
    367      * @return  a new file system
    368      *
    369      * @throws  ProviderNotFoundException
    370      *          if a provider supporting this file type cannot be located
    371      * @throws  ServiceConfigurationError
    372      *          when an error occurs while loading a service provider
    373      * @throws  IOException
    374      *          if an I/O error occurs
    375      * @throws  SecurityException
    376      *          if a security manager is installed and it denies an unspecified
    377      *          permission
    378      */
    379     public static FileSystem newFileSystem(Path path,
    380                                            ClassLoader loader)
    381         throws IOException
    382     {
    383         if (path == null)
    384             throw new NullPointerException();
    385         Map<String,?> env = Collections.emptyMap();
    386 
    387         // check installed providers
    388         for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
    389             try {
    390                 return provider.newFileSystem(path, env);
    391             } catch (UnsupportedOperationException uoe) {
    392             }
    393         }
    394 
    395         // if not found, use service-provider loading facility
    396         if (loader != null) {
    397             ServiceLoader<FileSystemProvider> sl = ServiceLoader
    398                 .load(FileSystemProvider.class, loader);
    399             for (FileSystemProvider provider: sl) {
    400                 try {
    401                     return provider.newFileSystem(path, env);
    402                 } catch (UnsupportedOperationException uoe) {
    403                 }
    404             }
    405         }
    406 
    407         throw new ProviderNotFoundException("Provider not found");
    408     }
    409 }
    410