All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.vfs2.impl.DefaultFileSystemManager Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.vfs2.impl;

import java.io.File;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs2.CacheStrategy;
import org.apache.commons.vfs2.Capability;
import org.apache.commons.vfs2.FileContentInfoFactory;
import org.apache.commons.vfs2.FileName;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystem;
import org.apache.commons.vfs2.FileSystemConfigBuilder;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.FilesCache;
import org.apache.commons.vfs2.NameScope;
import org.apache.commons.vfs2.VFS;
import org.apache.commons.vfs2.cache.SoftRefFilesCache;
import org.apache.commons.vfs2.operations.FileOperationProvider;
import org.apache.commons.vfs2.provider.AbstractFileName;
import org.apache.commons.vfs2.provider.AbstractFileProvider;
import org.apache.commons.vfs2.provider.DefaultURLStreamHandler;
import org.apache.commons.vfs2.provider.FileProvider;
import org.apache.commons.vfs2.provider.FileReplicator;
import org.apache.commons.vfs2.provider.LocalFileProvider;
import org.apache.commons.vfs2.provider.TemporaryFileStore;
import org.apache.commons.vfs2.provider.UriParser;
import org.apache.commons.vfs2.provider.VfsComponent;

/**
 * The default file system manager implementation.
 */
public class DefaultFileSystemManager implements FileSystemManager, AutoCloseable {
    /**
     * Mapping from URI scheme to FileProvider.
     */
    private final Map providers = new HashMap<>();

    /**
     * List of the schemes of virtual file systems added.
     */
    private final List virtualFileSystemSchemes = new ArrayList<>();

    /**
     * All components used by this manager.
     */
    private final ArrayList components = new ArrayList<>();

    /**
     * The context to pass to providers.
     */
    private final DefaultVfsComponentContext context = new DefaultVfsComponentContext(this);

    /**
     * Operations providers added to this manager.
     */
    private final Map> operationProviders = new HashMap<>();

    /**
     * Mappings of file types.
     */
    private final FileTypeMap typeMap = new FileTypeMap();

    /**
     * The provider for local files.
     */
    private LocalFileProvider localFileProvider;

    /**
     * The default provider.
     */
    private FileProvider defaultProvider;

    /**
     * The file replicator to use.
     */
    private FileReplicator fileReplicator;

    /**
     * The base file to use for relative URI.
     */
    private FileObject baseFile;

    /**
     * The files cache
     */
    private FilesCache filesCache;

    /**
     * The cache strategy
     */
    private CacheStrategy fileCacheStrategy;

    /**
     * Class which decorates all returned fileObjects
     */
    private Class fileObjectDecorator;
    /**
     * Reflection constructor extracted from {@link #fileObjectDecorator}
     */
    private Constructor fileObjectDecoratorConst;

    /**
     * The class to use to determine the content-type (mime-type)
     */
    private FileContentInfoFactory fileContentInfoFactory;

    /**
     * The logger to use. Default implementation.
     */
    private Log log = LogFactory.getLog(getClass());

    /**
     * The temporary file store to use.
     */
    private TemporaryFileStore tempFileStore;

    /**
     * The virtual file provider.
     */
    private VirtualFileProvider vfsProvider;

    /**
     * Flag, if manager is initialized (after init() and before close()).
     */
    private boolean init;

    /**
     * Returns the logger used by this manager.
     *
     * @return the Logger.
     */
    protected Log getLogger() {
        return log;
    }

    /**
     * Registers a file system provider.
     * 

* The manager takes care of all lifecycle management. A provider may be registered multiple times. The first * {@link LocalFileProvider} added will be remembered for {@link #getLocalFileProvider()}. * * @param urlScheme The scheme the provider will handle. * @param provider The provider. * @throws FileSystemException if an error occurs adding the provider. */ public void addProvider(final String urlScheme, final FileProvider provider) throws FileSystemException { addProvider(new String[] { urlScheme }, provider); } /** * Registers a file system provider. *

* The manager takes care of all lifecycle management. A provider may be registered multiple times. The first * {@link LocalFileProvider} added will be remembered for {@link #getLocalFileProvider()}. * * @param urlSchemes The schemes the provider will handle. * @param provider The provider. * @throws FileSystemException if an error occurs adding the provider. */ public void addProvider(final String[] urlSchemes, final FileProvider provider) throws FileSystemException { // fail duplicate schemes for (final String scheme : urlSchemes) { if (providers.containsKey(scheme)) { throw new FileSystemException("vfs.impl/multiple-providers-for-scheme.error", scheme); } } // Contextualise the component (if not already) setupComponent(provider); // Add to map for (final String scheme : urlSchemes) { providers.put(scheme, provider); } if (provider instanceof LocalFileProvider && localFileProvider == null) { localFileProvider = (LocalFileProvider) provider; } } /** * Returns true if this manager has a provider for a particular scheme. * * @param scheme The scheme to check. * @return true if a provider is configured for this scheme, false otherwise. */ @Override public boolean hasProvider(final String scheme) { return providers.containsKey(scheme); } /** * Adds an file name extension mapping. * * @param extension The file name extension. * @param scheme The scheme to use for files with this extension. */ public void addExtensionMap(final String extension, final String scheme) { typeMap.addExtension(extension, scheme); } /** * Adds a mime type mapping. * * @param mimeType The mime type. * @param scheme The scheme to use for files with this mime type. */ public void addMimeTypeMap(final String mimeType, final String scheme) { typeMap.addMimeType(mimeType, scheme); } /** * Sets the default provider. This is the provider that will handle URI with unknown schemes. The manager takes care * of all lifecycle management. * * @param provider The FileProvider. * @throws FileSystemException if an error occurs setting the provider. */ public void setDefaultProvider(final FileProvider provider) throws FileSystemException { setupComponent(provider); defaultProvider = provider; } /** * Returns the filesCache implementation used to cache files. * * @return The FilesCache. */ @Override public FilesCache getFilesCache() { return filesCache; } /** * Sets the filesCache implementation used to cache files. *

* Can only be set before the FileSystemManager is initialized. *

* The manager takes care of the lifecycle. If none is set, a default is picked in {@link #init()}. * * @param filesCache The FilesCache. * @throws FileSystemException if an error occurs setting the cache.. */ public void setFilesCache(final FilesCache filesCache) throws FileSystemException { if (init) { throw new FileSystemException("vfs.impl/already-inited.error"); } this.filesCache = filesCache; } /** * Set the cache strategy to use when dealing with file object data. *

* Can only be set before the FileSystemManager is initialized. *

* The default is {@link CacheStrategy#ON_RESOLVE} * * @param fileCacheStrategy The CacheStrategy to use. * @throws FileSystemException if this is not possible. e.g. it is already set. */ public void setCacheStrategy(final CacheStrategy fileCacheStrategy) throws FileSystemException { if (init) { throw new FileSystemException("vfs.impl/already-inited.error"); } this.fileCacheStrategy = fileCacheStrategy; } /** * Get the cache strategy used. * * @return The CacheStrategy. */ @Override public CacheStrategy getCacheStrategy() { return fileCacheStrategy; } /** * Get the file object decorator used. * * @return The decorator. */ @Override public Class getFileObjectDecorator() { return fileObjectDecorator; } /** * The constructor associated to the fileObjectDecorator. We cache it here for performance reasons. * * @return The decorator's Constructor. */ @Override public Constructor getFileObjectDecoratorConst() { return fileObjectDecoratorConst; } /** * Set a fileObject decorator to be used for ALL returned file objects. *

* Can only be set before the FileSystemManager is initialized. * * @param fileObjectDecorator must be inherted from {@link DecoratedFileObject} a has to provide a constructor with * a single {@link FileObject} as argument * @throws FileSystemException if an error occurs setting the decorator. */ public void setFileObjectDecorator(final Class fileObjectDecorator) throws FileSystemException { if (init) { throw new FileSystemException("vfs.impl/already-inited.error"); } if (!DecoratedFileObject.class.isAssignableFrom(fileObjectDecorator)) { throw new FileSystemException("vfs.impl/invalid-decorator.error", fileObjectDecorator.getName()); } try { fileObjectDecoratorConst = fileObjectDecorator.getConstructor(new Class[] { FileObject.class }); } catch (final NoSuchMethodException e) { throw new FileSystemException("vfs.impl/invalid-decorator.error", fileObjectDecorator.getName(), e); } this.fileObjectDecorator = fileObjectDecorator; } /** * get the fileContentInfoFactory used to determine the infos of a file content. * * @return The FileContentInfoFactory. */ @Override public FileContentInfoFactory getFileContentInfoFactory() { return fileContentInfoFactory; } /** * set the fileContentInfoFactory used to determine the infos of a file content. *

* Can only be set before the FileSystemManager is initialized. * * @param fileContentInfoFactory The FileContentInfoFactory. * @throws FileSystemException if an error occurs setting the FileContentInfoFactory. */ public void setFileContentInfoFactory(final FileContentInfoFactory fileContentInfoFactory) throws FileSystemException { if (init) { throw new FileSystemException("vfs.impl/already-inited.error"); } this.fileContentInfoFactory = fileContentInfoFactory; } /** * Sets the file replicator to use. *

* The manager takes care of all lifecycle management. * * @param replicator The FileReplicator. * @throws FileSystemException if an error occurs setting the replicator. */ public void setReplicator(final FileReplicator replicator) throws FileSystemException { setupComponent(replicator); fileReplicator = replicator; } /** * Sets the temporary file store to use. *

* The manager takes care of all lifecycle management. * * @param tempFileStore The temporary FileStore. * @throws FileSystemException if an error occurs adding the file store. */ public void setTemporaryFileStore(final TemporaryFileStore tempFileStore) throws FileSystemException { setupComponent(tempFileStore); this.tempFileStore = tempFileStore; } /** * Sets the logger to use. *

* This overwrites the default logger for this manager and is not reset in {@link #close()}. * * @param log The Logger to use. */ @Override public void setLogger(final Log log) { this.log = log; } /** * Initializes a component, if it has not already been initialised. * * @param component The component to setup. * @throws FileSystemException if an error occurs. */ private void setupComponent(final Object component) throws FileSystemException { if (!components.contains(component)) { if (component instanceof VfsComponent) { final VfsComponent vfsComponent = (VfsComponent) component; vfsComponent.setLogger(getLogger()); vfsComponent.setContext(context); vfsComponent.init(); } components.add(component); } } /** * Closes a component, if it has not already been closed. * * @param component The component to close. */ private void closeComponent(final Object component) { if (component != null && components.contains(component)) { if (component instanceof VfsComponent) { final VfsComponent vfsComponent = (VfsComponent) component; vfsComponent.close(); } components.remove(component); } } /** * Returns the file replicator. * * @return The file replicator. Never returns null. * @throws FileSystemException if there is no FileReplicator. */ public FileReplicator getReplicator() throws FileSystemException { return FileSystemException.requireNonNull(fileReplicator, "vfs.impl/no-replicator.error"); } /** * Returns the temporary file store. * * @return The file store. Never returns null. * @throws FileSystemException if there is no TemporaryFileStore. */ public TemporaryFileStore getTemporaryFileStore() throws FileSystemException { return FileSystemException.requireNonNull(tempFileStore, "vfs.impl/no-temp-file-store.error"); } /** * Initializes this manager. *

* If no value for the following properties was specified, it will use the following defaults: *

    *
  • fileContentInfoFactory = new FileContentInfoFilenameFactory()
  • *
  • filesCache = new SoftRefFilesCache()
  • *
  • fileCacheStrategy = CacheStrategy.ON_RESOLVE
  • *
* * @throws FileSystemException if an error occurs during initialization. */ public void init() throws FileSystemException { if (fileContentInfoFactory == null) { fileContentInfoFactory = new FileContentInfoFilenameFactory(); } if (filesCache == null) { // filesCache = new DefaultFilesCache(); filesCache = new SoftRefFilesCache(); } if (fileCacheStrategy == null) { fileCacheStrategy = CacheStrategy.ON_RESOLVE; } setupComponent(filesCache); vfsProvider = new VirtualFileProvider(); setupComponent(vfsProvider); init = true; } /** * Closes the manager. *

* This will close all providers (all files), it will also close all managed components including temporary files, * replicator, file cache and file operations. *

* The manager is in uninitialized state after this method. */ public void close() { if (!init) { return; } // make sure all discovered components in // org.apache.commons.vfs2.impl.StandardFileSystemManager.configure(Element) // are closed here // Close the file system providers. for (final FileProvider provider : providers.values()) { closeComponent(provider); } // Close the other components closeComponent(vfsProvider); closeComponent(fileReplicator); closeComponent(tempFileStore); closeComponent(filesCache); closeComponent(defaultProvider); // unregister all providers here, so if any components have local file references // they can still resolve against the supported schemes providers.clear(); // FileOperations are components, too for (final List opproviders : operationProviders.values()) { for (final FileOperationProvider p : opproviders) { closeComponent(p); } } // unregister all operationProviders.clear(); // collections with add() typeMap.clear(); // should not happen, but make debugging easier: if (!components.isEmpty()) { log.warn("DefaultFilesystemManager.close: not all components are closed: " + components.toString()); } components.clear(); // managed components vfsProvider = null; // virtual schemas virtualFileSystemSchemes.clear(); // setters and derived state defaultProvider = null; baseFile = null; fileObjectDecorator = null; fileObjectDecoratorConst = null; localFileProvider = null; fileReplicator = null; tempFileStore = null; // setters with init() defaults filesCache = null; fileCacheStrategy = null; fileContentInfoFactory = null; init = false; } /** * Free all resources used by unused file systems created by this manager. */ public void freeUnusedResources() { if (!init) { return; } // Close the providers. for (final FileProvider fileProvider : providers.values()) { final AbstractFileProvider provider = (AbstractFileProvider) fileProvider; provider.freeUnusedResources(); } // vfsProvider does not need to free resources } /** * Sets the base file to use when resolving relative URI. * * @param baseFile The new base FileObject. * @throws FileSystemException if an error occurs. */ public void setBaseFile(final FileObject baseFile) throws FileSystemException { this.baseFile = baseFile; } /** * Sets the base file to use when resolving relative URI. * * @param baseFile The new base FileObject. * @throws FileSystemException if an error occurs. */ public void setBaseFile(final File baseFile) throws FileSystemException { this.baseFile = getLocalFileProvider().findLocalFile(baseFile); } /** * Returns the base file used to resolve relative URI. * * @return The FileObject that represents the base file. * @throws FileSystemException if an error occurs. */ @Override public FileObject getBaseFile() throws FileSystemException { return baseFile; } /** * Locates a file by URI. * * @param uri The URI of the file to locate. * @return The FileObject for the located file. * @throws FileSystemException if the file cannot be located or an error occurs. */ @Override public FileObject resolveFile(final String uri) throws FileSystemException { return resolveFile(getBaseFile(), uri); } /** * Locate a file by URI, use the FileSystemOptions for file-system creation. * * @param uri The URI of the file to locate. * @param fileSystemOptions The options for the FileSystem. * @return The FileObject for the located file. * @throws FileSystemException if the file cannot be located or an error occurs. */ @Override public FileObject resolveFile(final String uri, final FileSystemOptions fileSystemOptions) throws FileSystemException { // return resolveFile(baseFile, uri, fileSystemOptions); return resolveFile(getBaseFile(), uri, fileSystemOptions); } /** * Resolves a URI, relative to base file. *

* Uses the {@linkplain #getLocalFileProvider() local file provider} to locate the system file. * * @param baseFile The base File to use to locate the file. * @param uri The URI of the file to locate. * @return The FileObject for the located file. * @throws FileSystemException if the file cannot be located or an error occurs. */ @Override public FileObject resolveFile(final File baseFile, final String uri) throws FileSystemException { final FileObject baseFileObj = getLocalFileProvider().findLocalFile(baseFile); return resolveFile(baseFileObj, uri); } /** * Resolves a URI, relative to a base file. * * @param baseFile The base FileOjbect to use to locate the file. * @param uri The URI of the file to locate. * @return The FileObject for the located file. * @throws FileSystemException if the file cannot be located or an error occurs. */ @Override public FileObject resolveFile(final FileObject baseFile, final String uri) throws FileSystemException { return resolveFile(baseFile, uri, baseFile == null ? null : baseFile.getFileSystem().getFileSystemOptions()); } /** * Resolves a URI, relative to a base file with specified FileSystem configuration. * * @param baseFile The base file. * @param uri The file name. May be a fully qualified or relative path or a url. * @param fileSystemOptions Options to pass to the file system. * @return A FileObject representing the target file. * @throws FileSystemException if an error occurs accessing the file. */ public FileObject resolveFile(final FileObject baseFile, final String uri, final FileSystemOptions fileSystemOptions) throws FileSystemException { final FileObject realBaseFile; if (baseFile != null && VFS.isUriStyle() && baseFile.getName().isFile()) { realBaseFile = baseFile.getParent(); } else { realBaseFile = baseFile; } // TODO: use resolveName and use this name to resolve the fileObject UriParser.checkUriEncoding(uri); if (uri == null) { throw new IllegalArgumentException(); } // Extract the scheme final String scheme = UriParser.extractScheme(getSchemes(),uri); if (scheme != null) { // An absolute URI - locate the provider final FileProvider provider = providers.get(scheme); if (provider != null) { return provider.findFile(realBaseFile, uri, fileSystemOptions); } // Otherwise, assume a local file } // Handle absolute file names if (localFileProvider != null && localFileProvider.isAbsoluteLocalName(uri)) { return localFileProvider.findLocalFile(uri); } if (scheme != null) { // An unknown scheme - hand it to the default provider FileSystemException.requireNonNull(defaultProvider, "vfs.impl/unknown-scheme.error", scheme, uri); return defaultProvider.findFile(realBaseFile, uri, fileSystemOptions); } // Assume a relative name - use the supplied base file FileSystemException.requireNonNull(realBaseFile, "vfs.impl/find-rel-file.error", uri); return realBaseFile.resolveFile(uri); } /** * Resolves a name, relative to the file. If the supplied name is an absolute path, then it is resolved relative to * the root of the file system that the file belongs to. If a relative name is supplied, then it is resolved * relative to this file name. * * @param root The base FileName. * @param path The path to the file relative to the base FileName or an absolute path. * @return The constructed FileName. * @throws FileSystemException if an error occurs constructing the FileName. */ @Override public FileName resolveName(final FileName root, final String path) throws FileSystemException { return resolveName(root, path, NameScope.FILE_SYSTEM); } /** * Resolves a name, relative to the root. * * @param base the base file name * @param name the name * @param scope the {@link NameScope} * @return The FileName of the file. * @throws FileSystemException if an error occurs. */ @Override public FileName resolveName(final FileName base, final String name, final NameScope scope) throws FileSystemException { FileSystemException.requireNonNull(base, "Invalid base FileName."); FileSystemException.requireNonNull(name, "Invalid name FileName."); final FileName realBase; if (VFS.isUriStyle() && base.isFile()) { realBase = base.getParent(); } else { realBase = base; } final StringBuilder buffer = new StringBuilder(name); // Adjust separators UriParser.fixSeparators(buffer); String scheme = UriParser.extractScheme(getSchemes(), buffer.toString()); // Determine whether to prepend the base path if (name.length() == 0 || (scheme == null && buffer.charAt(0) != FileName.SEPARATOR_CHAR)) { // Supplied path is not absolute if (!VFS.isUriStyle()) { // when using uris the parent already do have the trailing "/" buffer.insert(0, FileName.SEPARATOR_CHAR); } buffer.insert(0, realBase.getPath()); } // Normalise the path final FileType fileType = UriParser.normalisePath(buffer); // Check the name is ok final String resolvedPath = buffer.toString(); if (!AbstractFileName.checkName(realBase.getPath(), resolvedPath, scope)) { throw new FileSystemException("vfs.provider/invalid-descendent-name.error", name); } String fullPath; if (scheme != null) { fullPath = resolvedPath; } else { scheme = realBase.getScheme(); fullPath = realBase.getRootURI() + resolvedPath; } final FileProvider provider = providers.get(scheme); if (provider != null) { // TODO: extend the file name parser to be able to parse // only a pathname and take the missing informations from // the base. Then we can get rid of the string operation. // // String fullPath = base.getRootURI() + // resolvedPath.substring(1); return provider.parseUri(realBase, fullPath); } // An unknown scheme - hand it to the default provider - if possible if (scheme != null && defaultProvider != null) { return defaultProvider.parseUri(realBase, fullPath); } // TODO: avoid fallback to this point // this happens if we have a virtual filesystem (no provider for scheme) return ((AbstractFileName) realBase).createName(resolvedPath, fileType); } /** * Resolve the uri to a file name. * * @param uri The URI to resolve. * @return The FileName of the file. * @throws FileSystemException if an error occurs. */ @Override public FileName resolveURI(final String uri) throws FileSystemException { UriParser.checkUriEncoding(uri); if (uri == null) { throw new IllegalArgumentException(); } // Extract the scheme final String scheme = UriParser.extractScheme(getSchemes(), uri); if (scheme != null) { // An absolute URI - locate the provider final FileProvider provider = providers.get(scheme); if (provider != null) { return provider.parseUri(null, uri); } // Otherwise, assume a local file } // Handle absolute file names if (localFileProvider != null && localFileProvider.isAbsoluteLocalName(uri)) { return localFileProvider.parseUri(null, uri); } if (scheme != null) { // An unknown scheme - hand it to the default provider FileSystemException.requireNonNull(defaultProvider, "vfs.impl/unknown-scheme.error", scheme, uri); return defaultProvider.parseUri(null, uri); } // Assume a relative name - use the supplied base file FileSystemException.requireNonNull(baseFile, "vfs.impl/find-rel-file.error", uri); return resolveName(baseFile.getName(), uri, NameScope.FILE_SYSTEM); } /** * Converts a local file into a {@link FileObject}. * * @param file The input File. * @return the create FileObject * @throws FileSystemException if an error occurs creating the file. */ @Override public FileObject toFileObject(final File file) throws FileSystemException { return getLocalFileProvider().findLocalFile(file); } /** * Creates a layered file system. * * @param scheme The scheme to use. * @param file The FileObject. * @return The layered FileObject. * @throws FileSystemException if an error occurs. */ @Override public FileObject createFileSystem(final String scheme, final FileObject file) throws FileSystemException { final FileProvider provider = providers.get(scheme); FileSystemException.requireNonNull(provider, "vfs.impl/unknown-provider.error", scheme, file); return provider.createFileSystem(scheme, file, file.getFileSystem().getFileSystemOptions()); } /** * Creates a layered file system. * * @param file The FileObject to use. * @return The layered FileObject. * @throws FileSystemException if an error occurs. */ @Override public FileObject createFileSystem(final FileObject file) throws FileSystemException { final String scheme = typeMap.getScheme(file); FileSystemException.requireNonNull(scheme, "vfs.impl/no-provider-for-file.error", file); return createFileSystem(scheme, file); } /** * Determines if a layered file system can be created for a given file. * * @param file The file to check for. * @return true if the FileSystem can be created. * @throws FileSystemException if an error occurs. */ @Override public boolean canCreateFileSystem(final FileObject file) throws FileSystemException { return typeMap.getScheme(file) != null; } /** * Creates a virtual file system. * * @param rootFile The FileObject to use. * @return The FileObject in the VirtualFileSystem. * @throws FileSystemException if an error occurs creating the file. */ @Override public FileObject createVirtualFileSystem(final FileObject rootFile) throws FileSystemException { final FileObject fileObject = vfsProvider.createFileSystem(rootFile); addVirtualFileSystemScheme(rootFile.getName().getScheme()); return fileObject; } /** * Creates an empty virtual file system. * * @param rootUri The URI to use as the root of the FileSystem. * @return A FileObject in the virtual FileSystem. * @throws FileSystemException if an error occurs. */ @Override public FileObject createVirtualFileSystem(final String rootUri) throws FileSystemException { final FileObject fileObject = vfsProvider.createFileSystem(rootUri); addVirtualFileSystemScheme(rootUri); return fileObject; } protected void addVirtualFileSystemScheme(String rootUri) { if (rootUri.indexOf(':') != -1) { rootUri = rootUri.substring(0, rootUri.indexOf(':')); } virtualFileSystemSchemes.add(rootUri); } /** * Locates the local file provider. *

* The local file provider is the first {@linkplain #addProvider(String[], FileProvider) provider added} * implementing {@link LocalFileProvider}. * * @return The LocalFileProvider. * @throws FileSystemException if no local file provider was set. */ private LocalFileProvider getLocalFileProvider() throws FileSystemException { return FileSystemException.requireNonNull(localFileProvider, "vfs.impl/no-local-file-provider.error"); } /** * Get the URLStreamHandlerFactory. * * @return The URLStreamHandlerFactory. */ @Override public URLStreamHandlerFactory getURLStreamHandlerFactory() { return new VfsStreamHandlerFactory(); } /** * Closes the given file system. *

* If you use VFS as singleton it is VERY dangerous to call this method. * * @param fileSystem The FileSystem to close. */ @Override public void closeFileSystem(final FileSystem fileSystem) { // inform the cache ... getFilesCache().clear(fileSystem); // just in case the cache didnt call _closeFileSystem _closeFileSystem(fileSystem); } /** * Closes the given file system. *

* If you use VFS as singleton it is VERY dangerous to call this method *

* * @param fileSystem The FileSystem to close. */ public void _closeFileSystem(final FileSystem fileSystem) { final FileProvider provider = providers.get(fileSystem.getRootName().getScheme()); if (provider != null) { ((AbstractFileProvider) provider).closeFileSystem(fileSystem); } else if (fileSystem instanceof VirtualFileSystem) { // vfsProvider does not implement AbstractFileProvider vfsProvider.closeFileSystem(fileSystem); } } /** * This is an internal class because it needs access to the private member providers. */ final class VfsStreamHandlerFactory implements URLStreamHandlerFactory { @Override public URLStreamHandler createURLStreamHandler(final String protocol) { final FileProvider provider = providers.get(protocol); if (provider != null) { return new DefaultURLStreamHandler(context); } // Route all other calls to the default URLStreamHandlerFactory return new URLStreamHandlerProxy(); } } /** * Get the schemes currently available. * * @return The array of scheme names. */ @Override public String[] getSchemes() { final List schemes = new ArrayList<>(providers.size() + virtualFileSystemSchemes.size()); schemes.addAll(providers.keySet()); schemes.addAll(virtualFileSystemSchemes); return schemes.toArray(new String[]{}); } /** * Get the capabilities for a given scheme. * * @param scheme The scheme to located. * @return A Collection of capabilities. * @throws FileSystemException if the given scheme is not konwn */ @Override public Collection getProviderCapabilities(final String scheme) throws FileSystemException { final FileProvider provider = providers.get(scheme); FileSystemException.requireNonNull(provider, "vfs.impl/unknown-scheme.error", scheme); return provider.getCapabilities(); } /** * Get the configuration builder for the given scheme. * * @param scheme The scheme to locate. * @return The FileSystemConfigBuilder for the scheme. * @throws FileSystemException if the given scheme is not konwn */ @Override public FileSystemConfigBuilder getFileSystemConfigBuilder(final String scheme) throws FileSystemException { final FileProvider provider = providers.get(scheme); FileSystemException.requireNonNull(provider, "vfs.impl/unknown-scheme.error", scheme); return provider.getConfigBuilder(); } // -- OPERATIONS -- /** * Adds the specified FileOperationProvider for the specified scheme. Several FileOperationProvider's might be * registered for the same scheme. For example, for "file" scheme we can register SvnWsOperationProvider and * CvsOperationProvider. * * @param scheme The scheme the provider should be registered for. * @param operationProvider The FileOperationProvider. * @throws FileSystemException if an error occurs adding the provider. */ @Override public void addOperationProvider(final String scheme, final FileOperationProvider operationProvider) throws FileSystemException { addOperationProvider(new String[] { scheme }, operationProvider); } /** * @see FileSystemManager#addOperationProvider(String, org.apache.commons.vfs2.operations.FileOperationProvider) * * @param schemes The array of schemes the provider should apply to. * @param operationProvider The FileOperationProvider. * @throws FileSystemException if an error occurs. */ @Override public void addOperationProvider(final String[] schemes, final FileOperationProvider operationProvider) throws FileSystemException { for (final String scheme : schemes) { if (!operationProviders.containsKey(scheme)) { final List providers = new ArrayList<>(); operationProviders.put(scheme, providers); } final List providers = operationProviders.get(scheme); if (providers.contains(operationProvider)) { throw new FileSystemException("vfs.operation/operation-provider-already-added.error", scheme); } setupComponent(operationProvider); providers.add(operationProvider); } } /** * @param scheme the scheme for wich we want to get the list af registered providers. * * @return the registered FileOperationProviders for the specified scheme. If there were no providers registered for * the scheme, it returns null. * * @throws FileSystemException if an error occurs. */ @Override public FileOperationProvider[] getOperationProviders(final String scheme) throws FileSystemException { final List providers = operationProviders.get(scheme); if (providers == null || providers.size() == 0) { return null; } return providers.toArray(new FileOperationProvider[] {}); } /** * Converts a URI into a {@link FileObject}. * * @param uri The URI to convert. * @return The {@link FileObject} that represents the URI. Never returns null. * @throws FileSystemException On error converting the URI. * @since 2.1 */ @Override public FileObject resolveFile(final URI uri) throws FileSystemException { // TODO Push the URI deeper into VFS return resolveFile(baseFile, uri.toString(), null); } /** * Converts a URL into a {@link FileObject}. * * @param url The URL to convert. * @return The {@link FileObject} that represents the URL. Never returns null. * @throws FileSystemException On error converting the URL. * @since 2.1 */ @Override public FileObject resolveFile(final URL url) throws FileSystemException { try { return this.resolveFile(url.toURI()); } catch (final URISyntaxException e) { throw new FileSystemException(e); } } }