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.cache;
18  
19  import java.util.Map;
20  import java.util.concurrent.ConcurrentHashMap;
21  import java.util.concurrent.ConcurrentMap;
22  
23  import org.apache.commons.vfs2.FileName;
24  import org.apache.commons.vfs2.FileObject;
25  import org.apache.commons.vfs2.FileSystem;
26  
27  /**
28   * A simple {@link org.apache.commons.vfs2.FilesCache FilesCache} implementation.
29   * <p>
30   * This implementation caches every file with no expire or limit. All files and file systems are hard reachable
31   * references. This implementation holds a list of file system specific {@linkplain ConcurrentHashMap ConcurrentHashMaps}
32   * in the main cache map.
33   * </p>
34   * <p>
35   * Cached {@linkplain FileObject FileObjects} as well as {@linkplain FileSystem FileSystems} are only removed when
36   * {@link #clear(FileSystem)} is called (i.e. on file system close). When the used
37   * {@link org.apache.commons.vfs2.FileSystemManager FileSystemManager} is closed, it will also {@linkplain #close()
38   * close} this cache (which frees all entries).
39   * </p>
40   * <p>
41   * Despite its name, this is not the fallback implementation used by
42   * {@link org.apache.commons.vfs2.impl.DefaultFileSystemManager#init() DefaultFileSystemManager#init()} anymore.
43   * </p>
44   */
45  public class DefaultFilesCache extends AbstractFilesCache {
46  
47      /** The FileSystem cache. Keeps one Map for each FileSystem. */
48      private final ConcurrentMap<FileSystem, ConcurrentMap<FileName, FileObject>> filesystemCache = new ConcurrentHashMap<>(
49              10);
50  
51      @Override
52      public void putFile(final FileObject file) {
53          final Map<FileName, FileObject> files = getOrCreateFilesystemCache(file.getFileSystem());
54          files.put(file.getName(), file);
55      }
56  
57      @Override
58      public boolean putFileIfAbsent(final FileObject file) {
59          final ConcurrentMap<FileName, FileObject> files = getOrCreateFilesystemCache(file.getFileSystem());
60          return files.putIfAbsent(file.getName(), file) == null;
61      }
62  
63      @Override
64      public FileObject getFile(final FileSystem filesystem, final FileName name) {
65          // avoid creating filesystem entry for empty filesystem cache:
66          final Map<FileName, FileObject> files = filesystemCache.get(filesystem);
67          if (files == null) {
68              // cache for filesystem is not known => file is not cached:
69              return null;
70          }
71  
72          return files.get(name); // or null
73      }
74  
75      @Override
76      public void clear(final FileSystem filesystem) {
77          // avoid keeping a reference to the FileSystem (key) object
78          final Map<FileName, FileObject> files = filesystemCache.remove(filesystem);
79          if (files != null) {
80              files.clear(); // help GC
81          }
82      }
83  
84      protected ConcurrentMap<FileName, FileObject> getOrCreateFilesystemCache(final FileSystem filesystem) {
85          ConcurrentMap<FileName, FileObject> files = filesystemCache.get(filesystem);
86          // we loop to make sure we never return null even when concurrent clean is called
87          while (files == null) {
88              filesystemCache.putIfAbsent(filesystem, new ConcurrentHashMap<>(200, 0.75f, 8));
89              files = filesystemCache.get(filesystem);
90          }
91  
92          return files;
93      }
94  
95      @Override
96      public void close() {
97          super.close();
98          filesystemCache.clear();
99      }
100 
101     @Override
102     public void removeFile(final FileSystem filesystem, final FileName name) {
103         // avoid creating filesystem entry for empty filesystem cache:
104         final Map<FileName, FileObject> files = filesystemCache.get(filesystem);
105         if (files != null) {
106             files.remove(name);
107             // This would be too racey:
108             // if (files.empty()) filesystemCache.remove(filessystem);
109         }
110     }
111 }