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