| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.vfs.cache; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.apache.commons.collections.map.AbstractLinkedMap; |
| import org.apache.commons.collections.map.LRUMap; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.commons.vfs.FileName; |
| import org.apache.commons.vfs.FileObject; |
| import org.apache.commons.vfs.FileSystem; |
| import org.apache.commons.vfs.FileSystemException; |
| import org.apache.commons.vfs.VfsLog; |
| import org.apache.commons.vfs.util.Messages; |
| |
| /** |
| * This implementation caches every file using {@link LRUMap}.<br> |
| * The default constructor uses a LRU size of 100 per filesystem. |
| * |
| * @author <a href="mailto:imario@apache.org">Mario Ivankovits</a> |
| * @version $Revision$ $Date$ |
| */ |
| public class LRUFilesCache extends AbstractFilesCache |
| { |
| /** The default LRU size */ |
| private static final int DEFAULT_LRU_SIZE = 100; |
| /** |
| * The logger to use. |
| */ |
| private final Log log = LogFactory.getLog(LRUFilesCache.class); |
| |
| /** The FileSystem cache */ |
| private final Map filesystemCache = new HashMap(10); |
| |
| /** The size of the cache */ |
| private final int lruSize; |
| |
| /** |
| * The file cache |
| */ |
| private class MyLRUMap extends LRUMap |
| { |
| /** The FileSystem */ |
| private final FileSystem filesystem; |
| |
| public MyLRUMap(final FileSystem filesystem, int size) |
| { |
| super(size, true); |
| this.filesystem = filesystem; |
| } |
| |
| protected boolean removeLRU(final AbstractLinkedMap.LinkEntry linkEntry) |
| { |
| synchronized (LRUFilesCache.this) |
| { |
| FileObject file = (FileObject) linkEntry.getValue(); |
| |
| // System.err.println(">>> " + size() + " check removeLRU:" + linkEntry.getKey().toString()); |
| |
| if (file.isAttached() || file.isContentOpen()) |
| { |
| // do not allow open or attached files to be removed |
| // System.err.println(">>> " + size() + " VETO removeLRU:" + |
| // linkEntry.getKey().toString() + " (" + file.isAttached() + "/" + |
| // file.isContentOpen() + ")"); |
| return false; |
| } |
| |
| // System.err.println(">>> " + size() + " removeLRU:" + linkEntry.getKey().toString()); |
| if (super.removeLRU(linkEntry)) |
| { |
| try |
| { |
| // force detach |
| file.close(); |
| } |
| catch (FileSystemException e) |
| { |
| VfsLog.warn(getLogger(), log, Messages.getString("vfs.impl/LRUFilesCache-remove-ex.warn"), e); |
| } |
| |
| Map files = (Map) filesystemCache.get(filesystem); |
| if (files.size() < 1) |
| { |
| filesystemCache.remove(filesystem); |
| } |
| |
| return true; |
| } |
| |
| return false; |
| } |
| } |
| } |
| |
| /** |
| * Default constructor. Uses a LRU size of 100 per filesystem. |
| */ |
| public LRUFilesCache() |
| { |
| this(DEFAULT_LRU_SIZE); |
| } |
| |
| /** |
| * Set the desired LRU size. |
| * |
| * @param lruSize the LRU size |
| */ |
| public LRUFilesCache(int lruSize) |
| { |
| this.lruSize = lruSize; |
| } |
| |
| public void putFile(final FileObject file) |
| { |
| synchronized (this) |
| { |
| Map files = getOrCreateFilesystemCache(file.getFileSystem()); |
| |
| // System.err.println(">>> " + files.size() + " put:" + file.toString()); |
| |
| files.put(file.getName(), file); |
| } |
| } |
| |
| public FileObject getFile(final FileSystem filesystem, final FileName name) |
| { |
| synchronized (this) |
| { |
| Map files = getOrCreateFilesystemCache(filesystem); |
| |
| // FileObject fo = (FileObject) files.get(name); |
| // System.err.println(">>> " + files.size() + " get:" + name.toString() + " " + fo); |
| |
| return (FileObject) files.get(name); |
| } |
| } |
| |
| public void clear(final FileSystem filesystem) |
| { |
| synchronized (this) |
| { |
| // System.err.println(">>> clear fs " + filesystem); |
| |
| Map files = getOrCreateFilesystemCache(filesystem); |
| files.clear(); |
| |
| filesystemCache.remove(filesystem); |
| } |
| } |
| |
| protected Map getOrCreateFilesystemCache(final FileSystem filesystem) |
| { |
| Map files = (Map) filesystemCache.get(filesystem); |
| if (files == null) |
| { |
| // System.err.println(">>> create fs " + filesystem); |
| |
| files = new MyLRUMap(filesystem, lruSize); |
| filesystemCache.put(filesystem, files); |
| } |
| |
| return files; |
| } |
| |
| public void close() |
| { |
| super.close(); |
| |
| synchronized (this) |
| { |
| // System.err.println(">>> clear all"); |
| |
| filesystemCache.clear(); |
| } |
| } |
| |
| public void removeFile(final FileSystem filesystem, final FileName name) |
| { |
| synchronized (this) |
| { |
| Map files = getOrCreateFilesystemCache(filesystem); |
| |
| // System.err.println(">>> " + files.size() + " remove:" + name.toString()); |
| |
| files.remove(name); |
| |
| if (files.size() < 1) |
| { |
| filesystemCache.remove(filesystem); |
| } |
| } |
| } |
| |
| public void touchFile(final FileObject file) |
| { |
| // this moves the file back on top |
| getFile(file.getFileSystem(), file.getName()); |
| } |
| } |