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
032 * file systems created by the provider.
033 */
034public abstract class AbstractFileProvider
035    extends AbstractVfsContainer
036    implements FileProvider
037{
038    /**
039     * The cached file systems.  This is a mapping from root URI to
040     * FileSystem object.
041     */
042    // private final Map fileSystems = new HashMap();
043    private final Map<FileSystemKey, FileSystem> fileSystems = new TreeMap<FileSystemKey, FileSystem>();
044
045    private FileNameParser parser;
046
047    public AbstractFileProvider()
048    {
049        parser = GenericFileNameParser.getInstance();
050    }
051
052    protected FileNameParser getFileNameParser()
053    {
054        return parser;
055    }
056
057    protected void setFileNameParser(final FileNameParser parser)
058    {
059        this.parser = parser;
060    }
061
062    /**
063     * Closes the file systems created by this provider.
064     */
065    @Override
066    public void close()
067    {
068        synchronized (this)
069        {
070            fileSystems.clear();
071        }
072
073        super.close();
074    }
075
076    /**
077     * Creates a layered file system.  This method throws a 'not supported' exception.
078     * @param scheme The protocol to use to access the file.
079     * @param file a FileObject.
080     * @param properties Options to the file system.
081     * @return A FileObject associated with the new FileSystem.
082     * @throws FileSystemException if an error occurs.
083     */
084    @Override
085    public FileObject createFileSystem(final String scheme, final FileObject file, final FileSystemOptions properties)
086        throws FileSystemException
087    {
088        // Can't create a layered file system
089        throw new FileSystemException("vfs.provider/not-layered-fs.error", scheme);
090    }
091
092    /**
093     * Adds a file system to those cached by this provider.  The file system
094     * may implement {@link VfsComponent}, in which case it is initialised.
095     */
096    protected void addFileSystem(final Comparable<?> key, final FileSystem fs)
097        throws FileSystemException
098    {
099        // Add to the cache
100        addComponent(fs);
101
102        final FileSystemKey treeKey = new FileSystemKey(key, fs.getFileSystemOptions());
103        ((AbstractFileSystem) fs).setCacheKey(treeKey);
104
105        synchronized (this)
106        {
107            fileSystems.put(treeKey, fs);
108        }
109    }
110
111    /**
112     * Locates a cached file system
113     *
114     * @return The provider, or null if it is not cached.
115     */
116    protected FileSystem findFileSystem(final Comparable<?> key, final FileSystemOptions fileSystemProps)
117    {
118        final FileSystemKey treeKey = new FileSystemKey(key, fileSystemProps);
119
120        synchronized (this)
121        {
122            return fileSystems.get(treeKey);
123        }
124    }
125
126    /**
127     * Returns the FileSystemConfigBuidler.
128     * @return the FileSystemConfigBuilder.
129     */
130    @Override
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 (final Object element : item)
147        {
148            final AbstractFileSystem fs = (AbstractFileSystem) element;
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        final 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} needs to be absolute
180     * @param uri The URI to parse.
181     * @return The FileName.
182     * @throws FileSystemException if an error occurs.
183     */
184    @Override
185    public FileName parseUri(final FileName base, final String uri) throws FileSystemException
186    {
187        if (getFileNameParser() != null)
188        {
189            return getFileNameParser().parseUri(getContext(), base, uri);
190        }
191
192        throw new FileSystemException("vfs.provider/filename-parser-missing.error");
193        // return GenericFileName.parseUri(getFileNameParser(), uri, 0);
194    }
195}