diff --git a/src/main/java/envoy/data/Config.java b/src/main/java/envoy/data/Config.java new file mode 100644 index 0000000..c281d0e --- /dev/null +++ b/src/main/java/envoy/data/Config.java @@ -0,0 +1,78 @@ +package envoy.data; + +import java.util.*; + +import envoy.exception.EnvoyException; + +/** + * Manages all application settings that are set during application startup by + * either loading them from the {@link Properties} file + * {@code client.properties} or parsing them from the command line arguments of + * the application.
+ *
+ * Project: envoy-client
+ * File: Config.java
+ * Created: 12 Oct 2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy Common v0.1-beta + */ +public class Config { + + protected Map> items = new HashMap<>(); + + /** + * Parses config items from a properties object. + * + * @param properties the properties object to parse + * @since Envoy Common v0.1-beta + */ + public void load(Properties properties) { + items.entrySet() + .stream() + .filter(e -> properties.containsKey(e.getKey())) + .forEach(e -> e.getValue().parse(properties.getProperty(e.getKey()))); + } + + /** + * Parses config items from an array of command line arguments. + * + * @param args the command line arguments to parse + * @throws EnvoyException if the command line arguments contain an unknown token + * @since Envoy Common v0.1-beta + */ + public void load(String[] args) throws EnvoyException { + for (int i = 0; i < args.length; i++) + for (ConfigItem item : items.values()) + if (args[i].startsWith("--")) { + if (args[i].length() == 2) throw new EnvoyException("Malformed command line argument at position " + i); + final String commandLong = args[i].substring(2); + if (item.getCommandLong().equals(commandLong)) { + item.parse(args[++i]); + break; + } + } else if (args[i].startsWith("-")) { + if (args[i].length() == 1) throw new EnvoyException("Malformed command line argument at position " + i); + final String commandShort = args[i].substring(1); + if (item.getCommandShort().equals(commandShort)) { + item.parse(args[++i]); + break; + } + } else throw new EnvoyException("Malformed command line argument at position " + i); + } + + /** + * @return {@code true} if all mandatory config items are initialized + * @since Envoy Common v0.1-beta + */ + public boolean isInitialized() { + return items.values().stream().filter(ConfigItem::isMandatory).map(ConfigItem::get).noneMatch(Objects::isNull); + } + + /** + * @param name the name of the config item to return + * @return the config item with the specified name + * @since Envoy Common v0.1-beta + */ + public ConfigItem get(String name) { return items.get(name); } +} diff --git a/src/main/java/envoy/data/ConfigItem.java b/src/main/java/envoy/data/ConfigItem.java new file mode 100644 index 0000000..028b599 --- /dev/null +++ b/src/main/java/envoy/data/ConfigItem.java @@ -0,0 +1,92 @@ +package envoy.data; + +import java.util.function.Function; + +/** + * Contains a single {@link Config} value as well as the corresponding command + * line arguments and its default value.
+ *
+ * Project: envoy-clientChess
+ * File: ConfigItem.javaEvent.java
+ * Created: 21.12.2019
+ * + * @author Kai S. K. Engelbart + * @param the type of the config item's value + * @since Envoy Common v0.1-beta + */ +public class ConfigItem { + + private final String commandLong, commandShort; + private final Function parseFunction; + private final boolean mandatory; + + private T value; + + /** + * Initializes a {@link ConfigItem}. + * + * @param commandLong the long command line argument to set this value + * @param commandShort the short command line argument to set this value + * @param parseFunction the {@code Function} that parses the value + * from a string + * @param defaultValue the optional default value to set before parsing + * @param mandatory indicated that this config item must be initialized with + * a non-null value + * @since Envoy Common v0.1-beta + */ + public ConfigItem(String commandLong, String commandShort, Function parseFunction, T defaultValue, boolean mandatory) { + this.commandLong = commandLong; + this.commandShort = commandShort; + this.parseFunction = parseFunction; + this.mandatory = mandatory; + value = defaultValue; + } + + /** + * Initializes an optional {@link ConfigItem} without a default value. + * + * @param commandLong the long command line argument to set this value + * @param commandShort the short command line argument to set this value + * @param parseFunction the {@code Function} that parses the value + * from a string + * @since Envoy Common v0.1-beta + */ + public ConfigItem(String commandLong, String commandShort, Function parseFunction) { + this(commandLong, commandShort, parseFunction, null, false); + } + + /** + * Parses this {@ConfigItem}'s value from a string. + * + * @param input the string to parse from + * @since Envoy Common v0.1-beta + */ + public void parse(String input) { value = parseFunction.apply(input); } + + /** + * @return The long command line argument to set the value of this + * {@link ConfigItem} + * @since Envoy Common v0.1-beta + */ + public String getCommandLong() { return commandLong; } + + /** + * @return The short command line argument to set the value of this + * {@link ConfigItem} + * @since Envoy Common v0.1-beta + */ + public String getCommandShort() { return commandShort; } + + /** + * @return the value of this {@link ConfigItem} + * @since Envoy Common v0.1-beta + */ + public T get() { return value; } + + /** + * @return {@code true} if this {@link ConfigItem} is mandatory for successful + * application initialization + * @since Envoy Common v0.1-beta + */ + public boolean isMandatory() { return mandatory; } +} diff --git a/src/main/java/envoy/util/EnvoyLog.java b/src/main/java/envoy/util/EnvoyLog.java new file mode 100644 index 0000000..deba66d --- /dev/null +++ b/src/main/java/envoy/util/EnvoyLog.java @@ -0,0 +1,118 @@ +package envoy.util; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.*; + +import envoy.data.Config; + +/** + * Configures the {@link java.util.logging} API to output the log into the + * console and a log file.
+ *
+ * Call the {@link EnvoyLog#attach(String)} method to configure a part of the + * logger hierarchy.
+ *
+ * Project: envoy-client
+ * File: EnvoyLogger.java
+ * Created: 14 Dec 2019
+ * + * @author Leon Hofmeister + * @author Kai S. K. Engelbart + * @since Envoy Common v0.1-beta + */ +public class EnvoyLog { + + private static FileHandler fileHandler; + private static StreamHandler consoleHandler; + private static boolean initialized; + + private EnvoyLog() {} + + /** + * Initializes logging. Call this method before calling the + * {@link EnvoyLog#attach(String)} method. + * + * @param config the config providing the console and log file barriers + * @since Envoy Common v0.1-beta + */ + public static void initialize(Config config) { + if (initialized) throw new IllegalStateException("EnvoyLog is already initialized"); + + // Remove default console handler + LogManager.getLogManager().reset(); + + // Configure log file + File logFile = new File((File) config.get("homeDirectory").get(), + "log/envoy_user_" + new SimpleDateFormat("yyyy-MM-dd--hh-mm-mm").format(new Date()) + ".log"); + logFile.getParentFile().mkdirs(); + + // Configure formatting + System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT] [%4$-7s] [%3$s] %5$s %n"); + SimpleFormatter formatter = new SimpleFormatter(); + + try { + fileHandler = new FileHandler(logFile.getAbsolutePath()); + fileHandler.setLevel((Level) config.get("fileLevelBarrier").get()); + fileHandler.setFormatter(formatter); + } catch (SecurityException | IOException e) { + e.printStackTrace(); + } + consoleHandler = new StreamHandler(System.out, formatter); + consoleHandler.setLevel((Level) config.get("consoleLevelBarrier").get()); + consoleHandler.setFormatter(formatter); + + initialized = true; + } + + /** + * Configures all loggers that are contained within the hierarchy of a specific + * path to use the console and file handlers. + * + * @param path the path to the loggers to configure + * @since Envoy Common v0.1-beta + */ + public static void attach(String path) { + if (!initialized) throw new IllegalStateException("EnvoyLog is not initialized"); + + // Get root logger + Logger logger = Logger.getLogger(path); + + // Add handlers + if (fileHandler != null) logger.addHandler(fileHandler); + logger.addHandler(consoleHandler); + + // Delegate logger level filtering to the handlers + logger.setLevel(Level.ALL); + } + + /** + * Creates a logger for a specified class, which output will be displayed inside + * the console and written to the log file. + * + * @param logClass the class in which the logger is used + * @return the created logger + * @since Envoy Common v0.1-beta + */ + public static Logger getLogger(Class logClass) { return Logger.getLogger(logClass.getCanonicalName()); } + + /** + * Defines the logger level required for a record to be written to the log file. + * + * @param fileLevelBarrier the log file level + * @since Envoy Common v0.1-beta + */ + public static void setFileLevelBarrier(Level fileLevelBarrier) { if (fileHandler != null) fileHandler.setLevel(fileLevelBarrier); } + + /** + * Defines the logger level required for a record to be written to the console. + * + * @param consoleLevelBarrier the console logger level + * @since Envoy Common v0.1-beta + */ + public static void setConsoleLevelBarrier(Level consoleLevelBarrier) { + if (consoleHandler != null) consoleHandler.setLevel(consoleLevelBarrier); + } +}