001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.vfs2.provider; 018 019import java.util.Map; 020import java.util.TreeMap; 021 022import org.apache.commons.vfs2.FileName; 023import org.apache.commons.vfs2.FileObject; 024import org.apache.commons.vfs2.FileSystem; 025import org.apache.commons.vfs2.FileSystemConfigBuilder; 026import org.apache.commons.vfs2.FileSystemException; 027import org.apache.commons.vfs2.FileSystemOptions; 028import org.apache.commons.vfs2.provider.local.GenericFileNameParser; 029 030/** 031 * A partial {@link FileProvider} implementation. Takes care of managing the file systems created by the provider. 032 */ 033public abstract class AbstractFileProvider extends AbstractVfsContainer implements FileProvider { 034 private static final AbstractFileSystem[] EMPTY_ABSTRACTFILESYSTEMS = new AbstractFileSystem[0]; 035 036 /** 037 * The cached file systems. 038 * <p> 039 * This is a mapping from {@link FileSystemKey} (root URI and options) to {@link FileSystem}. 040 */ 041 private final Map<FileSystemKey, FileSystem> fileSystems = new TreeMap<>(); // @GuardedBy("self") 042 043 private FileNameParser parser; 044 045 public AbstractFileProvider() { 046 parser = GenericFileNameParser.getInstance(); 047 } 048 049 protected FileNameParser getFileNameParser() { 050 return parser; 051 } 052 053 protected void setFileNameParser(final FileNameParser parser) { 054 this.parser = parser; 055 } 056 057 /** 058 * Closes the file systems created by this provider. 059 */ 060 @Override 061 public void close() { 062 synchronized (fileSystems) { 063 fileSystems.clear(); 064 } 065 066 super.close(); 067 } 068 069 /** 070 * Creates a layered file system. This method throws a 'not supported' exception. 071 * 072 * @param scheme The protocol to use to access the file. 073 * @param file a FileObject. 074 * @param properties Options to the file system. 075 * @return A FileObject associated with the new FileSystem. 076 * @throws FileSystemException if an error occurs. 077 */ 078 @Override 079 public FileObject createFileSystem(final String scheme, final FileObject file, final FileSystemOptions properties) 080 throws FileSystemException { 081 // Can't create a layered file system 082 throw new FileSystemException("vfs.provider/not-layered-fs.error", scheme); 083 } 084 085 /** 086 * Adds a file system to those cached by this provider. 087 * <p> 088 * The file system may implement {@link VfsComponent}, in which case it is initialised. 089 * 090 * @param key The root file of the file system, part of the cache key. 091 * @param fs the file system to add. 092 * @throws FileSystemException if any error occurs. 093 */ 094 protected void addFileSystem(final Comparable<?> key, final FileSystem fs) throws FileSystemException { 095 // Add to the container and initialize 096 addComponent(fs); 097 098 final FileSystemKey treeKey = new FileSystemKey(key, fs.getFileSystemOptions()); 099 ((AbstractFileSystem) fs).setCacheKey(treeKey); 100 101 synchronized (fileSystems) { 102 fileSystems.put(treeKey, fs); 103 } 104 } 105 106 /** 107 * Locates a cached file system. 108 * 109 * @param key The root file of the file system, part of the cache key. 110 * @param fileSystemProps file system options the file system instance must have. 111 * @return The file system instance, or null if it is not cached. 112 */ 113 protected FileSystem findFileSystem(final Comparable<?> key, final FileSystemOptions fileSystemProps) { 114 final FileSystemKey treeKey = new FileSystemKey(key, fileSystemProps); 115 116 synchronized (fileSystems) { 117 return fileSystems.get(treeKey); 118 } 119 } 120 121 /** 122 * Returns the FileSystemConfigBuidler. 123 * 124 * @return the FileSystemConfigBuilder. 125 */ 126 @Override 127 public FileSystemConfigBuilder getConfigBuilder() { 128 return null; 129 } 130 131 /** 132 * Free unused resources. 133 */ 134 public void freeUnusedResources() { 135 AbstractFileSystem[] abstractFileSystems; 136 synchronized (fileSystems) { 137 // create snapshot under lock 138 abstractFileSystems = fileSystems.values().toArray(EMPTY_ABSTRACTFILESYSTEMS); 139 } 140 141 // process snapshot outside lock 142 for (final AbstractFileSystem fs : abstractFileSystems) { 143 if (fs.isReleaseable()) { 144 fs.closeCommunicationLink(); 145 } 146 } 147 } 148 149 /** 150 * Close the FileSystem. 151 * 152 * @param filesystem The FileSystem to close. 153 */ 154 public void closeFileSystem(final FileSystem filesystem) { 155 final AbstractFileSystem fs = (AbstractFileSystem) filesystem; 156 157 final FileSystemKey key = fs.getCacheKey(); 158 if (key != null) { 159 synchronized (fileSystems) { 160 fileSystems.remove(key); 161 } 162 } 163 164 removeComponent(fs); 165 fs.close(); 166 } 167 168 /** 169 * Parses an absolute URI. 170 * 171 * @param base The base file - if null the {@code uri} needs to be absolute 172 * @param uri The URI to parse. 173 * @return The FileName. 174 * @throws FileSystemException if an error occurs. 175 */ 176 @Override 177 public FileName parseUri(final FileName base, final String uri) throws FileSystemException { 178 if (getFileNameParser() != null) { 179 return getFileNameParser().parseUri(getContext(), base, uri); 180 } 181 182 throw new FileSystemException("vfs.provider/filename-parser-missing.error"); 183 } 184}