1 /*
   2  * Copyright (c) 2007, 2009, 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.spi;
  27 
  28 import java.nio.file.*;
  29 import java.nio.file.attribute.FileAttribute;
  30 import java.nio.channels.*;
  31 import java.net.URI;
  32 import java.util.*;
  33 import java.util.concurrent.ExecutorService;
  34 import java.security.AccessController;
  35 import java.security.PrivilegedAction;
  36 import java.io.IOException;
  37 
  38 /**
  39  * Service-provider class for file systems.
  40  *
  41  * <p> A file system provider is a concrete implementation of this class that
  42  * implements the abstract methods defined by this class. A provider is
  43  * identified by a {@code URI} {@link #getScheme() scheme}. The default provider
  44  * is identified by the URI scheme "file". It creates the {@link FileSystem} that
  45  * provides access to the file systems accessible to the Java virtual machine.
  46  * The {@link FileSystems} class defines how file system providers are located
  47  * and loaded. The default provider is typically a system-default provider but
  48  * may be overridden if the system property {@code
  49  * java.nio.file.spi.DefaultFileSystemProvider} is set. In that case, the
  50  * provider has a one argument constructor whose formal parameter type is {@code
  51  * FileSystemProvider}. All other providers have a zero argument constructor
  52  * that initializes the provider.
  53  *
  54  * <p> A provider is a factory for one or more {@link FileSystem} instances. Each
  55  * file system is identified by a {@code URI} where the URI's scheme matches
  56  * the provider's {@link #getScheme scheme}. The default file system, for example,
  57  * is identified by the URI {@code "file:///"}. A memory-based file system,
  58  * for example, may be identified by a URI such as {@code "memory:///?name=logfs"}.
  59  * The {@link #newFileSystem newFileSystem} method may be used to create a file
  60  * system, and the {@link #getFileSystem getFileSystem} method may be used to
  61  * obtain a reference to an existing file system created by the provider. Where
  62  * a provider is the factory for a single file system then it is provider dependent
  63  * if the file system is created when the provider is initialized, or later when
  64  * the {@code newFileSystem} method is invoked. In the case of the default
  65  * provider, the {@code FileSystem} is created when the provider is initialized.
  66  *
  67  * <p> In addition to file systems, a provider is also a factory for {@link
  68  * FileChannel} and {@link AsynchronousFileChannel} channels. The {@link
  69  * #newFileChannel newFileChannel} and {@link #newAsynchronousFileChannel
  70  * AsynchronousFileChannel} methods are defined to open or create files, returning
  71  * a channel to access the file. These methods are invoked by static factory
  72  * methods defined in the {@link java.nio.channels} package.
  73  *
  74  * <p> All of the methods in this class are safe for use by multiple concurrent
  75  * threads.
  76  *
  77  * @since 1.7
  78  */
  79 
  80 public abstract class FileSystemProvider {
  81     // lock using when loading providers
  82     private static final Object lock = new Object();
  83 
  84     // installed providers
  85     private static volatile List<FileSystemProvider> installedProviders;
  86 
  87     // used to avoid recursive loading of instaled providers
  88     private static boolean loadingProviders  = false;
  89 
  90     private static Void checkPermission() {
  91         SecurityManager sm = System.getSecurityManager();
  92         if (sm != null)
  93             sm.checkPermission(new RuntimePermission("fileSystemProvider"));
  94         return null;
  95     }
  96     private FileSystemProvider(Void ignore) { }
  97 
  98     /**
  99      * Initializes a new instance of this class.
 100      *
 101      * <p> During construction a provider may safely access files associated
 102      * with the default provider but care needs to be taken to avoid circular
 103      * loading of other installed providers. If circular loading of installed
 104      * providers is detected then an unspecified error is thrown.
 105      *
 106      * @throws  SecurityException
 107      *          If a security manager has been installed and it denies
 108      *          {@link RuntimePermission}<tt>("fileSystemProvider")</tt>
 109      */
 110     protected FileSystemProvider() {
 111         this(checkPermission());
 112     }
 113 
 114     // loads all installed providers
 115     private static List<FileSystemProvider> loadInstalledProviders() {
 116         List<FileSystemProvider> list = new ArrayList<FileSystemProvider>();
 117 
 118         ServiceLoader<FileSystemProvider> sl = ServiceLoader
 119             .load(FileSystemProvider.class, ClassLoader.getSystemClassLoader());
 120 
 121         // ServiceConfigurationError may be throw here
 122         for (FileSystemProvider provider: sl) {
 123             String scheme = provider.getScheme();
 124 
 125             // add to list if the provider is not "file" and isn't a duplicate
 126             if (!scheme.equalsIgnoreCase("file")) {
 127                 boolean found = false;
 128                 for (FileSystemProvider p: list) {
 129                     if (p.getScheme().equalsIgnoreCase(scheme)) {
 130                         found = true;
 131                         break;
 132                     }
 133                 }
 134                 if (!found) {
 135                     list.add(provider);
 136                 }
 137             }
 138         }
 139         return list;
 140     }
 141 
 142     /**
 143      * Returns a list of the installed file system providers.
 144      *
 145      * <p> The first invocation of this method causes the default provider to be
 146      * initialized (if not already initialized) and loads any other installed
 147      * providers as described by the {@link FileSystems} class.
 148      *
 149      * @return  An unmodifiable list of the installed file system providers. The
 150      *          list contains at least one element, that is the default file
 151      *          system provider
 152      *
 153      * @throws  ServiceConfigurationError
 154      *          When an error occurs while loading a service provider
 155      */
 156     public static List<FileSystemProvider> installedProviders() {
 157         if (installedProviders == null) {
 158             // ensure default provider is initialized
 159             FileSystemProvider defaultProvider = FileSystems.getDefault().provider();
 160 
 161             synchronized (lock) {
 162                 if (installedProviders == null) {
 163                     if (loadingProviders) {
 164                         throw new Error("Circular loading of installed providers detected");
 165                     }
 166                     loadingProviders = true;
 167 
 168                     List<FileSystemProvider> list = AccessController
 169                         .doPrivileged(new PrivilegedAction<List<FileSystemProvider>>() {
 170                             @Override
 171                             public List<FileSystemProvider> run() {
 172                                 return loadInstalledProviders();
 173                         }});
 174 
 175                     // insert the default provider at the start of the list
 176                     list.add(0, defaultProvider);
 177 
 178                     installedProviders = Collections.unmodifiableList(list);
 179                 }
 180             }
 181         }
 182         return installedProviders;
 183     }
 184 
 185     /**
 186      * Returns the URI scheme that identifies this provider.
 187      *
 188      * @return  The URI scheme
 189      */
 190     public abstract String getScheme();
 191 
 192     /**
 193      * Constructs a new {@code FileSystem} object identified by a URI. This
 194      * method is invoked by the {@link FileSystems#newFileSystem(URI,Map)}
 195      * method to open a new file system identified by a URI.
 196      *
 197      * <p> The {@code uri} parameter is an absolute, hierarchical URI, with a
 198      * scheme equal (without regard to case) to the scheme supported by this
 199      * provider. The exact form of the URI is highly provider dependent. The
 200      * {@code env} parameter is a map of provider specific properties to configure
 201      * the file system.
 202      *
 203      * <p> This method throws {@link FileSystemAlreadyExistsException} if the
 204      * file system already exists because it was previously created by an
 205      * invocation of this method. Once a file system is {@link FileSystem#close
 206      * closed} it is provider-dependent if the provider allows a new file system
 207      * to be created with the same URI as a file system it previously created.
 208      *
 209      * @param   uri
 210      *          URI reference
 211      * @param   env
 212      *          A map of provider specific properties to configure the file system;
 213      *          may be empty
 214      *
 215      * @return  A new file system
 216      *
 217      * @throws  IllegalArgumentException
 218      *          If the pre-conditions for the {@code uri} parameter aren't met,
 219      *          or the {@code env} parameter does not contain properties required
 220      *          by the provider, or a property value is invalid
 221      * @throws  IOException
 222      *          An I/O error occurs creating the file system
 223      * @throws  SecurityException
 224      *          If a security manager is installed and it denies an unspecified
 225      *          permission required by the file system provider implementation
 226      * @throws  FileSystemAlreadyExistsException
 227      *          If the file system has already been created
 228      */
 229     public abstract FileSystem newFileSystem(URI uri, Map<String,?> env)
 230         throws IOException;
 231 
 232     /**
 233      * Returns an existing {@code FileSystem} created by this provider.
 234      *
 235      * <p> This method returns a reference to a {@code FileSystem} that was
 236      * created by invoking the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)}
 237      * method. File systems created the {@link #newFileSystem(FileRef,Map)
 238      * newFileSystem(FileRef,Map)} method are not returned by this method.
 239      * The file system is identified by its {@code URI}. Its exact form
 240      * is highly provider dependent. In the case of the default provider the URI's
 241      * path component is {@code "/"} and the authority, query and fragment components
 242      * are undefined (Undefined components are represented by {@code null}).
 243      *
 244      * <p> Once a file system created by this provider is {@link FileSystem#close
 245      * closed} it is provider-dependent if this method returns a reference to
 246      * the closed file system or throws {@link FileSystemNotFoundException}.
 247      * If the provider allows a new file system to be created with the same URI
 248      * as a file system it previously created then this method throws the
 249      * exception if invoked after the file system is closed (and before a new
 250      * instance is created by the {@link #newFileSystem newFileSystem} method).
 251      *
 252      * <p> If a security manager is installed then a provider implementation
 253      * may require to check a permission before returning a reference to an
 254      * existing file system. In the case of the {@link FileSystems#getDefault
 255      * default} file system, no permission check is required.
 256      *
 257      * @param   uri
 258      *          URI reference
 259      *
 260      * @return  The file system
 261      *
 262      * @throws  IllegalArgumentException
 263      *          If the pre-conditions for the {@code uri} parameter aren't met
 264      * @throws  FileSystemNotFoundException
 265      *          If the file system does not exist
 266      * @throws  SecurityException
 267      *          If a security manager is installed and it denies an unspecified
 268      *          permission.
 269      */
 270     public abstract FileSystem getFileSystem(URI uri);
 271 
 272     /**
 273      * Return a {@code Path} object by converting the given {@link URI}. The
 274      * resulting {@code Path} is associated with a {@link FileSystem} that
 275      * already exists or is constructed automatically.
 276      *
 277      * <p> The exact form of the URI is file system provider dependent. In the
 278      * case of the default provider, the URI scheme is {@code "file"} and the
 279      * given URI has a non-empty path component, and undefined query, and
 280      * fragment components. The resulting {@code Path} is associated with the
 281      * default {@link FileSystems#getDefault default} {@code FileSystem}.
 282      *
 283      * <p> If a security manager is installed then a provider implementation
 284      * may require to check a permission. In the case of the {@link
 285      * FileSystems#getDefault default} file system, no permission check is
 286      * required.
 287      *
 288      * @param   uri
 289      *          The URI to convert
 290      *
 291      * @throws  IllegalArgumentException
 292      *          If the URI scheme does not identify this provider or other
 293      *          preconditions on the uri parameter do not hold
 294      * @throws  FileSystemNotFoundException
 295      *          The file system, identified by the URI, does not exist and
 296      *          cannot be created automatically
 297      * @throws  SecurityException
 298      *          If a security manager is installed and it denies an unspecified
 299      *          permission.
 300      */
 301     public abstract Path getPath(URI uri);
 302 
 303     /**
 304      * Constructs a new {@code FileSystem} to access the contents of a file as a
 305      * file system.
 306      *
 307      * <p> This method is intended for specialized providers of pseudo file
 308      * systems where the contents of one or more files is treated as a file
 309      * system. The {@code file} parameter is a reference to an existing file
 310      * and the {@code env} parameter is a map of provider specific properties to
 311      * configure the file system.
 312      *
 313      * <p> If this provider does not support the creation of such file systems
 314      * or if the provider does not recognize the file type of the given file then
 315      * it throws {@code UnsupportedOperationException}. The default implementation
 316      * of this method throws {@code UnsupportedOperationException}.
 317      *
 318      * @param   file
 319      *          The file
 320      * @param   env
 321      *          A map of provider specific properties to configure the file system;
 322      *          may be empty
 323      *
 324      * @return  A new file system
 325      *
 326      * @throws  UnsupportedOperationException
 327      *          If this provider does not support access to the contents as a
 328      *          file system or it does not recognize the file type of the
 329      *          given file
 330      * @throws  IllegalArgumentException
 331      *          If the {@code env} parameter does not contain properties required
 332      *          by the provider, or a property value is invalid
 333      * @throws  IOException
 334      *          If an I/O error occurs
 335      * @throws  SecurityException
 336      *          If a security manager is installed and it denies an unspecified
 337      *          permission.
 338      */
 339     public FileSystem newFileSystem(FileRef file, Map<String,?> env)
 340         throws IOException
 341     {
 342         throw new UnsupportedOperationException();
 343     }
 344 
 345     /**
 346      * Opens or creates a file for reading and/or writing, returning a file
 347      * channel to access the file.
 348      *
 349      * <p> This method is invoked by the {@link FileChannel#open(Path,Set,FileAttribute[])
 350      * FileChannel.open} method to open a file channel. A provider that does not
 351      * support all the features required to construct a file channel throws
 352      * {@code UnsupportedOperationException}. The default provider is required
 353      * to support the creation of file channels. When not overridden, the
 354      * default implementation throws {@code UnsupportedOperationException}.
 355      *
 356      * @param   path
 357      *          The path of the file to open or create
 358      * @param   options
 359      *          Options specifying how the file is opened
 360      * @param   attrs
 361      *          An optional list of file attributes to set atomically when
 362      *          creating the file
 363      *
 364      * @return  A new file channel
 365      *
 366      * @throws  IllegalArgumentException
 367      *          If the set contains an invalid combination of options
 368      * @throws  UnsupportedOperationException
 369      *          If this provider that does not support creating file channels,
 370      *          or an unsupported open option or file attribute is specified
 371      * @throws  IOException
 372      *          If an I/O error occurs
 373      * @throws  SecurityException
 374      *          In the case of the default file system, the {@link
 375      *          SecurityManager#checkRead(String)} method is invoked to check
 376      *          read access if the file is opened for reading. The {@link
 377      *          SecurityManager#checkWrite(String)} method is invoked to check
 378      *          write access if the file is opened for writing
 379      */
 380     public FileChannel newFileChannel(Path path,
 381                                       Set<? extends OpenOption> options,
 382                                       FileAttribute<?>... attrs)
 383         throws IOException
 384     {
 385         throw new UnsupportedOperationException();
 386     }
 387 
 388     /**
 389      * Opens or creates a file for reading and/or writing, returning an
 390      * asynchronous file channel to access the file.
 391      *
 392      * <p> This method is invoked by the {@link
 393      * AsynchronousFileChannel#open(Path,Set,ExecutorService,FileAttribute[])
 394      * AsynchronousFileChannel.open} method to open an asynchronous file channel.
 395      * A provider that does not support all the features required to construct
 396      * an asynchronous file channel throws {@code UnsupportedOperationException}.
 397      * The default provider is required to support the creation of asynchronous
 398      * file channels. When not overridden, the default implementation of this
 399      * method throws {@code UnsupportedOperationException}.
 400      *
 401      * @param   path
 402      *          The path of the file to open or create
 403      * @param   options
 404      *          Options specifying how the file is opened
 405      * @param   executor
 406      *          The thread pool or {@code null} to associate the channel with
 407      *          the default thread pool
 408      * @param   attrs
 409      *          An optional list of file attributes to set atomically when
 410      *          creating the file
 411      *
 412      * @return  A new asynchronous file channel
 413      *
 414      * @throws  IllegalArgumentException
 415      *          If the set contains an invalid combination of options
 416      * @throws  UnsupportedOperationException
 417      *          If this provider that does not support creating asynchronous file
 418      *          channels, or an unsupported open option or file attribute is
 419      *          specified
 420      * @throws  IOException
 421      *          If an I/O error occurs
 422      * @throws  SecurityException
 423      *          In the case of the default file system, the {@link
 424      *          SecurityManager#checkRead(String)} method is invoked to check
 425      *          read access if the file is opened for reading. The {@link
 426      *          SecurityManager#checkWrite(String)} method is invoked to check
 427      *          write access if the file is opened for writing
 428      */
 429     public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
 430                                                               Set<? extends OpenOption> options,
 431                                                               ExecutorService executor,
 432                                                               FileAttribute<?>... attrs)
 433         throws IOException
 434     {
 435         throw new UnsupportedOperationException();
 436     }
 437 }