package tools; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import config.YamlConfig; import database.note.NoteRowMapper; import org.jdbi.v3.core.Handle; import org.jdbi.v3.core.Jdbi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.time.Duration; import java.time.Instant; import static java.util.concurrent.TimeUnit.SECONDS; /** * @author Frz (Big Daddy) * @author The Real Spookster - some modifications to this beautiful code * @author Ronan - some connection pool to this beautiful code */ public class DatabaseConnection { private static final Logger log = LoggerFactory.getLogger(DatabaseConnection.class); private static HikariDataSource dataSource; private static Jdbi jdbi; public static Connection getConnection() throws SQLException { if (dataSource == null) { throw new IllegalStateException("Unable to get connection - connection pool is uninitialized"); } return dataSource.getConnection(); } public static Handle getHandle() { if (jdbi == null) { throw new IllegalStateException("Unable to get handle - connection pool is uninitialized"); } return jdbi.open(); } 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; } 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); final int initFailTimeoutSeconds = YamlConfig.config.server.INIT_CONNECTION_POOL_TIMEOUT; config.setInitializationFailTimeout(SECONDS.toMillis(initFailTimeoutSeconds)); config.setConnectionTimeout(SECONDS.toMillis(30)); // Hikari default config.setMaximumPoolSize(10); // Hikari default config.addDataSourceProperty("cachePrepStmts", true); config.addDataSourceProperty("prepStmtCacheSize", 25); config.addDataSourceProperty("prepStmtCacheSqlLimit", 2048); return config; } /** * Initiate connection to the database * * @return true if connection to the database initiated successfully, false if not successful */ public static boolean initializeConnectionPool() { if (dataSource != null) { return true; } log.info("Initializing connection pool..."); final HikariConfig config = getConfig(); Instant initStart = Instant.now(); try { dataSource = new HikariDataSource(config); initializeJdbi(dataSource); long initDuration = Duration.between(initStart, Instant.now()).toMillis(); log.info("Connection pool initialized in {} ms", initDuration); return true; } catch (Exception e) { long timeout = Duration.between(initStart, Instant.now()).getSeconds(); log.error("Failed to initialize database connection pool. Gave up after {} seconds.", timeout); } // Timed out - failed to initialize return false; } private static void initializeJdbi(DataSource dataSource) { jdbi = Jdbi.create(dataSource) .registerRowMapper(new NoteRowMapper()); } }