package org.netbeans.gradle.project.model;
import java.io.IOException;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import org.jtrim.utils.ExceptionHelper;
import org.netbeans.gradle.project.properties.SettingsFiles;
import org.netbeans.gradle.project.util.NbFileUtils;
import org.netbeans.gradle.project.util.NbFunction;
import org.netbeans.gradle.project.util.StringUtils;
public final class MultiFileModelCache<T> implements PersistentModelCache<T> {
private final PersistentModelStore<T> modelPersister;
private final NbFunction<? super T, ? extends PersistentModelKey> modelKeyFactory;
public MultiFileModelCache(
PersistentModelStore<T> modelPersister,
NbFunction<? super T, ? extends PersistentModelKey> modelKeyFactory) {
ExceptionHelper.checkNotNullArgument(modelPersister, "modelPersister");
ExceptionHelper.checkNotNullArgument(modelKeyFactory, "modelKeyFactory");
this.modelPersister = modelPersister;
this.modelKeyFactory = modelKeyFactory;
}
private static MessageDigest getMD5() {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException("Unable to load the MD5 calculator.", ex);
}
}
@Override
public T tryGetModel(PersistentModelKey modelKey) throws IOException {
Path cacheFilePath = getCacheFilePath(modelKey, getMD5());
return modelPersister.tryLoadModel(cacheFilePath);
}
@Override
public void saveGradleModels(Collection<? extends T> models) throws IOException {
MessageDigest hashCalculator = getMD5();
for (T model: models) {
Path cacheFilePath = getCacheFilePath(model, hashCalculator);
modelPersister.persistModel(model, cacheFilePath);
}
}
private static String limitLength(String str, int maxLength) {
return str.length() > maxLength ? str.substring(0, maxLength) : str;
}
private static String getCacheKey(PersistentModelKey modelKey) throws IOException {
Path rootDir = modelKey.getRootPath();
String rootDirStr = rootDir.toString();
String projectDirStr = modelKey.getProjectDir().toString();
if (projectDirStr.startsWith(rootDirStr)) {
projectDirStr = projectDirStr.substring(rootDirStr.length());
}
return projectDirStr;
}
private static String getCacheFileName(
PersistentModelKey modelKey,
MessageDigest hashCalculator) throws IOException {
String cacheKey = getCacheKey(modelKey);
// We do this to limit the key length and make it usable as part of a file name.
hashCalculator.reset();
String keyHash = StringUtils.byteArrayToHex(hashCalculator.digest(cacheKey.getBytes(StringUtils.UTF8)));
return limitLength(NbFileUtils.getFileNameStr(modelKey.getProjectDir()), 16) + "-" + keyHash;
}
private Path getCacheFilePath(T model, MessageDigest hashCalculator) throws IOException {
PersistentModelKey modelKey = modelKeyFactory.apply(model);
return getCacheFilePath(modelKey, hashCalculator);
}
private static Path getCacheFilePath(
PersistentModelKey modelKey,
MessageDigest hashCalculator) throws IOException {
String fileName = getCacheFileName(modelKey, hashCalculator);
return SettingsFiles.getCacheDir(modelKey.getRootPath()).resolve(fileName);
}
}