From 1fb593c4cdcd409c28d73b4f99db1fc7b307a82e Mon Sep 17 00:00:00 2001 From: Gursharan Singh <3442979+G8XSU@users.noreply.github.com> Date: Fri, 12 May 2023 10:33:21 -0700 Subject: [PATCH 1/2] Add Base DI setup, use guice as DI using hk2-guice bridge --- app/build.gradle | 5 ++++ app/src/main/java/org/vss/VSSApplication.java | 23 ++++++++++++++++++- .../main/java/org/vss/guice/BaseModule.java | 13 +++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/vss/guice/BaseModule.java diff --git a/app/build.gradle b/app/build.gradle index eb110ba..9b91f56 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,6 +35,7 @@ dependencies { implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation('org.glassfish.jersey.containers:jersey-container-servlet:3.1.0') + implementation('org.glassfish.jersey.inject:jersey-hk2:3.1.0') //jOOQ & Postgres impl deps implementation "org.jooq:jooq:$jooqVersion" @@ -44,6 +45,10 @@ dependencies { jooqGenerator "org.postgresql:postgresql:$postgresVersion" implementation "com.google.inject:guice:$guiceVersion" + implementation "org.glassfish.hk2:guice-bridge:3.0.3" + + compileOnly 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' compileOnly 'org.projectlombok:lombok:1.18.24' annotationProcessor 'org.projectlombok:lombok:1.18.24' diff --git a/app/src/main/java/org/vss/VSSApplication.java b/app/src/main/java/org/vss/VSSApplication.java index 0080669..c836b39 100644 --- a/app/src/main/java/org/vss/VSSApplication.java +++ b/app/src/main/java/org/vss/VSSApplication.java @@ -1,10 +1,31 @@ package org.vss; +import com.google.inject.Guice; +import com.google.inject.Injector; +import jakarta.inject.Inject; import jakarta.ws.rs.ApplicationPath; +import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.jersey.server.ResourceConfig; +import org.jvnet.hk2.guice.bridge.api.GuiceBridge; +import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge; +import org.vss.guice.BaseModule; @ApplicationPath("/") public class VSSApplication extends ResourceConfig { - public VSSApplication() { + + @Inject + public VSSApplication(ServiceLocator serviceLocator) { + packages("org.vss"); + Injector injector = Guice.createInjector(new BaseModule()); + initGuiceIntoHK2Bridge(serviceLocator, injector); + } + + // By default, Jersey framework uses HK2 for dependency injection. + // To use Guice as our dependency injection framework, we provide guice injector to hk2-bridge. + // So that hk2 can query guice injector for creating/injecting objects. + private void initGuiceIntoHK2Bridge(ServiceLocator serviceLocator, Injector injector) { + GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator); + GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class); + guiceBridge.bridgeGuiceInjector(injector); } } diff --git a/app/src/main/java/org/vss/guice/BaseModule.java b/app/src/main/java/org/vss/guice/BaseModule.java new file mode 100644 index 0000000..19b9204 --- /dev/null +++ b/app/src/main/java/org/vss/guice/BaseModule.java @@ -0,0 +1,13 @@ +package org.vss.guice; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import org.vss.KVStore; +import org.vss.impl.postgres.PostgresBackendImpl; + +public class BaseModule extends AbstractModule { + @Override + protected void configure() { + bind(KVStore.class).to(PostgresBackendImpl.class).in(Singleton.class); + } +} From eb55e33e21d76f430b735522455782c0b2890d36 Mon Sep 17 00:00:00 2001 From: Gursharan Singh <3442979+G8XSU@users.noreply.github.com> Date: Wed, 12 Jul 2023 11:21:39 -0700 Subject: [PATCH 2/2] Bind PostgresKVStore as default KV, Add HikariCp connection pooling --- app/build.gradle | 6 +- .../main/java/org/vss/guice/BaseModule.java | 70 +++++++++++++++++++ app/src/main/resources/hikariJdbc.properties | 23 ++++++ 3 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 app/src/main/resources/hikariJdbc.properties diff --git a/app/build.gradle b/app/build.gradle index 9b91f56..d3e0d46 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,7 +35,6 @@ dependencies { implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation('org.glassfish.jersey.containers:jersey-container-servlet:3.1.0') - implementation('org.glassfish.jersey.inject:jersey-hk2:3.1.0') //jOOQ & Postgres impl deps implementation "org.jooq:jooq:$jooqVersion" @@ -43,16 +42,15 @@ dependencies { implementation "org.jooq:jooq-codegen:$jooqVersion" runtimeOnly "org.postgresql:postgresql:$postgresVersion" jooqGenerator "org.postgresql:postgresql:$postgresVersion" + implementation 'com.zaxxer:HikariCP:5.0.1' // Connection pooling for postgres/jdbc implementation "com.google.inject:guice:$guiceVersion" + implementation('org.glassfish.jersey.inject:jersey-hk2:3.1.0') implementation "org.glassfish.hk2:guice-bridge:3.0.3" compileOnly 'org.projectlombok:lombok:1.18.24' annotationProcessor 'org.projectlombok:lombok:1.18.24' - compileOnly 'org.projectlombok:lombok:1.18.24' - annotationProcessor 'org.projectlombok:lombok:1.18.24' - testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" testImplementation "org.mockito:mockito-core:$mockitoVersion" diff --git a/app/src/main/java/org/vss/guice/BaseModule.java b/app/src/main/java/org/vss/guice/BaseModule.java index 19b9204..a33ccac 100644 --- a/app/src/main/java/org/vss/guice/BaseModule.java +++ b/app/src/main/java/org/vss/guice/BaseModule.java @@ -1,13 +1,83 @@ package org.vss.guice; import com.google.inject.AbstractModule; +import com.google.inject.Provides; import com.google.inject.Singleton; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import org.jooq.DSLContext; +import org.jooq.SQLDialect; +import org.jooq.impl.DSL; import org.vss.KVStore; import org.vss.impl.postgres.PostgresBackendImpl; public class BaseModule extends AbstractModule { + @Override protected void configure() { + // Provide PostgresBackend as default implementation for KVStore. bind(KVStore.class).to(PostgresBackendImpl.class).in(Singleton.class); } + + @Provides + @Singleton + // Provide DSLContext which is to be used by PostgresBackend + public DSLContext provideDSLContext() throws ClassNotFoundException { + // Required to load postgres drivers in tomcat + Class.forName("org.postgresql.Driver"); + return DSL.using(HikariCPDataSource.dataSource, SQLDialect.POSTGRES); + } +} + +// Provide Hikari Connection Pooling configuration for jdbc connection management. +// Hikari is high-performance connection pooling library which will maintain a set of connections +// to the database for us. +// When we provide `HikariCPDataSource` to DSLContext, jOOQ will internally `acquire` and `release` +// connections from pool. +// For HikariCP config, we provide some sane defaults, but they are meant to be changed and tuned. +// For specific parameter functionality, refer to HikariCP docs. +class HikariCPDataSource { + + private static HikariConfig config = new HikariConfig(); + public static HikariDataSource dataSource; + + static { + try (InputStream input = HikariCPDataSource.class.getClassLoader() + .getResourceAsStream("hikariJdbc.properties")) { + Properties hikariJdbcProperties = new Properties(); + hikariJdbcProperties.load(input); + + config.setJdbcUrl(hikariJdbcProperties.getProperty("jdbc.url")); + config.setUsername(hikariJdbcProperties.getProperty("jdbc.username")); + config.setPassword(hikariJdbcProperties.getProperty("jdbc.password")); + + config.setMaximumPoolSize( + Integer.parseInt(hikariJdbcProperties.getProperty("hikaricp.maxPoolSize"))); + config.setMinimumIdle( + Integer.parseInt(hikariJdbcProperties.getProperty("hikaricp.minimumIdle"))); + config.setConnectionTimeout( + Long.parseLong(hikariJdbcProperties.getProperty("hikaricp.connectionTimeout"))); + config.setIdleTimeout( + Long.parseLong(hikariJdbcProperties.getProperty("hikaricp.idleTimeout"))); + config.setMaxLifetime( + Long.parseLong(hikariJdbcProperties.getProperty("hikaricp.maxLifetime"))); + + config.addDataSourceProperty("cachePrepStmts", + hikariJdbcProperties.getProperty("hikaricp.cachePrepStmts")); + config.addDataSourceProperty("prepStmtCacheSize", + hikariJdbcProperties.getProperty("hikaricp.prepStmtCacheSize")); + config.addDataSourceProperty("prepStmtCacheSqlLimit", + hikariJdbcProperties.getProperty("hikaricp.prepStmtCacheSqlLimit")); + + dataSource = new HikariDataSource(config); + } catch (IOException e) { + throw new RuntimeException("Unable to read hikariJdbcProperties from resources"); + } + } + + private HikariCPDataSource() { + } } diff --git a/app/src/main/resources/hikariJdbc.properties b/app/src/main/resources/hikariJdbc.properties new file mode 100644 index 0000000..fd8dcfb --- /dev/null +++ b/app/src/main/resources/hikariJdbc.properties @@ -0,0 +1,23 @@ +# Default properties, these are meant to be changed according to application needs. + +jdbc.url=jdbc:postgresql://localhost:5432/postgres +jdbc.username=postgres +jdbc.password= + +# Idle Timeout +hikaricp.minimumIdle=10 + +# Set connectionTimeout to 30 secs +hikaricp.connectionTimeout=30000 + +# Set idle timeout to 10 minutes +hikaricp.idleTimeout=600000 + +# Set Maximum lifetime of a connection to 30minutes +hikaricp.maxLifetime=1800000 + +# Performance Optimizations +hikaricp.maxPoolSize=50 +hikaricp.cachePrepStmts=true +hikaricp.prepStmtCacheSize=250 +hikaricp.prepStmtCacheSqlLimit=2048