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     */
017    package org.apache.commons.vfs2.provider;
018    
019    import java.util.Map;
020    import java.util.TreeMap;
021    
022    import org.apache.commons.vfs2.FileName;
023    import org.apache.commons.vfs2.FileObject;
024    import org.apache.commons.vfs2.FileSystem;
025    import org.apache.commons.vfs2.FileSystemConfigBuilder;
026    import org.apache.commons.vfs2.FileSystemException;
027    import org.apache.commons.vfs2.FileSystemOptions;
028    import org.apache.commons.vfs2.provider.local.GenericFileNameParser;
029    
030    /**
031     * A partial {@link FileProvider} implementation.  Takes care of managing the
032     * file systems created by the provider.
033     *
034     * @author <a href="http://commons.apache.org/vfs/team-list.html">Commons VFS team</a>
035     */
036    public abstract class AbstractFileProvider
037        extends AbstractVfsContainer
038        implements FileProvider
039    {
040        /**
041         * The cached file systems.  This is a mapping from root URI to
042         * FileSystem object.
043         */
044        // private final Map fileSystems = new HashMap();
045        private final Map<FileSystemKey, FileSystem> fileSystems = new TreeMap<FileSystemKey, FileSystem>();
046    
047        private FileNameParser parser;
048    
049        public AbstractFileProvider()
050        {
051            parser = GenericFileNameParser.getInstance();
052        }
053    
054        protected FileNameParser getFileNameParser()
055        {
056            return parser;
057        }
058    
059        protected void setFileNameParser(FileNameParser parser)
060        {
061            this.parser = parser;
062        }
063    
064        /**
065         * Closes the file systems created by this provider.
066         */
067        @Override
068        public void close()
069        {
070            synchronized (this)
071            {
072                fileSystems.clear();
073            }
074    
075            super.close();
076        }
077    
078        /**
079         * Creates a layered file system.  This method throws a 'not supported' exception.
080         * @param scheme The protocol to use to access the file.
081         * @param file a FileObject.
082         * @param properties Options to the file system.
083         * @return A FileObject associated with the new FileSystem.
084         * @throws FileSystemException if an error occurs.
085         */
086        public FileObject createFileSystem(final String scheme, final FileObject file, final FileSystemOptions properties)
087            throws FileSystemException
088        {
089            // Can't create a layered file system
090            throw new FileSystemException("vfs.provider/not-layered-fs.error", scheme);
091        }
092    
093        /**
094         * Adds a file system to those cached by this provider.  The file system
095         * may implement {@link VfsComponent}, in which case it is initialised.
096         */
097        protected void addFileSystem(final Comparable<?> key, final FileSystem fs)
098            throws FileSystemException
099        {
100            // Add to the cache
101            addComponent(fs);
102    
103            FileSystemKey treeKey = new FileSystemKey(key, fs.getFileSystemOptions());
104            ((AbstractFileSystem) fs).setCacheKey(treeKey);
105    
106            synchronized (this)
107            {
108                fileSystems.put(treeKey, fs);
109            }
110        }
111    
112        /**
113         * Locates a cached file system
114         *
115         * @return The provider, or null if it is not cached.
116         */
117        protected FileSystem findFileSystem(final Comparable<?> key, final FileSystemOptions fileSystemProps)
118        {
119            FileSystemKey treeKey = new FileSystemKey(key, fileSystemProps);
120    
121            synchronized (this)
122            {
123                return fileSystems.get(treeKey);
124            }
125        }
126    
127        /**
128         * Returns the FileSystemConfigBuidler.
129         * @return the FileSystemConfigBuilder.
130         */
131        public FileSystemConfigBuilder getConfigBuilder()
132        {
133            return null;
134        }
135    
136        /**
137         * Free unused resources.
138         */
139        public void freeUnusedResources()
140        {
141            Object[] item;
142            synchronized (this)
143            {
144                item = fileSystems.values().toArray();
145            }
146            for (int i = 0; i < item.length; ++i)
147            {
148                AbstractFileSystem fs = (AbstractFileSystem) item[i];
149                if (fs.isReleaseable())
150                {
151                    fs.closeCommunicationLink();
152                }
153            }
154        }
155    
156        /**
157         * Close the FileSystem.
158         * @param filesystem The FileSystem to close.
159         */
160        public void closeFileSystem(final FileSystem filesystem)
161        {
162            AbstractFileSystem fs = (AbstractFileSystem) filesystem;
163    
164            synchronized (this)
165            {
166                if (fs.getCacheKey() != null)
167                {
168                    fileSystems.remove(fs.getCacheKey());
169                }
170            }
171    
172            removeComponent(fs);
173            fs.close();
174        }
175    
176        /**
177         * Parses an absolute URI.
178         *
179         * @param base The base file - if null the <code>uri</code> needs to be absolute
180         * @param uri The URI to parse.
181         * @return The FileName.
182         * @throws FileSystemException if an error occurs.
183         */
184        public FileName parseUri(FileName base, String uri) throws FileSystemException
185        {
186            if (getFileNameParser() != null)
187            {
188                return getFileNameParser().parseUri(getContext(), base, uri);
189            }
190    
191            throw new FileSystemException("vfs.provider/filename-parser-missing.error");
192            // return GenericFileName.parseUri(getFileNameParser(), uri, 0);
193        }
194    }