StringKeyFileManager.java
package net.morimekta.providence.storage.dir;
import net.morimekta.util.FileUtil;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.Normalizer;
import java.util.Collection;
import java.util.HashSet;
/**
* File manager for the {@link net.morimekta.providence.storage.DirectoryMessageStore}
* and {@link net.morimekta.providence.storage.DirectoryMessageListStore} store
* classes that keeps all files in a single directory, and keeps a <code>.tmp</code>
* directory for temporary files. Note that this differs from the DefaultFileManager
* that it does not allow full paths for the key, e.g. cannot contain file separator
* in the key string.
*/
public class StringKeyFileManager implements FileManager<String> {
private static final String TMP_DIR = ".tmp";
private final Path directory;
private final Path tempDir;
public StringKeyFileManager(@Nonnull Path directory) {
try {
if (!Files.isDirectory(directory)) {
throw new IllegalArgumentException("Not a directory: " + directory.toString());
}
this.directory = FileUtil.readCanonicalPath(directory);
this.tempDir = this.directory.resolve(TMP_DIR);
if (!Files.exists(tempDir)) {
Files.createDirectories(tempDir);
} else if (!Files.isDirectory(tempDir)) {
throw new IllegalStateException("File blocking temp directory: " + tempDir.toString());
}
} catch (IOException e) {
throw new UncheckedIOException(e.getMessage(), e);
}
}
@Override
public Path getFileFor(@Nonnull String key) {
return directory.resolve(validateKey(key));
}
@Override
public Path tmpFileFor(@Nonnull String key) {
return tempDir.resolve(validateKey(key));
}
@Override
public Collection<String> initialKeySet() {
HashSet<String> set = new HashSet<>();
try {
Files.list(directory)
.forEach(file -> {
try {
if (Files.isRegularFile(file) &&
!Files.isHidden(file) &&
!file.getFileName().startsWith(".")) {
set.add(file.getFileName().toString());
}
} catch (Exception e) {
throw new IllegalStateException("Unable to get key from file: " + file, e);
}
});
} catch (IOException e) {
throw new IllegalStateException("Storage directory no longer a directory.", e);
}
return set;
}
private String validateKey(String key) {
key = Normalizer.normalize(key, Normalizer.Form.NFKC);
if (key.startsWith(".")) {
throw new IllegalArgumentException("Special file char in start of key " + key);
}
if (key.contains(File.separator)) {
throw new IllegalArgumentException("Path name separator in key " + key);
}
return key;
}
}