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: */
017: package org.apache.commons.vfs.cache;
018:
019: import java.util.HashMap;
020: import java.util.Map;
021:
022: import org.apache.commons.collections.map.AbstractLinkedMap;
023: import org.apache.commons.collections.map.LRUMap;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.apache.commons.vfs.FileName;
027: import org.apache.commons.vfs.FileObject;
028: import org.apache.commons.vfs.FileSystem;
029: import org.apache.commons.vfs.FileSystemException;
030: import org.apache.commons.vfs.VfsLog;
031: import org.apache.commons.vfs.util.Messages;
032:
033: /**
034: * This implementation caches every file using {@link LRUMap}.<br>
035: * The default constructor uses a LRU size of 100 per filesystem.
036: *
037: * @author <a href="mailto:imario@apache.org">Mario Ivankovits</a>
038: * @version $Revision: 480428 $ $Date: 2006-11-28 22:15:24 -0800 (Tue, 28 Nov 2006) $
039: */
040: public class LRUFilesCache extends AbstractFilesCache {
041: /**
042: * The logger to use.
043: */
044: private Log log = LogFactory.getLog(LRUFilesCache.class);
045:
046: private final Map filesystemCache = new HashMap(10);
047: private final int lruSize;
048:
049: private class MyLRUMap extends LRUMap {
050: final FileSystem filesystem;
051:
052: public MyLRUMap(final FileSystem filesystem, int size) {
053: super (size, true);
054: this .filesystem = filesystem;
055: }
056:
057: protected boolean removeLRU(
058: final AbstractLinkedMap.LinkEntry linkEntry) {
059: synchronized (LRUFilesCache.this ) {
060: FileObject file = (FileObject) linkEntry.getValue();
061:
062: // System.err.println(">>> " + size() + " check removeLRU:" + linkEntry.getKey().toString());
063:
064: if (file.isAttached() || file.isContentOpen()) {
065: // do not allow open or attached files to be removed
066: // System.err.println(">>> " + size() + " VETO removeLRU:" + linkEntry.getKey().toString() + " (" + file.isAttached() + "/" + file.isContentOpen() + ")");
067: return false;
068: }
069:
070: // System.err.println(">>> " + size() + " removeLRU:" + linkEntry.getKey().toString());
071: if (super .removeLRU(linkEntry)) {
072: try {
073: // force detach
074: file.close();
075: } catch (FileSystemException e) {
076: VfsLog
077: .warn(
078: getLogger(),
079: log,
080: Messages
081: .getString("vfs.impl/LRUFilesCache-remove-ex.warn"),
082: e);
083: }
084:
085: Map files = (Map) filesystemCache.get(filesystem);
086: if (files.size() < 1) {
087: filesystemCache.remove(filesystem);
088: }
089:
090: return true;
091: }
092:
093: return false;
094: }
095: }
096: }
097:
098: /**
099: * Default constructor. Uses a LRU size of 100 per filesystem.
100: */
101: public LRUFilesCache() {
102: this (100);
103: }
104:
105: /**
106: * Set the desired LRU size.
107: *
108: * @param lruSize the LRU size
109: */
110: public LRUFilesCache(int lruSize) {
111: this .lruSize = lruSize;
112: }
113:
114: public void putFile(final FileObject file) {
115: synchronized (this ) {
116: Map files = getOrCreateFilesystemCache(file.getFileSystem());
117:
118: // System.err.println(">>> " + files.size() + " put:" + file.toString());
119:
120: files.put(file.getName(), file);
121: }
122: }
123:
124: public FileObject getFile(final FileSystem filesystem,
125: final FileName name) {
126: synchronized (this ) {
127: Map files = getOrCreateFilesystemCache(filesystem);
128:
129: // FileObject fo = (FileObject) files.get(name);
130: // System.err.println(">>> " + files.size() + " get:" + name.toString() + " " + fo);
131:
132: return (FileObject) files.get(name);
133: }
134: }
135:
136: public void clear(final FileSystem filesystem) {
137: synchronized (this ) {
138: // System.err.println(">>> clear fs " + filesystem);
139:
140: Map files = getOrCreateFilesystemCache(filesystem);
141: files.clear();
142:
143: filesystemCache.remove(filesystem);
144: }
145: }
146:
147: protected Map getOrCreateFilesystemCache(final FileSystem filesystem) {
148: Map files = (Map) filesystemCache.get(filesystem);
149: if (files == null) {
150: // System.err.println(">>> create fs " + filesystem);
151:
152: files = new MyLRUMap(filesystem, lruSize);
153: filesystemCache.put(filesystem, files);
154: }
155:
156: return files;
157: }
158:
159: public void close() {
160: super .close();
161:
162: synchronized (this ) {
163: // System.err.println(">>> clear all");
164:
165: filesystemCache.clear();
166: }
167: }
168:
169: public void removeFile(final FileSystem filesystem,
170: final FileName name) {
171: synchronized (this ) {
172: Map files = getOrCreateFilesystemCache(filesystem);
173:
174: // System.err.println(">>> " + files.size() + " remove:" + name.toString());
175:
176: files.remove(name);
177:
178: if (files.size() < 1) {
179: filesystemCache.remove(filesystem);
180: }
181: }
182: }
183:
184: public void touchFile(final FileObject file) {
185: // this moves the file back on top
186: getFile(file.getFileSystem(), file.getName());
187: }
188: }
|