package org.eclipse.team.internal.core;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.osgi.util.NLS;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.variants.CachedResourceVariant;
public class ResourceVariantCache {
private static final String CACHE_DIRECTORY = ".cache";
private static final long CACHE_FILE_LIFESPAN = 60*60*1000;
private static Map<String, ResourceVariantCache> caches = new HashMap<>();
private String name;
private Map<String, ResourceVariantCacheEntry> cacheEntries;
private long lastCacheCleanup;
private int cacheDirSize;
private ILock lock = Job.getJobManager().newLock();
public static synchronized void enableCaching(String cacheId) {
if (isCachingEnabled(cacheId)) return;
ResourceVariantCache cache = new ResourceVariantCache(cacheId);
cache.createCacheDirectory();
caches.put(cacheId, cache);
}
public static boolean isCachingEnabled(String cacheId) {
return getCache(cacheId) != null;
}
public static void disableCache(String cacheId) {
ResourceVariantCache cache = getCache(cacheId);
if (cache == null) {
return;
}
caches.remove(cacheId);
cache.deleteCacheDirectory();
}
public static synchronized ResourceVariantCache getCache(String cacheId) {
return caches.get(cacheId);
}
public static synchronized void shutdown() {
String[] keys = caches.keySet().toArray(new String[caches.size()]);
for (String id : keys) {
disableCache(id);
}
}
private ResourceVariantCache(String name) {
this.name = name;
}
public boolean hasEntry(String id) {
return internalGetCacheEntry(id) != null;
}
protected IPath getCachePath() {
return getStateLocation().append(CACHE_DIRECTORY).append(name);
}
private IPath getStateLocation() {
return TeamPlugin.getPlugin().getStateLocation();
}
private synchronized void clearOldCacheEntries() {
long current = new Date().getTime();
if ((lastCacheCleanup!=-1) && (current - lastCacheCleanup < CACHE_FILE_LIFESPAN)) return;
List<ResourceVariantCacheEntry> stale = new ArrayList<>();
for (ResourceVariantCacheEntry entry : cacheEntries.values()) {
long lastHit = entry.getLastAccessTimeStamp();
if ((current - lastHit) > CACHE_FILE_LIFESPAN){
stale.add(entry);
}
}
for (ResourceVariantCacheEntry entry : stale) {
entry.dispose();
}
}
private synchronized void purgeFromCache(String id) {
ResourceVariantCacheEntry entry = cacheEntries.get(id);
File f = entry.getFile();
try {
deleteFile(f);
} catch (TeamException e) {
}
cacheEntries.remove(id);
}
private synchronized void createCacheDirectory() {
IPath cacheLocation = getCachePath();
File file = cacheLocation.toFile();
if (file.exists()) {
try {
deleteFile(file);
} catch (TeamException e) {
File[] fileList = file.listFiles();
if (file.exists() && (!file.isDirectory() || (fileList != null && fileList.length != 0))) {
TeamPlugin.log(e);
}
}
}
if (! file.exists() && ! file.mkdirs()) {
TeamPlugin.log(new TeamException(NLS.bind(Messages.RemoteContentsCache_fileError, new String[] { file.getAbsolutePath() })));
}
cacheEntries = new HashMap<>();
lastCacheCleanup = -1;
cacheDirSize = 0;
}
private synchronized void deleteCacheDirectory() {
cacheEntries = null;
lastCacheCleanup = -1;
cacheDirSize = 0;
IPath cacheLocation = getCachePath();
File file = cacheLocation.toFile();
if (file.exists()) {
try {
deleteFile(file);
} catch (TeamException e) {
}
}
}
private void deleteFile(File file) throws TeamException {
if (file.isDirectory()) {
File[] children = file.listFiles();
if(children == null) {
throw new TeamException(NLS.bind(Messages.RemoteContentsCache_fileError, new String[] { file.getAbsolutePath() }));
}
for (File f : children) {
deleteFile(f);
}
}
if (! file.delete()) {
throw new TeamException(NLS.bind(Messages.RemoteContentsCache_fileError, new String[] { file.getAbsolutePath() }));
}
}
protected void purgeFromCache(ResourceVariantCacheEntry entry) {
purgeFromCache(entry.getId());
}
private synchronized ResourceVariantCacheEntry internalGetCacheEntry(String id) {
if (cacheEntries == null) {
throw new IllegalStateException(NLS.bind(Messages.RemoteContentsCache_cacheDisposed, new String[] { name }));
}
ResourceVariantCacheEntry entry = cacheEntries.get(id);
if (entry != null) {
entry.registerHit();
}
return entry;
}
public ResourceVariantCacheEntry getCacheEntry(String id) {
return internalGetCacheEntry(id);
}
public synchronized ResourceVariantCacheEntry add(String id, CachedResourceVariant resource) {
clearOldCacheEntries();
String filePath = String.valueOf(cacheDirSize++);
ResourceVariantCacheEntry entry = new ResourceVariantCacheEntry(this, lock, id, filePath);
entry.setResourceVariant(resource);
cacheEntries.put(id, entry);
return entry;
}
public String getName() {
return name;
}
public ResourceVariantCacheEntry[] getEntries() {
return cacheEntries.values().toArray(new ResourceVariantCacheEntry[cacheEntries.size()]);
}
}