001: package org.columba.core.io;
002:
003: import java.io.File;
004: import java.io.FileInputStream;
005: import java.io.FileNotFoundException;
006: import java.io.FileOutputStream;
007: import java.io.IOException;
008: import java.io.InputStream;
009: import java.io.ObjectInputStream;
010: import java.io.ObjectOutputStream;
011: import java.io.Serializable;
012: import java.util.ArrayList;
013: import java.util.Collections;
014: import java.util.Comparator;
015: import java.util.Date;
016: import java.util.Iterator;
017: import java.util.List;
018:
019: public class StreamCache {
020:
021: public static final long DEFAULT_SIZE = 10 * 1024 * 1024;// Byte
022:
023: public static final String FIFO_FILE = ".fifo";
024:
025: private File dir;
026:
027: private List<CacheEntry> fifo;
028:
029: private long actSize;
030:
031: private long maxSize;
032:
033: public StreamCache(File directory) {
034: this (directory, DEFAULT_SIZE);
035: }
036:
037: public StreamCache(File directory, long maxSize) {
038: dir = directory;
039: if (!dir.exists()) {
040: if (!dir.mkdirs()) {
041: throw new RuntimeException(dir.toString()
042: + " could not be created!");
043: }
044: } else {
045: // try to restore from previous session
046: try {
047: restore();
048: } catch (IOException e) {
049: // Never mind
050: }
051: }
052: actSize = 0;
053:
054: // If the fifo could not be restored initialize it
055: if (fifo == null) {
056: fifo = new ArrayList<CacheEntry>(100);
057: }
058:
059: this .maxSize = maxSize;
060: }
061:
062: public InputStream passiveAdd(Object key, InputStream in)
063: throws IOException {
064: File streamFile = new File(dir.getAbsoluteFile()
065: + File.separator + key.toString() + ".cache");
066: return new StreamCacheCopyStream(in, key, streamFile, this );
067: }
068:
069: public void activeAdd(Object key, InputStream in)
070: throws IOException {
071: File streamFile = new File(dir.getAbsoluteFile()
072: + File.separator + key.toString() + ".cache");
073: StreamUtils.streamCopy(in, new FileOutputStream(streamFile));
074: add(key, streamFile);
075: }
076:
077: void add(Object key, File out) {
078: fifo.add(new CacheEntry(key, out));
079:
080: actSize += out.length();
081:
082: Comparator _myComperator = new Comparator() {
083:
084: public int compare(Object arg0, Object arg1) {
085: Date a = ((CacheEntry) arg0).lastAccess;
086: Date b = ((CacheEntry) arg1).lastAccess;
087:
088: if (a.before(b))
089: return 1;
090: if (a.after(b))
091: return -1;
092: return 0;
093: }
094:
095: };
096: Collections.sort(fifo, _myComperator);
097:
098: ensureMaxSize();
099: }
100:
101: private void ensureMaxSize() {
102: while (actSize > maxSize) {
103: CacheEntry entry = fifo.remove(fifo.size() - 1);
104: actSize -= entry.file.length();
105: entry.file.delete();
106: }
107: }
108:
109: public InputStream get(Object key) {
110: Iterator it = fifo.iterator();
111:
112: while (it.hasNext()) {
113: CacheEntry c = (CacheEntry) it.next();
114: if (c.key.equals(key)) {
115: try {
116: return c.createStream();
117: } catch (FileNotFoundException e) {
118: it.remove();
119: actSize -= c.file.length();
120: }
121: }
122: }
123:
124: return null;
125: }
126:
127: public long getActSize() {
128: return actSize;
129: }
130:
131: public void clear() {
132: Iterator it = fifo.iterator();
133:
134: while (it.hasNext()) {
135: CacheEntry c = (CacheEntry) it.next();
136: if (!c.file.delete()) {
137: // Try again after shutdown
138: c.file.deleteOnExit();
139: }
140: it.remove();
141: }
142:
143: actSize = 0;
144: }
145:
146: public void persist() throws IOException {
147: File file = new File(dir.getAbsoluteFile() + File.separator
148: + FIFO_FILE);
149: ObjectOutputStream out = new ObjectOutputStream(
150: new FileOutputStream(file));
151: out.writeObject(fifo);
152: out.close();
153: }
154:
155: public void restore() throws IOException {
156: File file = new File(dir.getAbsoluteFile() + File.separator
157: + FIFO_FILE);
158: try {
159: fifo = (List<CacheEntry>) new ObjectInputStream(
160: new FileInputStream(file)).readObject();
161: } catch (ClassNotFoundException e) {
162: // ignore this yet
163: }
164: }
165:
166: public long getMaxSize() {
167: return maxSize;
168: }
169:
170: public void setMaxSize(long maxSize) {
171: this .maxSize = maxSize;
172: ensureMaxSize();
173: }
174: }
175:
176: @SuppressWarnings({"serial","serial"})
177: class CacheEntry implements Serializable {
178: Date lastAccess;
179:
180: Object key;
181:
182: File file;
183:
184: public CacheEntry(Object key, File file) {
185: this .key = key;
186: this .file = file;
187: this .lastAccess = new Date();
188: }
189:
190: public InputStream createStream() throws FileNotFoundException {
191: this .lastAccess = new Date();
192: return new FileInputStream(file);
193: }
194:
195: /**
196: * @return Returns the file.
197: */
198: public File getFile() {
199: return file;
200: }
201:
202: /**
203: * @param file
204: * The file to set.
205: */
206: public void setFile(File file) {
207: this .file = file;
208: }
209:
210: /**
211: * @return Returns the key.
212: */
213: public Object getKey() {
214: return key;
215: }
216:
217: /**
218: * @param key
219: * The key to set.
220: */
221: public void setKey(Object key) {
222: this .key = key;
223: }
224:
225: /**
226: * @return Returns the lastAccess.
227: */
228: public Date getLastAccess() {
229: return lastAccess;
230: }
231:
232: /**
233: * @param lastAccess
234: * The lastAccess to set.
235: */
236: public void setLastAccess(Date lastAccess) {
237: this.lastAccess = lastAccess;
238: }
239: }
|