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 {
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
defaultFileSystem()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
getDefaultProvider()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      */
getDefault()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      */
getFileSystem(URI uri)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      */
newFileSystem(URI uri, Map<String,?> env)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      */
newFileSystem(URI uri, Map<String,?> env, ClassLoader loader)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      */
newFileSystem(Path path, ClassLoader loader)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