package com.limegroup.gnutella.auth;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.limegroup.gnutella.ErrorService;
import com.limegroup.gnutella.URN;
import com.limegroup.gnutella.util.CommonUtils;
import com.limegroup.gnutella.util.IOUtils;
/**
* A repository of content responses.
*/
class ContentCache {
private static final Log LOG = LogFactory.getLog(ContentCache.class);
/** The amount of time to keep a response in the cache. */
private static final long EXPIRY_TIME = 7 * 24 * 60 * 60 * 1000; // one week.
/** File where the licenses are serialized. */
private final File CACHE_FILE =
new File(CommonUtils.getUserSettingsDir(), "responses.cache");
/** Map of SHA1 to Responses. */
private Map /* URN -> ContentResponseData */ responses = new HashMap();
/** Whether or not data is dirty since the last time we wrote to disk. */
private boolean dirty = false;
/** Determines if there is a response for the given URN. */
synchronized boolean hasResponseFor(URN urn) {
return responses.containsKey(urn);
}
/** Adds the given response for the given URN. */
synchronized void addResponse(URN urn, ContentResponseData response) {
responses.put(urn, response);
dirty = true;
}
/** Gets the response for the given URN. */
synchronized ContentResponseData getResponse(URN urn) {
return (ContentResponseData)responses.get(urn);
}
/** Initializes this cache. */
synchronized void initialize() {
dirty = false;
deserialize();
}
/** Writes to disk. */
synchronized void writeToDisk() {
if(dirty)
persistCache();
dirty = false;
}
/**
* Loads values from cache file, if available.
*/
private void deserialize() {
long cutoff = System.currentTimeMillis() - EXPIRY_TIME;
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(CACHE_FILE)));
Map map = (Map)ois.readObject();
if(map != null) {
for(Iterator i = map.entrySet().iterator(); i.hasNext(); ) {
// Remove values that aren't correct.
Map.Entry next = (Map.Entry)i.next();
Object key = next.getKey();
Object value = next.getValue();
if( !(key instanceof URN) || !(value instanceof ContentResponseData) ) {
if(LOG.isWarnEnabled())
LOG.warn("Invalid k[" + key + "], v[" + value + "]");
i.remove();
dirty = true;
}
if(((ContentResponseData)value).getCreationTime() < cutoff) {
if(LOG.isWarnEnabled())
LOG.warn("Removing old response [" + value + "]");
i.remove();
dirty = true;
}
}
} else {
map = new HashMap();
}
responses = map;
} catch(Throwable t) {
dirty = true;
LOG.error("Can't read responses", t);
} finally {
IOUtils.close(ois);
if(responses == null)
responses = new HashMap();
}
}
/**
* Write cache so that we only have to calculate them once.
*/
public void persistCache() {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(CACHE_FILE)));
oos.writeObject(responses);
oos.flush();
} catch (IOException e) {
ErrorService.error(e);
} finally {
IOUtils.close(oos);
}
}
}