Skip to content

Commit 90a6491

Browse files
committed
[#3562] Migrate to Quarkus JDBC implementation
1 parent e6e312d commit 90a6491

File tree

10 files changed

+104
-21
lines changed

10 files changed

+104
-21
lines changed

services/base-jdbc/pom.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3-
Copyright (c) 2020, 2021 Contributors to the Eclipse Foundation
3+
Copyright (c) 2020, 2023 Contributors to the Eclipse Foundation
44
55
See the NOTICE file(s) distributed with this work for additional
66
information regarding copyright ownership.
@@ -86,6 +86,10 @@
8686
<scope>provided</scope>
8787
<optional>true</optional>
8888
</dependency>
89+
<dependency>
90+
<groupId>io.quarkus</groupId>
91+
<artifactId>quarkus-agroal</artifactId>
92+
</dependency>
8993

9094
<!-- testing -->
9195
<dependency>

services/base-jdbc/src/main/java/org/eclipse/hono/service/base/jdbc/config/JdbcOptions.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2022 Contributors to the Eclipse Foundation
2+
* Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation
33
*
44
* See the NOTICE file(s) distributed with this work for additional
55
* information regarding copyright ownership.
@@ -85,6 +85,14 @@ public interface JdbcOptions {
8585
@WithDefault("3600")
8686
int maximumIdleTime();
8787

88+
/**
89+
* Gets the maximum connection time for acquiring a connection from the DB connection pool.
90+
*
91+
* @return The maximum connection time for acquiring a connection from the pool.
92+
*/
93+
@WithDefault("30")
94+
int maximumConnectionTime();
95+
8896
/**
8997
* Gets the name of the table that contains the data.
9098
*

services/base-jdbc/src/main/java/org/eclipse/hono/service/base/jdbc/config/JdbcProperties.java

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2020, 2022 Contributors to the Eclipse Foundation
2+
* Copyright (c) 2020, 2023 Contributors to the Eclipse Foundation
33
*
44
* See the NOTICE file(s) distributed with this work for additional
55
* information regarding copyright ownership.
@@ -13,14 +13,22 @@
1313

1414
package org.eclipse.hono.service.base.jdbc.config;
1515

16+
import java.time.Duration;
1617
import java.util.Objects;
18+
import java.util.Optional;
1719

1820
import org.slf4j.Logger;
1921
import org.slf4j.LoggerFactory;
2022

2123
import com.fasterxml.jackson.annotation.JsonInclude;
2224
import com.fasterxml.jackson.annotation.JsonInclude.Include;
2325

26+
import io.agroal.api.configuration.AgroalConnectionPoolConfiguration.ConnectionValidator;
27+
import io.agroal.api.configuration.AgroalDataSourceConfiguration.DataSourceImplementation;
28+
import io.agroal.api.configuration.supplier.AgroalDataSourceConfigurationSupplier;
29+
import io.agroal.api.security.NamePrincipal;
30+
import io.agroal.api.security.SimplePassword;
31+
import io.agroal.pool.DataSource;
2432
import io.vertx.core.Vertx;
2533
import io.vertx.core.json.JsonObject;
2634
import io.vertx.ext.jdbc.JDBCClient;
@@ -35,6 +43,7 @@ public class JdbcProperties {
3543
public static final int DEFAULT_MINIMUM_POOL_SIZE = 3;
3644
public static final int DEFAULT_INITIAL_POOL_SIZE = 3;
3745
public static final int DEFAULT_MAXIMUM_IDLE_TIME = 3600;
46+
public static final int DEFAULT_MAXIMUM_CONNECTION_TIME = 30;
3847
private static final Logger log = LoggerFactory.getLogger(JdbcProperties.class);
3948

4049
private String url;
@@ -45,6 +54,7 @@ public class JdbcProperties {
4554
private int minimumPoolSize = DEFAULT_MINIMUM_POOL_SIZE;
4655
private int initialPoolSize = DEFAULT_INITIAL_POOL_SIZE;
4756
private int maximumIdleTime = DEFAULT_MAXIMUM_IDLE_TIME;
57+
private int maximumConnectionTime = DEFAULT_MAXIMUM_CONNECTION_TIME;
4858
private String tableName;
4959

5060
/**
@@ -67,6 +77,7 @@ public JdbcProperties(final JdbcOptions options) {
6777
setMinimumPoolSize(options.minimumPoolSize());
6878
setInitialPoolSize(options.initialPoolSize());
6979
setMaximumIdleTime(options.maximumIdleTime());
80+
setMaximumConnectionTime(options.maximumConnectionTime());
7081
options.password().ifPresent(this::setPassword);
7182
options.tableName().ifPresent(this::setTableName);
7283
setUrl(options.url());
@@ -129,6 +140,13 @@ public int getMaximumIdleTime() {
129140
return maximumIdleTime;
130141
}
131142

143+
public void setMaximumConnectionTime(final int maximumConnectionTime) {
144+
this.maximumConnectionTime = maximumConnectionTime;
145+
}
146+
public int getMaximumConnectionTime() {
147+
return maximumConnectionTime;
148+
}
149+
132150
public String getTableName() {
133151
return tableName;
134152
}
@@ -155,11 +173,14 @@ public static JDBCClient dataSource(final Vertx vertx, final JdbcProperties data
155173
config.put("driver_class", dataSourceProperties.getDriverClass());
156174
}
157175

176+
final String maxIdleLabel = "max_idle_time";
177+
final String maxConnectionLabel = "max_connection_time";
158178
final String minSizeLabel = "min_pool_size";
159179
final String maxSizeLabel = "max_pool_size";
160180
final String initSizeLabel = "initial_pool_size";
161181

162-
putValidValueIntoConfig(config, "max_idle_time", dataSourceProperties.getMaximumIdleTime(), 0, true);
182+
putValidValueIntoConfig(config, maxIdleLabel, dataSourceProperties.getMaximumIdleTime(), 0, true);
183+
putValidValueIntoConfig(config, maxConnectionLabel, dataSourceProperties.getMaximumConnectionTime(), 0, true);
163184
putValidValueIntoConfig(config, minSizeLabel, dataSourceProperties.getMinimumPoolSize(), 0, true);
164185
putValidValueIntoConfig(config, maxSizeLabel, dataSourceProperties.getMaximumPoolSize(), Math.max(1, config.getInteger(minSizeLabel)), true);
165186
// check that initial pool size is between min and max pool size
@@ -168,14 +189,41 @@ public static JDBCClient dataSource(final Vertx vertx, final JdbcProperties data
168189

169190
log.info("Creating new SQL client: {} - table: {}", config, dataSourceProperties.getTableName());
170191

171-
// put password after logging
172-
173-
config
174-
.put("password", dataSourceProperties.getPassword());
175-
176192
// create new client
177193

178-
return JDBCClient.create(vertx, config);
194+
final int minSize = config.getInteger(minSizeLabel);
195+
final int maxSize = config.getInteger(maxSizeLabel);
196+
final int initSize = config.getInteger(initSizeLabel);
197+
final Duration idleTimeout = Duration.ofSeconds(config.getInteger(maxIdleLabel));
198+
final Duration connectionTimeout = Duration.ofSeconds(config.getInteger(maxConnectionLabel));
199+
final NamePrincipal username = Optional
200+
.ofNullable(dataSourceProperties.getUsername())
201+
.map(NamePrincipal::new)
202+
.orElse(null);
203+
final SimplePassword password = Optional
204+
.ofNullable(dataSourceProperties.getPassword())
205+
.map(SimplePassword::new)
206+
.orElse(null);
207+
208+
final AgroalDataSourceConfigurationSupplier configuration = new AgroalDataSourceConfigurationSupplier()
209+
.metricsEnabled(false)
210+
.dataSourceImplementation(DataSourceImplementation.AGROAL)
211+
.connectionPoolConfiguration(poolConfig -> poolConfig
212+
.minSize(minSize)
213+
.maxSize(maxSize)
214+
.initialSize(initSize)
215+
.acquisitionTimeout(connectionTimeout)
216+
.validationTimeout(Duration.ofSeconds(5))
217+
.leakTimeout(Duration.ofSeconds(60))
218+
.reapTimeout(idleTimeout)
219+
.connectionValidator(ConnectionValidator.defaultValidator())
220+
.connectionFactoryConfiguration(connConfig -> connConfig
221+
.jdbcUrl(dataSourceProperties.getUrl())
222+
.connectionProviderClassName(dataSourceProperties.getDriverClass())
223+
.principal(username)
224+
.credential(password)));
225+
226+
return JDBCClient.create(vertx, new DataSource(configuration.get()));
179227

180228
}
181229

services/base-jdbc/src/main/java/org/eclipse/hono/service/base/jdbc/store/device/AbstractDeviceStore.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2020, 2022 Contributors to the Eclipse Foundation
2+
* Copyright (c) 2020, 2023 Contributors to the Eclipse Foundation
33
*
44
* See the NOTICE file(s) distributed with this work for additional
55
* information regarding copyright ownership.
@@ -124,7 +124,7 @@ protected Future<ResultSet> read(final SQLOperations operations, final DeviceKey
124124

125125
return expanded
126126
.trace(this.tracer, spanContext)
127-
.query(this.client);
127+
.query(operations);
128128

129129
}
130130

services/base-jdbc/src/main/java/org/eclipse/hono/service/base/jdbc/store/device/TableManagementStore.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import io.vertx.ext.jdbc.JDBCClient;
6060
import io.vertx.ext.sql.ResultSet;
6161
import io.vertx.ext.sql.SQLConnection;
62+
import io.vertx.ext.sql.SQLOperations;
6263
import io.vertx.ext.sql.UpdateResult;
6364

6465
/**
@@ -336,14 +337,14 @@ public Future<Versioned<Void>> createDevice(
336337

337338
log.debug("createDevice - statement: {}", expanded);
338339

339-
return getDeviceCount(key.getTenantId(), span.context(), this.countDevicesOfTenantStatement, null, null)
340+
return getDeviceCount(connection, key.getTenantId(), span.context(), this.countDevicesOfTenantStatement, null, null)
340341
.compose(currentDeviceCount -> tenant.checkDeviceLimitReached(
341342
key.getTenantId(),
342343
currentDeviceCount,
343344
globalDevicesPerTenantLimit))
344345
.compose(ok -> expanded
345346
.trace(this.tracer, context)
346-
.update(this.client)
347+
.update(connection)
347348
.recover(SQL::translateException))
348349

349350
.compose(x -> createGroups(connection, key, new HashSet<>(device.getMemberOf()), context));
@@ -657,6 +658,7 @@ public Future<UpdateResult> dropTenant(final String tenantId, final SpanContext
657658
/**
658659
* Gets the number of devices that are registered for a tenant.
659660
*
661+
* @param operations The SQL operations instance to use.
660662
* @param tenantId The tenant to count devices for.
661663
* @param spanContext The span to contribute to.
662664
* @param countStatement The count statement to use.
@@ -665,7 +667,7 @@ public Future<UpdateResult> dropTenant(final String tenantId, final SpanContext
665667
* @return A future tracking the outcome of the operation.
666668
* @throws NullPointerException if tenant is {@code null}.
667669
*/
668-
public Future<Integer> getDeviceCount(final String tenantId, final SpanContext spanContext, final Statement countStatement, final String field, final String value) {
670+
public Future<Integer> getDeviceCount(final SQLOperations operations, final String tenantId, final SpanContext spanContext, final Statement countStatement, final String field, final String value) {
669671

670672
Objects.requireNonNull(tenantId);
671673

@@ -683,7 +685,7 @@ public Future<Integer> getDeviceCount(final String tenantId, final SpanContext s
683685

684686
return expanded
685687
.trace(this.tracer, span.context())
686-
.query(this.client)
688+
.query(operations)
687689
.map(r -> {
688690
final var entries = r.getRows(true);
689691
switch (entries.size()) {
@@ -957,7 +959,7 @@ public Future<SearchResult<DeviceWithId>> findDevices(final String tenantId, fin
957959
.withTag(TracingHelper.TAG_TENANT_ID, tenantId)
958960
.start();
959961

960-
final Future<Integer> deviceCountFuture = getDeviceCount(tenantId, span.context(), countStatement, field, value);
962+
final Future<Integer> deviceCountFuture = getDeviceCount(this.client, tenantId, span.context(), countStatement, field, value);
961963

962964
return deviceCountFuture
963965
.compose(count -> expanded.trace(this.tracer, span.context()).query(this.client))

services/base-jdbc/src/main/java/org/eclipse/hono/service/base/jdbc/store/tenant/ManagementStore.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ public Future<Versioned<Void>> create(final String tenantId, final Tenant tenant
220220
log.debug("create - statement: {}", expanded);
221221
return expanded
222222
.trace(this.tracer, span.context())
223-
.update(this.client)
223+
.update(connection)
224224
.recover(SQL::translateException)
225225

226226
// insert all trust anchors
@@ -444,13 +444,13 @@ protected Future<UpdateResult> updateJsonField(
444444
// execute update
445445
final var result = expanded
446446
.trace(this.tracer, span.context())
447-
.update(this.client);
447+
.update(operations);
448448

449449
// process result, check optimistic lock
450450
return checkOptimisticLock(
451451
result, span,
452452
resourceVersion,
453-
checkSpan -> readTenantEntryById(this.client, tenantId, checkSpan.context()));
453+
checkSpan -> readTenantEntryById(operations, tenantId, checkSpan.context()));
454454
}
455455

456456
/**

services/device-registry-jdbc/pom.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3-
Copyright (c) 2022 Contributors to the Eclipse Foundation
3+
Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation
44
55
See the NOTICE file(s) distributed with this work for additional
66
information regarding copyright ownership.
@@ -62,8 +62,20 @@
6262
<groupId>io.quarkus</groupId>
6363
<artifactId>quarkus-kafka-client</artifactId>
6464
</dependency>
65+
<dependency>
66+
<groupId>io.quarkus</groupId>
67+
<artifactId>quarkus-agroal</artifactId>
68+
</dependency>
6569

6670
<!-- JDBC drivers -->
71+
<dependency>
72+
<groupId>io.quarkus</groupId>
73+
<artifactId>quarkus-jdbc-postgresql</artifactId>
74+
</dependency>
75+
<dependency>
76+
<groupId>io.quarkus</groupId>
77+
<artifactId>quarkus-jdbc-h2</artifactId>
78+
</dependency>
6779
<dependency>
6880
<groupId>com.h2database</groupId>
6981
<artifactId>h2</artifactId>

services/device-registry-jdbc/src/main/resources/application.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ quarkus.jackson.accept-case-insensitive-enums=true
33
# fail deserialization of JSON objects sent by clients if they contain unexpected content
44
quarkus.jackson.fail-on-unknown-properties=true
55

6+
# enable h2 and postgres extensions
7+
quarkus.datasource.h2.db-kind=h2
8+
quarkus.datasource.pg.db-kind=pg

services/device-registry-jdbc/src/test/java/org/eclipse/hono/deviceregistry/jdbc/impl/AbstractJdbcRegistryTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ void startDevices(final Vertx vertx) throws IOException, SQLException {
153153

154154
private JdbcProperties resolveJdbcProperties() {
155155
final var jdbc = new JdbcProperties();
156+
jdbc.setInitialPoolSize(0);
157+
jdbc.setMinimumPoolSize(0);
156158
if (DATABASE_TYPE != DatabaseType.H2) {
157159
final JdbcDatabaseContainer<?> databaseContainer = getDatabaseContainer();
158160
jdbc.setDriverClass(databaseContainer.getDriverClassName());

site/documentation/content/admin-guide/jdbc-device-registry-config.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ and availability.
6969
| `HONO_REGISTRY_JDBC_ADAPTER_MINIMUMPOOLSIZE` <br> `hono.registry.jdbc.adapter.minimumPoolSize` | no | `3` | The minimum size of the connection pool. |
7070
| `HONO_REGISTRY_JDBC_ADAPTER_INITIALPOOLSIZE` <br> `hono.registry.jdbc.adapter.initialPoolSize` | no | `3` | Number of connections a pool will try to acquire upon startup. Should be between minPoolSize and maxPoolSize. |
7171
| `HONO_REGISTRY_JDBC_ADAPTER_MAXIMUMIDLETIME` <br> `hono.registry.jdbc.adapter.maximumIdleTime` | no | `3600` | Seconds a connection can remain pooled but unused before being discarded. Zero means idle connections never expire. |
72+
| `HONO_REGISTRY_JDBC_ADAPTER_MAXIMUMCONNECTIONTIME` <br> `hono.registry.jdbc.adapter.maximumConnectionTime` | no | `30` | Seconds acquiring a connection from pool can take. Zero means acquiring a connection never timeouts. |
7273
| `HONO_REGISTRY_JDBC_ADAPTER_TABLENAME` <br> `hono.registry.jdbc.adapter.tableName` | no | - | The name of the table the datastore uses. If the datastore requires multiple tables, this is the prefix. |
7374
| `HONO_REGISTRY_JDBC_MANAGEMENT_URL` <br> `hono.registry.jdbc.management.url` | yes | - | The JDBC URL to the database. |
7475
| `HONO_REGISTRY_JDBC_MANAGEMENT_DRIVERCLASS` <br> `hono.registry.jdbc.management.driverClass` | no | The default driver registered for the JDBC URL. | The class name of the JDBC driver. |
@@ -78,6 +79,7 @@ and availability.
7879
| `HONO_REGISTRY_JDBC_MANAGEMENT_MINIMUMPOOLSIZE` <br> `hono.registry.jdbc.management.minimumPoolSize` | no | `3` | The minimum size of the connection pool. |
7980
| `HONO_REGISTRY_JDBC_MANAGEMENT_INITIALPOOLSIZE` <br> `hono.registry.jdbc.management.initialPoolSize` | no | `3` | Number of connections a pool will try to acquire upon startup. Should be between minPoolSize and maxPoolSize. |
8081
| `HONO_REGISTRY_JDBC_MANAGEMENT_MAXIMUMIDLETIME` <br> `hono.registry.jdbc.management.maximumIdleTime` | no | `3600` | Seconds a connection can remain pooled but unused before being discarded. Zero means idle connections never expire. |
82+
| `HONO_REGISTRY_JDBC_MANAGEMENT_MAXIMUMCONNECTIONTIME` <br> `hono.registry.jdbc.management.maximumConnectionTime` | no | `30` | Seconds acquiring a connection from pool can take. Zero means acquiring a connection never timeouts. |
8183
| `HONO_REGISTRY_JDBC_MANAGEMENT_TABLENAME` <br> `hono.registry.jdbc.management.tableName` | no | - | The name of the table the datastore uses. If the datastore requires multiple tables, this is the prefix. |
8284
| `HONO_REGISTRY_SVC_CREDENTIALSTTL` <br> `hono.registry.svc.credentialsTtl` | no | `1m` | The TTL for credentials responses. |
8385
| `HONO_REGISTRY_SVC_HASHALGORITHMSWHITELIST` <br> `hono.registry.svc.hashAlgorithmsWhitelist` | no | `empty` | An array of supported hashing algorithms to be used with the `hashed-password` type of credentials. When not set, all values will be accepted. |
@@ -93,6 +95,7 @@ and availability.
9395
| `HONO_TENANT_JDBC_ADAPTER_MINIMUMPOOLSIZE` <br> `hono.tenant.jdbc.adapter.minimumPoolSize` | no | `3` | The minimum size of the connection pool. |
9496
| `HONO_TENANT_JDBC_ADAPTER_INITIALPOOLSIZE` <br> `hono.tenant.jdbc.adapter.initialPoolSize` | no | `3` | Number of connections a pool will try to acquire upon startup. Should be between minPoolSize and maxPoolSize. |
9597
| `HONO_TENANT_JDBC_ADAPTER_MAXIMUMIDLETIME` <br> `hono.tenant.jdbc.adapter.maximumIdleTime` | no | `3600` | Seconds a connection can remain pooled but unused before being discarded. Zero means idle connections never expire. |
98+
| `HONO_TENANT_JDBC_ADAPTER_MAXIMUMCONNECTIONTIME` <br> `hono.tenant.jdbc.adapter.maximumConnectionTime` | no | `30` | Seconds acquiring a connection from pool can take. Zero means acquiring a connection never timeouts. |
9699
| `HONO_TENANT_JDBC_ADAPTER_TABLENAME` <br> `hono.tenant.jdbc.adapter.tableName` | no | - | The name of the table the datastore uses. If the datastore requires multiple tables, this is the prefix. |
97100
| `HONO_TENANT_JDBC_MANAGEMENT_URL` <br> `hono.tenant.jdbc.management.url` | yes | - | The JDBC URL to the database. |
98101
| `HONO_TENANT_JDBC_MANAGEMENT_DRIVERCLASS` <br> `hono.tenant.jdbc.management.driverClass` | no | The default driver registered for the JDBC URL. | The class name of the JDBC driver. |
@@ -102,6 +105,7 @@ and availability.
102105
| `HONO_TENANT_JDBC_MANAGEMENT_MINIMUMPOOLSIZE` <br> `hono.tenant.jdbc.management.minimumPoolSize` | no | `3` | The minimum size of the connection pool. |
103106
| `HONO_TENANT_JDBC_MANAGEMENT_INITIALPOOLSIZE` <br> `hono.tenant.jdbc.management.initialPoolSize` | no | `3` | Number of connections a pool will try to acquire upon startup. Should be between minPoolSize and maxPoolSize. |
104107
| `HONO_TENANT_JDBC_MANAGEMENT_MAXIMUMIDLETIME` <br> `hono.tenant.jdbc.management.maximumIdleTime` | no | `3600` | Seconds a connection can remain pooled but unused before being discarded. Zero means idle connections never expire. |
108+
| `HONO_TENANT_JDBC_MANAGEMENT_MAXIMUMCONNECTIONTIME` <br> `hono.tenant.jdbc.management.maximumConnectionTime` | no | `30` | Seconds acquiring a connection from pool can take. Zero means acquiring a connection never timeouts. |
105109
| `HONO_TENANT_JDBC_MANAGEMENT_TABLENAME` <br> `hono.tenant.jdbc.management.tableName` | no | - | The name of the table the datastore uses. If the datastore requires multiple tables, this is the prefix. |
106110
| `HONO_TENANT_SVC_TENANTTTL` <br> `hono.tenant.service.tenantTtl` | no | `1m` | The TTL for tenant responses. |
107111

0 commit comments

Comments
 (0)