View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2.provider;
18  
19  import java.util.Map;
20  import java.util.TreeMap;
21  import java.util.stream.Stream;
22  
23  import org.apache.commons.vfs2.FileName;
24  import org.apache.commons.vfs2.FileObject;
25  import org.apache.commons.vfs2.FileSystem;
26  import org.apache.commons.vfs2.FileSystemConfigBuilder;
27  import org.apache.commons.vfs2.FileSystemException;
28  import org.apache.commons.vfs2.FileSystemOptions;
29  import org.apache.commons.vfs2.provider.local.GenericFileNameParser;
30  
31  /**
32   * A partial {@link FileProvider} implementation. Takes care of managing the file systems created by the provider.
33   */
34  public abstract class AbstractFileProvider extends AbstractVfsContainer implements FileProvider {
35  
36      private static final AbstractFileSystemtractFileSystem">AbstractFileSystem[] EMPTY_ABSTRACT_FILE_SYSTEMS = new AbstractFileSystem[0];
37  
38      /**
39       * The cached file systems.
40       * <p>
41       * This is a mapping from {@link FileSystemKey} (root URI and options) to {@link FileSystem}.
42       * </p>
43       */
44      private final Map<FileSystemKey, FileSystem> fileSystemMap = new TreeMap<>(); // @GuardedBy("self")
45  
46      private FileNameParser parser;
47  
48      public AbstractFileProvider() {
49          parser = GenericFileNameParser.getInstance();
50      }
51  
52      protected FileNameParser getFileNameParser() {
53          return parser;
54      }
55  
56      protected void setFileNameParser(final FileNameParser parser) {
57          this.parser = parser;
58      }
59  
60      /**
61       * Closes the file systems created by this provider.
62       */
63      @Override
64      public void close() {
65          synchronized (fileSystemMap) {
66              fileSystemMap.clear();
67          }
68          super.close();
69      }
70  
71      /**
72       * Creates a layered file system. This method throws a 'not supported' exception.
73       *
74       * @param scheme The protocol to use to access the file.
75       * @param file a FileObject.
76       * @param fileSystemOptions Options to the file system.
77       * @return A FileObject associated with the new FileSystem.
78       * @throws FileSystemException if an error occurs.
79       */
80      @Override
81      public FileObject createFileSystem(FileObject="jxr_keyword">final String scheme, final FileObject file,
82          final FileSystemOptions fileSystemOptions) throws FileSystemException {
83          // Can't create a layered file system
84          throw new FileSystemException("vfs.provider/not-layered-fs.error", scheme);
85      }
86  
87      /**
88       * Adds a file system to those cached by this provider.
89       * <p>
90       * The file system may implement {@link VfsComponent}, in which case it is initialized.
91       * </p>
92       *
93       * @param key The root file of the file system, part of the cache key.
94       * @param fs the file system to add.
95       * @throws FileSystemException if any error occurs.
96       */
97      protected void addFileSystem(final Comparable<?> key, final FileSystem fs) throws FileSystemException {
98          // Add to the container and initialize
99          addComponent(fs);
100 
101         final FileSystemKeyFileSystemKey.html#FileSystemKey">FileSystemKey treeKey = new FileSystemKey(key, fs.getFileSystemOptions());
102         ((AbstractFileSystem) fs).setCacheKey(treeKey);
103 
104         synchronized (fileSystemMap) {
105             fileSystemMap.put(treeKey, fs);
106         }
107     }
108 
109     /**
110      * Locates a cached file system.
111      *
112      * @param key The root file of the file system, part of the cache key.
113      * @param fileSystemOptions file system options the file system instance must have, may be null.
114      * @return The file system instance, or null if it is not cached.
115      */
116     protected FileSystem findFileSystem(final Comparable<?> key, final FileSystemOptions fileSystemOptions) {
117         synchronized (fileSystemMap) {
118             return fileSystemMap.get(new FileSystemKey(key, fileSystemOptions));
119         }
120     }
121 
122     /**
123      * Returns the FileSystemConfigBuidler.
124      *
125      * @return the FileSystemConfigBuilder.
126      */
127     @Override
128     public FileSystemConfigBuilder getConfigBuilder() {
129         return null;
130     }
131 
132     /**
133      * Free unused resources.
134      */
135     public void freeUnusedResources() {
136         final AbstractFileSystem[] abstractFileSystems;
137         synchronized (fileSystemMap) {
138             // create snapshot under lock
139             abstractFileSystems = fileSystemMap.values().toArray(EMPTY_ABSTRACT_FILE_SYSTEMS);
140         }
141 
142         // process snapshot outside lock
143         Stream.of(abstractFileSystems).filter(AbstractFileSystem::isReleaseable)
144                                       .forEach(AbstractFileSystem::closeCommunicationLink);
145     }
146 
147     /**
148      * Close the FileSystem.
149      *
150      * @param fileSystem The FileSystem to close.
151      */
152     public void closeFileSystem(final FileSystem fileSystem) {
153         final AbstractFileSystem/../../org/apache/commons/vfs2/provider/AbstractFileSystem.html#AbstractFileSystem">AbstractFileSystem fs = (AbstractFileSystem) fileSystem;
154 
155         final FileSystemKey key = fs.getCacheKey();
156         if (key != null) {
157             synchronized (fileSystemMap) {
158                 fileSystemMap.remove(key);
159             }
160         }
161 
162         removeComponent(fs);
163         fs.close();
164     }
165 
166     /**
167      * Parses an absolute URI.
168      *
169      * @param base The base file - if null the {@code uri} needs to be absolute
170      * @param uri The URI to parse.
171      * @return The FileName.
172      * @throws FileSystemException if an error occurs.
173      */
174     @Override
175     public FileNameame.html#FileName">FileName parseUri(final FileName base, final String uri) throws FileSystemException {
176         if (getFileNameParser() != null) {
177             return getFileNameParser().parseUri(getContext(), base, uri);
178         }
179 
180         throw new FileSystemException("vfs.provider/filename-parser-missing.error");
181     }
182 }