improved Application class
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
package net.woggioni.jwo;
|
package net.woggioni.jwo;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.Builder;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -12,9 +13,27 @@ import java.nio.file.Paths;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static net.woggioni.jwo.JWO.optional2Stream;
|
||||||
|
import static net.woggioni.jwo.JWO.streamCat;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@Builder(builderMethodName = "", builderClassName = "Builder")
|
||||||
class Application {
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class Application {
|
||||||
|
private final String name;
|
||||||
|
private final String configurationDirectoryPropertyKey;
|
||||||
|
private final String cacheDirectoryPropertyKey;
|
||||||
|
private final String dataDirectoryPropertyKey;
|
||||||
|
private final String configurationDirectoryEnvVar;
|
||||||
|
private final String cacheDirectoryEnvVar;
|
||||||
|
private final String dataDirectoryEnvVar;
|
||||||
|
|
||||||
|
private static final String MAC_FOLDER_LIBRARY = "Library";
|
||||||
|
private static final String MAC_FOLDER_APPLICATION_SUPPORT = "Application Support";
|
||||||
|
|
||||||
|
public static Builder builder(String name) {
|
||||||
|
return new Builder().name(name);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean validateConfigurationDirectory(Path candidate) {
|
private static boolean validateConfigurationDirectory(Path candidate) {
|
||||||
try {
|
try {
|
||||||
@@ -49,69 +68,142 @@ class Application {
|
|||||||
.orElseThrow((Sup<Throwable>) () -> new FileNotFoundException(errorMessage));
|
.orElseThrow((Sup<Throwable>) () -> new FileNotFoundException(errorMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
private static boolean validateWritableDirectory(Path candidate) {
|
||||||
private static Path computeCacheDirectory(String appName, String jvmPropertyKey) {
|
try {
|
||||||
Stream<Path> candidates;
|
if (!Files.exists(candidate)) {
|
||||||
if(OS.isUnix) {
|
Files.createDirectories(candidate);
|
||||||
candidates = JWO.optional2Stream(
|
log.trace("Created and selected directory '{}'", candidate);
|
||||||
Optional.ofNullable(System.getProperty(jvmPropertyKey)).map(Paths::get),
|
return true;
|
||||||
Optional.ofNullable(System.getenv("XDG_CACHE_HOME")).map(prefix -> Paths.get(prefix, appName)),
|
} else if (!Files.isDirectory(candidate)) {
|
||||||
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, ".cache", appName)),
|
log.trace("Directory '{}' discarded because it is not a directory", candidate);
|
||||||
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + appName, "cache"))
|
return false;
|
||||||
|
} else if (!Files.isWritable(candidate)) {
|
||||||
|
log.trace("Directory '{}' discarded because it is not writable", candidate);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
log.trace("Selected existing directory '{}'", candidate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception ioe) {
|
||||||
|
log.trace(
|
||||||
|
String.format("Directory '%s' discarded: %s", candidate.toString(), ioe.getMessage()),
|
||||||
|
ioe
|
||||||
);
|
);
|
||||||
} else if(OS.isMac) {
|
return false;
|
||||||
candidates = JWO.optional2Stream(
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private Path selectWritableDirectory(Stream<Path> candidates, String successMessage, String errorMessage) {
|
||||||
|
return candidates
|
||||||
|
.filter(Application::validateWritableDirectory)
|
||||||
|
.peek(p -> log.debug(successMessage, p))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow((Sup<Throwable>) () -> new FileNotFoundException(errorMessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public Path computeCacheDirectory() {
|
||||||
|
Stream<Path> commonCandidates = optional2Stream(
|
||||||
|
Optional.ofNullable(cacheDirectoryPropertyKey).map(System::getProperty).map(Paths::get),
|
||||||
|
Optional.ofNullable(cacheDirectoryEnvVar).map(System::getProperty).map(Paths::get)
|
||||||
|
);
|
||||||
|
Stream<Path> osSpecificCandidates;
|
||||||
|
if (OS.isMac) {
|
||||||
|
osSpecificCandidates = optional2Stream(
|
||||||
Optional.ofNullable(System.getProperty("user.home"))
|
Optional.ofNullable(System.getProperty("user.home"))
|
||||||
.map(prefix -> Paths.get(prefix, "Library", "Application support", appName, "cache")),
|
.map(prefix -> Paths.get(prefix, MAC_FOLDER_LIBRARY, MAC_FOLDER_APPLICATION_SUPPORT, name, "cache")),
|
||||||
Optional.ofNullable(System.getProperty("user.home"))
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + name, "cache"))
|
||||||
.map(prefix -> Paths.get(prefix, "." + appName, "cache"))
|
);
|
||||||
|
} else if (OS.isUnix) {
|
||||||
|
osSpecificCandidates = optional2Stream(
|
||||||
|
Optional.ofNullable(System.getenv("XDG_CACHE_HOME")).map(prefix -> Paths.get(prefix, name)),
|
||||||
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, ".cache", name)),
|
||||||
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + name, "cache"))
|
||||||
);
|
);
|
||||||
} else if (OS.isWindows) {
|
} else if (OS.isWindows) {
|
||||||
candidates = JWO.optional2Stream(
|
osSpecificCandidates = optional2Stream(
|
||||||
Optional.ofNullable(System.getenv("LOCALAPPDATA"))
|
Optional.ofNullable(System.getenv("LOCALAPPDATA"))
|
||||||
.map(prefix -> Paths.get(prefix, appName, "cache")),
|
.map(prefix -> Paths.get(prefix, name, "cache")),
|
||||||
Optional.ofNullable(System.getProperty("user.home"))
|
Optional.ofNullable(System.getProperty("user.home"))
|
||||||
.map(prefix -> Paths.get(prefix, "Application Data", "Local Settings", "Application Data", appName, "cache")));
|
.map(prefix -> Paths.get(prefix, "Application Data", "Local Settings", "Application Data", name, "cache")));
|
||||||
} else {
|
} else {
|
||||||
candidates = JWO.optional2Stream(
|
osSpecificCandidates = optional2Stream(
|
||||||
Optional.ofNullable(System.getProperty("user.home"))
|
Optional.ofNullable(System.getProperty("user.home"))
|
||||||
.map(prefix -> Paths.get(prefix, "." + appName, "cache")));
|
.map(prefix -> Paths.get(prefix, "." + name, "cache")));
|
||||||
}
|
}
|
||||||
return selectCandidate(candidates,
|
return selectWritableDirectory(streamCat(commonCandidates, osSpecificCandidates),
|
||||||
"Using cache directory '{}'",
|
"Using cache directory '{}'",
|
||||||
"Unable to find a usable cache directory");
|
"Unable to find a usable cache directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private static Path computeConfigurationDirectory(String appName, String jvmPropertyKey) {
|
public Path computeDataDirectory() {
|
||||||
Stream<Path> candidates;
|
Stream<Path> commonCandidates = optional2Stream(
|
||||||
if(OS.isUnix) {
|
Optional.ofNullable(dataDirectoryPropertyKey).map(System::getProperty).map(Paths::get),
|
||||||
candidates = JWO.optional2Stream(
|
Optional.ofNullable(dataDirectoryEnvVar).map(System::getProperty).map(Paths::get)
|
||||||
Optional.ofNullable(System.getProperty(jvmPropertyKey)).map(Paths::get),
|
|
||||||
Optional.ofNullable(System.getenv("XDG_CONFIG_HOME")).map(prefix -> Paths.get(prefix, appName)),
|
|
||||||
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, ".config", appName)),
|
|
||||||
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + appName, "config"))
|
|
||||||
);
|
);
|
||||||
} else if(OS.isMac) {
|
Stream<Path> osSpecificCandidates;
|
||||||
candidates = JWO.optional2Stream(
|
if (OS.isMac) {
|
||||||
|
osSpecificCandidates = optional2Stream(
|
||||||
Optional.ofNullable(System.getProperty("user.home"))
|
Optional.ofNullable(System.getProperty("user.home"))
|
||||||
.map(prefix -> Paths.get(prefix, "Library", "Application support", appName, "config")),
|
.map(prefix -> Paths.get(prefix, MAC_FOLDER_LIBRARY, MAC_FOLDER_APPLICATION_SUPPORT, name)),
|
||||||
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + appName, "config"))
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + name))
|
||||||
|
);
|
||||||
|
} else if (OS.isUnix) {
|
||||||
|
osSpecificCandidates = optional2Stream(
|
||||||
|
Optional.ofNullable(System.getenv("XDG_DATA_HOME")).map(prefix -> Paths.get(prefix, name)),
|
||||||
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, ".local", "share", name)),
|
||||||
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + name))
|
||||||
);
|
);
|
||||||
} else if (OS.isWindows) {
|
} else if (OS.isWindows) {
|
||||||
candidates = JWO.optional2Stream(
|
osSpecificCandidates = optional2Stream(
|
||||||
Optional.ofNullable(System.getenv("LOCALAPPDATA"))
|
Optional.ofNullable(System.getenv("LOCALAPPDATA"))
|
||||||
.map(prefix -> Paths.get(prefix, appName, "config")),
|
.map(prefix -> Paths.get(prefix, name)),
|
||||||
Optional.ofNullable(System.getProperty("user.home"))
|
Optional.ofNullable(System.getProperty("user.home"))
|
||||||
.map(prefix -> Paths.get(prefix, "Application Data", "Local Settings", "Application Data", appName, "config")));
|
.map(prefix -> Paths.get(prefix, "Application Data", "Local Settings", "Application Data", name)));
|
||||||
} else {
|
} else {
|
||||||
candidates = JWO.optional2Stream(Optional.ofNullable(System.getProperty("user.home"))
|
osSpecificCandidates = optional2Stream(
|
||||||
.map(prefix -> Paths.get(prefix, "." + appName, "config")));
|
Optional.ofNullable(System.getProperty("user.home"))
|
||||||
|
.map(prefix -> Paths.get(prefix, "." + name)));
|
||||||
}
|
}
|
||||||
return selectCandidate(candidates,
|
return selectWritableDirectory(streamCat(commonCandidates, osSpecificCandidates),
|
||||||
|
"Using data directory '{}'",
|
||||||
|
"Unable to find a usable data directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public Path computeConfigurationDirectory() {
|
||||||
|
Stream<Path> commonCandidates = optional2Stream(
|
||||||
|
Optional.ofNullable(configurationDirectoryPropertyKey).map(System::getProperty).map(Paths::get),
|
||||||
|
Optional.ofNullable(configurationDirectoryEnvVar).map(System::getProperty).map(Paths::get)
|
||||||
|
);
|
||||||
|
Stream<Path> osSpecificCandidates;
|
||||||
|
if (OS.isMac) {
|
||||||
|
osSpecificCandidates = optional2Stream(
|
||||||
|
Optional.ofNullable(System.getProperty("user.home"))
|
||||||
|
.map(prefix -> Paths.get(prefix, MAC_FOLDER_LIBRARY, MAC_FOLDER_APPLICATION_SUPPORT, name, "config")),
|
||||||
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + name, "config"))
|
||||||
|
);
|
||||||
|
} else if (OS.isUnix) {
|
||||||
|
osSpecificCandidates = optional2Stream(
|
||||||
|
Optional.ofNullable(System.getenv("XDG_CONFIG_HOME")).map(prefix -> Paths.get(prefix, name)),
|
||||||
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, ".config", name)),
|
||||||
|
Optional.ofNullable(System.getProperty("user.home")).map(prefix -> Paths.get(prefix, "." + name, "config"))
|
||||||
|
);
|
||||||
|
} else if (OS.isWindows) {
|
||||||
|
osSpecificCandidates = optional2Stream(
|
||||||
|
Optional.ofNullable(System.getenv("LOCALAPPDATA"))
|
||||||
|
.map(prefix -> Paths.get(prefix, name, "config")),
|
||||||
|
Optional.ofNullable(System.getProperty("user.home"))
|
||||||
|
.map(prefix -> Paths.get(prefix, "Application Data", "Local Settings", "Application Data", name, "config")));
|
||||||
|
} else {
|
||||||
|
osSpecificCandidates = optional2Stream(
|
||||||
|
Optional.ofNullable(System.getProperty("user.home")
|
||||||
|
).map(prefix -> Paths.get(prefix, "." + name, "config")));
|
||||||
|
}
|
||||||
|
return selectWritableDirectory(streamCat(commonCandidates, osSpecificCandidates),
|
||||||
"Using configuration directory '{}'",
|
"Using configuration directory '{}'",
|
||||||
"Unable to find a usable configuration directory");
|
"Unable to find a usable configuration directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -426,40 +426,6 @@ public class JWO {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public static Path computeCacheDirectory(String appName) {
|
|
||||||
return Stream.of(
|
|
||||||
Optional.ofNullable(System.getProperty("user.home"))
|
|
||||||
.map(prefix -> Paths.get(prefix, ".cache", appName)),
|
|
||||||
Optional.ofNullable(System.getProperty("java.io.tmpdir")).map(Paths::get).map(p -> p.resolve(appName)),
|
|
||||||
Optional.of(Paths.get("/tmp", appName)))
|
|
||||||
.flatMap(JWO::optional2Stream)
|
|
||||||
.filter(JWO::validateCacheDirectory)
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow(() -> newThrowable(FileNotFoundException.class, "Unable to find a usable cache directory"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean validateCacheDirectory(Path candidate) {
|
|
||||||
try {
|
|
||||||
if (!Files.exists(candidate)) {
|
|
||||||
Files.createDirectories(candidate);
|
|
||||||
return true;
|
|
||||||
} else if (!Files.isDirectory(candidate)) {
|
|
||||||
log.debug("Cache directory '{}' discarded because it is not a directory", candidate.toString());
|
|
||||||
return false;
|
|
||||||
} else if (!Files.isWritable(candidate)) {
|
|
||||||
log.debug("Cache directory '{}' discarded because it is not writable", candidate.toString());
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
log.info("Using cache directory '{}'", candidate.toString());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (Exception ioe) {
|
|
||||||
log.debug(String.format("Cache directory '%s' discarded: %s", candidate.toString(), ioe.getMessage()), ioe);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T, U extends T> Optional<U> cast(T value, Class<U> cls) {
|
public static <T, U extends T> Optional<U> cast(T value, Class<U> cls) {
|
||||||
if (cls.isInstance(value)) {
|
if (cls.isInstance(value)) {
|
||||||
return Optional.of((U) value);
|
return Optional.of((U) value);
|
||||||
|
Reference in New Issue
Block a user