|
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<String,String> env = new HashMap<String,String>(); |
|
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 } |