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