package edu.colostate.vchill.cache;
import edu.colostate.vchill.ControlMessage;
import java.util.*;
/**
* Implementation of a cache that removes it's
* eldest element first once it reaches a
* maximum allowable size. It's supposed to be
* an LRU (Least Recently Used) cache it looks
* like but fails to implement this functionality.
* This implementation is fully synchronized -
* external synchronization is not necessary.
*
* @author Jochen Deyke
* @author jpont
* @version 2010-08-30
*/
public class CacheMainLRU extends CacheMain {
private final Map<ControlMessage, CacheType<Object>> cache;
/**
* @param maxTypesToCache the maximum number of sweeps/types to store at once
*/
public CacheMainLRU(final int maxTypesToCache) {
this.cache = new LinkedHashMap<ControlMessage, CacheType<Object>>(maxTypesToCache) {
/**
*
*/
private static final long serialVersionUID = 7608231869146777712L;
@Override
protected boolean removeEldestEntry(Map.Entry<ControlMessage, CacheType<Object>> eldest) {
return this.size() > maxTypesToCache;
}
};
}
/**
* Retrieves data from the cache
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the desired data
* @param ray the 0-based index of the desired data within the sweep/type
* @return the requested data
*/
@Override
public Object getData(final ControlMessage key, final String type, final int ray) {
return selectType(key).getData(type, ray);
}
/**
* Retrieves data from the cache. If the data is not yet available, waits
* for the data to become available or the sweep to be marked complete.
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the desired data
* @param ray the 0-based index of the desired data within the sweep/type
* @return the requested data
*/
@Override
public Object getDataWait(final ControlMessage key, final String type, final int ray) {
return selectType(key).getDataWait(type, ray);
}
/**
* Retrieves data from the cache. If the data is not yet available, waits
* for the data to become available or the sweep to be marked complete.
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the desired data
* @param ray the 0-based index of the desired data within the sweep/type
* @param timeout the maximum number of milliseconds to wait
* @return the requested data
*/
@Override
public Object getDataWait(final ControlMessage key, final String type, final int ray, final long timeout) {
return selectType(key).getDataWait(type, ray, timeout);
}
/**
* Appends data to the cache
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the desired data
* @param type the field name to deal with
* @param data the data to store
*/
@Override
public void addRay(final ControlMessage key, final String type, final Object data) {
if (!getCompleteFlag(key, type)) selectType(key).addRay(type, data);
}
/**
* Retrieves the CacheType matching <i>key</i> from the cache.
* <p/>
* If the desired CacheType does not exist, it is created and added to the cache.
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the desired data
* @return the requested CacheType
*/
private CacheType<Object> selectType(final ControlMessage key) {
synchronized (this.cache) {
CacheType<Object> type = this.cache.get(key);
if (type == null) this.cache.put(key, (type = new CacheType<Object>()));
return type;
}
}
/**
* Removes a sweep/type from the cache. This is useful for removing partially loaded / aborted data.
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the desired data
* @param type the field name to deal with
*/
@Override
public void removeType(final ControlMessage key, final String type) {
synchronized (this.cache) {
this.cache.remove(key);
}
}
/**
* Gets the number of cached rays
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the desired data
* @param type the field name to deal with
* @return the number of available rays of the specified sweep/type
*/
@Override
public int getNumberOfRays(final ControlMessage key, final String type) {
return selectType(key).getNumberOfRays(type);
}
/**
* Gets the list of all currently active connections.
* Each is identified by a string of the format servername:port
*
* @return a Collection of String objects containing available servers and ports
*/
@Override
public Collection<String> getConnectionList() {
synchronized (this.cache) {
Set<String> urls = new HashSet<String>();
for (ControlMessage msg : this.cache.keySet()) urls.add(msg.getURL());
return urls;
}
}
/**
* Gets a list of available directories, given a server and port number
*
* @param key ControlMessage containing server and port (other fields are ignored)
* @return a Collection of String objects in the format other Cache methods want
*/
public Collection<String> getDirectoryList(final ControlMessage key) {
synchronized (this.cache) {
Set<String> dirs = new HashSet<String>();
for (ControlMessage msg : this.cache.keySet()) {
if (key.getURL().equals(msg.getURL())) dirs.add(msg.getDir());
}
dirs.remove(null); //just in case
return dirs;
}
}
/**
* Gets a list of available files in a given directory
*
* @param key ControlMessage containing the directory, server, and port to list (other fields are ignored)
* @return a Collection of String objects in the format other Cache methods want
*/
public Collection<String> getFileList(final ControlMessage key) {
synchronized (this.cache) {
Set<String> files = new HashSet<String>();
for (ControlMessage msg : this.cache.keySet()) {
if (key.getURL().equals(msg.getURL()) && key.getDir().equals(msg.getDir())) files.add(msg.getFile());
}
return files;
}
}
/**
* Gets a list of available sweeps in a given file
*
* @param key ControlMessage containing the file, directory, server, and port to list (other fields are ignored)
* @return a Collection of String objects in the format other Cache methods want
*/
@Override
public Collection<String> getSweepList(final ControlMessage key) {
synchronized (this.cache) {
Set<String> sweeps = new HashSet<String>();
for (ControlMessage msg : this.cache.keySet()) {
if (key.getURL().equals(msg.getURL()) && key.getDir().equals(msg.getDir()) && key.getFile().equals(msg.getFile()))
sweeps.add(msg.getSweep());
}
return sweeps;
}
}
/**
* Marks a sweep/type as complete
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the sweep/type to mark complete
* @param type the field name to deal with
*/
@Override
public void setCompleteFlag(final ControlMessage key, final String type) {
selectType(key).setCompleteFlag(type);
}
/**
* Checks whether a sweep/type is complete
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the sweep/type to check
* @param type the field name to deal with
* @return is the sweep/type complete?
*/
@Override
public boolean getCompleteFlag(final ControlMessage key, final String type) {
return selectType(key).getCompleteFlag(type);
}
/**
* Checks whether a sweep/type is empty
*
* @param key ControlMessage containing server, port, dir, file, sweep, and type information of the sweep/type to check
* @param type the field name to deal with
* @return is the sweep/type empty?
*/
@Override
public boolean isEmpty(final ControlMessage key, final String type) {
return selectType(key).isEmpty(type);
}
/**
* Removes all entries from the cache
*/
@Override
public void clear() {
synchronized (this.cache) {
this.cache.clear();
}
}
}