package lombok.core.configuration;
import java.io.File;
import java.net.URI;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import lombok.core.debug.ProblemReporter;
public class FileSystemSourceCache {
private static final long FULL_CACHE_CLEAR_INTERVAL = TimeUnit.MINUTES.toMillis(30);
private static final long RECHECK_FILESYSTEM = TimeUnit.SECONDS.toMillis(2);
private static final long NEVER_CHECKED = -1;
static final long MISSING = -88;
private final ConcurrentMap<ConfigurationFile, Content> fileCache = new ConcurrentHashMap<ConfigurationFile, Content>();
private final ConcurrentMap<URI, ConfigurationFile> uriCache = new ConcurrentHashMap<URI, ConfigurationFile>();
private volatile long lastCacheClear = System.currentTimeMillis();
private void cacheClear() {
long now = System.currentTimeMillis();
long delta = now - lastCacheClear;
if (delta > FULL_CACHE_CLEAR_INTERVAL) {
lastCacheClear = now;
fileCache.clear();
uriCache.clear();
}
}
public ConfigurationFileToSource fileToSource(final ConfigurationParser parser) {
return new ConfigurationFileToSource() {
@Override public ConfigurationSource parsed(ConfigurationFile fileLocation) {
return parseIfNeccesary(fileLocation, parser);
}
};
}
public ConfigurationFile forUri(URI javaFile) {
if (javaFile == null) return null;
cacheClear();
ConfigurationFile result = uriCache.get(javaFile);
if (result == null) {
URI uri = javaFile.normalize();
if (!uri.isAbsolute()) uri = URI.create("file:" + uri.toString());
try {
File file = new File(uri);
if (!file.exists()) throw new IllegalArgumentException("File does not exist: " + uri);
File directory = file.isDirectory() ? file : file.getParentFile();
if (directory != null) result = ConfigurationFile.forDirectory(directory);
uriCache.put(javaFile, result);
} catch (IllegalArgumentException e) {
} catch (Exception e) {
ProblemReporter.error("Can't find absolute path of file being compiled: " + javaFile, e);
}
}
return result;
}
private ConfigurationSource parseIfNeccesary(ConfigurationFile file, ConfigurationParser parser) {
long now = System.currentTimeMillis();
Content content = ensureContent(file);
synchronized (content) {
if (content.lastChecked != NEVER_CHECKED && now - content.lastChecked < RECHECK_FILESYSTEM) {
return content.source;
}
content.lastChecked = now;
long previouslyModified = content.lastModified;
content.lastModified = file.getLastModifiedOrMissing();
if (content.lastModified != previouslyModified) content.source = content.lastModified == MISSING ? null : SingleConfigurationSource.parse(file, parser);
return content.source;
}
}
private Content ensureContent(ConfigurationFile context) {
Content content = fileCache.get(context);
if (content != null) {
return content;
}
fileCache.putIfAbsent(context, Content.empty());
return fileCache.get(context);
}
private static class Content {
ConfigurationSource source;
long lastModified;
long lastChecked;
private Content(ConfigurationSource source, long lastModified, long lastChecked) {
this.source = source;
this.lastModified = lastModified;
this.lastChecked = lastChecked;
}
static Content empty() {
return new Content(null, MISSING, NEVER_CHECKED);
}
}
}