Skip to content

Commit ffb429c

Browse files
committed
Quartz - Defer driver discovery to runtime in order to provide more flexibility to users
1 parent ac78cdc commit ffb429c

File tree

5 files changed

+119
-44
lines changed

5 files changed

+119
-44
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
package io.quarkus.quartz.deployment;
22

3+
import java.util.List;
34
import java.util.Optional;
45

56
import io.quarkus.builder.item.SimpleBuildItem;
7+
import io.quarkus.quartz.runtime.jdbc.JDBCDataSource;
68

79
/**
8-
* Holds the SQL driver dialect {@link org.quartz.impl.jdbcjobstore.StdJDBCDelegate driver delegate} to use.
10+
* Holds the necessary information to determine SQL driver dialect.
11+
* <p>
12+
* This can mean either a custom driver registered by user or one of Quarkus built-in drivers.
13+
* If it is the latter, we defer discovering the driver to runtime, see also {@link io.quarkus.quartz.runtime.QuartzSupport}.
914
*/
1015
final class QuartzJDBCDriverDialectBuildItem extends SimpleBuildItem {
1116
private final Optional<String> driver;
17+
private List<JDBCDataSource> dataSources;
1218

13-
public QuartzJDBCDriverDialectBuildItem(Optional<String> driver) {
19+
public QuartzJDBCDriverDialectBuildItem(Optional<String> driver, List<JDBCDataSource> dataSources) {
1420
this.driver = driver;
21+
this.dataSources = dataSources;
1522
}
1623

1724
public Optional<String> getDriver() {
1825
return driver;
1926
}
27+
28+
public List<JDBCDataSource> getDataSources() {
29+
return dataSources;
30+
}
2031
}

extensions/quartz/deployment/src/main/java/io/quarkus/quartz/deployment/QuartzProcessor.java

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import io.quarkus.arc.deployment.AutoAddScopeBuildItem;
4545
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
4646
import io.quarkus.arc.processor.BuiltinScope;
47-
import io.quarkus.datasource.common.runtime.DatabaseKind;
4847
import io.quarkus.deployment.Capabilities;
4948
import io.quarkus.deployment.Capability;
5049
import io.quarkus.deployment.Feature;
@@ -65,6 +64,7 @@
6564
import io.quarkus.quartz.runtime.QuartzRuntimeConfig;
6665
import io.quarkus.quartz.runtime.QuartzSchedulerImpl;
6766
import io.quarkus.quartz.runtime.QuartzSupport;
67+
import io.quarkus.quartz.runtime.jdbc.JDBCDataSource;
6868
import io.quarkus.quartz.runtime.jdbc.QuarkusDBv8Delegate;
6969
import io.quarkus.quartz.runtime.jdbc.QuarkusHSQLDBDelegate;
7070
import io.quarkus.quartz.runtime.jdbc.QuarkusMSSQLDelegate;
@@ -122,8 +122,8 @@ QuartzJDBCDriverDialectBuildItem driver(List<JdbcDataSourceBuildItem> jdbcDataSo
122122
if (config.clustered()) {
123123
throw new ConfigurationException("Clustered jobs configured with unsupported job store option");
124124
}
125-
126-
return new QuartzJDBCDriverDialectBuildItem(Optional.empty());
125+
// No DB storage, the driver can stay empty, and we don't need data sources either
126+
return new QuartzJDBCDriverDialectBuildItem(Optional.empty(), null);
127127
}
128128

129129
if (capabilities.isMissing(Capability.AGROAL)) {
@@ -162,43 +162,17 @@ QuartzJDBCDriverDialectBuildItem driver(List<JdbcDataSourceBuildItem> jdbcDataSo
162162
throw new ConfigurationException(message);
163163
}
164164
}
165+
// A custom delegate implementation, we don't need to check datasources
166+
return new QuartzJDBCDriverDialectBuildItem(driverDelegate, null);
165167
} else {
166-
Optional<JdbcDataSourceBuildItem> selectedJdbcDataSourceBuildItem = jdbcDataSourceBuildItems.stream()
167-
.filter(i -> config.dataSourceName().isPresent() ? config.dataSourceName().get().equals(i.getName())
168-
: i.isDefault())
169-
.findFirst();
170-
171-
if (!selectedJdbcDataSourceBuildItem.isPresent()) {
172-
String message = String.format(
173-
"JDBC Store configured but the '%s' datasource is not configured properly. You can configure your datasource by following the guide available at: https://quarkus.io/guides/datasource",
174-
config.dataSourceName().isPresent() ? config.dataSourceName().get() : "default");
175-
throw new ConfigurationException(message);
168+
List<JDBCDataSource> dataSources = new ArrayList<>();
169+
for (JdbcDataSourceBuildItem jdbcDataSourceBuildItem : jdbcDataSourceBuildItems) {
170+
dataSources.add(new JDBCDataSource(jdbcDataSourceBuildItem.getName(), jdbcDataSourceBuildItem.isDefault(),
171+
jdbcDataSourceBuildItem.getDbKind()));
176172
}
177-
driverDelegate = Optional.of(guessDriver(selectedJdbcDataSourceBuildItem));
173+
// Defer driver determination to runtime
174+
return new QuartzJDBCDriverDialectBuildItem(Optional.empty(), dataSources);
178175
}
179-
return new QuartzJDBCDriverDialectBuildItem(driverDelegate);
180-
}
181-
182-
private String guessDriver(Optional<JdbcDataSourceBuildItem> jdbcDataSource) {
183-
if (!jdbcDataSource.isPresent()) {
184-
return QuarkusStdJDBCDelegate.class.getName();
185-
}
186-
187-
String dataSourceKind = jdbcDataSource.get().getDbKind();
188-
if (DatabaseKind.isPostgreSQL(dataSourceKind)) {
189-
return QuarkusPostgreSQLDelegate.class.getName();
190-
}
191-
if (DatabaseKind.isH2(dataSourceKind)) {
192-
return QuarkusHSQLDBDelegate.class.getName();
193-
}
194-
if (DatabaseKind.isMsSQL(dataSourceKind)) {
195-
return QuarkusMSSQLDelegate.class.getName();
196-
}
197-
if (DatabaseKind.isDB2(dataSourceKind)) {
198-
return QuarkusDBv8Delegate.class.getName();
199-
}
200-
201-
return QuarkusStdJDBCDelegate.class.getName();
202176
}
203177

204178
@BuildStep
@@ -250,7 +224,20 @@ List<ReflectiveClassBuildItem> reflectiveClasses(QuartzBuildTimeConfig config,
250224
reflectiveClasses.add(ReflectiveClassBuildItem.builder(Connection.class)
251225
.reason(getClass().getName()).methods()
252226
.fields().build());
253-
reflectiveClasses.add(ReflectiveClassBuildItem.builder(driverDialect.getDriver().get())
227+
// Since we determine driver delegate at runtime, we need to register all of them
228+
reflectiveClasses.add(ReflectiveClassBuildItem.builder(QuarkusDBv8Delegate.class.getName())
229+
.reason(getClass().getName())
230+
.methods().build());
231+
reflectiveClasses.add(ReflectiveClassBuildItem.builder(QuarkusHSQLDBDelegate.class.getName())
232+
.reason(getClass().getName())
233+
.methods().build());
234+
reflectiveClasses.add(ReflectiveClassBuildItem.builder(QuarkusMSSQLDelegate.class.getName())
235+
.reason(getClass().getName())
236+
.methods().build());
237+
reflectiveClasses.add(ReflectiveClassBuildItem.builder(QuarkusPostgreSQLDelegate.class.getName())
238+
.reason(getClass().getName())
239+
.methods().build());
240+
reflectiveClasses.add(ReflectiveClassBuildItem.builder(QuarkusStdJDBCDelegate.class.getName())
254241
.reason(getClass().getName())
255242
.methods().build());
256243
reflectiveClasses.add(ReflectiveClassBuildItem.builder("io.quarkus.quartz.runtime.QuartzSchedulerImpl$InvokerJob")
@@ -348,6 +335,7 @@ public void quartzSupportBean(QuartzRuntimeConfig runtimeConfig, QuartzBuildTime
348335
.scope(Singleton.class) // this should be @ApplicationScoped but it fails for some reason
349336
.setRuntimeInit()
350337
.supplier(recorder.quartzSupportSupplier(runtimeConfig, buildTimeConfig, driverDialect.getDriver(),
338+
driverDialect.getDataSources(),
351339
nonconcurrentMethods))
352340
.done());
353341
}

extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzRecorder.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
package io.quarkus.quartz.runtime;
22

3+
import java.util.List;
34
import java.util.Optional;
45
import java.util.Set;
56
import java.util.function.Supplier;
67

8+
import io.quarkus.quartz.runtime.jdbc.JDBCDataSource;
79
import io.quarkus.runtime.annotations.Recorder;
810

911
@Recorder
1012
public class QuartzRecorder {
1113

1214
public Supplier<QuartzSupport> quartzSupportSupplier(QuartzRuntimeConfig runtimeConfig,
13-
QuartzBuildTimeConfig buildTimeConfig, Optional<String> driverDialect, Set<String> nonconcurrentMethods) {
15+
QuartzBuildTimeConfig buildTimeConfig, Optional<String> driverDialect,
16+
List<JDBCDataSource> dataSources, Set<String> nonconcurrentMethods) {
1417
return new Supplier<QuartzSupport>() {
1518
@Override
1619
public QuartzSupport get() {
17-
return new QuartzSupport(runtimeConfig, buildTimeConfig, driverDialect, nonconcurrentMethods);
20+
return new QuartzSupport(runtimeConfig, buildTimeConfig, driverDialect, dataSources,
21+
nonconcurrentMethods);
1822
}
1923
};
2024
}

extensions/quartz/runtime/src/main/java/io/quarkus/quartz/runtime/QuartzSupport.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
package io.quarkus.quartz.runtime;
22

3+
import java.util.List;
34
import java.util.Optional;
45
import java.util.Set;
56

7+
import io.quarkus.datasource.common.runtime.DatabaseKind;
68
import io.quarkus.quartz.Nonconcurrent;
9+
import io.quarkus.quartz.runtime.jdbc.JDBCDataSource;
10+
import io.quarkus.quartz.runtime.jdbc.QuarkusDBv8Delegate;
11+
import io.quarkus.quartz.runtime.jdbc.QuarkusHSQLDBDelegate;
12+
import io.quarkus.quartz.runtime.jdbc.QuarkusMSSQLDelegate;
13+
import io.quarkus.quartz.runtime.jdbc.QuarkusPostgreSQLDelegate;
14+
import io.quarkus.quartz.runtime.jdbc.QuarkusStdJDBCDelegate;
15+
import io.quarkus.runtime.configuration.ConfigurationException;
716
import io.quarkus.scheduler.common.runtime.ScheduledMethod;
817

918
public class QuartzSupport {
@@ -15,11 +24,41 @@ public class QuartzSupport {
1524
private final Set<String> nonconcurrentMethods;
1625

1726
public QuartzSupport(QuartzRuntimeConfig runtimeConfig, QuartzBuildTimeConfig buildTimeConfig,
18-
Optional<String> driverDialect, Set<String> nonconcurrentMethods) {
27+
Optional<String> driverDialect, List<JDBCDataSource> dataSources, Set<String> nonconcurrentMethods) {
1928
this.runtimeConfig = runtimeConfig;
2029
this.buildTimeConfig = buildTimeConfig;
21-
this.driverDialect = driverDialect;
2230
this.nonconcurrentMethods = Set.copyOf(nonconcurrentMethods);
31+
32+
if (dataSources == null) {
33+
this.driverDialect = driverDialect;
34+
} else {
35+
// Determine the driver dialect
36+
Optional<JDBCDataSource> selectedDataSource = dataSources.stream()
37+
.filter(i -> buildTimeConfig.dataSourceName().isPresent()
38+
? buildTimeConfig.dataSourceName().get().equals(i.getName())
39+
: i.getIsDefault())
40+
.findFirst();
41+
42+
if (!selectedDataSource.isPresent()) {
43+
String message = String.format(
44+
"JDBC Store configured but the '%s' datasource is not configured properly. You can configure your datasource by following the guide available at: https://quarkus.io/guides/datasource",
45+
buildTimeConfig.dataSourceName().isPresent() ? buildTimeConfig.dataSourceName().get() : "default");
46+
throw new ConfigurationException(message);
47+
}
48+
49+
String dataSourceKind = selectedDataSource.get().getDbKind();
50+
if (DatabaseKind.isPostgreSQL(dataSourceKind)) {
51+
this.driverDialect = Optional.of(QuarkusPostgreSQLDelegate.class.getName());
52+
} else if (DatabaseKind.isH2(dataSourceKind)) {
53+
this.driverDialect = Optional.of(QuarkusHSQLDBDelegate.class.getName());
54+
} else if (DatabaseKind.isMsSQL(dataSourceKind)) {
55+
this.driverDialect = Optional.of(QuarkusMSSQLDelegate.class.getName());
56+
} else if (DatabaseKind.isDB2(dataSourceKind)) {
57+
this.driverDialect = Optional.of(QuarkusDBv8Delegate.class.getName());
58+
} else {
59+
this.driverDialect = Optional.of(QuarkusStdJDBCDelegate.class.getName());
60+
}
61+
}
2362
}
2463

2564
public QuartzRuntimeConfig getRuntimeConfig() {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.quarkus.quartz.runtime.jdbc;
2+
3+
import io.quarkus.runtime.annotations.RecordableConstructor;
4+
5+
/**
6+
* A simplified representation of JDBC data source which we need in order to defer resolving a data source until runtime.
7+
*
8+
*/
9+
public class JDBCDataSource {
10+
11+
private final String name;
12+
private final boolean isDefault;
13+
private final String dbKind;
14+
15+
@RecordableConstructor
16+
public JDBCDataSource(String name, boolean isDefault, String dbKind) {
17+
this.name = name;
18+
this.isDefault = isDefault;
19+
this.dbKind = dbKind;
20+
}
21+
22+
public String getName() {
23+
return name;
24+
}
25+
26+
public boolean getIsDefault() {
27+
return isDefault;
28+
}
29+
30+
public String getDbKind() {
31+
return dbKind;
32+
}
33+
}

0 commit comments

Comments
 (0)