diff --git a/.env.example b/.env.example
new file mode 100644
index 00000000000..c24b95f81e8
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,7 @@
+# Database Configuration
+# Copy this file to .env and fill in your actual database credentials
+# Defaults to config.yaml if not set, remove lines to use config.yaml's values
+DB_HOST=localhost
+DB_USER=root
+DB_PASS=your_password_here
+DB_URL_FORMAT=jdbc:mysql://%s:3306/cosmic
diff --git a/.gitignore b/.gitignore
index 27980c65f98..5bdcfc32f7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,6 @@ database/docker-pg-db-data
# macOS files
.DS_Store
+
+# Environment variables
+.env
diff --git a/pom.xml b/pom.xml
index 945a417fd89..4f1884059a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,6 +69,7 @@
4.32.0
5.13.1
5.18.0
+ 3.0.0
@@ -82,6 +83,11 @@
jcip-annotations
${jcip-annotations.version}
+
+ io.github.cdimascio
+ dotenv-java
+ ${dotenv-java.version}
+
diff --git a/src/main/java/tools/DatabaseConnection.java b/src/main/java/tools/DatabaseConnection.java
index b0313b92fac..31da2a2cf3a 100644
--- a/src/main/java/tools/DatabaseConnection.java
+++ b/src/main/java/tools/DatabaseConnection.java
@@ -46,18 +46,17 @@ public static Handle getHandle() {
private static String getDbUrl() {
// Environment variables override what's defined in the config file
// This feature is used for the Docker support
- String hostOverride = System.getenv("DB_HOST");
- String host = hostOverride != null ? hostOverride : YamlConfig.config.server.DB_HOST;
- String dbUrl = String.format(YamlConfig.config.server.DB_URL_FORMAT, host);
- return dbUrl;
+ String host = EnvironmentConfig.get("DB_HOST", YamlConfig.config.server.DB_HOST);
+ String urlFormat = EnvironmentConfig.get("DB_URL_FORMAT", YamlConfig.config.server.DB_URL_FORMAT);
+ return String.format(urlFormat, host);
}
private static HikariConfig getConfig() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(getDbUrl());
- config.setUsername(YamlConfig.config.server.DB_USER);
- config.setPassword(YamlConfig.config.server.DB_PASS);
+ config.setUsername(EnvironmentConfig.get("DB_USER", YamlConfig.config.server.DB_USER));
+ config.setPassword(EnvironmentConfig.get("DB_PASS", YamlConfig.config.server.DB_PASS));
final int initFailTimeoutSeconds = YamlConfig.config.server.INIT_CONNECTION_POOL_TIMEOUT;
config.setInitializationFailTimeout(SECONDS.toMillis(initFailTimeoutSeconds));
diff --git a/src/main/java/tools/EnvironmentConfig.java b/src/main/java/tools/EnvironmentConfig.java
new file mode 100644
index 00000000000..e582aae1cc7
--- /dev/null
+++ b/src/main/java/tools/EnvironmentConfig.java
@@ -0,0 +1,50 @@
+package tools;
+
+import io.github.cdimascio.dotenv.Dotenv;
+
+/**
+ * Provides access to configuration values from .env files and system environment variables.
+ * Priority order:
+ * 1. .env file values
+ * 2. System environment variables
+ * 3. Provided default value
+ */
+public class EnvironmentConfig {
+ private static final Dotenv dotenv;
+
+ static {
+ dotenv = Dotenv.configure()
+ .ignoreIfMissing()
+ .load();
+ }
+
+ /**
+ * Get an environment variable value with fallback to a default.
+ *
+ * @param key the environment variable key
+ * @param defaultValue the default value to use if the variable is not found
+ * @return the environment variable value, or the default if not found
+ */
+ public static String get(String key, String defaultValue) {
+ if (key == null || key.isEmpty()) {
+ return defaultValue;
+ }
+
+ // First try .env file
+ if (dotenv != null) {
+ String value = dotenv.get(key);
+ if (value != null && !value.isEmpty()) {
+ return value;
+ }
+ }
+
+ // Then try system environment
+ String value = System.getenv(key);
+ if (value != null && !value.isEmpty()) {
+ return value;
+ }
+
+ // Finally use the provided default
+ return defaultValue;
+ }
+}
diff --git a/src/test/java/tools/EnvironmentConfigTest.java b/src/test/java/tools/EnvironmentConfigTest.java
new file mode 100644
index 00000000000..bfde0309c04
--- /dev/null
+++ b/src/test/java/tools/EnvironmentConfigTest.java
@@ -0,0 +1,14 @@
+package tools;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class EnvironmentConfigTest {
+
+ @Test
+ void getShouldReturnDefaultWhenVariableNotFound() {
+ String value = EnvironmentConfig.get("NONEXISTENT_VARIABLE_XYZ", "my_default");
+ assertEquals("my_default", value);
+ }
+}