package org.dru.clay.respository.cache;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.dru.clay.respository.transport.FileInfo;
import org.dru.clay.respository.transport.Transport;
import org.dru.clay.respository.transport.filesystem.FileSystemTransport;
import org.dru.clay.util.URIUtil;
import org.dru.clay.util.io.IOUtils;
public class CacheTransport implements Transport {
private static final Logger logger = Logger.getLogger(CacheTransport.class.getName());
private final Transport transport;
private final URI transportBase;
private final URI cacheBase;
private final CacheStrategy strategy;
private final FileSystemTransport cache;
private final CacheReader reader;
public CacheTransport(URI cacheBase, URI transportBase, Transport transport) {
this.cacheBase = cacheBase;
this.transportBase = transportBase;
this.transport = transport;
this.strategy = new CacheStrategy();
this.cache = new FileSystemTransport();
this.reader = new CacheReader();
}
public Transport getTransport() {
return transport;
}
@Override
public FileInfo get(URI uri) {
final URI cachedUri = URIUtil.rebase(uri, transportBase, cacheBase);
final CacheEntry cacheEntry = reader.load(cachedUri);
if (!strategy.updateCache(cachedUri, cacheEntry)) {
try {
return cache.get(cachedUri);
} catch (Exception e) {
logger.fine("Cache miss for " + cachedUri + " : " + e.getMessage());
}
}
final FileInfo fileInfo = transport.get(uri);
final byte[] content = fileInfo.getContent();
FileOutputStream outputStream = null;
final File file = new File(cachedUri.getPath());
try {
file.getParentFile().mkdirs();
outputStream = new FileOutputStream(file);
outputStream.write(content, 0, content.length);
} catch (Exception e) {
logger.warning("Couldn't update file cache for " + cachedUri);
} finally {
IOUtils.silentClose(outputStream);
}
file.setLastModified(fileInfo.getLastModified());
reader.touch(cachedUri, fileInfo.getLastModified());
return fileInfo;
}
@Override
public void get(URI uri, File destination) {
final URI cachedUri = URIUtil.rebase(uri, transportBase, cacheBase);
final CacheEntry cacheEntry = reader.load(cachedUri);
if (!strategy.updateCache(cachedUri, cacheEntry)) {
try {
cache.get(cachedUri, destination);
return;
} catch (Exception e) {
logger.fine("Cache miss for " + cachedUri + " : " + e.getMessage());
}
}
transport.getIfNewer(uri, destination);
cache.get(destination.toURI(), new File(cachedUri.getPath()));
reader.touch(cachedUri, destination.lastModified());
}
@Override
public void getIfNewer(URI uri, File destination) {
get(uri, destination);
}
@Override
public void put(File source, URI destination) {
final URI cachedUri = URIUtil.rebase(destination, transportBase, cacheBase);
transport.put(source, destination);
cache.put(source, cachedUri);
reader.touch(cachedUri, source.lastModified());
}
@Override
public List<URI> list(URI directory) {
final URI cachedUri = URIUtil.rebase(directory, transportBase, cacheBase);
final CacheEntry cacheEntry = reader.load(cachedUri);
if (!strategy.updateCache(cachedUri, cacheEntry)) {
final List<URI> list = new ArrayList<URI>();
for (URI uri : cache.list(cachedUri)) {
list.add(URIUtil.rebase(uri, cacheBase, transportBase));
}
return list;
}
final List<URI> list = transport.list(directory);
reader.touch(cachedUri, System.currentTimeMillis());
return list;
}
@Override
public void cleanup() {
transport.cleanup();
}
}