From 5d26d33497bfcd5f21536e362fb22cdc87796159 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 22 Aug 2020 13:15:42 +0200 Subject: [PATCH] Updated config mechanism and added config for the server Additionally fixed a small bug in EnvoyLog and envoy.server.Startup, fixed Receiver not stopping when the server was stopped and added access token authorization for the server config --- .../java/envoy/client/data/ClientConfig.java | 41 ++---- .../main/java/envoy/client/net/Receiver.java | 13 +- .../main/java/envoy/client/ui/Startup.java | 25 +--- client/src/main/resources/client.properties | 10 +- common/src/main/java/envoy/data/Config.java | 130 ++++++++++++++++-- .../src/main/java/envoy/data/ConfigItem.java | 12 +- common/src/main/java/envoy/util/EnvoyLog.java | 40 ++---- .../src/main/java/envoy/server/Startup.java | 35 ++--- .../java/envoy/server/data/ServerConfig.java | 82 +++++++++++ .../processors/IssueProposalProcessor.java | 45 +++--- server/src/main/resources/server.properties | 14 ++ 11 files changed, 287 insertions(+), 160 deletions(-) create mode 100644 server/src/main/java/envoy/server/data/ServerConfig.java create mode 100644 server/src/main/resources/server.properties diff --git a/client/src/main/java/envoy/client/data/ClientConfig.java b/client/src/main/java/envoy/client/data/ClientConfig.java index 3a18f08..2b3da37 100644 --- a/client/src/main/java/envoy/client/data/ClientConfig.java +++ b/client/src/main/java/envoy/client/data/ClientConfig.java @@ -3,10 +3,8 @@ package envoy.client.data; import static java.util.function.Function.identity; import java.io.File; -import java.util.logging.Level; import envoy.data.Config; -import envoy.data.ConfigItem; /** * Implements a configuration specific to the Envoy Client with default values @@ -33,15 +31,13 @@ public class ClientConfig extends Config { } private ClientConfig() { - items.put("server", new ConfigItem<>("server", "s", identity(), null, true)); - items.put("port", new ConfigItem<>("port", "p", Integer::parseInt, null, true)); - items.put("localDB", new ConfigItem<>("localDB", "db", File::new, new File("localDB"), true)); - items.put("ignoreLocalDB", new ConfigItem<>("ignoreLocalDB", "nodb", Boolean::parseBoolean, false, false)); - items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", File::new, new File(System.getProperty("user.home"), ".envoy"), true)); - items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", Level::parse, Level.OFF, true)); - items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", Level::parse, Level.OFF, true)); - items.put("user", new ConfigItem<>("user", "u", identity())); - items.put("password", new ConfigItem<>("password", "pw", identity())); + super(".envoy"); + put("server", "s", identity(), true); + put("port", "p", Integer::parseInt, true); + put("localDB", "db", File::new, true); + put("ignoreLocalDB", "nodb", Boolean::parseBoolean); + put("user", "u", identity()); + put("password", "pw", identity()); } /** @@ -66,25 +62,10 @@ public class ClientConfig extends Config { * @return {@code true} if the local database is to be ignored * @since Envoy Client v0.3-alpha */ - public Boolean isIgnoreLocalDB() { return (Boolean) items.get("ignoreLocalDB").get(); } - - /** - * @return the directory in which all local files are saves - * @since Envoy Client v0.2-alpha - */ - public File getHomeDirectory() { return (File) items.get("homeDirectory").get(); } - - /** - * @return the minimal {@link Level} to log inside the log file - * @since Envoy Client v0.2-alpha - */ - public Level getFileLevelBarrier() { return (Level) items.get("fileLevelBarrier").get(); } - - /** - * @return the minimal {@link Level} to log inside the console - * @since Envoy Client v0.2-alpha - */ - public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); } + public Boolean isIgnoreLocalDB() { + final var ignoreLocalDB = items.get("ignoreLocalDB").get(); + return ignoreLocalDB != null && (Boolean) ignoreLocalDB; + } /** * @return the user name diff --git a/client/src/main/java/envoy/client/net/Receiver.java b/client/src/main/java/envoy/client/net/Receiver.java index fdfa1e8..acbfeb5 100644 --- a/client/src/main/java/envoy/client/net/Receiver.java +++ b/client/src/main/java/envoy/client/net/Receiver.java @@ -24,6 +24,8 @@ import envoy.util.SerializationUtils; */ public class Receiver extends Thread { + private boolean isAlive = true; + private final InputStream in; private final Map, Consumer> processors = new HashMap<>(); @@ -49,7 +51,7 @@ public class Receiver extends Thread { @Override public void run() { - while (true) { + while (isAlive) try { // Read object length final byte[] lenBytes = new byte[4]; @@ -64,6 +66,12 @@ public class Receiver extends Thread { // Catch LV encoding errors if (len != bytesRead) { + // Server has stopped sending, i.e. because he went offline + if (len == 0 && bytesRead == -1) { + isAlive = false; + logger.log(Level.WARNING, "Lost connection to the server. Exiting receiver"); + continue; + } logger.log(Level.WARNING, String.format("LV encoding violated: expected %d bytes, received %d bytes. Discarding object...", len, bytesRead)); continue; @@ -87,7 +95,6 @@ public class Receiver extends Thread { } catch (final Exception e) { logger.log(Level.SEVERE, "Error on receiver thread", e); } - } } /** @@ -102,7 +109,7 @@ public class Receiver extends Thread { /** * Adds a map of object processors to this {@link Receiver}. - * + * * @param processors the processors to add the processors to add * @since Envoy Client v0.1-beta */ diff --git a/client/src/main/java/envoy/client/ui/Startup.java b/client/src/main/java/envoy/client/ui/Startup.java index 464b8e3..7c2bff6 100644 --- a/client/src/main/java/envoy/client/ui/Startup.java +++ b/client/src/main/java/envoy/client/ui/Startup.java @@ -2,7 +2,6 @@ package envoy.client.ui; import java.io.File; import java.io.IOException; -import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -19,7 +18,6 @@ import envoy.data.GroupMessage; import envoy.data.Message; import envoy.event.GroupMessageStatusChange; import envoy.event.MessageStatusChange; -import envoy.exception.EnvoyException; import envoy.util.EnvoyLog; /** @@ -57,30 +55,13 @@ public final class Startup extends Application { @Override public void start(Stage stage) throws Exception { try { - // Load the configuration from client.properties first - final Properties properties = new Properties(); - properties.load(Startup.class.getClassLoader().getResourceAsStream("client.properties")); - config.load(properties); - - // Override configuration values with command line arguments - final String[] args = getParameters().getRaw().toArray(new String[0]); - if (args.length > 0) config.load(args); - - // Check if all mandatory configuration values have been initialized - if (!config.isInitialized()) throw new EnvoyException("Configuration is not fully initialized"); - } catch (final Exception e) { + config.loadAll(Startup.class, "client.properties", getParameters().getRaw().toArray(new String[0])); + EnvoyLog.initialize(config); + } catch (final IllegalStateException e) { new Alert(AlertType.ERROR, "Error loading configuration values:\n" + e); logger.log(Level.SEVERE, "Error loading configuration values: ", e); - e.printStackTrace(); System.exit(1); } - - // Setup logger for the envoy package - EnvoyLog.initialize(config); - EnvoyLog.attach("envoy"); - EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); - EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); - logger.log(Level.INFO, "Envoy starting..."); // Initialize the local database diff --git a/client/src/main/resources/client.properties b/client/src/main/resources/client.properties index 25f1ffd..6f3d633 100644 --- a/client/src/main/resources/client.properties +++ b/client/src/main/resources/client.properties @@ -1,4 +1,6 @@ -server=localhost -port=8080 -localDB=localDB -consoleLevelBarrier=FINER +server=localhost +port=8080 +localDB=localDB +consoleLevelBarrier=FINER +fileLevelBarrier=OFF +ignoreLocalDB=false diff --git a/common/src/main/java/envoy/data/Config.java b/common/src/main/java/envoy/data/Config.java index bcff68c..b51acea 100644 --- a/common/src/main/java/envoy/data/Config.java +++ b/common/src/main/java/envoy/data/Config.java @@ -1,8 +1,13 @@ package envoy.data; +import java.io.File; +import java.io.IOException; import java.util.*; +import java.util.function.Function; +import java.util.logging.Level; +import java.util.stream.Collectors; -import envoy.exception.EnvoyException; +import envoy.util.EnvoyLog; /** * Manages all application settings that are set during application startup by @@ -21,13 +26,23 @@ public class Config { protected Map> items = new HashMap<>(); + private boolean modificationDisabled; + + protected Config(String folderName) { + final var rootDirectory = new File(System.getProperty("user.home"), folderName); + put("homeDirectory", "home", File::new, true); + ((ConfigItem) get("homeDirectory")).setValue(rootDirectory); + put("fileLevelBarrier", "fb", Level::parse, true); + put("consoleLevelBarrier", "cb", Level::parse, true); + } + /** * 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) { + private void load(Properties properties) { items.entrySet() .stream() .filter(e -> properties.containsKey(e.getKey())) @@ -38,43 +53,77 @@ public class Config { * 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 + * @throws IllegalStateException if a malformed command line argument has been + * supplied * @since Envoy Common v0.1-beta */ - public void load(String[] args) throws EnvoyException { + private void load(String[] args) { for (int i = 0; i < args.length; i++) - for (ConfigItem item : items.values()) + for (final ConfigItem item : items.values()) if (args[i].startsWith("--")) { - if (args[i].length() == 2) throw new EnvoyException("Malformed command line argument at position " + i); + if (args[i].length() == 2) throw new IllegalStateException("Malformed command line argument at position " + i + ": " + args[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); + if (args[i].length() == 1) throw new IllegalStateException("Malformed command line argument at position " + i + ": " + args[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); + } else throw new IllegalStateException("Malformed command line argument at position " + i + ": " + args[i]); } /** - * Initializes config items from a map. - * - * @param items the items to include in this config + * Supplies default values from the given .properties file and + * parses the configuration from an array of command line arguments. + * + * @param declaringClass the class calling this method + * @param propertiesFilePath the path to where the .properties file can be found + * - will be only the file name if it is located + * directly inside the {@code src/main/resources} + * folder + * @param args the command line arguments to parse + * @throws IllegalStateException if this method is getting called again or if a + * malformed command line argument has been + * supplied * @since Envoy Common v0.1-beta */ - public void load(Map> items) { this.items.putAll(items); } + public void loadAll(Class declaringClass, String propertiesFilePath, String[] args) { + if (modificationDisabled) throw new IllegalStateException("Cannot change config after isInitialized has been called"); + // Load the defaults from the given .properties file first + final var properties = new Properties(); + try { + properties.load(declaringClass.getClassLoader().getResourceAsStream(propertiesFilePath)); + } catch (final IOException e) { + EnvoyLog.getLogger(Config.class).log(Level.SEVERE, "An error occurred when reading in the configuration: ", e); + } + load(properties); + + // Override configuration values with command line arguments + if (args.length > 0) load(args); + + // Check if all mandatory configuration values have been initialized + isInitialized(); + // Disable further editing of the config + modificationDisabled = true; + } /** - * @return {@code true} if all mandatory config items are initialized + * @throws IllegalStateException if a mandatory {@link ConfigItem} has not been + * initialized * @since Envoy Common v0.1-beta */ - public boolean isInitialized() { - return items.values().stream().filter(ConfigItem::isMandatory).map(ConfigItem::get).noneMatch(Objects::isNull); + private void isInitialized() { + if (items.values().stream().filter(ConfigItem::isMandatory).map(ConfigItem::get).anyMatch(Objects::isNull)) + throw new IllegalStateException("config item(s) has/ have not been initialized:" + items.values() + .stream() + .filter(configItem -> configItem.isMandatory() && configItem.get() == null) + .map(ConfigItem::getCommandLong) + .collect(Collectors.toSet())); } /** @@ -83,4 +132,55 @@ public class Config { * @since Envoy Common v0.1-beta */ public ConfigItem get(String name) { return items.get(name); } + + /** + * Shorthand for
+ * {@code items.put(commandName, new ConfigItem<>(commandName, commandShort, parseFunction, defaultValue, mandatory))}. + * + * @param the type of the {@link ConfigItem} + * @param commandName the key for this config item as well as its long name + * @param commandShort the abbreviation of this config item + * @param parseFunction the {@code Function} that parses the value + * from a string + * @param mandatory indicated that this config item must be initialized with + * a non-null value + * @since Envoy Common v0.2-beta + */ + protected void put(String commandName, String commandShort, Function parseFunction, boolean mandatory) { + items.put(commandName, new ConfigItem<>(commandName, commandShort, parseFunction, mandatory)); + } + + /** + * Shorthand for
+ * {@code put(commandName, commandShort, parseFunction, false)}. + * + * @param the type of the {@link ConfigItem} + * @param commandName the key for this config item as well as its long name + * @param commandShort the abbreviation of this config item + * @param parseFunction the {@code Function} that parses the value + * from a string + * @since Envoy Common v0.2-beta + */ + protected void put(String commandName, String commandShort, Function parseFunction) { + put(commandName, commandShort, parseFunction, false); + } + + /** + * @return the directory in which all local files are saves + * @since Envoy Client v0.2-beta + */ + public File getHomeDirectory() { return (File) items.get("homeDirectory").get(); } + + /** + * @return the minimal {@link Level} to log inside the log file + * @since Envoy Client v0.2-beta + */ + public Level getFileLevelBarrier() { return (Level) items.get("fileLevelBarrier").get(); } + + /** + * @return the minimal {@link Level} to log inside the console + * @since Envoy Client v0.2-beta + */ + public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); } + } diff --git a/common/src/main/java/envoy/data/ConfigItem.java b/common/src/main/java/envoy/data/ConfigItem.java index 028b599..9ed1462 100644 --- a/common/src/main/java/envoy/data/ConfigItem.java +++ b/common/src/main/java/envoy/data/ConfigItem.java @@ -29,17 +29,15 @@ public class ConfigItem { * @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) { + public ConfigItem(String commandLong, String commandShort, Function parseFunction, boolean mandatory) { this.commandLong = commandLong; this.commandShort = commandShort; this.parseFunction = parseFunction; this.mandatory = mandatory; - value = defaultValue; } /** @@ -52,7 +50,7 @@ public class ConfigItem { * @since Envoy Common v0.1-beta */ public ConfigItem(String commandLong, String commandShort, Function parseFunction) { - this(commandLong, commandShort, parseFunction, null, false); + this(commandLong, commandShort, parseFunction, false); } /** @@ -83,6 +81,12 @@ public class ConfigItem { */ public T get() { return value; } + /** + * @param value the value to set + * @since Envoy Common v0.2-beta + */ + protected void setValue(T value) { this.value = value; } + /** * @return {@code true} if this {@link ConfigItem} is mandatory for successful * application initialization diff --git a/common/src/main/java/envoy/util/EnvoyLog.java b/common/src/main/java/envoy/util/EnvoyLog.java index d64e69f..c15c4d4 100644 --- a/common/src/main/java/envoy/util/EnvoyLog.java +++ b/common/src/main/java/envoy/util/EnvoyLog.java @@ -12,12 +12,9 @@ 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
+ * Created: 14.12.2019
* * @author Leon Hofmeister * @author Kai S. K. Engelbart @@ -32,8 +29,7 @@ public class EnvoyLog { private EnvoyLog() {} /** - * Initializes logging. Call this method before calling the - * {@link EnvoyLog#attach(String)} method. + * Initializes logging. * * @param config the config providing the console and log file barriers * @since Envoy Common v0.1-beta @@ -45,18 +41,19 @@ public class EnvoyLog { LogManager.getLogManager().reset(); // Configure log file - final File logFile = new File((File) config.get("homeDirectory").get(), - "log/envoy_user_" + DateTimeFormatter.ofPattern("yyyy-MM-dd--hh-mm-mm").format(LocalDateTime.now()) + ".log"); + final File logFile = new File(config.getHomeDirectory(), + "log/" + DateTimeFormatter.ofPattern("yyyy-MM-dd--hh-mm").format(LocalDateTime.now()) + ".log"); logFile.getParentFile().mkdirs(); // Configure formatting - // Sample log entry: [2020-06-13 16:50:26] [INFORMATION] [envoy.client.ui.Startup] Closing connection... + // Sample log entry: [2020-06-13 16:50:26] [INFORMATION] + // [envoy.client.ui.Startup] Closing connection... System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT] [%4$-7s] [%3$s] %5$s %6$s%n"); final SimpleFormatter formatter = new SimpleFormatter(); try { fileHandler = new FileHandler(logFile.getAbsolutePath()); - fileHandler.setLevel((Level) config.get("fileLevelBarrier").get()); + fileHandler.setLevel(config.getFileLevelBarrier()); fileHandler.setFormatter(formatter); } catch (SecurityException | IOException e) { e.printStackTrace(); @@ -69,10 +66,11 @@ public class EnvoyLog { flush(); } }; - consoleHandler.setLevel((Level) config.get("consoleLevelBarrier").get()); + consoleHandler.setLevel(config.getConsoleLevelBarrier()); consoleHandler.setFormatter(formatter); initialized = true; + EnvoyLog.attach("envoy"); } /** @@ -82,7 +80,7 @@ public class EnvoyLog { * @param path the path to the loggers to configure * @since Envoy Common v0.1-beta */ - public static void attach(String path) { + private static void attach(String path) { if (!initialized) throw new IllegalStateException("EnvoyLog is not initialized"); // Get root logger @@ -105,22 +103,4 @@ public class EnvoyLog { * @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); - } } diff --git a/server/src/main/java/envoy/server/Startup.java b/server/src/main/java/envoy/server/Startup.java index 84b569c..7232cba 100755 --- a/server/src/main/java/envoy/server/Startup.java +++ b/server/src/main/java/envoy/server/Startup.java @@ -1,16 +1,13 @@ package envoy.server; -import java.io.File; import java.io.IOException; -import java.util.HashMap; import java.util.Set; import java.util.logging.Level; import com.jenkov.nioserver.Server; -import envoy.data.Config; -import envoy.data.ConfigItem; import envoy.server.data.PersistenceManager; +import envoy.server.data.ServerConfig; import envoy.server.net.ConnectionManager; import envoy.server.net.ObjectMessageProcessor; import envoy.server.net.ObjectMessageReader; @@ -30,23 +27,9 @@ import envoy.util.EnvoyLog; public class Startup { /** - * Initializes the logger with a new config instance. - * - * @since Envoy Server Standalone v0.1-beta + * Stores the configuration used for the whole server */ - private static void initLogging() { - final var items = new HashMap>(); - items.put("homeDirectory", - new ConfigItem<>("homeDirectory", "h", File::new, new File(System.getProperty("user.home"), ".envoy-server"), true)); - items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", Level::parse, Level.WARNING, true)); - items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", Level::parse, Level.FINEST, true)); - - final var config = new Config(); - config.load(items); - - EnvoyLog.initialize(config); - EnvoyLog.attach("envoy"); - } + public static final ServerConfig config = ServerConfig.getInstance(); /** * Starts the server. @@ -57,7 +40,13 @@ public class Startup { * @since Envoy Server Standalone v0.1-alpha */ public static void main(String[] args) throws IOException { - initLogging(); + try { + config.loadAll(Startup.class, "server.properties", args); + EnvoyLog.initialize(config); + } catch (final IllegalStateException e) { + EnvoyLog.getLogger(Startup.class).log(Level.SEVERE, "Error loading configuration values: ", e); + System.exit(1); + } final var server = new Server(8080, ObjectMessageReader::new, new ObjectMessageProcessor(Set.of(new LoginCredentialProcessor(), @@ -84,8 +73,8 @@ public class Startup { server.start(); server.getSocketProcessor().registerSocketIdListener(ConnectionManager.getInstance()); - if (args.length == 0 || !args[0].equalsIgnoreCase("no-enter-to-stop")) { - System.out.println("Press the return key to stop the server..."); + if (config.isEnterToStop()) { + System.out.println("Press Enter to stop the server..."); System.in.read(); System.out.println("Stopped"); System.exit(0); diff --git a/server/src/main/java/envoy/server/data/ServerConfig.java b/server/src/main/java/envoy/server/data/ServerConfig.java new file mode 100644 index 0000000..bb9a9ae --- /dev/null +++ b/server/src/main/java/envoy/server/data/ServerConfig.java @@ -0,0 +1,82 @@ +package envoy.server.data; + +import static java.util.function.Function.identity; + +import envoy.data.Config; + +/** + * Project: server
+ * File: ServerConfig.java
+ * Created: 21.08.2020
+ * + * @author Leon Hofmeister + * @since Envoy Server v0.2-beta + */ +public class ServerConfig extends Config { + + private static ServerConfig config; + + /** + * @return the singleton instance of the server config + * @since Envoy Client v0.1-beta + */ + public static ServerConfig getInstance() { return config == null ? config = new ServerConfig() : config; } + + private ServerConfig() { + super(".envoy-server"); + put("enter-to-stop", "dev-stop", Boolean::parseBoolean, true); + // parameters for issue reporting + put("issueCreationURL", "i-url", identity(), true); + put("issueAuthToken", "i-token", identity()); + put("userMadeLabel", "l-um", identity(), true); + put("bugLabel", "l-b", identity(), true); + put("featureLabel", "l-f", identity(), true); + // enabling/ disabling several processors + put("enableIssueReporting", "e-ir", Boolean::parseBoolean, true); + } + + /** + * @return true if this server should be stoppable by pressing enter + * @since Envoy Server v0.2-beta + */ + public Boolean isEnterToStop() { return (Boolean) items.get("enter-to-stop").get(); } + + /** + * @return {@code true} if issue reporting is enabled + * @since Envoy Client v0.3-alpha + */ + public Boolean isIssueReportingEnabled() { return (Boolean) items.get("enableIssueReporting").get(); } + + /** + * @return the URL where issues should be uploaded to + * @since Envoy Client v0.1-alpha + */ + public String getIssueReportingURL() { return (String) items.get("issueCreationURL").get(); } + + /** + * @return the String representation for the "{@code user made}" - label + * @since Envoy Client v0.1-alpha + */ + public String getUserMadeLabel() { return (String) items.get("userMadeLabel").get(); } + + /** + * @return the String representation for the "{@code user made}" - label + * @since Envoy Client v0.1-alpha + */ + public String getBugLabel() { return (String) items.get("bugLabel").get(); } + + /** + * @return the String representation for the "{@code user made}" - label + * @since Envoy Client v0.1-alpha + */ + public String getFeatureLabel() { return (String) items.get("featureLabel").get(); } + + /** + * @return the authorization token used to authenticate to + * {@link ServerConfig#getIssueReportingURL()}. If null, + * authorization is expected to occur via a query_param or via a basic + * user-password-combination + * @since Envoy Server v0.2-beta + */ + public String getIssueAuthToken() { return (String) items.get("issueAuthToken").get(); } +} diff --git a/server/src/main/java/envoy/server/processors/IssueProposalProcessor.java b/server/src/main/java/envoy/server/processors/IssueProposalProcessor.java index 97a9b54..8aa639c 100644 --- a/server/src/main/java/envoy/server/processors/IssueProposalProcessor.java +++ b/server/src/main/java/envoy/server/processors/IssueProposalProcessor.java @@ -1,5 +1,7 @@ package envoy.server.processors; +import static envoy.server.Startup.config; + import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; @@ -23,27 +25,32 @@ import envoy.util.EnvoyLog; */ public class IssueProposalProcessor implements ObjectProcessor { - private static boolean issueReportingEnabled = true; - private static final Logger logger = EnvoyLog.getLogger(IssueProposalProcessor.class); + private static final Logger logger = EnvoyLog.getLogger(IssueProposalProcessor.class); @Override public void process(IssueProposal issueProposal, long socketID, ObjectWriteProxy writeProxy) throws IOException { // Do nothing if manually disabled - if (!issueReportingEnabled) return; + if (!config.isIssueReportingEnabled()) return; try { - final var url = new URL( - "https://git.kske.dev/api/v1/repos/zdm/envoy/issues?access_token=6d8ec2a72d64cbaf6319434aa2e7caf0130701b3"); + final var url = new URL(config.getIssueReportingURL()); final var connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json; utf-8"); connection.setRequestProperty("Accept", "application/json"); + // Two types of authorization are currently supported: access token as + // query param or access token as authorization header + final var authenticationToken = config.getIssueAuthToken(); + if (authenticationToken != null) { + final String auth = "token " + authenticationToken; + connection.setRequestProperty("Authorization", auth); + } connection.setDoOutput(true); - final var json = String.format("{\"title\":\"%s\",\"body\":\"%s\",\"labels\":[240, %d]}", + final var json = String.format("{\"title\":\"%s\",\"body\":\"%s\",\"labels\":[%s, %s]}", issueProposal.get(), issueProposal.getDescription(), - // Label 240 should be user-made, label 117 bug and label 119 feature - issueProposal.isBug() ? 117 : 119); + config.getUserMadeLabel(), + issueProposal.isBug() ? config.getBugLabel() : config.getFeatureLabel()); try (final var os = connection.getOutputStream()) { final byte[] input = json.getBytes("utf-8"); os.write(input, 0, input.length); @@ -51,29 +58,9 @@ public class IssueProposalProcessor implements ObjectProcessor { final var status = connection.getResponseCode(); if (status == 201) logger.log(Level.INFO, "Successfully created an issue"); else logger.log(Level.WARNING, - String.format("Tried creating an issue for %s but received status code %d - Request params:title=%s,description=%s,json=%s", - url, - status, - issueProposal.get(), - issueProposal.getDescription(), - json)); + String.format("Tried creating an issue for %s but received status code %d - Request params:%s", url, status, json)); } catch (final IOException e) { logger.log(Level.WARNING, "An error occurred while creating an issue: ", e); } } - - /** - * @return whether issue reporting is enabled - * @since Envoy Server v0.2-beta - */ - public static boolean isIssueReportingEnabled() { return issueReportingEnabled; } - - /** - * @param issueReportingEnabled whether issue reporting should be enabled - true - * by default - * @since Envoy Server v0.2-beta - */ - public static void setIssueReportingEnabled(boolean issueReportingEnabled) { - IssueProposalProcessor.issueReportingEnabled = issueReportingEnabled; - } } diff --git a/server/src/main/resources/server.properties b/server/src/main/resources/server.properties new file mode 100644 index 0000000..216288d --- /dev/null +++ b/server/src/main/resources/server.properties @@ -0,0 +1,14 @@ +enter-to-stop=true +enableIssueReporting=true +# git.kske.dev config +issueCreationURL=https://git.kske.dev/api/v1/repos/zdm/envoy/issues?access_token=6d8ec2a72d64cbaf6319434aa2e7caf0130701b3 +userMadeLabel=240 +bugLabel=117 +featureLabel=119 +# api.github.com config - supply an additional auth token +#issueCreationURL=https://api.github.com/repos/informatik-ag-ngl/envoy/issues +#userMadeLabel="user made" +#bugLabel="bug" +#featureLabel="feature" +consoleLevelBarrier=FINEST +fileLevelBarrier=WARNING \ No newline at end of file