FileSystems.java revision 11805:98ce6490ceff
1217739Sadrian/*
2217739Sadrian * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
3217739Sadrian * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4217739Sadrian *
5217739Sadrian * This code is free software; you can redistribute it and/or modify it
6217739Sadrian * under the terms of the GNU General Public License version 2 only, as
7217739Sadrian * published by the Free Software Foundation.  Oracle designates this
8217739Sadrian * particular file as subject to the "Classpath" exception as provided
9217739Sadrian * by Oracle in the LICENSE file that accompanied this code.
10217739Sadrian *
11217739Sadrian * This code is distributed in the hope that it will be useful, but WITHOUT
12217739Sadrian * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13217739Sadrian * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14217739Sadrian * version 2 for more details (a copy is included in the LICENSE file that
15217739Sadrian * accompanied this code).
16217739Sadrian *
17217739Sadrian * You should have received a copy of the GNU General Public License version
18217739Sadrian * 2 along with this work; if not, write to the Free Software Foundation,
19217739Sadrian * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20217739Sadrian *
21217739Sadrian * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22217739Sadrian * or visit www.oracle.com if you need additional information or have any
23217739Sadrian * questions.
24217739Sadrian */
25217739Sadrian
26217739Sadrianpackage java.nio.file;
27217739Sadrian
28217739Sadrianimport java.nio.file.spi.FileSystemProvider;
29217739Sadrianimport java.net.URI;
30217739Sadrianimport java.io.IOException;
31217739Sadrianimport java.security.AccessController;
32217739Sadrianimport java.security.PrivilegedAction;
33217739Sadrianimport java.util.*;
34217739Sadrianimport java.lang.reflect.Constructor;
35217739Sadrian
36217739Sadrian/**
37217739Sadrian * Factory methods for file systems. This class defines the {@link #getDefault
38217739Sadrian * getDefault} method to get the default file system and factory methods to
39217739Sadrian * construct other types of file systems.
40217739Sadrian *
41217739Sadrian * <p> The first invocation of any of the methods defined by this class causes
42217739Sadrian * the default {@link FileSystemProvider provider} to be loaded. The default
43217739Sadrian * provider, identified by the URI scheme "file", creates the {@link FileSystem}
44217739Sadrian * that provides access to the file systems accessible to the Java virtual
45217739Sadrian * machine. If the process of loading or initializing the default provider fails
46217739Sadrian * then an unspecified error is thrown.
47217739Sadrian *
48217739Sadrian * <p> The first invocation of the {@link FileSystemProvider#installedProviders
49217739Sadrian * installedProviders} method, by way of invoking any of the {@code
50217739Sadrian * newFileSystem} methods defined by this class, locates and loads all
51217739Sadrian * installed file system providers. Installed providers are loaded using the
52217739Sadrian * service-provider loading facility defined by the {@link ServiceLoader} class.
53217739Sadrian * Installed providers are loaded using the system class loader. If the
54217739Sadrian * system class loader cannot be found then the extension class loader is used;
55217739Sadrian * if there is no extension class loader then the bootstrap class loader is used.
56217739Sadrian * Providers are typically installed by placing them in a JAR file on the
57217739Sadrian * application class path, the JAR file contains a
58217739Sadrian * provider-configuration file named {@code java.nio.file.spi.FileSystemProvider}
59217739Sadrian * in the resource directory {@code META-INF/services}, and the file lists one or
60217739Sadrian * more fully-qualified names of concrete subclass of {@link FileSystemProvider}
61217739Sadrian * that have a zero argument constructor.
62217739Sadrian * The ordering that installed providers are located is implementation specific.
63217739Sadrian * If a provider is instantiated and its {@link FileSystemProvider#getScheme()
64217739Sadrian * getScheme} returns the same URI scheme of a provider that was previously
65217739Sadrian * instantiated then the most recently instantiated duplicate is discarded. URI
66217739Sadrian * schemes are compared without regard to case. During construction a provider
67217739Sadrian * may safely access files associated with the default provider but care needs
68217739Sadrian * to be taken to avoid circular loading of other installed providers. If
69217739Sadrian * circular loading of installed providers is detected then an unspecified error
70217739Sadrian * is thrown.
71217739Sadrian *
72217739Sadrian * <p> This class also defines factory methods that allow a {@link ClassLoader}
73217739Sadrian * to be specified when locating a provider. As with installed providers, the
74217739Sadrian * provider classes are identified by placing the provider configuration file
75217739Sadrian * in the resource directory {@code META-INF/services}.
76217739Sadrian *
77217739Sadrian * <p> If a thread initiates the loading of the installed file system providers
78217739Sadrian * and another thread invokes a method that also attempts to load the providers
79217739Sadrian * then the method will block until the loading completes.
80217739Sadrian *
81217739Sadrian * @since 1.7
82217739Sadrian */
83217739Sadrian
84217739Sadrianpublic final class FileSystems {
85217739Sadrian    private FileSystems() {
86217739Sadrian    }
87217739Sadrian
88217739Sadrian    // lazy initialization of default file system
89217739Sadrian    private static class DefaultFileSystemHolder {
90217739Sadrian        static final FileSystem defaultFileSystem = defaultFileSystem();
91217739Sadrian
92217739Sadrian        // returns default file system
93217739Sadrian        private static FileSystem defaultFileSystem() {
94217739Sadrian            // load default provider
95217739Sadrian            FileSystemProvider provider = AccessController
96217739Sadrian                .doPrivileged(new PrivilegedAction<>() {
97217739Sadrian                    public FileSystemProvider run() {
98217739Sadrian                        return getDefaultProvider();
99217739Sadrian                    }
100217739Sadrian                });
101217739Sadrian
102217739Sadrian            // return file system
103217739Sadrian            return provider.getFileSystem(URI.create("file:///"));
104217739Sadrian        }
105217739Sadrian
106217739Sadrian        // returns default provider
107217739Sadrian        private static FileSystemProvider getDefaultProvider() {
108217739Sadrian            FileSystemProvider provider = sun.nio.fs.DefaultFileSystemProvider.create();
109217739Sadrian
110217739Sadrian            // if the property java.nio.file.spi.DefaultFileSystemProvider is
111217739Sadrian            // set then its value is the name of the default provider (or a list)
112217739Sadrian            String propValue = System
113217739Sadrian                .getProperty("java.nio.file.spi.DefaultFileSystemProvider");
114217739Sadrian            if (propValue != null) {
115217739Sadrian                for (String cn: propValue.split(",")) {
116217739Sadrian                    try {
117217739Sadrian                        Class<?> c = Class
118217739Sadrian                            .forName(cn, true, ClassLoader.getSystemClassLoader());
119217739Sadrian                        Constructor<?> ctor = c
120217739Sadrian                            .getDeclaredConstructor(FileSystemProvider.class);
121217739Sadrian                        provider = (FileSystemProvider)ctor.newInstance(provider);
122217739Sadrian
123217739Sadrian                        // must be "file"
124217739Sadrian                        if (!provider.getScheme().equals("file"))
125217739Sadrian                            throw new Error("Default provider must use scheme 'file'");
126244969Sadrian
127217739Sadrian                    } catch (Exception x) {
128217739Sadrian                        throw new Error(x);
129217739Sadrian                    }
130217739Sadrian                }
131217739Sadrian            }
132217739Sadrian            return provider;
133217739Sadrian        }
134217739Sadrian    }
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