jdk/src/share/classes/java/nio/file/FileSystems.java
changeset 2057 3acf8e5e2ca0
child 2072 80dfe4469bbd
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any 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 create
       
   168      * 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      * @throws  IllegalArgumentException
       
   204      *          If the pre-conditions for the {@code uri} parameter aren't met
       
   205      * @throws  FileSystemNotFoundException
       
   206      *          If the file system, identified by the URI, does not exist
       
   207      * @throws  ProviderNotFoundException
       
   208      *          If a provider supporting the URI scheme is not installed
       
   209      * @throws  SecurityException
       
   210      *          If a security manager is installed and it denies an unspecified
       
   211      *          permission.
       
   212      */
       
   213     public static FileSystem getFileSystem(URI uri) {
       
   214         String scheme = uri.getScheme();
       
   215         for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
       
   216             if (scheme.equalsIgnoreCase(provider.getScheme())) {
       
   217                 return provider.getFileSystem(uri);
       
   218             }
       
   219         }
       
   220         throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
       
   221     }
       
   222 
       
   223     /**
       
   224      * Constructs a new file system that is identified by a {@link URI}
       
   225      *
       
   226      * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
       
   227      * installed} providers to locate the provider that is identified by the URI
       
   228      * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
       
   229      * without regard to case. The exact form of the URI is highly provider
       
   230      * dependent. If found, the provider's {@link FileSystemProvider#newFileSystem(URI,Map)
       
   231      * newFileSystem(URI,Map)} method is invoked to construct the new file system.
       
   232      *
       
   233      * <p> Once a file system is {@link FileSystem#close closed} it is
       
   234      * provider-dependent if the provider allows a new file system to be created
       
   235      * with the same URI as a file system it previously created.
       
   236      *
       
   237      * <p> <b>Usage Example:</b>
       
   238      * Suppose there is a provider identified by the scheme {@code "memory"}
       
   239      * installed:
       
   240      * <pre>
       
   241      *   Map&lt;String,String&gt; env = new HashMap&lt;String,String&gt;();
       
   242      *   env.put("capacity", "16G");
       
   243      *   env.put("blockSize", "4k");
       
   244      *   FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
       
   245      * </pre>
       
   246      *
       
   247      * @param   uri
       
   248      *          The URI identifying the file system
       
   249      * @param   env
       
   250      *          A map of provider specific properties to configure the file system;
       
   251      *          may be empty
       
   252      *
       
   253      * @return  A new file system
       
   254      *
       
   255      * @throws  IllegalArgumentException
       
   256      *          If the pre-conditions for the {@code uri} parameter aren't met,
       
   257      *          or the {@code env} parameter does not contain properties required
       
   258      *          by the provider, or a property value is invalid
       
   259      * @throws  FileSystemAlreadyExistsException
       
   260      *          If the file system has already been created
       
   261      * @throws  ProviderNotFoundException
       
   262      *          If a provider supporting the URI scheme is not installed
       
   263      * @throws  IOException
       
   264      *          An I/O error occurs creating the file system
       
   265      * @throws  SecurityException
       
   266      *          If a security manager is installed and it denies an unspecified
       
   267      *          permission required by the file system provider implementation
       
   268      */
       
   269     public static FileSystem newFileSystem(URI uri, Map<String,?> env)
       
   270         throws IOException
       
   271     {
       
   272         return newFileSystem(uri, env, null);
       
   273     }
       
   274 
       
   275     /**
       
   276      * Constructs a new file system that is identified by a {@link URI}
       
   277      *
       
   278      * <p> This method first attempts to locate an installed provider in exactly
       
   279      * the same manner as the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)}
       
   280      * method. If none of the installed providers support the URI scheme then an
       
   281      * attempt is made to locate the provider using the given class loader. If a
       
   282      * provider supporting the URI scheme is located then its {@link
       
   283      * FileSystemProvider#newFileSystem(URI,Map) newFileSystem(URI,Map)} is
       
   284      * invoked to construct the new file system.
       
   285      *
       
   286      * @param   uri
       
   287      *          The URI identifying the file system
       
   288      * @param   env
       
   289      *          A map of provider specific properties to configure the file system;
       
   290      *          may be empty
       
   291      * @param   loader
       
   292      *          The class loader to locate the provider or {@code null} to only
       
   293      *          attempt to locate an installed provider
       
   294      *
       
   295      * @return  A new file system
       
   296      *
       
   297      * @throws  IllegalArgumentException
       
   298      *          If the pre-conditions for the {@code uri} parameter aren't met,
       
   299      *          or the {@code env} parameter does not contain properties required
       
   300      *          by the provider, or a property value is invalid
       
   301      * @throws  FileSystemAlreadyExistsException
       
   302      *          If the URI scheme identifies an installed provider and the file
       
   303      *          system has already been created
       
   304      * @throws  ProviderNotFoundException
       
   305      *          If a provider supporting the URI scheme is not found
       
   306      * @throws  ServiceConfigurationError
       
   307      *          When an error occurs while loading a service provider
       
   308      * @throws  IOException
       
   309      *          An I/O error occurs creating the file system
       
   310      * @throws  SecurityException
       
   311      *          If a security manager is installed and it denies an unspecified
       
   312      *          permission required by the file system provider implementation
       
   313      */
       
   314     public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader)
       
   315         throws IOException
       
   316     {
       
   317         String scheme = uri.getScheme();
       
   318 
       
   319         // check installed providers
       
   320         for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
       
   321             if (scheme.equalsIgnoreCase(provider.getScheme())) {
       
   322                 return provider.newFileSystem(uri, env);
       
   323             }
       
   324         }
       
   325 
       
   326         // if not found, use service-provider loading facility
       
   327         if (loader != null) {
       
   328             ServiceLoader<FileSystemProvider> sl = ServiceLoader
       
   329                 .load(FileSystemProvider.class, loader);
       
   330             for (FileSystemProvider provider: sl) {
       
   331                 if (scheme.equalsIgnoreCase(provider.getScheme())) {
       
   332                     return provider.newFileSystem(uri, env);
       
   333                 }
       
   334             }
       
   335         }
       
   336 
       
   337         throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
       
   338     }
       
   339 
       
   340     /**
       
   341      * Constructs a new {@code FileSystem} to access the contents of a file as a
       
   342      * file system.
       
   343      *
       
   344      * <p> This method makes use of specialized providers that create pseudo file
       
   345      * systems where the contents of one or more files is treated as a file
       
   346      * system. The {@code file} parameter is a reference to an existing file
       
   347      * and the {@code env} parameter is a map of provider specific properties to
       
   348      * configure the file system.
       
   349      *
       
   350      * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
       
   351      * installed} providers. It invokes, in turn, each provider's {@link
       
   352      * FileSystemProvider#newFileSystem(FileRef,Map) newFileSystem(FileRef,Map)} method.
       
   353      * If a provider returns a file system then the iteration terminates
       
   354      * and the file system is returned. If none of the installed providers return
       
   355      * a {@code FileSystem} then an attempt is made to locate the provider using
       
   356      * the given class loader. If a provider returns a file system then the lookup
       
   357      * terminates and the file system is returned.
       
   358      *
       
   359      * @param   file
       
   360      *          A reference to a file
       
   361      * @param   env
       
   362      *          A map of provider specific properties to configure the file system;
       
   363      *          may be empty
       
   364      * @param   loader
       
   365      *          The class loader to locate the provider or {@code null} to only
       
   366      *          attempt to locate an installed provider
       
   367      *
       
   368      * @return  A new file system
       
   369      *
       
   370      * @throws  IllegalArgumentException
       
   371      *          If the {@code env} parameter does not contain properties required
       
   372      *          by the provider, or a property value is invalid
       
   373      * @throws  ProviderNotFoundException
       
   374      *          If a provider supporting this file type cannot be located
       
   375      * @throws  ServiceConfigurationError
       
   376      *          When an error occurs while loading a service provider
       
   377      * @throws  IOException
       
   378      *          If an I/O error occurs
       
   379      * @throws  SecurityException
       
   380      *          If a security manager is installed and it denies an unspecified
       
   381      *          permission.
       
   382      */
       
   383     public static FileSystem newFileSystem(FileRef file,
       
   384                                            Map<String,?> env,
       
   385                                            ClassLoader loader)
       
   386         throws IOException
       
   387     {
       
   388         if (file == null)
       
   389             throw new NullPointerException();
       
   390 
       
   391         // check installed providers
       
   392         for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
       
   393             try {
       
   394                 return provider.newFileSystem(file, env);
       
   395             } catch (UnsupportedOperationException uoe) {
       
   396             }
       
   397         }
       
   398 
       
   399         // if not found, use service-provider loading facility
       
   400         if (loader != null) {
       
   401             ServiceLoader<FileSystemProvider> sl = ServiceLoader
       
   402                 .load(FileSystemProvider.class, loader);
       
   403             for (FileSystemProvider provider: sl) {
       
   404                 try {
       
   405                     return provider.newFileSystem(file, env);
       
   406                 } catch (UnsupportedOperationException uoe) {
       
   407                 }
       
   408             }
       
   409         }
       
   410 
       
   411         throw new ProviderNotFoundException("Provider not found");
       
   412     }
       
   413 }