diff --git a/.gitignore b/.gitignore index 5f694736ba..d301e7549e 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,4 @@ gradle-app.setting # End of https://www.toptal.com/developers/gitignore/api/netbeans,intellij,java,gradle,eclipse application/db/ +config.json diff --git a/application/build.gradle b/application/build.gradle index 996364a9d4..ba2b92f46d 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -45,8 +45,11 @@ dependencies { implementation 'org.apache.logging.log4j:log4j-api:2.14.1' implementation 'org.apache.logging.log4j:log4j-core:2.14.1' implementation 'org.apache.logging.log4j:log4j-slf4j18-impl:2.14.1' + implementation 'org.jooq:jooq:3.15.3' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.5' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.0' } diff --git a/application/src/main/java/org/togetherjava/tjbot/Application.java b/application/src/main/java/org/togetherjava/tjbot/Application.java index 2d6a32daac..e8819b0304 100644 --- a/application/src/main/java/org/togetherjava/tjbot/Application.java +++ b/application/src/main/java/org/togetherjava/tjbot/Application.java @@ -5,36 +5,48 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.CommandHandler; +import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.db.Database; import javax.security.auth.login.LoginException; +import java.io.IOException; import java.nio.file.Path; import java.sql.SQLException; -/*** +/** * Main class of the application. Use {@link #main(String[])} to start an instance of it. */ public enum Application { ; private static final Logger logger = LoggerFactory.getLogger(Application.class); + private static final String DEFAULT_CONFIG_PATH = "config.json"; /** * Starts the application. * - * @param args command line arguments - [the token of the bot, the path to the database] + * @param args command line arguments - [the path to the configuration file (optional, by + * default "config.json")] */ public static void main(final String[] args) { - if (args.length != 2) { - throw new IllegalArgumentException("Expected two arguments but " + args.length - + " arguments were provided. The first argument must be the token of the bot" - + " and the second the path to the database."); + if (args.length > 1) { + throw new IllegalArgumentException("Expected no or one argument but " + args.length + + " arguments were provided. The first argument is the path to the configuration file. If no argument was provided, '" + + DEFAULT_CONFIG_PATH + "' will be assumed."); } - String token = args[0]; - String databasePath = args[1]; + Path configPath = Path.of(args.length == 1 ? args[0] : DEFAULT_CONFIG_PATH); try { - runBot(token, Path.of(databasePath)); + Config.load(configPath); + } catch (IOException e) { + logger.error("Unable to load the configuration file from path '{}'", + configPath.toAbsolutePath(), e); + return; + } + + try { + Config config = Config.getInstance(); + runBot(config.getToken(), Path.of(config.getDatabasePath())); } catch (Exception t) { logger.error("Unknown error", t); } diff --git a/application/src/main/java/org/togetherjava/tjbot/config/Config.java b/application/src/main/java/org/togetherjava/tjbot/config/Config.java new file mode 100644 index 0000000000..10f4ed08e9 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/config/Config.java @@ -0,0 +1,95 @@ +package org.togetherjava.tjbot.config; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; + +/** + * Configuration of the application, as singleton. + *
+ * Create instances using {@link #load(Path)} and then access them with {@link #getInstance()}. + */ +public final class Config { + + private static Config config; + + private final String token; + private final String databasePath; + private final String projectWebsite; + private final String discordGuildInvite; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + private Config(@JsonProperty("token") String token, + @JsonProperty("databasePath") String databasePath, + @JsonProperty("projectWebsite") String projectWebsite, + @JsonProperty("discordGuildInvite") String discordGuildInvite) { + this.token = token; + this.databasePath = databasePath; + this.projectWebsite = projectWebsite; + this.discordGuildInvite = discordGuildInvite; + } + + /** + * Loads the configuration from the given file. Will override any previously loaded data. + *
+ * Access the instance using {@link #getInstance()}. + * + * @param path the configuration file, as JSON object + * @throws IOException if the file could not be loaded + */ + public static void load(Path path) throws IOException { + config = new ObjectMapper().readValue(path.toFile(), Config.class); + } + + /** + * Gets the singleton instance of the configuration. + *
+ * Must be loaded beforehand using {@link #load(Path)}. + * + * @return the previously loaded configuration + */ + public static Config getInstance() { + return Objects.requireNonNull(config, + "can not get the configuration before it has been loaded"); + } + + /** + * Gets the token of the Discord bot to connect this application to. + * + * @return the Discord bot token + */ + public String getToken() { + return token; + } + + /** + * Gets the path where the database of the application is located at. + * + * @return the path of the database + */ + public String getDatabasePath() { + return databasePath; + } + + /** + * Gets a URL of the project's website, for example to tell the user where he can contribute. + * + * @return the website of the project + */ + public String getProjectWebsite() { + return projectWebsite; + } + + /** + * Gets an invite-URL to join the Discord guild this application is connected to. + * + * @return an invite-URL for this Discord guild + */ + public String getDiscordGuildInvite() { + return discordGuildInvite; + } +}