From a63de4a5eae9fd4c8c680ef49b01c771f249b9ac Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Fri, 31 Jan 2025 00:21:41 +0000 Subject: [PATCH 01/10] Lazy System Properties for native image --- .../runtime/configuration/Substitutions.java | 348 ++++++++++++++++++ 1 file changed, 348 insertions(+) diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/Substitutions.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/Substitutions.java index 78d04d1ccb5a7a..468eae13c2e306 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/Substitutions.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/Substitutions.java @@ -1,5 +1,23 @@ package io.quarkus.runtime.configuration; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.Enumeration; +import java.util.InvalidPropertiesFormatException; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + import org.eclipse.microprofile.config.spi.ConfigProviderResolver; import com.oracle.svm.core.annotate.Alias; @@ -97,4 +115,334 @@ public byte[] getClassBytes() { return null; } } + + /** + * The GraalVM provides a lazy implementation to access system properties that are expensive to calculate. Still, it + * ends up calculating all the properties anyway when {@link System#getProperties()} is called, which is a common + * call. Used, for instance, to get the list of names in Quarkus configuration, but also in + * GetPropertyAction#privilegedGetProperties() is used in many JVM APIs, for instance, when determining the default + * timezone. Such initialization may cost a few milliseconds of the native image startup time (measured between 5-6, + * depending on the system). + *

+ * This Substitution provides a delegate to the GraalVM lazy implementation, expanding the lazy check to each + * individual method of {@link Properties}. + */ + @TargetClass(className = "com.oracle.svm.core.jdk.SystemPropertiesSupport") + static final class Target_SystemPropertiesSupport { + @Alias + private Properties properties; + + @Alias + private void ensureFullyInitialized() { + } + + @Alias + private void initializeLazyValue(String key) { + } + + @Substitute + public Properties getProperties() { + return new Properties() { + @Override + public synchronized Object setProperty(final String key, final String value) { + initializeLazyValue(key); + return properties.setProperty(key, value); + } + + @Override + public synchronized void load(final Reader reader) throws IOException { + properties.load(reader); + } + + @Override + public synchronized void load(final InputStream inStream) throws IOException { + properties.load(inStream); + } + + @Override + public void save(final OutputStream out, final String comments) { + ensureFullyInitialized(); + properties.save(out, comments); + } + + @Override + public void store(final Writer writer, final String comments) throws IOException { + ensureFullyInitialized(); + properties.store(writer, comments); + } + + @Override + public void store(final OutputStream out, final String comments) throws IOException { + ensureFullyInitialized(); + properties.store(out, comments); + } + + @Override + public synchronized void loadFromXML(final InputStream in) + throws IOException, InvalidPropertiesFormatException { + properties.loadFromXML(in); + } + + @Override + public void storeToXML(final OutputStream os, final String comment) throws IOException { + ensureFullyInitialized(); + properties.storeToXML(os, comment); + } + + @Override + public void storeToXML(final OutputStream os, final String comment, final String encoding) + throws IOException { + ensureFullyInitialized(); + properties.storeToXML(os, comment, encoding); + } + + @Override + public void storeToXML(final OutputStream os, final String comment, final Charset charset) + throws IOException { + ensureFullyInitialized(); + properties.storeToXML(os, comment, charset); + } + + @Override + public String getProperty(final String key) { + initializeLazyValue(key); + return properties.getProperty(key); + } + + @Override + public String getProperty(final String key, final String defaultValue) { + initializeLazyValue(key); + return properties.getProperty(key, defaultValue); + } + + @Override + public Enumeration propertyNames() { + return properties.propertyNames(); + } + + @Override + public Set stringPropertyNames() { + return properties.stringPropertyNames(); + } + + @Override + public void list(final PrintStream out) { + ensureFullyInitialized(); + properties.list(out); + } + + @Override + public void list(final PrintWriter out) { + ensureFullyInitialized(); + properties.list(out); + } + + @Override + public int size() { + return properties.size(); + } + + @Override + public boolean isEmpty() { + return properties.isEmpty(); + } + + @Override + public Enumeration keys() { + return properties.keys(); + } + + @Override + public Enumeration elements() { + ensureFullyInitialized(); + return properties.elements(); + } + + @Override + public boolean contains(final Object value) { + ensureFullyInitialized(); + return properties.contains(value); + } + + @Override + public boolean containsValue(final Object value) { + ensureFullyInitialized(); + return properties.containsValue(value); + } + + @Override + public boolean containsKey(final Object key) { + return properties.containsKey(key); + } + + @Override + public Object get(final Object key) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.get(key); + } + + @Override + public synchronized Object put(final Object key, final Object value) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.put(key, value); + } + + @Override + public synchronized Object remove(final Object key) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.remove(key); + } + + @Override + public synchronized void putAll(final Map t) { + properties.putAll(t); + } + + @Override + public synchronized void clear() { + properties.clear(); + } + + @Override + public synchronized String toString() { + ensureFullyInitialized(); + return properties.toString(); + } + + @Override + public Set keySet() { + return properties.keySet(); + } + + @Override + public Collection values() { + ensureFullyInitialized(); + return properties.values(); + } + + @Override + public Set> entrySet() { + ensureFullyInitialized(); + return properties.entrySet(); + } + + @Override + public synchronized boolean equals(final Object o) { + ensureFullyInitialized(); + return properties.equals(o); + } + + @Override + public synchronized int hashCode() { + ensureFullyInitialized(); + return properties.hashCode(); + } + + @Override + public Object getOrDefault(final Object key, final Object defaultValue) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.getOrDefault(key, defaultValue); + } + + @Override + public synchronized void forEach(final BiConsumer action) { + ensureFullyInitialized(); + properties.forEach(action); + } + + @Override + public synchronized void replaceAll(final BiFunction function) { + ensureFullyInitialized(); + properties.replaceAll(function); + } + + @Override + public synchronized Object putIfAbsent(final Object key, final Object value) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.putIfAbsent(key, value); + } + + @Override + public synchronized boolean remove(final Object key, final Object value) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.remove(key, value); + } + + @Override + public synchronized boolean replace(final Object key, final Object oldValue, final Object newValue) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.replace(key, oldValue, newValue); + } + + @Override + public synchronized Object replace(final Object key, final Object value) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.replace(key, value); + } + + @Override + public synchronized Object computeIfAbsent( + final Object key, + final Function mappingFunction) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.computeIfAbsent(key, mappingFunction); + } + + @Override + public synchronized Object computeIfPresent( + final Object key, + final BiFunction remappingFunction) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.computeIfPresent(key, remappingFunction); + } + + @Override + public synchronized Object compute( + final Object key, + final BiFunction remappingFunction) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.compute(key, remappingFunction); + } + + @Override + public synchronized Object merge( + final Object key, + final Object value, + final BiFunction remappingFunction) { + if (key instanceof String) { + initializeLazyValue((String) key); + } + return properties.merge(key, value, remappingFunction); + } + + @Override + public synchronized Object clone() { + ensureFullyInitialized(); + return properties.clone(); + } + }; + } + } } From d8b58f056440e31dd699e13c179b143108292c5a Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Tue, 4 Feb 2025 09:59:46 +0100 Subject: [PATCH 02/10] Ensure that the copied native executable has the executable permission when copied from the host to the container image. Fix https://github.com/quarkusio/quarkus/issues/46036 --- docs/src/main/asciidoc/building-native-image.adoc | 13 +++++++++---- .../main/asciidoc/quarkus-runtime-base-image.adoc | 11 ++++------- .../base/src/main/docker/Dockerfile.tpl.qute.native | 2 +- .../main/docker/Dockerfile.tpl.qute.native-micro | 2 +- .../awt/src/main/docker/Dockerfile.native | 2 +- .../src/main/docker/Dockerfile.native | 2 +- .../app/src/main/docker/Dockerfile.native | 2 +- .../app/src/main/docker/Dockerfile.native-micro | 2 +- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/src/main/asciidoc/building-native-image.adoc b/docs/src/main/asciidoc/building-native-image.adoc index baa9be1b69fb9a..47efa22252d15e 100644 --- a/docs/src/main/asciidoc/building-native-image.adoc +++ b/docs/src/main/asciidoc/building-native-image.adoc @@ -495,10 +495,15 @@ The project generation has provided a `Dockerfile.native-micro` in the `src/main ---- FROM quay.io/quarkus/quarkus-micro-image:2.0 WORKDIR /work/ -COPY target/*-runner /work/application -RUN chmod 775 /work +RUN chown 1001 /work \ + && chmod "g+rwX" /work \ + && chown 1001:root /work +COPY --chown=1001:root --chmod=755 target/*-runner /work/application + EXPOSE 8080 -CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] +USER 1001 + +ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"] ---- [NOTE] @@ -543,7 +548,7 @@ WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ && chown 1001:root /work -COPY --chown=1001:root target/*-runner /work/application +COPY --chown=1001:root --chmod=0755 target/*-runner /work/application EXPOSE 8080 USER 1001 diff --git a/docs/src/main/asciidoc/quarkus-runtime-base-image.adoc b/docs/src/main/asciidoc/quarkus-runtime-base-image.adoc index c9640697f42acc..cec558eea93d1e 100644 --- a/docs/src/main/asciidoc/quarkus-runtime-base-image.adoc +++ b/docs/src/main/asciidoc/quarkus-runtime-base-image.adoc @@ -24,8 +24,7 @@ In your `Dockerfile`, just use: ---- FROM quay.io/quarkus/quarkus-micro-image:2.0 WORKDIR /work/ -COPY target/*-runner /work/application -RUN chmod 775 /work +COPY --chmod=0755 target/*-runner /work/application EXPOSE 8080 CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] ---- @@ -51,8 +50,7 @@ COPY --from=BUILD \ /lib64/ WORKDIR /work/ -COPY target/*-runner /work/application -RUN chmod 775 /work +COPY --chmod=0755 target/*-runner /work/application EXPOSE 8080 CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] ---- @@ -95,8 +93,7 @@ COPY --from=BUILD \ /etc/fonts /etc/fonts WORKDIR /work/ -COPY target/*-runner /work/application -RUN chmod 775 /work +COPY --chmod=0755 target/*-runner /work/application EXPOSE 8080 CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] ---- @@ -117,7 +114,7 @@ WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ && chown 1001:root /work -COPY --chown=1001:root target/*-runner /work/application +COPY --chown=1001:root --chmod=0755 target/*-runner /work/application EXPOSE 8080 USER 1001 diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/dockerfiles/base/src/main/docker/Dockerfile.tpl.qute.native b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/dockerfiles/base/src/main/docker/Dockerfile.tpl.qute.native index dd2a17091aa4a1..5f66f4f142fadb 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/dockerfiles/base/src/main/docker/Dockerfile.tpl.qute.native +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/dockerfiles/base/src/main/docker/Dockerfile.tpl.qute.native @@ -19,7 +19,7 @@ WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ && chown 1001:root /work -COPY --chown=1001:root {buildtool.build-dir}/*-runner /work/application +COPY --chown=1001:root --chmod=0755 {buildtool.build-dir}/*-runner /work/application EXPOSE 8080 USER 1001 diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/dockerfiles/base/src/main/docker/Dockerfile.tpl.qute.native-micro b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/dockerfiles/base/src/main/docker/Dockerfile.tpl.qute.native-micro index fe30d4da1cf5df..50d3d021d65807 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/dockerfiles/base/src/main/docker/Dockerfile.tpl.qute.native-micro +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus/tooling/dockerfiles/base/src/main/docker/Dockerfile.tpl.qute.native-micro @@ -22,7 +22,7 @@ WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ && chown 1001:root /work -COPY --chown=1001:root {buildtool.build-dir}/*-runner /work/application +COPY --chown=1001:root --chmod=0755 {buildtool.build-dir}/*-runner /work/application EXPOSE 8080 USER 1001 diff --git a/integration-tests/awt/src/main/docker/Dockerfile.native b/integration-tests/awt/src/main/docker/Dockerfile.native index c0db67b9018a69..af3b78b6e5896b 100644 --- a/integration-tests/awt/src/main/docker/Dockerfile.native +++ b/integration-tests/awt/src/main/docker/Dockerfile.native @@ -8,7 +8,7 @@ RUN chown 1001 /work \ && chown 1001:root /work # Shared objects to be dynamically loaded at runtime as needed COPY --chown=1001:root target/*.so /work/ -COPY --chown=1001:root target/*-runner /work/application +COPY --chown=1001:root --chmod=0755 target/*-runner /work/application # Permissions fix for Windows RUN chmod "ugo+x" /work/application EXPOSE 8081 diff --git a/integration-tests/container-image/maven-invoker-way/src/it/container-native-main/src/main/docker/Dockerfile.native b/integration-tests/container-image/maven-invoker-way/src/it/container-native-main/src/main/docker/Dockerfile.native index 60b0f9a4cc88ba..8ab368d1965523 100644 --- a/integration-tests/container-image/maven-invoker-way/src/it/container-native-main/src/main/docker/Dockerfile.native +++ b/integration-tests/container-image/maven-invoker-way/src/it/container-native-main/src/main/docker/Dockerfile.native @@ -19,7 +19,7 @@ WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ && chown 1001:root /work -COPY --chown=1001:root target/*-runner /work/application +COPY --chown=1001:root --chmod=0755 target/*-runner /work/application EXPOSE 8080 USER 1001 diff --git a/integration-tests/maven/src/test/resources-filtered/projects/codegen-config-factory/app/src/main/docker/Dockerfile.native b/integration-tests/maven/src/test/resources-filtered/projects/codegen-config-factory/app/src/main/docker/Dockerfile.native index af439d708a8d29..4870add481f200 100644 --- a/integration-tests/maven/src/test/resources-filtered/projects/codegen-config-factory/app/src/main/docker/Dockerfile.native +++ b/integration-tests/maven/src/test/resources-filtered/projects/codegen-config-factory/app/src/main/docker/Dockerfile.native @@ -19,7 +19,7 @@ WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ && chown 1001:root /work -COPY --chown=1001:root target/*-runner /work/application +COPY --chown=1001:root --chmod=0755 target/*-runner /work/application EXPOSE 8080 USER 1001 diff --git a/integration-tests/maven/src/test/resources-filtered/projects/codegen-config-factory/app/src/main/docker/Dockerfile.native-micro b/integration-tests/maven/src/test/resources-filtered/projects/codegen-config-factory/app/src/main/docker/Dockerfile.native-micro index f2380078856e4e..3c33cd2241e315 100644 --- a/integration-tests/maven/src/test/resources-filtered/projects/codegen-config-factory/app/src/main/docker/Dockerfile.native-micro +++ b/integration-tests/maven/src/test/resources-filtered/projects/codegen-config-factory/app/src/main/docker/Dockerfile.native-micro @@ -22,7 +22,7 @@ WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ && chown 1001:root /work -COPY --chown=1001:root target/*-runner /work/application +COPY --chown=1001:root --chmod=0755 target/*-runner /work/application EXPOSE 8080 USER 1001 From 881007fce6f5624d82737725b72a0db768b3a2a3 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Mon, 3 Feb 2025 16:03:40 +0100 Subject: [PATCH 03/10] SmallRye Fault Tolerance: upgrade to 6.8.0 --- bom/application/pom.xml | 2 +- .../asciidoc/smallrye-fault-tolerance.adoc | 3 + .../deployment/ConfigUtilJandex.java | 35 +++++--- .../faulttolerance/test/reuse/MyGuard.java | 3 +- .../test/reuse/ReuseCircuitBreakerTest.java | 14 +-- .../config/ConfigReuseCircuitBreakerTest.java | 88 +++++++++++++++++++ .../test/reuse/config/HelloService.java | 19 ++++ .../test/reuse/config/MyGuard.java | 20 +++++ ...uarkusFaultToleranceOperationProvider.java | 12 +-- .../SmallRyeFaultToleranceRecorder.java | 2 +- 10 files changed, 172 insertions(+), 26 deletions(-) create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/ConfigReuseCircuitBreakerTest.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/HelloService.java create mode 100644 extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/MyGuard.java diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 60be51228bdcb2..06bcc8fdb0ddce 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -52,7 +52,7 @@ 4.0.0 4.0.8 2.12.1 - 6.7.3 + 6.8.0 4.6.1 2.2.0 1.0.13 diff --git a/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc b/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc index e7823b4ba164e4..33d98302ab6b62 100644 --- a/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc +++ b/docs/src/main/asciidoc/smallrye-fault-tolerance.adoc @@ -626,6 +626,9 @@ The `""` below is: * `"/"` for per method configuration * `""` for per class configuration * `global` for global configuration +* It may also be an `@Identifier` value for configuring a programmatically constructed `Guard` or `TypedGuard` that is used declaratively through `@ApplyGuard`. +Note that in this case, the `Guard`/`TypedGuard` should *NEVER* be used programmatically, because configuration is applied on creation, which happens lazily, on the first use. +This first use must be through `@ApplyGuard`, otherwise configuration would be ignored. include::{generated-dir}/config/quarkus-smallrye-fault-tolerance.adoc[opts=optional, leveloffset=+1] diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/ConfigUtilJandex.java b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/ConfigUtilJandex.java index f1acb8af6f4b7d..4cec8f984c497c 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/ConfigUtilJandex.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/ConfigUtilJandex.java @@ -5,16 +5,14 @@ import org.jboss.jandex.ClassInfo; import org.jboss.jandex.MethodInfo; -import io.smallrye.faulttolerance.config.ConfigPrefix; -import io.smallrye.faulttolerance.config.NewConfig; +import io.smallrye.config.common.utils.StringUtil; +import io.smallrye.faulttolerance.autoconfig.ConfigConstants; -// copy of `io.smallrye.faulttolerance.config.ConfigUtil` and translation from reflection to Jandex +// copy of a past version of `io.smallrye.faulttolerance.basicconfig.ConfigUtil` and translation from reflection to Jandex final class ConfigUtilJandex { - static final String GLOBAL = "global"; - static String newKey(Class annotation, String member, MethodInfo declaringMethod) { - return ConfigPrefix.VALUE + "\"" + declaringMethod.declaringClass().name() + "/" + declaringMethod.name() - + "\"." + NewConfig.get(annotation, member); + return ConfigConstants.PREFIX + "\"" + declaringMethod.declaringClass().name() + "/" + declaringMethod.name() + + "\"." + newAnnotationName(annotation) + "." + newMemberName(member); } static String oldKey(Class annotation, String member, MethodInfo declaringMethod) { @@ -23,8 +21,8 @@ static String oldKey(Class annotation, String member, Meth } static String newKey(Class annotation, String member, ClassInfo declaringClass) { - return ConfigPrefix.VALUE + "\"" + declaringClass.name() + "\"." - + NewConfig.get(annotation, member); + return ConfigConstants.PREFIX + "\"" + declaringClass.name() + "\"." + + newAnnotationName(annotation) + "." + newMemberName(member); } static String oldKey(Class annotation, String member, ClassInfo declaringClass) { @@ -32,7 +30,8 @@ static String oldKey(Class annotation, String member, Clas } static String newKey(Class annotation, String member) { - return ConfigPrefix.VALUE + GLOBAL + "." + NewConfig.get(annotation, member); + return ConfigConstants.PREFIX + ConfigConstants.GLOBAL + "." + + newAnnotationName(annotation) + "." + newMemberName(member); } static String oldKey(Class annotation, String member) { @@ -40,4 +39,20 @@ static String oldKey(Class annotation, String member) { } // no need to have the `isEnabled()` method, that is only needed at runtime + + // --- + // these 2 methods are mostly copied from `io.smallrye.faulttolerance.autoconfig.processor.AutoConfigProcessor` + + private static String newAnnotationName(Class annotationDeclaration) { + return StringUtil.skewer(annotationDeclaration.getSimpleName()); + } + + private static String newMemberName(String annotationMember) { + String name = switch (annotationMember) { + case "jitterDelayUnit" -> "jitterUnit"; + case "durationUnit" -> "maxDurationUnit"; + default -> annotationMember; + }; + return StringUtil.skewer(name); + } } diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/MyGuard.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/MyGuard.java index e7d992c7f60d20..ea28797932a3b9 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/MyGuard.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/MyGuard.java @@ -12,10 +12,11 @@ public class MyGuard { static final int THRESHOLD = 5; static final int DELAY = 500; + static final String NAME = "hello"; @Produces @Identifier("my-guard") public static final Guard GUARD = Guard.create() - .withCircuitBreaker().requestVolumeThreshold(THRESHOLD).delay(DELAY, ChronoUnit.MILLIS).name("hello").done() + .withCircuitBreaker().requestVolumeThreshold(THRESHOLD).delay(DELAY, ChronoUnit.MILLIS).name(NAME).done() .build(); } diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/ReuseCircuitBreakerTest.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/ReuseCircuitBreakerTest.java index 233c2c3703d7a0..2e7dbadb84cd51 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/ReuseCircuitBreakerTest.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/ReuseCircuitBreakerTest.java @@ -45,12 +45,12 @@ public void test() { CircuitBreakerMaintenance cbm = CircuitBreakerMaintenance.get(); - assertThat(cb.currentState("hello")).isEqualTo(CircuitBreakerState.CLOSED); - assertThat(cbm.currentState("hello")).isEqualTo(CircuitBreakerState.CLOSED); + assertThat(cb.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.CLOSED); + assertThat(cbm.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.CLOSED); AtomicInteger helloStateChanges = new AtomicInteger(); - cbm.onStateChange("hello", ignored -> { + cbm.onStateChange(MyGuard.NAME, ignored -> { helloStateChanges.incrementAndGet(); }); @@ -60,8 +60,8 @@ public void test() { }).isExactlyInstanceOf(IOException.class); } - assertThat(cb.currentState("hello")).isEqualTo(CircuitBreakerState.OPEN); - assertThat(cbm.currentState("hello")).isEqualTo(CircuitBreakerState.OPEN); + assertThat(cb.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.OPEN); + assertThat(cbm.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.OPEN); // 1. closed -> open assertThat(helloStateChanges).hasValue(1); @@ -72,8 +72,8 @@ public void test() { assertThat(helloService.hello(null)).isEqualTo(HelloService.OK); }); - assertThat(cb.currentState("hello")).isEqualTo(CircuitBreakerState.CLOSED); - assertThat(cbm.currentState("hello")).isEqualTo(CircuitBreakerState.CLOSED); + assertThat(cb.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.CLOSED); + assertThat(cbm.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.CLOSED); // 2. open -> half-open // 3. half-open -> closed diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/ConfigReuseCircuitBreakerTest.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/ConfigReuseCircuitBreakerTest.java new file mode 100644 index 00000000000000..1e240d670f5528 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/ConfigReuseCircuitBreakerTest.java @@ -0,0 +1,88 @@ +package io.quarkus.smallrye.faulttolerance.test.reuse.config; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.awaitility.Awaitility.await; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.inject.Inject; + +import org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.faulttolerance.api.CircuitBreakerMaintenance; +import io.smallrye.faulttolerance.api.CircuitBreakerState; + +public class ConfigReuseCircuitBreakerTest { + private static final int NEW_THRESHOLD = 5; + private static final int NEW_DELAY = 500; + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot(jar -> jar.addClasses(HelloService.class, MyGuard.class)) + .overrideConfigKey("quarkus.fault-tolerance.\"my-guard\".circuit-breaker.request-volume-threshold", + "" + NEW_THRESHOLD) + .overrideConfigKey("quarkus.fault-tolerance.\"my-guard\".circuit-breaker.delay", "" + NEW_DELAY); + + @Inject + HelloService helloService; + + @Inject + CircuitBreakerMaintenance cb; + + @BeforeEach + public void reset() { + CircuitBreakerMaintenance.get().resetAll(); + } + + @Test + public void test() { + // force guard instantiation + assertThatCode(() -> { + helloService.hello(null); + }).doesNotThrowAnyException(); + + CircuitBreakerMaintenance cbm = CircuitBreakerMaintenance.get(); + + assertThat(cb.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.CLOSED); + assertThat(cbm.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.CLOSED); + + AtomicInteger helloStateChanges = new AtomicInteger(); + + cbm.onStateChange(MyGuard.NAME, ignored -> { + helloStateChanges.incrementAndGet(); + }); + + for (int i = 0; i < NEW_THRESHOLD - 1; i++) { // `- 1` because of the initial invocation above + assertThatThrownBy(() -> { + helloService.hello(new IOException()); + }).isExactlyInstanceOf(IOException.class); + } + + assertThat(cb.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.OPEN); + assertThat(cbm.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.OPEN); + + // 1. closed -> open + assertThat(helloStateChanges).hasValue(1); + + await().atMost(NEW_DELAY * 2, TimeUnit.MILLISECONDS) + .ignoreException(CircuitBreakerOpenException.class) + .untilAsserted(() -> { + assertThat(helloService.hello(null)).isEqualTo(HelloService.OK); + }); + + assertThat(cb.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.CLOSED); + assertThat(cbm.currentState(MyGuard.NAME)).isEqualTo(CircuitBreakerState.CLOSED); + + // 2. open -> half-open + // 3. half-open -> closed + assertThat(helloStateChanges).hasValue(3); + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/HelloService.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/HelloService.java new file mode 100644 index 00000000000000..cfedfdb8fb09b6 --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/HelloService.java @@ -0,0 +1,19 @@ +package io.quarkus.smallrye.faulttolerance.test.reuse.config; + +import jakarta.enterprise.context.ApplicationScoped; + +import io.smallrye.faulttolerance.api.ApplyGuard; + +@ApplicationScoped +public class HelloService { + static final String OK = "Hello"; + + @ApplyGuard("my-guard") + public String hello(Exception exception) throws Exception { + if (exception != null) { + throw exception; + } + + return OK; + } +} diff --git a/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/MyGuard.java b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/MyGuard.java new file mode 100644 index 00000000000000..6f4bb21ceb31ce --- /dev/null +++ b/extensions/smallrye-fault-tolerance/deployment/src/test/java/io/quarkus/smallrye/faulttolerance/test/reuse/config/MyGuard.java @@ -0,0 +1,20 @@ +package io.quarkus.smallrye.faulttolerance.test.reuse.config; + +import java.time.temporal.ChronoUnit; + +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Singleton; + +import io.smallrye.common.annotation.Identifier; +import io.smallrye.faulttolerance.api.Guard; + +@Singleton +public class MyGuard { + static final String NAME = "hello"; + + @Produces + @Identifier("my-guard") + public static final Guard GUARD = Guard.create() + .withCircuitBreaker().requestVolumeThreshold(10).delay(5000, ChronoUnit.MILLIS).name(NAME).done() + .build(); +} diff --git a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/QuarkusFaultToleranceOperationProvider.java b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/QuarkusFaultToleranceOperationProvider.java index 2f8ccb2fa9fb2a..a7bab08f621e93 100644 --- a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/QuarkusFaultToleranceOperationProvider.java +++ b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/QuarkusFaultToleranceOperationProvider.java @@ -46,7 +46,7 @@ public FaultToleranceOperation get(Class beanClass, Method method) { private FaultToleranceOperation createAtRuntime(CacheKey key) { LOG.debugf("FaultToleranceOperation not found in the cache for %s creating it at runtime", key); - return FaultToleranceOperation.create(FaultToleranceMethods.create(key.beanClass, key.method)); + return new FaultToleranceOperation(FaultToleranceMethods.create(key.beanClass, key.method)); } public Map getOperationCache() { @@ -54,9 +54,9 @@ public Map getOperationCache() { } static class CacheKey { - private Class beanClass; - private Method method; - private int hashCode; + private final Class beanClass; + private final Method method; + private final int hashCode; public CacheKey(Class beanClass, Method method) { this.beanClass = beanClass; @@ -73,8 +73,8 @@ public boolean equals(Object o) { return false; } CacheKey cacheKey = (CacheKey) o; - return Objects.equals(beanClass, cacheKey.beanClass) && - Objects.equals(method, cacheKey.method); + return Objects.equals(beanClass, cacheKey.beanClass) + && Objects.equals(method, cacheKey.method); } @Override diff --git a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/SmallRyeFaultToleranceRecorder.java b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/SmallRyeFaultToleranceRecorder.java index 78824953316c26..d4830ccddc2521 100644 --- a/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/SmallRyeFaultToleranceRecorder.java +++ b/extensions/smallrye-fault-tolerance/runtime/src/main/java/io/quarkus/smallrye/faulttolerance/runtime/SmallRyeFaultToleranceRecorder.java @@ -23,7 +23,7 @@ public void createFaultToleranceOperation(List ftMethods) Map operationCache = new HashMap<>( ftMethods.size()); for (FaultToleranceMethod ftMethod : ftMethods) { - FaultToleranceOperation operation = FaultToleranceOperation.create(ftMethod); + FaultToleranceOperation operation = new FaultToleranceOperation(ftMethod); try { operation.validate(); From 914a67bbe602ac756c6812411f39383f4ec07198 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 4 Feb 2025 15:11:05 +0100 Subject: [PATCH 04/10] Mailer - Switch to @ConfigMapping --- extensions/mailer/deployment/pom.xml | 3 - .../mailer/deployment/MailerProcessor.java | 2 +- extensions/mailer/runtime/pom.xml | 3 - .../mailer/runtime/DkimSignOptionsConfig.java | 41 ++-- .../mailer/runtime/MailerRuntimeConfig.java | 116 ++++----- .../io/quarkus/mailer/runtime/Mailers.java | 144 +++++------ .../runtime/MailersBuildTimeConfig.java | 12 +- .../mailer/runtime/MailersRuntimeConfig.java | 22 +- .../io/quarkus/mailer/runtime/NtlmConfig.java | 9 +- .../mailer/runtime/TrustStoreConfig.java | 19 +- .../mailer/runtime/FakeSmtpTestBase.java | 223 +++++++++++++++--- .../mailer/runtime/MailerTLSRegistryTest.java | 45 +++- .../mailer/runtime/MailerTruststoreTest.java | 85 +++++-- 13 files changed, 465 insertions(+), 259 deletions(-) diff --git a/extensions/mailer/deployment/pom.xml b/extensions/mailer/deployment/pom.xml index 5a1a7d602f4604..5354e2b6fb0688 100644 --- a/extensions/mailer/deployment/pom.xml +++ b/extensions/mailer/deployment/pom.xml @@ -64,9 +64,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/mailer/deployment/src/main/java/io/quarkus/mailer/deployment/MailerProcessor.java b/extensions/mailer/deployment/src/main/java/io/quarkus/mailer/deployment/MailerProcessor.java index 70f8bc8e54f0b2..af68db9ac33362 100644 --- a/extensions/mailer/deployment/src/main/java/io/quarkus/mailer/deployment/MailerProcessor.java +++ b/extensions/mailer/deployment/src/main/java/io/quarkus/mailer/deployment/MailerProcessor.java @@ -81,7 +81,7 @@ public static class CacheAttachmentsEnabled implements BooleanSupplier { MailersBuildTimeConfig config; public boolean getAsBoolean() { - return config.cacheAttachments; + return config.cacheAttachments(); } } diff --git a/extensions/mailer/runtime/pom.xml b/extensions/mailer/runtime/pom.xml index d2710314650114..cd2a87d365d3db 100644 --- a/extensions/mailer/runtime/pom.xml +++ b/extensions/mailer/runtime/pom.xml @@ -95,9 +95,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/DkimSignOptionsConfig.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/DkimSignOptionsConfig.java index 21ca77c3666abc..5c55991474cba7 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/DkimSignOptionsConfig.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/DkimSignOptionsConfig.java @@ -6,88 +6,77 @@ import java.util.OptionalLong; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; +import io.smallrye.config.WithDefault; @ConfigGroup -public class DkimSignOptionsConfig { +public interface DkimSignOptionsConfig { /** * Enables DKIM signing. */ - @ConfigItem(defaultValue = "false") - public boolean enabled; + @WithDefault("false") + boolean enabled(); /** * Configures the PKCS#8 format private key used to sign the email. */ - @ConfigItem - public Optional privateKey = Optional.empty(); + Optional privateKey(); /** * Configures the PKCS#8 format private key file path. */ - @ConfigItem - public Optional privateKeyPath = Optional.empty(); + Optional privateKeyPath(); /** * Configures the Agent or User Identifier (AUID). */ - @ConfigItem - public Optional auid = Optional.empty(); + Optional auid(); /** * Configures the selector used to query the public key. */ - @ConfigItem - public Optional selector = Optional.empty(); + Optional selector(); /** * Configures the Signing Domain Identifier (SDID). */ - @ConfigItem - public Optional sdid = Optional.empty(); + Optional sdid(); /** * Configures the canonicalization algorithm for signed headers. */ - @ConfigItem - public Optional headerCanonAlgo = Optional.empty(); + Optional headerCanonAlgo(); /** * Configures the canonicalization algorithm for mail body. */ - @ConfigItem - public Optional bodyCanonAlgo = Optional.empty(); + Optional bodyCanonAlgo(); /** * Configures the body limit to sign. * * Must be greater than zero. */ - @ConfigItem - public OptionalInt bodyLimit = OptionalInt.empty(); + OptionalInt bodyLimit(); /** * Configures to enable or disable signature sign timestamp. */ - @ConfigItem - public Optional signatureTimestamp = Optional.empty(); + Optional signatureTimestamp(); /** * Configures the expire time in seconds when the signature sign will be expired. * * Must be greater than zero. */ - @ConfigItem - public OptionalLong expireTime = OptionalLong.empty(); + OptionalLong expireTime(); /** * Configures the signed headers in DKIM, separated by commas. * * The order in the list matters. */ - @ConfigItem - public Optional> signedHeaders = Optional.empty(); + Optional> signedHeaders(); public enum CanonicalizationAlgorithmOption { SIMPLE, diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailerRuntimeConfig.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailerRuntimeConfig.java index bd5c2879b6b317..745366403c6c4d 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailerRuntimeConfig.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailerRuntimeConfig.java @@ -7,18 +7,17 @@ import java.util.regex.Pattern; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.annotations.ConvertWith; +import io.smallrye.config.WithConverter; +import io.smallrye.config.WithDefault; @ConfigGroup -public class MailerRuntimeConfig { +public interface MailerRuntimeConfig { /** * Sets the default `from` attribute when not specified in the {@link io.quarkus.mailer.Mail} instance. * It's the sender email address. */ - @ConfigItem - public Optional from = Optional.empty(); + Optional from(); /** * Enables the mock mode. @@ -27,21 +26,19 @@ public class MailerRuntimeConfig { *

* Disabled by default on PROD, enabled by default on DEV and TEST modes. */ - @ConfigItem - public Optional mock = Optional.empty(); + Optional mock(); /** * Sets the default bounce email address. * A bounced email, or bounce, is an email message that gets rejected by a mail server. */ - @ConfigItem - public Optional bounceAddress = Optional.empty(); + Optional bounceAddress(); /** * Sets the SMTP host name. */ - @ConfigItem(defaultValue = "localhost") - public String host = "localhost"; + @WithDefault("localhost") + String host(); /** * The SMTP port. @@ -55,20 +52,17 @@ public class MailerRuntimeConfig { * Note that the port 465 may be used by SMTP servers, however, IANA has reassigned a new service to this port, * and it should no longer be used for SMTP communications. */ - @ConfigItem - public OptionalInt port = OptionalInt.empty(); + OptionalInt port(); /** * Sets the username to connect to the SMTP server. */ - @ConfigItem - public Optional username = Optional.empty(); + Optional username(); /** * Sets the password to connect to the SMTP server. */ - @ConfigItem - public Optional password = Optional.empty(); + Optional password(); /** * The name of the TLS configuration to use. @@ -80,8 +74,7 @@ public class MailerRuntimeConfig { *

* The default TLS configuration is not used by default. */ - @ConfigItem - public Optional tlsConfigurationName = Optional.empty(); + Optional tlsConfigurationName(); /** * Enables or disables the TLS/SSL. @@ -89,8 +82,8 @@ public class MailerRuntimeConfig { * @deprecated Use {{@link #tls}} */ @Deprecated - @ConfigItem(defaultValue = "false") - public boolean ssl; + @WithDefault("false") + boolean ssl(); /** * Whether the connection should be secured using TLS. @@ -104,8 +97,7 @@ public class MailerRuntimeConfig { * Note that if a TLS configuration is set, TLS is enabled automatically. So, setting this property to {@code false} is * required to not establish a connection with TLS. */ - @ConfigItem - public Optional tls; + Optional tls(); /** * Set whether all server certificates should be trusted. @@ -113,28 +105,26 @@ public class MailerRuntimeConfig { * * @deprecated Use the TLS registry instead. */ - @ConfigItem @Deprecated - public Optional trustAll = Optional.empty(); + Optional trustAll(); /** * Sets the max number of open connections to the mail server. */ - @ConfigItem(defaultValue = "10") - public int maxPoolSize = 10; + @WithDefault("10") + int maxPoolSize(); /** * Sets the hostname to be used for HELO/EHLO and the Message-ID. */ - @ConfigItem - public Optional ownHostName = Optional.empty(); + Optional ownHostName(); /** * Sets if connection pool is enabled. * If the connection pooling is disabled, the max number of sockets is enforced nevertheless. */ - @ConfigItem(defaultValue = "true") - public boolean keepAlive = true; + @WithDefault("true") + boolean keepAlive(); /** * Disable ESMTP. @@ -142,21 +132,20 @@ public class MailerRuntimeConfig { * The RFC-1869 states that clients should always attempt {@code EHLO} as first command to determine if ESMTP * is supported, if this returns an error code, {@code HELO} is tried to use the regular SMTP command. */ - @ConfigItem(defaultValue = "false") - public boolean disableEsmtp; + @WithDefault("false") + boolean disableEsmtp(); /** * Sets the TLS security mode for the connection. * Either {@code DISABLED}, {@code OPTIONAL} or {@code REQUIRED}. */ - @ConfigItem(defaultValue = "OPTIONAL") - public String startTLS = "OPTIONAL"; + @WithDefault("OPTIONAL") + String startTLS(); /** * Configures DKIM signature verification. */ - @ConfigItem - public DkimSignOptionsConfig dkim = new DkimSignOptionsConfig(); + DkimSignOptionsConfig dkim(); /** * Sets the login mode for the connection. @@ -169,8 +158,8 @@ public class MailerRuntimeConfig { *

  • XOAUTH2 means that a login will be attempted using Google Gmail Oauth2 tokens
  • * */ - @ConfigItem(defaultValue = "NONE") - public String login = "NONE"; + @WithDefault("NONE") + String login(); /** * Sets the allowed authentication methods. @@ -179,8 +168,7 @@ public class MailerRuntimeConfig { *

    * The list is given as a space separated list, such as {@code DIGEST-MD5 CRAM-SHA256 CRAM-SHA1 CRAM-MD5 PLAIN LOGIN}. */ - @ConfigItem - public Optional authMethods = Optional.empty(); + Optional authMethods(); /** * Set the trust store. @@ -188,67 +176,61 @@ public class MailerRuntimeConfig { * @deprecated Use the TLS registry instead. */ @Deprecated - @ConfigItem - public Optional keyStore = Optional.empty(); + Optional keyStore(); /** * Sets the trust store password if any. * * @deprecated Use the TLS registry instead. */ - @ConfigItem - @Deprecated - public Optional keyStorePassword = Optional.empty(); + Optional keyStorePassword(); /** * Configures the trust store. * * @deprecated Use the TLS registry instead. */ - @ConfigItem - @Deprecated - public TrustStoreConfig truststore = new TrustStoreConfig(); + TrustStoreConfig truststore(); /** * Whether the mail should always been sent as multipart even if they don't have attachments. * When sets to true, the mail message will be encoded as multipart even for simple mails without attachments. */ - @ConfigItem(defaultValue = "false") - public boolean multiPartOnly; + @WithDefault("false") + boolean multiPartOnly(); /** * Sets if sending allows recipients errors. * If set to true, the mail will be sent to the recipients that the server accepted, if any. */ - @ConfigItem(defaultValue = "false") - public boolean allowRcptErrors; + @WithDefault("false") + boolean allowRcptErrors(); /** * Enables or disables the pipelining capability if the SMTP server supports it. */ - @ConfigItem(defaultValue = "true") - public boolean pipelining = true; + @WithDefault("true") + boolean pipelining(); /** * Sets the connection pool cleaner period. * Zero disables expiration checks and connections will remain in the pool until they are closed. */ - @ConfigItem(defaultValue = "PT1S") - public Duration poolCleanerPeriod = Duration.ofSeconds(1L); + @WithDefault("PT1S") + Duration poolCleanerPeriod(); /** * Set the keep alive timeout for the SMTP connection. * This value determines how long a connection remains unused in the pool before being evicted and closed. * A timeout of 0 means there is no timeout. */ - @ConfigItem(defaultValue = "PT300S") - public Duration keepAliveTimeout = Duration.ofSeconds(300L); + @WithDefault("PT300S") + Duration keepAliveTimeout(); /** * Configures NTLM (Windows New Technology LAN Manager). */ - @ConfigItem - public NtlmConfig ntlm = new NtlmConfig(); + NtlmConfig ntlm(); /** * Allows sending emails to these recipients only. @@ -259,9 +241,7 @@ public class MailerRuntimeConfig { * * @see {@link #logRejectedRecipients} */ - @ConfigItem - @ConvertWith(TrimmedPatternConverter.class) - public Optional> approvedRecipients = Optional.empty(); + Optional> approvedRecipients(); /** * Log rejected recipients as warnings. @@ -270,8 +250,8 @@ public class MailerRuntimeConfig { * * @see {@link #approvedRecipients} */ - @ConfigItem(defaultValue = "false") - public boolean logRejectedRecipients = false; + @WithDefault("false") + boolean logRejectedRecipients(); /** * Log invalid recipients as warnings. @@ -279,6 +259,6 @@ public class MailerRuntimeConfig { * If false, the invalid recipients will not be logged and the thrown exception will not contain the invalid email address. * */ - @ConfigItem(defaultValue = "false") - public boolean logInvalidRecipients = false; + @WithDefault("false") + boolean logInvalidRecipients(); } diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/Mailers.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/Mailers.java index 2151d33d0396b4..c8f792ea077f7c 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/Mailers.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/Mailers.java @@ -64,7 +64,9 @@ public Mailers(Vertx vertx, io.vertx.mutiny.core.Vertx mutinyVertx, MailersRunti Map localMutinyMailers = new HashMap<>(); if (mailerSupport.hasDefaultMailer) { - MailClient mailClient = createMailClient(vertx, DEFAULT_MAILER_NAME, mailersRuntimeConfig.defaultMailer, + MailerRuntimeConfig defaultMailerConfig = mailersRuntimeConfig.mailers().get(DEFAULT_MAILER_NAME); + + MailClient mailClient = createMailClient(vertx, DEFAULT_MAILER_NAME, defaultMailerConfig, tlsRegistry); io.vertx.mutiny.ext.mail.MailClient mutinyMailClient = io.vertx.mutiny.ext.mail.MailClient.newInstance(mailClient); MockMailboxImpl mockMailbox = new MockMailboxImpl(); @@ -73,18 +75,17 @@ public Mailers(Vertx vertx, io.vertx.mutiny.core.Vertx mutinyVertx, MailersRunti localMockMailboxes.put(DEFAULT_MAILER_NAME, mockMailbox); localMutinyMailers.put(DEFAULT_MAILER_NAME, new MutinyMailerImpl(mutinyVertx, mutinyMailClient, mockMailbox, - mailersRuntimeConfig.defaultMailer.from.orElse(null), - mailersRuntimeConfig.defaultMailer.bounceAddress.orElse(null), - mailersRuntimeConfig.defaultMailer.mock.orElse(launchMode.isDevOrTest()), - mailersRuntimeConfig.defaultMailer.approvedRecipients.orElse(List.of()).stream() + defaultMailerConfig.from().orElse(null), + defaultMailerConfig.bounceAddress().orElse(null), + defaultMailerConfig.mock().orElse(launchMode.isDevOrTest()), + defaultMailerConfig.approvedRecipients().orElse(List.of()).stream() .filter(Objects::nonNull).collect(Collectors.toList()), - mailersRuntimeConfig.defaultMailer.logRejectedRecipients, - mailersRuntimeConfig.defaultMailer.logInvalidRecipients, sentMailEvent)); + defaultMailerConfig.logRejectedRecipients(), + defaultMailerConfig.logInvalidRecipients(), sentMailEvent)); } for (String name : mailerSupport.namedMailers) { - MailerRuntimeConfig namedMailerRuntimeConfig = mailersRuntimeConfig.namedMailers - .getOrDefault(name, new MailerRuntimeConfig()); + MailerRuntimeConfig namedMailerRuntimeConfig = mailersRuntimeConfig.mailers().get(name); MailClient namedMailClient = createMailClient(vertx, name, namedMailerRuntimeConfig, tlsRegistry); @@ -96,13 +97,13 @@ public Mailers(Vertx vertx, io.vertx.mutiny.core.Vertx mutinyVertx, MailersRunti localMockMailboxes.put(name, namedMockMailbox); localMutinyMailers.put(name, new MutinyMailerImpl(mutinyVertx, namedMutinyMailClient, namedMockMailbox, - namedMailerRuntimeConfig.from.orElse(null), - namedMailerRuntimeConfig.bounceAddress.orElse(null), - namedMailerRuntimeConfig.mock.orElse(false), - namedMailerRuntimeConfig.approvedRecipients.orElse(List.of()).stream() + namedMailerRuntimeConfig.from().orElse(null), + namedMailerRuntimeConfig.bounceAddress().orElse(null), + namedMailerRuntimeConfig.mock().orElse(false), + namedMailerRuntimeConfig.approvedRecipients().orElse(List.of()).stream() .filter(p -> p != null).collect(Collectors.toList()), - namedMailerRuntimeConfig.logRejectedRecipients, - namedMailerRuntimeConfig.logInvalidRecipients, + namedMailerRuntimeConfig.logRejectedRecipients(), + namedMailerRuntimeConfig.logInvalidRecipients(), sentMailEvent)); } @@ -149,53 +150,54 @@ private MailClient createMailClient(Vertx vertx, String name, MailerRuntimeConfi private io.vertx.ext.mail.DKIMSignOptions toVertxDkimSignOptions(DkimSignOptionsConfig optionsConfig) { DKIMSignOptions vertxDkimOptions = new io.vertx.ext.mail.DKIMSignOptions(); - String sdid = optionsConfig.sdid + String sdid = optionsConfig.sdid() .orElseThrow(() -> { throw new ConfigurationException("Must provide the Signing Domain Identifier (sdid)."); }); vertxDkimOptions.setSdid(sdid); - String selector = optionsConfig.selector + String selector = optionsConfig.selector() .orElseThrow(() -> { throw new ConfigurationException("Must provide the selector."); }); vertxDkimOptions.setSelector(selector); - if (optionsConfig.auid.isPresent()) { - vertxDkimOptions.setAuid(optionsConfig.auid.get()); + if (optionsConfig.auid().isPresent()) { + vertxDkimOptions.setAuid(optionsConfig.auid().get()); } - if (optionsConfig.bodyLimit.isPresent()) { - int bodyLimit = optionsConfig.bodyLimit.getAsInt(); + if (optionsConfig.bodyLimit().isPresent()) { + int bodyLimit = optionsConfig.bodyLimit().getAsInt(); vertxDkimOptions.setBodyLimit(bodyLimit); } - if (optionsConfig.expireTime.isPresent()) { - long expireTime = optionsConfig.expireTime.getAsLong(); + if (optionsConfig.expireTime().isPresent()) { + long expireTime = optionsConfig.expireTime().getAsLong(); vertxDkimOptions.setExpireTime(expireTime); } - if (optionsConfig.bodyCanonAlgo.isPresent()) { - vertxDkimOptions.setBodyCanonAlgo(CanonicalizationAlgorithm.valueOf(optionsConfig.bodyCanonAlgo.get().toString())); + if (optionsConfig.bodyCanonAlgo().isPresent()) { + vertxDkimOptions + .setBodyCanonAlgo(CanonicalizationAlgorithm.valueOf(optionsConfig.bodyCanonAlgo().get().toString())); } - if (optionsConfig.headerCanonAlgo.isPresent()) { + if (optionsConfig.headerCanonAlgo().isPresent()) { vertxDkimOptions - .setHeaderCanonAlgo(CanonicalizationAlgorithm.valueOf(optionsConfig.headerCanonAlgo.get().toString())); + .setHeaderCanonAlgo(CanonicalizationAlgorithm.valueOf(optionsConfig.headerCanonAlgo().get().toString())); } - if (optionsConfig.privateKey.isPresent()) { - vertxDkimOptions.setPrivateKey(optionsConfig.privateKey.get()); - } else if (optionsConfig.privateKeyPath.isPresent()) { - vertxDkimOptions.setPrivateKeyPath(optionsConfig.privateKeyPath.get()); + if (optionsConfig.privateKey().isPresent()) { + vertxDkimOptions.setPrivateKey(optionsConfig.privateKey().get()); + } else if (optionsConfig.privateKeyPath().isPresent()) { + vertxDkimOptions.setPrivateKeyPath(optionsConfig.privateKeyPath().get()); } - if (optionsConfig.signatureTimestamp.isPresent()) { - vertxDkimOptions.setSignatureTimestamp(optionsConfig.signatureTimestamp.get()); + if (optionsConfig.signatureTimestamp().isPresent()) { + vertxDkimOptions.setSignatureTimestamp(optionsConfig.signatureTimestamp().get()); } - if (optionsConfig.signedHeaders.isPresent()) { - List headers = optionsConfig.signedHeaders.get(); + if (optionsConfig.signedHeaders().isPresent()) { + List headers = optionsConfig.signedHeaders().get(); if (headers.stream().noneMatch(header -> header.equalsIgnoreCase("from"))) { throw new ConfigurationException( @@ -211,43 +213,43 @@ private io.vertx.ext.mail.DKIMSignOptions toVertxDkimSignOptions(DkimSignOptions private io.vertx.ext.mail.MailConfig toVertxMailConfig(String name, MailerRuntimeConfig config, TlsConfigurationRegistry tlsRegistry) { io.vertx.ext.mail.MailConfig cfg = new io.vertx.ext.mail.MailConfig(); - if (config.authMethods.isPresent()) { - cfg.setAuthMethods(config.authMethods.get()); + if (config.authMethods().isPresent()) { + cfg.setAuthMethods(config.authMethods().get()); } - cfg.setDisableEsmtp(config.disableEsmtp); - cfg.setHostname(config.host); - cfg.setKeepAlive(config.keepAlive); - cfg.setLogin(LoginOption.valueOf(config.login.toUpperCase())); - cfg.setMaxPoolSize(config.maxPoolSize); - - if (config.ownHostName.isPresent()) { - cfg.setOwnHostname(config.ownHostName.get()); + cfg.setDisableEsmtp(config.disableEsmtp()); + cfg.setHostname(config.host()); + cfg.setKeepAlive(config.keepAlive()); + cfg.setLogin(LoginOption.valueOf(config.login().toUpperCase())); + cfg.setMaxPoolSize(config.maxPoolSize()); + + if (config.ownHostName().isPresent()) { + cfg.setOwnHostname(config.ownHostName().get()); } - if (config.username.isPresent()) { - cfg.setUsername(config.username.get()); + if (config.username().isPresent()) { + cfg.setUsername(config.username().get()); } - if (config.password.isPresent()) { - cfg.setPassword(config.password.get()); + if (config.password().isPresent()) { + cfg.setPassword(config.password().get()); } - if (config.port.isPresent()) { - cfg.setPort(config.port.getAsInt()); + if (config.port().isPresent()) { + cfg.setPort(config.port().getAsInt()); } - if (config.dkim != null && config.dkim.enabled) { + if (config.dkim() != null && config.dkim().enabled()) { cfg.setEnableDKIM(true); - cfg.addDKIMSignOption(toVertxDkimSignOptions(config.dkim)); + cfg.addDKIMSignOption(toVertxDkimSignOptions(config.dkim())); } - cfg.setStarttls(StartTLSOptions.valueOf(config.startTLS.toUpperCase())); - cfg.setMultiPartOnly(config.multiPartOnly); + cfg.setStarttls(StartTLSOptions.valueOf(config.startTLS().toUpperCase())); + cfg.setMultiPartOnly(config.multiPartOnly()); - cfg.setAllowRcptErrors(config.allowRcptErrors); - cfg.setPipelining(config.pipelining); - cfg.setPoolCleanerPeriod((int) config.poolCleanerPeriod.toMillis()); + cfg.setAllowRcptErrors(config.allowRcptErrors()); + cfg.setPipelining(config.pipelining()); + cfg.setPoolCleanerPeriod((int) config.poolCleanerPeriod().toMillis()); cfg.setPoolCleanerPeriodUnit(TimeUnit.MILLISECONDS); - cfg.setKeepAliveTimeout((int) config.keepAliveTimeout.toMillis()); + cfg.setKeepAliveTimeout((int) config.keepAliveTimeout().toMillis()); cfg.setKeepAliveTimeoutUnit(TimeUnit.MILLISECONDS); configureTLS(name, config, tlsRegistry, cfg); @@ -264,11 +266,11 @@ private io.vertx.ext.mail.MailConfig toVertxMailConfig(String name, MailerRuntim private void configureTLS(String name, MailerRuntimeConfig config, TlsConfigurationRegistry tlsRegistry, MailConfig cfg) { TlsConfiguration configuration = null; boolean defaultTrustAll = false; - if (config.tlsConfigurationName.isPresent()) { - Optional maybeConfiguration = tlsRegistry.get(config.tlsConfigurationName.get()); + if (config.tlsConfigurationName().isPresent()) { + Optional maybeConfiguration = tlsRegistry.get(config.tlsConfigurationName().get()); if (!maybeConfiguration.isPresent()) { throw new IllegalStateException("Unable to find the TLS configuration " - + config.tlsConfigurationName.get() + " for the mailer " + name + "."); + + config.tlsConfigurationName().get() + " for the mailer " + name + "."); } configuration = maybeConfiguration.get(); } else if (tlsRegistry.getDefault().isPresent() && tlsRegistry.getDefault().get().isTrustAll()) { @@ -282,7 +284,7 @@ private void configureTLS(String name, MailerRuntimeConfig config, TlsConfigurat if (configuration != null) { // SMTP is a bit convoluted here. // You can start a non-TLS connection and then upgrade to TLS (using the STARTTLS command). - cfg.setSsl(config.tls.orElse(true)); + cfg.setSsl(config.tls().orElse(true)); if (configuration.getTrustStoreOptions() != null) { cfg.setTrustOptions(configuration.getTrustStoreOptions()); @@ -313,8 +315,8 @@ private void configureTLS(String name, MailerRuntimeConfig config, TlsConfigurat } } else { - boolean trustAll = config.trustAll.isPresent() ? config.trustAll.get() : defaultTrustAll; - cfg.setSsl(config.ssl || config.tls.orElse(trustAll)); + boolean trustAll = config.trustAll().isPresent() ? config.trustAll().get() : defaultTrustAll; + cfg.setSsl(config.ssl() || config.tls().orElse(trustAll)); cfg.setTrustAll(trustAll); applyTruststore(name, config, cfg); } @@ -322,26 +324,26 @@ private void configureTLS(String name, MailerRuntimeConfig config, TlsConfigurat private void applyTruststore(String name, MailerRuntimeConfig config, io.vertx.ext.mail.MailConfig cfg) { // Handle deprecated config - if (config.keyStore.isPresent()) { + if (config.keyStore().isPresent()) { LOGGER.warn("`quarkus.mailer.key-store` is deprecated, use `quarkus.mailer.trust-store.path` instead"); JksOptions options = new JksOptions(); - options.setPath(config.keyStore.get()); - if (config.keyStorePassword.isPresent()) { + options.setPath(config.keyStore().get()); + if (config.keyStorePassword().isPresent()) { LOGGER.warn( "`quarkus.mailer.key-store-password` is deprecated, use `quarkus.mailer.trust-store.password` instead"); - options.setPassword(config.keyStorePassword.get()); + options.setPassword(config.keyStorePassword().get()); } cfg.setTrustOptions(options); return; } - TrustStoreConfig truststore = config.truststore; + TrustStoreConfig truststore = config.truststore(); if (truststore.isConfigured()) { if (cfg.isTrustAll()) { // Use the value configured before. LOGGER.warn( "SMTP is configured with a trust store and also with trust-all, disable trust-all to enforce the trust store usage"); } - cfg.setTrustOptions(getTrustOptions(name, truststore.password, truststore.paths, truststore.type)); + cfg.setTrustOptions(getTrustOptions(name, truststore.password(), truststore.paths(), truststore.type())); } } diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailersBuildTimeConfig.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailersBuildTimeConfig.java index 02ca61227598c2..7eff94298a52cf 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailersBuildTimeConfig.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailersBuildTimeConfig.java @@ -1,16 +1,18 @@ package io.quarkus.mailer.runtime; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; -@ConfigRoot(name = "mailer", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) -public class MailersBuildTimeConfig { +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +@ConfigMapping(prefix = "quarkus.mailer") +public interface MailersBuildTimeConfig { /** * Caches data from attachment's Stream to a temporary file. * It tries to delete it after sending email. */ - @ConfigItem(defaultValue = "false") - public boolean cacheAttachments; + @WithDefault("false") + boolean cacheAttachments(); } diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailersRuntimeConfig.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailersRuntimeConfig.java index 0d5ca9c5b56775..f23c1a4c33488e 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailersRuntimeConfig.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailersRuntimeConfig.java @@ -4,24 +4,24 @@ import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefaults; +import io.smallrye.config.WithParentName; +import io.smallrye.config.WithUnnamedKey; -@ConfigRoot(name = "mailer", phase = ConfigPhase.RUN_TIME) -public class MailersRuntimeConfig { - - /** - * The default mailer. - */ - @ConfigItem(name = ConfigItem.PARENT) - public MailerRuntimeConfig defaultMailer; +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +@ConfigMapping(prefix = "quarkus.mailer") +public interface MailersRuntimeConfig { /** * Additional named mailers. */ @ConfigDocSection @ConfigDocMapKey("mailer-name") - @ConfigItem(name = ConfigItem.PARENT) - public Map namedMailers; + @WithParentName + @WithDefaults + @WithUnnamedKey(Mailers.DEFAULT_MAILER_NAME) + Map mailers(); } diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/NtlmConfig.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/NtlmConfig.java index 50f961475d3ff7..65e2f278b23e3b 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/NtlmConfig.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/NtlmConfig.java @@ -3,21 +3,18 @@ import java.util.Optional; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; @ConfigGroup -public class NtlmConfig { +public interface NtlmConfig { /** * Sets the workstation used on NTLM authentication. */ - @ConfigItem - public Optional workstation = Optional.empty(); + public Optional workstation(); /** * Sets the domain used on NTLM authentication. */ - @ConfigItem - public Optional domain = Optional.empty(); + public Optional domain(); } diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/TrustStoreConfig.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/TrustStoreConfig.java index 819ff56cf60b6d..eabc2f31b816f7 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/TrustStoreConfig.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/TrustStoreConfig.java @@ -4,19 +4,17 @@ import java.util.Optional; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.annotations.ConvertWith; import io.quarkus.runtime.configuration.TrimmedStringConverter; +import io.smallrye.config.WithConverter; @ConfigGroup -public class TrustStoreConfig { +public interface TrustStoreConfig { /** * Sets the trust store password if any. * Note that the password is only used for JKS and PCK#12 trust stores. */ - @ConfigItem - Optional password = Optional.empty(); + Optional password(); /** * Sets the location of the trust store files. @@ -25,9 +23,7 @@ public class TrustStoreConfig { *

    * The relative paths are relative to the application working directly. */ - @ConfigItem - @ConvertWith(TrimmedStringConverter.class) - Optional> paths = Optional.empty(); + Optional> paths(); /** * Sets the trust store type. @@ -37,13 +33,12 @@ public class TrustStoreConfig { * * Accepted values are: {@code JKS}, {@code PEM}, {@code PKCS}. */ - @ConfigItem - Optional type = Optional.empty(); + Optional type(); /** * @return {@code true} is the trust store is configured, {@code false otherwise} */ - public boolean isConfigured() { - return paths.isPresent() && !paths.get().isEmpty(); + default boolean isConfigured() { + return paths().isPresent() && !paths().get().isEmpty(); } } diff --git a/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/FakeSmtpTestBase.java b/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/FakeSmtpTestBase.java index fc8f0011b2a2a9..df44313865aad6 100644 --- a/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/FakeSmtpTestBase.java +++ b/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/FakeSmtpTestBase.java @@ -1,9 +1,12 @@ package io.quarkus.mailer.runtime; import java.time.Duration; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.OptionalInt; import java.util.Set; +import java.util.regex.Pattern; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -112,33 +115,199 @@ public void register(String name, TlsConfiguration configuration) { return mailers.reactiveMailerFromName(Mailers.DEFAULT_MAILER_NAME); } - protected MailersRuntimeConfig getDefaultConfig() { - MailersRuntimeConfig mailersConfig = new MailersRuntimeConfig(); - mailersConfig.defaultMailer = new MailerRuntimeConfig(); - mailersConfig.defaultMailer.from = Optional.of(FROM); - mailersConfig.defaultMailer.host = "localhost"; - mailersConfig.defaultMailer.port = OptionalInt.of(FAKE_SMTP_PORT); - mailersConfig.defaultMailer.startTLS = "DISABLED"; - mailersConfig.defaultMailer.login = "DISABLED"; - mailersConfig.defaultMailer.ssl = false; - mailersConfig.defaultMailer.tls = Optional.empty(); - mailersConfig.defaultMailer.authMethods = Optional.empty(); - mailersConfig.defaultMailer.maxPoolSize = 10; - mailersConfig.defaultMailer.ownHostName = Optional.empty(); - mailersConfig.defaultMailer.username = Optional.empty(); - mailersConfig.defaultMailer.password = Optional.empty(); - mailersConfig.defaultMailer.poolCleanerPeriod = Duration.ofSeconds(1); - mailersConfig.defaultMailer.keepAlive = true; - mailersConfig.defaultMailer.keepAliveTimeout = Duration.ofMinutes(5); - mailersConfig.defaultMailer.trustAll = Optional.empty(); - mailersConfig.defaultMailer.keyStore = Optional.empty(); - mailersConfig.defaultMailer.keyStorePassword = Optional.empty(); - mailersConfig.defaultMailer.truststore = new TrustStoreConfig(); - mailersConfig.defaultMailer.truststore.paths = Optional.empty(); - mailersConfig.defaultMailer.truststore.password = Optional.empty(); - mailersConfig.defaultMailer.truststore.type = Optional.empty(); - - return mailersConfig; + static class DefaultMailersRuntimeConfig implements MailersRuntimeConfig { + + private DefaultMailerRuntimeConfig defaultMailerRuntimeConfig; + + DefaultMailersRuntimeConfig() { + this(new DefaultMailerRuntimeConfig()); + } + + DefaultMailersRuntimeConfig(DefaultMailerRuntimeConfig defaultMailerRuntimeConfig) { + this.defaultMailerRuntimeConfig = defaultMailerRuntimeConfig; + } + + @Override + public Map mailers() { + return Map.of(Mailers.DEFAULT_MAILER_NAME, defaultMailerRuntimeConfig); + } + + } + + static class DefaultMailerRuntimeConfig implements MailerRuntimeConfig { + + @Override + public Optional from() { + return Optional.of(FROM); + } + + @Override + public Optional mock() { + return Optional.empty(); + } + + @Override + public Optional bounceAddress() { + return Optional.empty(); + } + + @Override + public String host() { + return "localhost"; + } + + @Override + public OptionalInt port() { + return OptionalInt.of(FAKE_SMTP_PORT); + } + + @Override + public Optional username() { + return Optional.empty(); + } + + @Override + public Optional password() { + return Optional.empty(); + } + + @Override + public Optional tlsConfigurationName() { + return Optional.empty(); + } + + @Override + public boolean ssl() { + return false; + } + + @Override + public Optional tls() { + return Optional.empty(); + } + + @Override + public Optional trustAll() { + return Optional.empty(); + } + + @Override + public int maxPoolSize() { + return 10; + } + + @Override + public Optional ownHostName() { + return Optional.empty(); + } + + @Override + public boolean keepAlive() { + return false; + } + + @Override + public boolean disableEsmtp() { + return false; + } + + @Override + public String startTLS() { + return "DISABLED"; + } + + @Override + public DkimSignOptionsConfig dkim() { + return null; + } + + @Override + public String login() { + return "DISABLED"; + } + + @Override + public Optional authMethods() { + return Optional.empty(); + } + + @Override + public Optional keyStore() { + return Optional.empty(); + } + + @Override + public Optional keyStorePassword() { + return Optional.empty(); + } + + @Override + public TrustStoreConfig truststore() { + return new TrustStoreConfig() { + + @Override + public Optional type() { + return Optional.empty(); + } + + @Override + public Optional> paths() { + return Optional.empty(); + } + + @Override + public Optional password() { + return Optional.empty(); + } + }; + } + + @Override + public boolean multiPartOnly() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean allowRcptErrors() { + return false; + } + + @Override + public boolean pipelining() { + return false; + } + + @Override + public Duration poolCleanerPeriod() { + return Duration.ofSeconds(1); + } + + @Override + public Duration keepAliveTimeout() { + return Duration.ofMinutes(5); + } + + @Override + public NtlmConfig ntlm() { + return null; + } + + @Override + public Optional> approvedRecipients() { + return Optional.empty(); + } + + @Override + public boolean logRejectedRecipients() { + return false; + } + + @Override + public boolean logInvalidRecipients() { + return false; + } + } } diff --git a/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/MailerTLSRegistryTest.java b/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/MailerTLSRegistryTest.java index 6e7d3dd843adc9..198da225df2c97 100644 --- a/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/MailerTLSRegistryTest.java +++ b/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/MailerTLSRegistryTest.java @@ -18,8 +18,17 @@ public class MailerTLSRegistryTest extends FakeSmtpTestBase { @Test public void sendMailWithCorrectTrustStore() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.tlsConfigurationName = Optional.of("my-mailer"); + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public Optional tlsConfigurationName() { + return Optional.of("my-mailer"); + } + + @Override + public Optional tls() { + return Optional.of(true); + } + }); ReactiveMailer mailer = getMailer(mailersConfig, "my-mailer", new BaseTlsConfiguration() { @Override @@ -37,7 +46,7 @@ public TrustOptions getTrustStoreOptions() { @Test public void sendMailWithDefaultTrustAll() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(); ReactiveMailer mailer = getMailer(mailersConfig, null, new BaseTlsConfiguration() { @Override @@ -51,8 +60,12 @@ public boolean isTrustAll() { @Test public void sendMailWithNamedTrustAll() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.tlsConfigurationName = Optional.of("my-mailer"); + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public Optional tlsConfigurationName() { + return Optional.of("my-mailer"); + } + }); ReactiveMailer mailer = getMailer(mailersConfig, "my-mailer", new BaseTlsConfiguration() { @Override @@ -66,9 +79,17 @@ public boolean isTrustAll() { @Test public void sendMailWithoutTrustStore() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.tlsConfigurationName = Optional.of("my-mailer"); - mailersConfig.defaultMailer.tls = Optional.of(true); + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public Optional tlsConfigurationName() { + return Optional.of("my-mailer"); + } + + @Override + public Optional tls() { + return Optional.of(true); + } + }); startServer(SERVER_JKS); ReactiveMailer mailer = getMailer(mailersConfig, "my-mailer", new BaseTlsConfiguration() { @@ -81,8 +102,12 @@ public void sendMailWithoutTrustStore() { @Test public void testWithWrongTlsName() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.tlsConfigurationName = Optional.of("missing-mailer-configuration"); + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public Optional tlsConfigurationName() { + return Optional.of("missing-mailer-configuration"); + } + }); Assertions.assertThatThrownBy(() -> getMailer(mailersConfig, "my-mailer", new BaseTlsConfiguration() { @Override diff --git a/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/MailerTruststoreTest.java b/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/MailerTruststoreTest.java index 92c1c9c0cdf14c..4d63de7b13be25 100644 --- a/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/MailerTruststoreTest.java +++ b/extensions/mailer/runtime/src/test/java/io/quarkus/mailer/runtime/MailerTruststoreTest.java @@ -1,6 +1,6 @@ package io.quarkus.mailer.runtime; -import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.concurrent.CompletionException; @@ -15,10 +15,33 @@ public class MailerTruststoreTest extends FakeSmtpTestBase { @Test public void sendMailWithCorrectTrustStore() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.ssl = true; - mailersConfig.defaultMailer.truststore.password = Optional.of("password"); - mailersConfig.defaultMailer.truststore.paths = Optional.of(Collections.singletonList(CLIENT_TRUSTSTORE)); + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public boolean ssl() { + return true; + } + + @Override + public TrustStoreConfig truststore() { + return new TrustStoreConfig() { + + @Override + public Optional type() { + return Optional.empty(); + } + + @Override + public Optional> paths() { + return Optional.of(List.of(CLIENT_TRUSTSTORE)); + } + + @Override + public Optional password() { + return Optional.of("password"); + } + }; + } + }); ReactiveMailer mailer = getMailer(mailersConfig); startServer(SERVER_JKS); @@ -28,10 +51,22 @@ public void sendMailWithCorrectTrustStore() { @SuppressWarnings("deprecation") @Test public void sendMailWithCorrectButDeprecatedTrustStore() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.ssl = true; - mailersConfig.defaultMailer.keyStorePassword = Optional.of("password"); - mailersConfig.defaultMailer.keyStore = Optional.of(CLIENT_TRUSTSTORE); + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public boolean ssl() { + return true; + } + + @Override + public Optional keyStorePassword() { + return Optional.of("password"); + } + + @Override + public Optional keyStore() { + return Optional.of(CLIENT_TRUSTSTORE); + } + }); ReactiveMailer mailer = getMailer(mailersConfig); startServer(SERVER_JKS); @@ -40,9 +75,18 @@ public void sendMailWithCorrectButDeprecatedTrustStore() { @Test public void sendMailWithTrustAll() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.ssl = true; - mailersConfig.defaultMailer.trustAll = Optional.of(true); + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public boolean ssl() { + return true; + } + + @Override + public Optional trustAll() { + return Optional.of(true); + } + }); + ReactiveMailer mailer = getMailer(mailersConfig); startServer(SERVER_JKS); mailer.send(getMail()).await().indefinitely(); @@ -50,8 +94,13 @@ public void sendMailWithTrustAll() { @Test public void sendMailWithGlobalTrustAll() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.ssl = true; + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public boolean ssl() { + return true; + } + }); + ReactiveMailer mailer = getMailer(mailersConfig, true); startServer(SERVER_JKS); mailer.send(getMail()).await().indefinitely(); @@ -59,8 +108,12 @@ public void sendMailWithGlobalTrustAll() { @Test public void sendMailWithoutTrustStore() { - MailersRuntimeConfig mailersConfig = getDefaultConfig(); - mailersConfig.defaultMailer.ssl = true; + MailersRuntimeConfig mailersConfig = new DefaultMailersRuntimeConfig(new DefaultMailerRuntimeConfig() { + @Override + public boolean ssl() { + return true; + } + }); startServer(SERVER_JKS); ReactiveMailer mailer = getMailer(mailersConfig); From f3033d615474a040d7e96e05c715a8d478b5411b Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 4 Feb 2025 15:14:29 +0100 Subject: [PATCH 05/10] Netty - Move to @ConfigMapping --- extensions/netty/deployment/pom.xml | 3 --- .../quarkus/netty/deployment/NettyBuildTimeConfig.java | 10 +++++----- .../io/quarkus/netty/deployment/NettyProcessor.java | 4 ++-- extensions/netty/runtime/pom.xml | 3 --- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/extensions/netty/deployment/pom.xml b/extensions/netty/deployment/pom.xml index ac6d6301d2c566..367d575a6684aa 100644 --- a/extensions/netty/deployment/pom.xml +++ b/extensions/netty/deployment/pom.xml @@ -42,9 +42,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyBuildTimeConfig.java b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyBuildTimeConfig.java index 64fdf514433bc4..39d4681cff9b2d 100644 --- a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyBuildTimeConfig.java +++ b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyBuildTimeConfig.java @@ -2,12 +2,13 @@ import java.util.OptionalInt; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; -@ConfigRoot(name = "netty", phase = ConfigPhase.BUILD_TIME) -public class NettyBuildTimeConfig { +@ConfigRoot(phase = ConfigPhase.BUILD_TIME) +@ConfigMapping(prefix = "quarkus.netty") +public interface NettyBuildTimeConfig { /** * The value configuring the {@code io.netty.allocator.maxOrder} system property of Netty. @@ -19,6 +20,5 @@ public class NettyBuildTimeConfig { * It must be used carefully. * More details on https://programmer.group/pool-area-of-netty-memory-pool.html. */ - @ConfigItem - public OptionalInt allocatorMaxOrder; + OptionalInt allocatorMaxOrder(); } diff --git a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java index 98a0d370ffcaf0..b2131c1837563d 100644 --- a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java +++ b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java @@ -58,7 +58,7 @@ public NativeImageSystemPropertyBuildItem limitMem() { @BuildStep public SystemPropertyBuildItem limitArenaSize(NettyBuildTimeConfig config, List minMaxOrderBuildItems) { - String maxOrder = calculateMaxOrder(config.allocatorMaxOrder, minMaxOrderBuildItems, true); + String maxOrder = calculateMaxOrder(config.allocatorMaxOrder(), minMaxOrderBuildItems, true); //in native mode we limit the size of the epoll array //if the array overflows the selector just moves the overflow to a map @@ -114,7 +114,7 @@ NativeImageConfigBuildItem build( .produce(ReflectiveClassBuildItem.builder("java.util.LinkedHashMap").build()); reflectiveClass.produce(ReflectiveClassBuildItem.builder("sun.nio.ch.SelectorImpl").methods().fields().build()); - String maxOrder = calculateMaxOrder(config.allocatorMaxOrder, minMaxOrderBuildItems, false); + String maxOrder = calculateMaxOrder(config.allocatorMaxOrder(), minMaxOrderBuildItems, false); NativeImageConfigBuildItem.Builder builder = NativeImageConfigBuildItem.builder() // Use small chunks to avoid a lot of wasted space. Default is 16mb * arenas (derived from core count) diff --git a/extensions/netty/runtime/pom.xml b/extensions/netty/runtime/pom.xml index a0c59483ce2439..47420416d286b0 100644 --- a/extensions/netty/runtime/pom.xml +++ b/extensions/netty/runtime/pom.xml @@ -82,9 +82,6 @@ ${project.version} - - -AlegacyConfigRoot=true - From e77d510ec4f8e281dcca64a42a1fef80ca41b701 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Tue, 4 Feb 2025 11:04:41 -0300 Subject: [PATCH 06/10] Swagger UI: Move to use `@ConfigMapping` --- .../devui/OpenApiDevUIProcessor.java | 2 +- extensions/swagger-ui/deployment/pom.xml | 3 - .../swaggerui/deployment/SwaggerUiConfig.java | 169 +++++------- .../deployment/SwaggerUiProcessor.java | 256 +++++++++--------- extensions/swagger-ui/runtime/pom.xml | 3 - .../swaggerui/runtime/SwaggerUiRecorder.java | 2 +- .../runtime/SwaggerUiRuntimeConfig.java | 10 +- 7 files changed, 195 insertions(+), 250 deletions(-) diff --git a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/devui/OpenApiDevUIProcessor.java b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/devui/OpenApiDevUIProcessor.java index f196add3d0c491..fa1e728f453d73 100644 --- a/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/devui/OpenApiDevUIProcessor.java +++ b/extensions/smallrye-openapi/deployment/src/main/java/io/quarkus/smallrye/openapi/deployment/devui/OpenApiDevUIProcessor.java @@ -19,7 +19,7 @@ public CardPageBuildItem pages(NonApplicationRootPathBuildItem nonApplicationRoo SwaggerUiConfig swaggerUiConfig, SmallRyeOpenApiConfig openApiConfig) { - String uiPath = nonApplicationRootPathBuildItem.resolveManagementPath(swaggerUiConfig.path, + String uiPath = nonApplicationRootPathBuildItem.resolveManagementPath(swaggerUiConfig.path(), managementBuildTimeConfig, launchModeBuildItem, openApiConfig.managementEnabled()); String schemaPath = nonApplicationRootPathBuildItem.resolveManagementPath(openApiConfig.path(), diff --git a/extensions/swagger-ui/deployment/pom.xml b/extensions/swagger-ui/deployment/pom.xml index 02376a04919b0f..ccf9d505b2c7ee 100644 --- a/extensions/swagger-ui/deployment/pom.xml +++ b/extensions/swagger-ui/deployment/pom.xml @@ -64,9 +64,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiConfig.java b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiConfig.java index f85bf85527f5bb..30c581c3357d32 100644 --- a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiConfig.java +++ b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiConfig.java @@ -6,14 +6,16 @@ import java.util.OptionalInt; import io.quarkus.runtime.annotations.ConfigDocMapKey; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; import io.smallrye.openapi.ui.DocExpansion; import io.smallrye.openapi.ui.HttpMethod; import io.smallrye.openapi.ui.ThemeHref; @ConfigRoot -public class SwaggerUiConfig { +@ConfigMapping(prefix = "quarkus.swagger-ui") +public interface SwaggerUiConfig { /** * The path where Swagger UI is available. @@ -21,89 +23,77 @@ public class SwaggerUiConfig { * The value `/` is not allowed as it blocks the application from serving anything else. * By default, this value will be resolved as a path relative to `${quarkus.http.non-application-root-path}`. */ - @ConfigItem(defaultValue = "swagger-ui") - public String path; + @WithDefault("swagger-ui") + String path(); /** * If this should be included every time. By default, this is only included when the application is running * in dev mode. */ - @ConfigItem(defaultValue = "false") - boolean alwaysInclude; + @WithDefault("false") + boolean alwaysInclude(); /** * The urls that will be included as options. By default, the OpenAPI path will be used. * Here you can override that and supply multiple urls that will appear in the TopBar plugin. */ - @ConfigItem @ConfigDocMapKey("name") - Map urls; + Map urls(); /** * If urls option is used, this will be the name of the default selection. */ - @ConfigItem - Optional urlsPrimaryName; + Optional urlsPrimaryName(); /** * The html title for the page. */ - @ConfigItem - Optional title; + Optional title(); /** * Swagger UI theme to be used. */ - @ConfigItem - Optional theme; + Optional theme(); /** * A footer for the html page. Nothing by default. */ - @ConfigItem - Optional footer; + Optional footer(); /** * If set to true, enables deep linking for tags and operations. */ - @ConfigItem - Optional deepLinking; + Optional deepLinking(); /** * Controls the display of operationId in operations list. The default is false. */ - @ConfigItem - Optional displayOperationId; + Optional displayOperationId(); /** * The default expansion depth for models (set to -1 completely hide the models). */ - @ConfigItem - OptionalInt defaultModelsExpandDepth; + OptionalInt defaultModelsExpandDepth(); /** * The default expansion depth for the model on the model-example section. */ - @ConfigItem - OptionalInt defaultModelExpandDepth; + OptionalInt defaultModelExpandDepth(); /** * Controls how the model is shown when the API is first rendered. */ - @ConfigItem - Optional defaultModelRendering; + Optional defaultModelRendering(); /** * Controls the display of the request duration (in milliseconds) for "Try it out" requests. */ - @ConfigItem - Optional displayRequestDuration; + Optional displayRequestDuration(); /** * Controls the default expansion setting for the operations and tags. */ - @ConfigItem - Optional docExpansion; + Optional docExpansion(); /** * If set, enables filtering. The top bar will show an edit box that you can use to filter the tagged operations that @@ -112,14 +102,12 @@ public class SwaggerUiConfig { * filter expression. * Filtering is case-sensitive matching the filter expression anywhere inside the tag. */ - @ConfigItem - Optional filter; + Optional filter(); /** * If set, limits the number of tagged operations displayed to at most this many. The default is to show all operations. */ - @ConfigItem - OptionalInt maxDisplayedTags; + OptionalInt maxDisplayedTags(); /** * Apply a sort to the operation list of each API. @@ -127,21 +115,18 @@ public class SwaggerUiConfig { * Array.prototype.sort() to know how sort function works). * Default is the order returned by the server unchanged. */ - @ConfigItem - Optional operationsSorter; + Optional operationsSorter(); /** * Controls the display of vendor extension (x-) fields and values for Operations, Parameters, and Schema. */ - @ConfigItem - Optional showExtensions; + Optional showExtensions(); /** * Controls the display of extensions (pattern, maxLength, minLength, maximum, minimum) fields and values for * Parameters. */ - @ConfigItem - Optional showCommonExtensions; + Optional showCommonExtensions(); /** * Apply a sort to the tag list of each API. @@ -149,64 +134,55 @@ public class SwaggerUiConfig { * sort function). * Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger UI. */ - @ConfigItem - Optional tagsSorter; + Optional tagsSorter(); /** * Provides a mechanism to be notified when Swagger UI has finished rendering a newly provided definition. */ - @ConfigItem - Optional onComplete; + Optional onComplete(); /** * Set to {@code false} to deactivate syntax highlighting of payloads and cURL command. Can be otherwise an object with the * {@code activate} and {@code theme} properties. */ - @ConfigItem - Optional syntaxHighlight; + Optional syntaxHighlight(); /** * OAuth redirect URL. */ - @ConfigItem - Optional oauth2RedirectUrl; + Optional oauth2RedirectUrl(); /** * MUST be a function. Function to intercept remote definition, "Try it out", and OAuth 2.0 requests. * Accepts one argument requestInterceptor(request) and must return the modified request, or a Promise that resolves to * the modified request. */ - @ConfigItem - Optional requestInterceptor; + Optional requestInterceptor(); /** * If set, MUST be an array of command line options available to the curl command. * This can be set on the mutated request in the requestInterceptor function. */ - @ConfigItem - Optional> requestCurlOptions; + Optional> requestCurlOptions(); /** * MUST be a function. Function to intercept remote definition, "Try it out", and OAuth 2.0 responses. * Accepts one argument responseInterceptor(response) and must return the modified response, or a Promise that resolves * to the modified response. */ - @ConfigItem - Optional responseInterceptor; + Optional responseInterceptor(); /** * If set to true, uses the mutated request returned from a requestInterceptor to produce the curl command in the UI, * otherwise the request before the requestInterceptor was applied is used. */ - @ConfigItem - Optional showMutatedRequest; + Optional showMutatedRequest(); /** * List of HTTP methods that have the "Try it out" feature enabled. * An empty array disables "Try it out" for all operations. This does not filter the operations from the display. */ - @ConfigItem - Optional> supportedSubmitMethods; + Optional> supportedSubmitMethods(); /** * By default, Swagger UI attempts to validate specs against swagger.io's online validator. @@ -214,160 +190,137 @@ public class SwaggerUiConfig { * Badge). * Setting it to either none, 127.0.0.1 or localhost will disable validation. */ - @ConfigItem - Optional validatorUrl; + Optional validatorUrl(); /** * If set to true, enables passing credentials, as defined in the Fetch standard, in CORS requests that are sent by the * browser. */ - @ConfigItem - Optional withCredentials; + Optional withCredentials(); /** * Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property * is immutable */ - @ConfigItem - Optional modelPropertyMacro; + Optional modelPropertyMacro(); /** * Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). * Operation and parameter are objects passed for context, both remain immutable */ - @ConfigItem - Optional parameterMacro; + Optional parameterMacro(); /** * If set to true, it persists authorization data and it would not be lost on browser close/refresh */ - @ConfigItem - Optional persistAuthorization; + Optional persistAuthorization(); /** * The name of a component available via the plugin system to use as the top-level layout for Swagger UI. */ - @ConfigItem - Optional layout; + Optional layout(); /** * A list of plugin functions to use in Swagger UI. */ - @ConfigItem - Optional> plugins; + Optional> plugins(); /** * A list of external scripts (usually plugins) to use in Swagger UI. */ - @ConfigItem - Optional> scripts; + Optional> scripts(); /** * A list of presets to use in Swagger UI. */ - @ConfigItem - Optional> presets; + Optional> presets(); /** * OAuth default clientId - Used in the initOAuth method. */ - @ConfigItem - Optional oauthClientId; + Optional oauthClientId(); /** * OAuth default clientSecret - Used in the initOAuth method. */ - @ConfigItem - Optional oauthClientSecret; + Optional oauthClientSecret(); /** * OAuth1 Realm query parameter added to authorizationUrl and tokenUrl - Used in the initOAuth method. */ - @ConfigItem - Optional oauthRealm; + Optional oauthRealm(); /** * OAuth application name, displayed in authorization popup - Used in the initOAuth method. */ - @ConfigItem - Optional oauthAppName; + Optional oauthAppName(); /** * OAuth scope separator for passing scopes - Used in the initOAuth method. */ - @ConfigItem - Optional oauthScopeSeparator; + Optional oauthScopeSeparator(); /** * OAuth Scopes, separated using the oauthScopeSeparator - Used in the initOAuth method. */ - @ConfigItem - Optional oauthScopes; + Optional oauthScopes(); /** * OAuth additional query parameters added to authorizationUrl and tokenUrl - Used in the initOAuth method. */ - @ConfigItem - Optional oauthAdditionalQueryStringParams; + Optional oauthAdditionalQueryStringParams(); /** * OAuth only activated for the accessCode flow. During the authorization_code request to the tokenUrl, pass the Client * Password using the HTTP Basic Authentication scheme - Used in the initOAuth method. */ - @ConfigItem - Optional oauthUseBasicAuthenticationWithAccessCodeGrant; + Optional oauthUseBasicAuthenticationWithAccessCodeGrant(); /** * OAuth only applies to authorization code flows. Proof Key for Code Exchange brings enhanced security for OAuth public * clients - Used in the initOAuth method. */ - @ConfigItem - Optional oauthUsePkceWithAuthorizationCodeGrant; + Optional oauthUsePkceWithAuthorizationCodeGrant(); /** * Pre-authorize Basic Auth, programmatically set DefinitionKey for a Basic authorization scheme - Used in the * preauthorizeBasic method. */ - @ConfigItem - Optional preauthorizeBasicAuthDefinitionKey; + Optional preauthorizeBasicAuthDefinitionKey(); /** * Pre-authorize Basic Auth, programmatically set Username for a Basic authorization scheme - Used in the preauthorizeBasic * method. */ - @ConfigItem - Optional preauthorizeBasicUsername; + Optional preauthorizeBasicUsername(); /** * Pre-authorize Basic Auth, programmatically set Password for a Basic authorization scheme - Used in the preauthorizeBasic * method. */ - @ConfigItem - Optional preauthorizeBasicPassword; + Optional preauthorizeBasicPassword(); /** * Pre-authorize ApiKey Auth, programmatically set DefinitionKey for an API key or Bearer authorization scheme - Used in the * preauthorizeApiKey method. */ - @ConfigItem - Optional preauthorizeApiKeyAuthDefinitionKey; + Optional preauthorizeApiKeyAuthDefinitionKey(); /** * Pre-authorize ApiKey Auth, programmatically set ApiKeyValue for an API key or Bearer authorization scheme - Used in the * preauthorizeApiKey method. */ - @ConfigItem - Optional preauthorizeApiKeyApiKeyValue; + Optional preauthorizeApiKeyApiKeyValue(); /** * If set to true, this allows the user to modify and test different query parameters in the API request */ - @ConfigItem(defaultValue = "false") - boolean queryConfigEnabled; + @WithDefault("false") + boolean queryConfigEnabled(); /** * If try it out should be enabled by default */ - @ConfigItem(defaultValue = "false") - boolean tryItOutEnabled; + @WithDefault("false") + boolean tryItOutEnabled(); } diff --git a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java index e78a3a3c8bb386..1a54a3749884c8 100644 --- a/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java +++ b/extensions/swagger-ui/deployment/src/main/java/io/quarkus/swaggerui/deployment/SwaggerUiProcessor.java @@ -94,13 +94,13 @@ public void getSwaggerUiFinalDestination( BuildProducer webJarBuildProducer) throws Exception { if (shouldInclude(launchMode, swaggerUiConfig)) { - if ("/".equals(swaggerUiConfig.path)) { + if ("/".equals(swaggerUiConfig.path())) { throw new ConfigurationException( "quarkus.swagger-ui.path was set to \"/\", this is not allowed as it blocks the application from serving anything else.", Set.of("quarkus.swagger-ui.path")); } - if (openapi.path().equalsIgnoreCase(swaggerUiConfig.path)) { + if (openapi.path().equalsIgnoreCase(swaggerUiConfig.path())) { throw new ConfigurationException( "quarkus.smallrye-openapi.path and quarkus.swagger-ui.path was set to the same value, this is not allowed as the paths needs to be unique [" + openapi.path() + "].", @@ -108,35 +108,17 @@ public void getSwaggerUiFinalDestination( } - if (devServicesLauncherConfig.isPresent()) { - DevServicesLauncherConfigResultBuildItem devServicesLauncherConfigResult = devServicesLauncherConfig.get(); - Map devServiceConfig = devServicesLauncherConfigResult.getConfig(); - if (devServiceConfig != null && !devServiceConfig.isEmpty()) { - // Map client Id from OIDC Dev Services - if (devServiceConfig.containsKey(OIDC_CLIENT_ID) && !swaggerUiConfig.oauthClientId.isPresent()) { - String clientId = devServiceConfig.get(OIDC_CLIENT_ID); - swaggerUiConfig.oauthClientId = Optional.of(clientId); - } - } - } - String openApiPath = nonApplicationRootPathBuildItem.resolvePath(openapi.path()); - String swaggerUiPath = nonApplicationRootPathBuildItem.resolvePath(swaggerUiConfig.path); - ThemeHref theme = swaggerUiConfig.theme.orElse(ThemeHref.feeling_blue); + String swaggerUiPath = nonApplicationRootPathBuildItem.resolvePath(swaggerUiConfig.path()); + ThemeHref theme = swaggerUiConfig.theme().orElse(ThemeHref.feeling_blue); NonApplicationRootPathBuildItem indexRootPathBuildItem = null; - if (launchMode.getLaunchMode().isDevOrTest()) { - indexRootPathBuildItem = nonApplicationRootPathBuildItem; - - // In dev mode, default to persist Authorization true - if (!swaggerUiConfig.persistAuthorization.isPresent()) { - swaggerUiConfig.persistAuthorization = Optional.of(true); - } - } - - byte[] indexHtmlContent = generateIndexHtml(openApiPath, swaggerUiPath, swaggerUiConfig, indexRootPathBuildItem); + byte[] indexHtmlContent = generateIndexHtml(openApiPath, swaggerUiPath, swaggerUiConfig, + indexRootPathBuildItem, + launchMode, + devServicesLauncherConfig.orElse(null)); webJarBuildProducer.produce( WebJarBuildItem.builder().artifactKey(SWAGGER_UI_WEBJAR_ARTIFACT_KEY) // .root(SWAGGER_UI_WEBJAR_STATIC_RESOURCES_PATH) // @@ -174,7 +156,7 @@ public void registerSwaggerUiHandler(SwaggerUiRecorder recorder, } if (shouldInclude(launchMode, swaggerUiConfig)) { - String swaggerUiPath = nonApplicationRootPathBuildItem.resolvePath(swaggerUiConfig.path); + String swaggerUiPath = nonApplicationRootPathBuildItem.resolvePath(swaggerUiConfig.path()); swaggerUiBuildProducer.produce(new SwaggerUiBuildItem(result.getFinalDestination(), swaggerUiPath)); Handler handler = recorder.handler(result.getFinalDestination(), @@ -183,7 +165,7 @@ public void registerSwaggerUiHandler(SwaggerUiRecorder recorder, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .management("quarkus.smallrye-openapi.management.enabled") - .route(swaggerUiConfig.path) + .route(swaggerUiConfig.path()) .displayOnNotFoundPage("Open API UI") .routeConfigKey("quarkus.swagger-ui.path") .handler(handler) @@ -191,14 +173,15 @@ public void registerSwaggerUiHandler(SwaggerUiRecorder recorder, routes.produce(nonApplicationRootPathBuildItem.routeBuilder() .management("quarkus.smallrye-openapi.management.enabled") - .route(swaggerUiConfig.path + "*") + .route(swaggerUiConfig.path() + "*") .handler(handler) .build()); } } private byte[] generateIndexHtml(String openApiPath, String swaggerUiPath, SwaggerUiConfig swaggerUiConfig, - NonApplicationRootPathBuildItem nonApplicationRootPath) + NonApplicationRootPathBuildItem nonApplicationRootPath, LaunchModeBuildItem launchMode, + DevServicesLauncherConfigResultBuildItem devServicesLauncherConfigResultBuildItem) throws IOException { Map options = new HashMap<>(); Map urlsMap = null; @@ -211,185 +194,197 @@ private byte[] generateIndexHtml(String openApiPath, String swaggerUiPath, Swagg } // Only add the url if the user did not specify urls - if (swaggerUiConfig.urls != null && !swaggerUiConfig.urls.isEmpty()) { - urlsMap = swaggerUiConfig.urls; + if (swaggerUiConfig.urls() != null && !swaggerUiConfig.urls().isEmpty()) { + urlsMap = swaggerUiConfig.urls(); } else { options.put(Option.url, openApiPath); } - if (swaggerUiConfig.title.isPresent()) { - options.put(Option.title, swaggerUiConfig.title.get()); + if (swaggerUiConfig.title().isPresent()) { + options.put(Option.title, swaggerUiConfig.title().get()); } else { options.put(Option.title, "OpenAPI UI (Powered by Quarkus " + Version.getVersion() + ")"); } - if (swaggerUiConfig.theme.isPresent()) { - options.put(Option.themeHref, swaggerUiConfig.theme.get().toString()); + if (swaggerUiConfig.theme().isPresent()) { + options.put(Option.themeHref, swaggerUiConfig.theme().get().toString()); } - if (swaggerUiConfig.footer.isPresent()) { - options.put(Option.footer, swaggerUiConfig.footer.get()); + if (swaggerUiConfig.footer().isPresent()) { + options.put(Option.footer, swaggerUiConfig.footer().get()); } - if (swaggerUiConfig.deepLinking.isPresent()) { - options.put(Option.deepLinking, swaggerUiConfig.deepLinking.get().toString()); + if (swaggerUiConfig.deepLinking().isPresent()) { + options.put(Option.deepLinking, swaggerUiConfig.deepLinking().get().toString()); } - if (swaggerUiConfig.displayOperationId.isPresent()) { - options.put(Option.displayOperationId, swaggerUiConfig.displayOperationId.get().toString()); + if (swaggerUiConfig.displayOperationId().isPresent()) { + options.put(Option.displayOperationId, swaggerUiConfig.displayOperationId().get().toString()); } - if (swaggerUiConfig.defaultModelsExpandDepth.isPresent()) { - options.put(Option.defaultModelsExpandDepth, String.valueOf(swaggerUiConfig.defaultModelsExpandDepth.getAsInt())); + if (swaggerUiConfig.defaultModelsExpandDepth().isPresent()) { + options.put(Option.defaultModelsExpandDepth, String.valueOf(swaggerUiConfig.defaultModelsExpandDepth().getAsInt())); } - if (swaggerUiConfig.defaultModelExpandDepth.isPresent()) { - options.put(Option.defaultModelExpandDepth, String.valueOf(swaggerUiConfig.defaultModelExpandDepth.getAsInt())); + if (swaggerUiConfig.defaultModelExpandDepth().isPresent()) { + options.put(Option.defaultModelExpandDepth, String.valueOf(swaggerUiConfig.defaultModelExpandDepth().getAsInt())); } - if (swaggerUiConfig.defaultModelRendering.isPresent()) { - options.put(Option.defaultModelRendering, swaggerUiConfig.defaultModelRendering.get()); + if (swaggerUiConfig.defaultModelRendering().isPresent()) { + options.put(Option.defaultModelRendering, swaggerUiConfig.defaultModelRendering().get()); } - if (swaggerUiConfig.displayRequestDuration.isPresent()) { - options.put(Option.displayRequestDuration, swaggerUiConfig.displayRequestDuration.get().toString()); + if (swaggerUiConfig.displayRequestDuration().isPresent()) { + options.put(Option.displayRequestDuration, swaggerUiConfig.displayRequestDuration().get().toString()); } - if (swaggerUiConfig.docExpansion.isPresent()) { - options.put(Option.docExpansion, swaggerUiConfig.docExpansion.get().toString()); + if (swaggerUiConfig.docExpansion().isPresent()) { + options.put(Option.docExpansion, swaggerUiConfig.docExpansion().get().toString()); } - if (swaggerUiConfig.filter.isPresent()) { - options.put(Option.filter, swaggerUiConfig.filter.get()); + if (swaggerUiConfig.filter().isPresent()) { + options.put(Option.filter, swaggerUiConfig.filter().get()); } - if (swaggerUiConfig.maxDisplayedTags.isPresent()) { - options.put(Option.maxDisplayedTags, String.valueOf(swaggerUiConfig.maxDisplayedTags.getAsInt())); + if (swaggerUiConfig.maxDisplayedTags().isPresent()) { + options.put(Option.maxDisplayedTags, String.valueOf(swaggerUiConfig.maxDisplayedTags().getAsInt())); } - if (swaggerUiConfig.operationsSorter.isPresent()) { - options.put(Option.operationsSorter, swaggerUiConfig.operationsSorter.get()); + if (swaggerUiConfig.operationsSorter().isPresent()) { + options.put(Option.operationsSorter, swaggerUiConfig.operationsSorter().get()); } - if (swaggerUiConfig.showExtensions.isPresent()) { - options.put(Option.showExtensions, swaggerUiConfig.showExtensions.get().toString()); + if (swaggerUiConfig.showExtensions().isPresent()) { + options.put(Option.showExtensions, swaggerUiConfig.showExtensions().get().toString()); } - if (swaggerUiConfig.showCommonExtensions.isPresent()) { - options.put(Option.showCommonExtensions, swaggerUiConfig.showCommonExtensions.get().toString()); + if (swaggerUiConfig.showCommonExtensions().isPresent()) { + options.put(Option.showCommonExtensions, swaggerUiConfig.showCommonExtensions().get().toString()); } - if (swaggerUiConfig.tagsSorter.isPresent()) { - options.put(Option.tagsSorter, swaggerUiConfig.tagsSorter.get()); + if (swaggerUiConfig.tagsSorter().isPresent()) { + options.put(Option.tagsSorter, swaggerUiConfig.tagsSorter().get()); } - if (swaggerUiConfig.onComplete.isPresent()) { - options.put(Option.onComplete, swaggerUiConfig.onComplete.get()); + if (swaggerUiConfig.onComplete().isPresent()) { + options.put(Option.onComplete, swaggerUiConfig.onComplete().get()); } - if (swaggerUiConfig.syntaxHighlight.isPresent()) { - options.put(Option.syntaxHighlight, swaggerUiConfig.syntaxHighlight.get()); + if (swaggerUiConfig.syntaxHighlight().isPresent()) { + options.put(Option.syntaxHighlight, swaggerUiConfig.syntaxHighlight().get()); } - if (swaggerUiConfig.oauth2RedirectUrl.isPresent()) { - options.put(Option.oauth2RedirectUrl, swaggerUiConfig.oauth2RedirectUrl.get()); + if (swaggerUiConfig.oauth2RedirectUrl().isPresent()) { + options.put(Option.oauth2RedirectUrl, swaggerUiConfig.oauth2RedirectUrl().get()); } else { options.put(Option.oauth2RedirectUrl, swaggerUiPath + "/oauth2-redirect.html"); } - if (swaggerUiConfig.requestInterceptor.isPresent()) { - options.put(Option.requestInterceptor, swaggerUiConfig.requestInterceptor.get()); + if (swaggerUiConfig.requestInterceptor().isPresent()) { + options.put(Option.requestInterceptor, swaggerUiConfig.requestInterceptor().get()); } - if (swaggerUiConfig.requestCurlOptions.isPresent()) { - String requestCurlOptions = swaggerUiConfig.requestCurlOptions.get().toString(); + if (swaggerUiConfig.requestCurlOptions().isPresent()) { + String requestCurlOptions = swaggerUiConfig.requestCurlOptions().get().toString(); options.put(Option.requestCurlOptions, requestCurlOptions); } - if (swaggerUiConfig.responseInterceptor.isPresent()) { - options.put(Option.responseInterceptor, swaggerUiConfig.responseInterceptor.get()); + if (swaggerUiConfig.responseInterceptor().isPresent()) { + options.put(Option.responseInterceptor, swaggerUiConfig.responseInterceptor().get()); } - if (swaggerUiConfig.showMutatedRequest.isPresent()) { - options.put(Option.showMutatedRequest, swaggerUiConfig.showMutatedRequest.get().toString()); + if (swaggerUiConfig.showMutatedRequest().isPresent()) { + options.put(Option.showMutatedRequest, swaggerUiConfig.showMutatedRequest().get().toString()); } - if (swaggerUiConfig.supportedSubmitMethods.isPresent()) { - String httpMethods = swaggerUiConfig.supportedSubmitMethods.get().toString(); + if (swaggerUiConfig.supportedSubmitMethods().isPresent()) { + String httpMethods = swaggerUiConfig.supportedSubmitMethods().get().toString(); options.put(Option.supportedSubmitMethods, httpMethods); } - if (swaggerUiConfig.validatorUrl.isPresent()) { - options.put(Option.validatorUrl, swaggerUiConfig.validatorUrl.get()); + if (swaggerUiConfig.validatorUrl().isPresent()) { + options.put(Option.validatorUrl, swaggerUiConfig.validatorUrl().get()); } - if (swaggerUiConfig.withCredentials.isPresent()) { - options.put(Option.withCredentials, swaggerUiConfig.withCredentials.get().toString()); + if (swaggerUiConfig.withCredentials().isPresent()) { + options.put(Option.withCredentials, swaggerUiConfig.withCredentials().get().toString()); } - if (swaggerUiConfig.modelPropertyMacro.isPresent()) { - options.put(Option.modelPropertyMacro, swaggerUiConfig.modelPropertyMacro.get()); + if (swaggerUiConfig.modelPropertyMacro().isPresent()) { + options.put(Option.modelPropertyMacro, swaggerUiConfig.modelPropertyMacro().get()); } - if (swaggerUiConfig.parameterMacro.isPresent()) { - options.put(Option.parameterMacro, swaggerUiConfig.parameterMacro.get()); + if (swaggerUiConfig.parameterMacro().isPresent()) { + options.put(Option.parameterMacro, swaggerUiConfig.parameterMacro().get()); } - if (swaggerUiConfig.persistAuthorization.isPresent()) { - options.put(Option.persistAuthorization, swaggerUiConfig.persistAuthorization.get().toString()); + if (swaggerUiConfig.persistAuthorization().isPresent()) { + options.put(Option.persistAuthorization, swaggerUiConfig.persistAuthorization().get().toString()); + } else if (launchMode.getLaunchMode().isDevOrTest()) { + // In dev mode, default to persist Authorization true + options.put(Option.persistAuthorization, String.valueOf(true)); } - if (swaggerUiConfig.layout.isPresent()) { - options.put(Option.layout, swaggerUiConfig.layout.get()); + if (swaggerUiConfig.layout().isPresent()) { + options.put(Option.layout, swaggerUiConfig.layout().get()); } - if (swaggerUiConfig.plugins.isPresent()) { - String plugins = swaggerUiConfig.plugins.get().toString(); + if (swaggerUiConfig.plugins().isPresent()) { + String plugins = swaggerUiConfig.plugins().get().toString(); options.put(Option.plugins, plugins); } - if (swaggerUiConfig.scripts.isPresent()) { - String scripts = String.join(",", swaggerUiConfig.scripts.get()); + if (swaggerUiConfig.scripts().isPresent()) { + String scripts = String.join(",", swaggerUiConfig.scripts().get()); options.put(Option.scripts, scripts); } - if (swaggerUiConfig.presets.isPresent()) { - String presets = swaggerUiConfig.presets.get().toString(); + if (swaggerUiConfig.presets().isPresent()) { + String presets = swaggerUiConfig.presets().get().toString(); options.put(Option.presets, presets); } - if (swaggerUiConfig.oauthClientId.isPresent()) { - String oauthClientId = swaggerUiConfig.oauthClientId.get(); + if (swaggerUiConfig.oauthClientId().isPresent()) { + String oauthClientId = swaggerUiConfig.oauthClientId().get(); options.put(Option.oauthClientId, oauthClientId); + } else if (devServicesLauncherConfigResultBuildItem != null) { + Map devServiceConfig = devServicesLauncherConfigResultBuildItem.getConfig(); + if (devServiceConfig != null && !devServiceConfig.isEmpty()) { + // Map client Id from OIDC Dev Services + if (devServiceConfig.containsKey(OIDC_CLIENT_ID)) { + String clientId = devServiceConfig.get(OIDC_CLIENT_ID); + options.put(Option.oauthClientId, clientId); + } + } } - if (swaggerUiConfig.oauthClientSecret.isPresent()) { - String oauthClientSecret = swaggerUiConfig.oauthClientSecret.get(); + if (swaggerUiConfig.oauthClientSecret().isPresent()) { + String oauthClientSecret = swaggerUiConfig.oauthClientSecret().get(); options.put(Option.oauthClientSecret, oauthClientSecret); } - if (swaggerUiConfig.oauthRealm.isPresent()) { - String oauthRealm = swaggerUiConfig.oauthRealm.get(); + if (swaggerUiConfig.oauthRealm().isPresent()) { + String oauthRealm = swaggerUiConfig.oauthRealm().get(); options.put(Option.oauthRealm, oauthRealm); } - if (swaggerUiConfig.oauthAppName.isPresent()) { - String oauthAppName = swaggerUiConfig.oauthAppName.get(); + if (swaggerUiConfig.oauthAppName().isPresent()) { + String oauthAppName = swaggerUiConfig.oauthAppName().get(); options.put(Option.oauthAppName, oauthAppName); } - if (swaggerUiConfig.oauthScopeSeparator.isPresent()) { - String oauthScopeSeparator = swaggerUiConfig.oauthScopeSeparator.get(); + if (swaggerUiConfig.oauthScopeSeparator().isPresent()) { + String oauthScopeSeparator = swaggerUiConfig.oauthScopeSeparator().get(); options.put(Option.oauthScopeSeparator, oauthScopeSeparator); } - if (swaggerUiConfig.oauthScopes.isPresent()) { - String oauthScopes = swaggerUiConfig.oauthScopes.get(); + if (swaggerUiConfig.oauthScopes().isPresent()) { + String oauthScopes = swaggerUiConfig.oauthScopes().get(); options.put(Option.oauthScopes, oauthScopes); } - if (swaggerUiConfig.queryConfigEnabled) { + if (swaggerUiConfig.queryConfigEnabled()) { options.put(Option.queryConfigEnabled, "true"); } ObjectMapper objectMapper = new ObjectMapper(); Map oauthAdditionalQueryStringParamMap = new HashMap<>(); - if (swaggerUiConfig.oauthAdditionalQueryStringParams.isPresent()) { - String oauthAdditionalQueryStringParams = swaggerUiConfig.oauthAdditionalQueryStringParams.get(); + if (swaggerUiConfig.oauthAdditionalQueryStringParams().isPresent()) { + String oauthAdditionalQueryStringParams = swaggerUiConfig.oauthAdditionalQueryStringParams().get(); Map map = objectMapper.readValue(oauthAdditionalQueryStringParams, Map.class); if (map == null || map.isEmpty()) { LOG.warn( @@ -406,44 +401,45 @@ private byte[] generateIndexHtml(String openApiPath, String swaggerUiPath, Swagg options.put(Option.oauthAdditionalQueryStringParams, objectMapper.writeValueAsString(oauthAdditionalQueryStringParamMap)); - if (swaggerUiConfig.oauthUseBasicAuthenticationWithAccessCodeGrant.isPresent()) { - String oauthUseBasicAuthenticationWithAccessCodeGrant = swaggerUiConfig.oauthUseBasicAuthenticationWithAccessCodeGrant + if (swaggerUiConfig.oauthUseBasicAuthenticationWithAccessCodeGrant().isPresent()) { + String oauthUseBasicAuthenticationWithAccessCodeGrant = swaggerUiConfig + .oauthUseBasicAuthenticationWithAccessCodeGrant() .get().toString(); options.put(Option.oauthUseBasicAuthenticationWithAccessCodeGrant, oauthUseBasicAuthenticationWithAccessCodeGrant); } - if (swaggerUiConfig.oauthUsePkceWithAuthorizationCodeGrant.isPresent()) { - String oauthUsePkceWithAuthorizationCodeGrant = swaggerUiConfig.oauthUsePkceWithAuthorizationCodeGrant.get() + if (swaggerUiConfig.oauthUsePkceWithAuthorizationCodeGrant().isPresent()) { + String oauthUsePkceWithAuthorizationCodeGrant = swaggerUiConfig.oauthUsePkceWithAuthorizationCodeGrant().get() .toString(); options.put(Option.oauthUsePkceWithAuthorizationCodeGrant, oauthUsePkceWithAuthorizationCodeGrant); } - if (swaggerUiConfig.preauthorizeBasicAuthDefinitionKey.isPresent()) { - String preauthorizeBasicAuthDefinitionKey = swaggerUiConfig.preauthorizeBasicAuthDefinitionKey.get(); + if (swaggerUiConfig.preauthorizeBasicAuthDefinitionKey().isPresent()) { + String preauthorizeBasicAuthDefinitionKey = swaggerUiConfig.preauthorizeBasicAuthDefinitionKey().get(); options.put(Option.preauthorizeBasicAuthDefinitionKey, preauthorizeBasicAuthDefinitionKey); } - if (swaggerUiConfig.preauthorizeBasicUsername.isPresent()) { - String preauthorizeBasicUsername = swaggerUiConfig.preauthorizeBasicUsername.get(); + if (swaggerUiConfig.preauthorizeBasicUsername().isPresent()) { + String preauthorizeBasicUsername = swaggerUiConfig.preauthorizeBasicUsername().get(); options.put(Option.preauthorizeBasicUsername, preauthorizeBasicUsername); } - if (swaggerUiConfig.preauthorizeBasicPassword.isPresent()) { - String preauthorizeBasicPassword = swaggerUiConfig.preauthorizeBasicPassword.get(); + if (swaggerUiConfig.preauthorizeBasicPassword().isPresent()) { + String preauthorizeBasicPassword = swaggerUiConfig.preauthorizeBasicPassword().get(); options.put(Option.preauthorizeBasicPassword, preauthorizeBasicPassword); } - if (swaggerUiConfig.preauthorizeApiKeyAuthDefinitionKey.isPresent()) { - String preauthorizeApiKeyAuthDefinitionKey = swaggerUiConfig.preauthorizeApiKeyAuthDefinitionKey.get(); + if (swaggerUiConfig.preauthorizeApiKeyAuthDefinitionKey().isPresent()) { + String preauthorizeApiKeyAuthDefinitionKey = swaggerUiConfig.preauthorizeApiKeyAuthDefinitionKey().get(); options.put(Option.preauthorizeApiKeyAuthDefinitionKey, preauthorizeApiKeyAuthDefinitionKey); } - if (swaggerUiConfig.preauthorizeApiKeyApiKeyValue.isPresent()) { - String preauthorizeApiKeyApiKeyValue = swaggerUiConfig.preauthorizeApiKeyApiKeyValue.get(); + if (swaggerUiConfig.preauthorizeApiKeyApiKeyValue().isPresent()) { + String preauthorizeApiKeyApiKeyValue = swaggerUiConfig.preauthorizeApiKeyApiKeyValue().get(); options.put(Option.preauthorizeApiKeyApiKeyValue, preauthorizeApiKeyApiKeyValue); } - if (swaggerUiConfig.tryItOutEnabled) { + if (swaggerUiConfig.tryItOutEnabled()) { options.put(Option.tryItOutEnabled, "true"); } - return IndexHtmlCreator.createIndexHtml(urlsMap, swaggerUiConfig.urlsPrimaryName.orElse(null), options); + return IndexHtmlCreator.createIndexHtml(urlsMap, swaggerUiConfig.urlsPrimaryName().orElse(null), options); } private static boolean shouldInclude(LaunchModeBuildItem launchMode, SwaggerUiConfig swaggerUiConfig) { - return launchMode.getLaunchMode().isDevOrTest() || swaggerUiConfig.alwaysInclude; + return launchMode.getLaunchMode().isDevOrTest() || swaggerUiConfig.alwaysInclude(); } } diff --git a/extensions/swagger-ui/runtime/pom.xml b/extensions/swagger-ui/runtime/pom.xml index ea8dbac939c470..7160cc65dc6cc4 100644 --- a/extensions/swagger-ui/runtime/pom.xml +++ b/extensions/swagger-ui/runtime/pom.xml @@ -46,9 +46,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/swagger-ui/runtime/src/main/java/io/quarkus/swaggerui/runtime/SwaggerUiRecorder.java b/extensions/swagger-ui/runtime/src/main/java/io/quarkus/swaggerui/runtime/SwaggerUiRecorder.java index 98ec75dc59b283..7284565cdfeebc 100644 --- a/extensions/swagger-ui/runtime/src/main/java/io/quarkus/swaggerui/runtime/SwaggerUiRecorder.java +++ b/extensions/swagger-ui/runtime/src/main/java/io/quarkus/swaggerui/runtime/SwaggerUiRecorder.java @@ -17,7 +17,7 @@ public Handler handler(String swaggerUiFinalDestination, String List webRootConfigurations, SwaggerUiRuntimeConfig runtimeConfig, ShutdownContext shutdownContext) { - if (runtimeConfig.enable) { + if (runtimeConfig.enable()) { WebJarStaticHandler handler = new WebJarStaticHandler(swaggerUiFinalDestination, swaggerUiPath, webRootConfigurations); shutdownContext.addShutdownTask(new ShutdownContext.CloseRunnable(handler)); diff --git a/extensions/swagger-ui/runtime/src/main/java/io/quarkus/swaggerui/runtime/SwaggerUiRuntimeConfig.java b/extensions/swagger-ui/runtime/src/main/java/io/quarkus/swaggerui/runtime/SwaggerUiRuntimeConfig.java index 41f1822224d398..b8c4f4da419517 100644 --- a/extensions/swagger-ui/runtime/src/main/java/io/quarkus/swaggerui/runtime/SwaggerUiRuntimeConfig.java +++ b/extensions/swagger-ui/runtime/src/main/java/io/quarkus/swaggerui/runtime/SwaggerUiRuntimeConfig.java @@ -1,17 +1,19 @@ package io.quarkus.swaggerui.runtime; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; +@ConfigMapping(prefix = "quarkus.swagger-ui") @ConfigRoot(phase = ConfigPhase.RUN_TIME) -public class SwaggerUiRuntimeConfig { +public interface SwaggerUiRuntimeConfig { /** * If Swagger UI is included, it should be enabled/disabled. By default, Swagger UI is enabled if it is included (see * {@code always-include}). */ - @ConfigItem(defaultValue = "true") - boolean enable; + @WithDefault("true") + boolean enable(); } From 5760f4957e666f79ccd7e35567c1c0601832d8c3 Mon Sep 17 00:00:00 2001 From: Rolfe Dlugy-Hegwer Date: Tue, 4 Feb 2025 11:01:17 -0500 Subject: [PATCH 07/10] Add missing IDs - critical for some links --- docs/src/main/asciidoc/security-jwt-build.adoc | 1 + docs/src/main/asciidoc/security-keycloak-authorization.adoc | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/src/main/asciidoc/security-jwt-build.adoc b/docs/src/main/asciidoc/security-jwt-build.adoc index 9ab7d1a8b70ca8..591788711d305e 100644 --- a/docs/src/main/asciidoc/security-jwt-build.adoc +++ b/docs/src/main/asciidoc/security-jwt-build.adoc @@ -3,6 +3,7 @@ This guide is maintained in the main Quarkus repository and pull requests should be submitted there: https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// +[id="security-jwt-build"] = Build, sign, and encrypt JSON Web Tokens include::_attributes.adoc[] :categories: security diff --git a/docs/src/main/asciidoc/security-keycloak-authorization.adoc b/docs/src/main/asciidoc/security-keycloak-authorization.adoc index 5e0e47f2fff097..58f8d5cdf6f9fa 100644 --- a/docs/src/main/asciidoc/security-keycloak-authorization.adoc +++ b/docs/src/main/asciidoc/security-keycloak-authorization.adoc @@ -3,6 +3,7 @@ This guide is maintained in the main Quarkus repository. To contribute, submit a pull request here: https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc //// +[id="security-keycloak-authorization"] = Using OpenID Connect (OIDC) and Keycloak to centralize authorization include::_attributes.adoc[] :diataxis-type: howto From 7b130b0a664ded2f77368a84024b79a05b5f7ee9 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 4 Feb 2025 17:26:45 +0100 Subject: [PATCH 08/10] Container Image - Finalize switch to @ConfigMapping There was some remaining config for container-image-s2i (extension removed a while ago) and I got rid of it. Part of #45446 --- .../buildpack/deployment/BuildpackBuild.java | 2 +- .../deployment/BuildpackBuildEnabled.java | 2 +- .../deployment/BuildpackProcessor.java | 4 +- .../common/deployment/CommonProcessor.java | 10 +- .../image/docker/deployment/DockerBuild.java | 2 +- .../image/jib/deployment/JibBuild.java | 2 +- .../image/jib/deployment/JibBuildEnabled.java | 2 +- .../image/jib/deployment/JibProcessor.java | 10 +- .../deployment/pom.xml | 3 - .../ContainerImageOpenshiftConfig.java | 76 ++++++------ .../openshift/deployment/OpenshiftBuild.java | 2 +- .../deployment/OpenshiftProcessor.java | 83 ++++++-------- .../openshift/deployment/OpenshiftUtils.java | 68 ----------- .../deployment/S2iBaseJavaImage.java | 63 ---------- .../deployment/S2iBaseNativeImage.java | 49 -------- .../image/openshift/deployment/S2iConfig.java | 108 ------------------ .../container-image-openshift/runtime/pom.xml | 3 - .../image/podman/deployment/PodmanBuild.java | 2 +- extensions/container-image/deployment/pom.xml | 3 - .../deployment/ContainerImageConfig.java | 69 +++++------ .../deployment/ContainerImageProcessor.java | 27 ++--- .../deployment/ContainerImageInfoTest.java | 27 ++--- .../deployment/InvalidConfigInNameTest.java | 9 +- extensions/container-image/runtime/pom.xml | 3 - .../deployment/OpenShiftConfig.java | 2 +- .../deployment/OpenshiftProcessor.java | 6 +- 26 files changed, 153 insertions(+), 484 deletions(-) delete mode 100644 extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iBaseJavaImage.java delete mode 100644 extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iBaseNativeImage.java delete mode 100644 extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iConfig.java diff --git a/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackBuild.java b/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackBuild.java index 141303d68b2932..5dc46308cb145a 100644 --- a/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackBuild.java +++ b/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackBuild.java @@ -14,6 +14,6 @@ public BuildpackBuild(ContainerImageConfig containerImageConfig) { @Override public boolean getAsBoolean() { - return containerImageConfig.builder.map(b -> b.equals(BuildpackProcessor.BUILDPACK)).orElse(true); + return containerImageConfig.builder().map(b -> b.equals(BuildpackProcessor.BUILDPACK)).orElse(true); } } diff --git a/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackBuildEnabled.java b/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackBuildEnabled.java index 022181c41fb173..53162d1f5903d1 100644 --- a/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackBuildEnabled.java +++ b/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackBuildEnabled.java @@ -15,6 +15,6 @@ public class BuildpackBuildEnabled implements BooleanSupplier { @Override public boolean getAsBoolean() { - return containerImageConfig.builder.map(b -> b.equals(BuildpackProcessor.BUILDPACK)).orElse(true); + return containerImageConfig.builder().map(b -> b.equals(BuildpackProcessor.BUILDPACK)).orElse(true); } } diff --git a/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackProcessor.java b/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackProcessor.java index 3a39af74584620..fbca75be5cb328 100644 --- a/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackProcessor.java +++ b/extensions/container-image/container-image-buildpack/deployment/src/main/java/io/quarkus/container/image/buildpack/deployment/BuildpackProcessor.java @@ -254,8 +254,8 @@ private String runBuildpackBuild(BuildpackConfig buildpackConfig, }); AuthConfig authConfig = new AuthConfig(); authConfig.withRegistryAddress(registry); - containerImageConfig.username.ifPresent(u -> authConfig.withUsername(u)); - containerImageConfig.password.ifPresent(p -> authConfig.withPassword(p)); + containerImageConfig.username().ifPresent(u -> authConfig.withUsername(u)); + containerImageConfig.password().ifPresent(p -> authConfig.withPassword(p)); log.info("Pushing image to " + authConfig.getRegistryAddress()); Stream.concat(Stream.of(containerImage.getImage()), containerImage.getAdditionalImageTags().stream()).forEach(i -> { diff --git a/extensions/container-image/container-image-docker-common/deployment/src/main/java/io/quarkus/container/image/docker/common/deployment/CommonProcessor.java b/extensions/container-image/container-image-docker-common/deployment/src/main/java/io/quarkus/container/image/docker/common/deployment/CommonProcessor.java index e3130f24362aad..d8c252b00bef9c 100644 --- a/extensions/container-image/container-image-docker-common/deployment/src/main/java/io/quarkus/container/image/docker/common/deployment/CommonProcessor.java +++ b/extensions/container-image/container-image-docker-common/deployment/src/main/java/io/quarkus/container/image/docker/common/deployment/CommonProcessor.java @@ -163,13 +163,13 @@ protected void loginToRegistryIfNeeded(ContainerImageConfig containerImageConfig }); // Check if we need to login first - if (containerImageConfig.username.isPresent() && containerImageConfig.password.isPresent()) { - var loginSuccessful = ExecUtil.exec(executableName, "login", registry, "-u", containerImageConfig.username.get(), - "-p", containerImageConfig.password.get()); + if (containerImageConfig.username().isPresent() && containerImageConfig.password().isPresent()) { + var loginSuccessful = ExecUtil.exec(executableName, "login", registry, "-u", containerImageConfig.username().get(), + "-p", containerImageConfig.password().get()); if (!loginSuccessful) { throw containerRuntimeException(executableName, - new String[] { "-u", containerImageConfig.username.get(), "-p", "********" }); + new String[] { "-u", containerImageConfig.username().get(), "-p", "********" }); } } } @@ -184,7 +184,7 @@ protected List getContainerCommonBuildArgs(String image, args.addAll(List.of("build", "-f", dockerfilePaths.dockerfilePath().toAbsolutePath().toString())); config.buildArgs().forEach((k, v) -> args.addAll(List.of("--build-arg", "%s=%s".formatted(k, v)))); - containerImageConfig.labels.forEach((k, v) -> args.addAll(List.of("--label", "%s=%s".formatted(k, v)))); + containerImageConfig.labels().forEach((k, v) -> args.addAll(List.of("--label", "%s=%s".formatted(k, v)))); config.cacheFrom() .filter(cacheFrom -> !cacheFrom.isEmpty()) .ifPresent(cacheFrom -> args.addAll(List.of("--cache-from", String.join(",", cacheFrom)))); diff --git a/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerBuild.java b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerBuild.java index 7b7032c7f21ad6..f1ee2de6a7d9e5 100644 --- a/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerBuild.java +++ b/extensions/container-image/container-image-docker/deployment/src/main/java/io/quarkus/container/image/docker/deployment/DockerBuild.java @@ -15,6 +15,6 @@ public class DockerBuild implements BooleanSupplier { @Override public boolean getAsBoolean() { - return containerImageConfig.builder.map(b -> b.equals(DockerProcessor.DOCKER_CONTAINER_IMAGE_NAME)).orElse(true); + return containerImageConfig.builder().map(b -> b.equals(DockerProcessor.DOCKER_CONTAINER_IMAGE_NAME)).orElse(true); } } diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuild.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuild.java index 6e25a5c0ae0a32..c987f6c193a4f4 100644 --- a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuild.java +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuild.java @@ -14,6 +14,6 @@ public JibBuild(ContainerImageConfig containerImageConfig) { @Override public boolean getAsBoolean() { - return containerImageConfig.builder.map(b -> b.equals(JibProcessor.JIB)).orElse(true); + return containerImageConfig.builder().map(b -> b.equals(JibProcessor.JIB)).orElse(true); } } diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuildEnabled.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuildEnabled.java index 4412c5d4d4d0f4..28fd4c33279f8d 100644 --- a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuildEnabled.java +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibBuildEnabled.java @@ -15,6 +15,6 @@ public class JibBuildEnabled implements BooleanSupplier { @Override public boolean getAsBoolean() { - return containerImageConfig.builder.map(b -> b.equals(JibProcessor.JIB)).orElse(true); + return containerImageConfig.builder().map(b -> b.equals(JibProcessor.JIB)).orElse(true); } } diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java index 4623955e39e3da..0b0a3a6b0227e0 100644 --- a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java @@ -268,8 +268,8 @@ private Containerizer createContainerizer(ContainerImageConfig containerImageCon if (imageReference.getRegistry() == null) { log.info("No container image registry was set, so 'docker.io' will be used"); } - RegistryImage registryImage = toRegistryImage(imageReference, containerImageConfig.username, - containerImageConfig.password); + RegistryImage registryImage = toRegistryImage(imageReference, containerImageConfig.username(), + containerImageConfig.password()); containerizer = Containerizer.to(registryImage); } else { DockerDaemonImage dockerDaemonImage = DockerDaemonImage.named(imageReference); @@ -296,7 +296,7 @@ private Containerizer createContainerizer(ContainerImageConfig containerImageCon log.log(toJBossLoggingLevel(e.getLevel()), e.getMessage()); } }); - containerizer.setAllowInsecureRegistries(containerImageConfig.insecure); + containerizer.setAllowInsecureRegistries(containerImageConfig.insecure()); containerizer.setAlwaysCacheBaseImage(jibConfig.alwaysCacheBaseImage()); containerizer.setOfflineMode(jibConfig.offlineMode()); jibConfig.baseImageLayersCache().ifPresent(cacheDir -> containerizer.setBaseImageLayersCache(Paths.get(cacheDir))); @@ -867,11 +867,11 @@ private void handleExtraFiles(OutputTargetBuildItem outputTarget, JibContainerBu private Map allLabels(ContainerImageJibConfig jibConfig, ContainerImageConfig containerImageConfig, List containerImageLabels) { - if (containerImageLabels.isEmpty() && containerImageConfig.labels.isEmpty()) { + if (containerImageLabels.isEmpty() && containerImageConfig.labels().isEmpty()) { return Collections.emptyMap(); } - final Map allLabels = new HashMap<>(containerImageConfig.labels); + final Map allLabels = new HashMap<>(containerImageConfig.labels()); for (ContainerImageLabelBuildItem containerImageLabel : containerImageLabels) { // we want the user supplied labels to take precedence so the user can override labels generated from other extensions if desired allLabels.putIfAbsent(containerImageLabel.getName(), containerImageLabel.getValue()); diff --git a/extensions/container-image/container-image-openshift/deployment/pom.xml b/extensions/container-image/container-image-openshift/deployment/pom.xml index 70ac92990e046f..c0458deba5dfc2 100644 --- a/extensions/container-image/container-image-openshift/deployment/pom.xml +++ b/extensions/container-image/container-image-openshift/deployment/pom.xml @@ -80,9 +80,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/ContainerImageOpenshiftConfig.java b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/ContainerImageOpenshiftConfig.java index 46042c656cec48..6503b9f107668e 100644 --- a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/ContainerImageOpenshiftConfig.java +++ b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/ContainerImageOpenshiftConfig.java @@ -9,12 +9,14 @@ import io.quarkus.deployment.images.ContainerImages; import io.quarkus.deployment.pkg.builditem.CompiledJavaVersionBuildItem; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; -@ConfigRoot(name = "openshift", phase = ConfigPhase.BUILD_TIME) -public class ContainerImageOpenshiftConfig { +@ConfigRoot(phase = ConfigPhase.BUILD_TIME) +@ConfigMapping(prefix = "quarkus.openshift") +public interface ContainerImageOpenshiftConfig { public static final String DEFAULT_NATIVE_TARGET_FILENAME = "application"; @@ -36,8 +38,8 @@ public static String getDefaultJvmImage(CompiledJavaVersionBuildItem.JavaVersion /** * The build config strategy to use. */ - @ConfigItem(defaultValue = "binary") - public BuildStrategy buildStrategy; + @WithDefault("binary") + BuildStrategy buildStrategy(); /** * The base image to be used when a container image is being produced for the jar build. @@ -48,8 +50,7 @@ public static String getDefaultJvmImage(CompiledJavaVersionBuildItem.JavaVersion * is used as the default. * Otherwise {@code registry.access.redhat.com/ubi8/openjdk-17:1.20} is used as the default. */ - @ConfigItem - public Optional baseJvmImage; + Optional baseJvmImage(); /** * The base image to be used when a container image is being produced for the native binary build. @@ -57,87 +58,80 @@ public static String getDefaultJvmImage(CompiledJavaVersionBuildItem.JavaVersion * When it references images already available in the internal Openshift registry, the corresponding streams are used * instead. */ - @ConfigItem(defaultValue = ContainerImages.QUARKUS_BINARY_S2I) - public String baseNativeImage; + @WithDefault(ContainerImages.QUARKUS_BINARY_S2I) + String baseNativeImage(); /** * The default Dockerfile to use for jvm builds */ - @ConfigItem(defaultValue = DEFAULT_JVM_DOCKERFILE) - public String jvmDockerfile; + @WithDefault(DEFAULT_JVM_DOCKERFILE) + String jvmDockerfile(); /** * The default Dockerfile to use for native builds */ - @ConfigItem(defaultValue = DEFAULT_NATIVE_DOCKERFILE) - public String nativeDockerfile; + @WithDefault(DEFAULT_NATIVE_DOCKERFILE) + String nativeDockerfile(); /** * The JVM arguments to pass to the JVM when starting the application */ - @ConfigItem - public Optional> jvmArguments; + Optional> jvmArguments(); /** * Additional arguments to pass when starting the native application */ - @ConfigItem - public Optional> nativeArguments; + Optional> nativeArguments(); /** * The directory where the jar is added during the assemble phase. * This is dependent on the S2I image and should be supplied if a non default image is used. */ - @ConfigItem - public Optional jarDirectory; + Optional jarDirectory(); /** * The resulting filename of the jar in the S2I image. * This option may be used if the selected S2I image uses a fixed name for the jar. */ - @ConfigItem - public Optional jarFileName; + Optional jarFileName(); /** * The directory where the native binary is added during the assemble phase. * This is dependent on the S2I image and should be supplied if a non-default image is used. */ - @ConfigItem - public Optional nativeBinaryDirectory; + Optional nativeBinaryDirectory(); /** * The resulting filename of the native binary in the S2I image. * This option may be used if the selected S2I image uses a fixed name for the native binary. */ - @ConfigItem - public Optional nativeBinaryFileName; + Optional nativeBinaryFileName(); /** * The build timeout. */ - @ConfigItem(defaultValue = "PT5M") - Duration buildTimeout; + @WithDefault("PT5M") + Duration buildTimeout(); /** * The log level of OpenShift build log. */ - @ConfigItem(defaultValue = DEFAULT_BUILD_LOG_LEVEL) - public Logger.Level buildLogLevel; + @WithDefault(DEFAULT_BUILD_LOG_LEVEL) + Logger.Level buildLogLevel(); /** * The image push secret to use for pushing to external registries. * (see: https://cloud.redhat.com/blog/pushing-application-images-to-an-external-registry) **/ - @ConfigItem - public Optional imagePushSecret; + Optional imagePushSecret(); /** * Check if baseJvmImage is the default * * @returns true if baseJvmImage is the default */ - public boolean hasDefaultBaseJvmImage() { - return baseJvmImage.isPresent(); + default boolean hasDefaultBaseJvmImage() { + return baseJvmImage().isPresent(); } /** @@ -145,8 +139,8 @@ public boolean hasDefaultBaseJvmImage() { * * @returns true if baseNativeImage is the default */ - public boolean hasDefaultBaseNativeImage() { - return baseNativeImage.equals(ContainerImages.QUARKUS_BINARY_S2I); + default boolean hasDefaultBaseNativeImage() { + return baseNativeImage().equals(ContainerImages.QUARKUS_BINARY_S2I); } /** @@ -154,8 +148,8 @@ public boolean hasDefaultBaseNativeImage() { * * @returns true if jvmDockerfile is the default */ - public boolean hasDefaultJvmDockerfile() { - return jvmDockerfile.equals(DEFAULT_JVM_DOCKERFILE); + default boolean hasDefaultJvmDockerfile() { + return jvmDockerfile().equals(DEFAULT_JVM_DOCKERFILE); } /** @@ -163,16 +157,16 @@ public boolean hasDefaultJvmDockerfile() { * * @returns true if nativeDockerfile is the default */ - public boolean hasDefaultNativeDockerfile() { - return nativeDockerfile.equals(DEFAULT_NATIVE_DOCKERFILE); + default boolean hasDefaultNativeDockerfile() { + return nativeDockerfile().equals(DEFAULT_NATIVE_DOCKERFILE); } /** * @return the effective JVM arguments to use by getting the jvmArguments and the jvmAdditionalArguments properties. */ - public List getEffectiveJvmArguments() { + default List getEffectiveJvmArguments() { List effectiveJvmArguments = new ArrayList<>(); - jvmArguments.ifPresent(effectiveJvmArguments::addAll); + jvmArguments().ifPresent(effectiveJvmArguments::addAll); return effectiveJvmArguments; } diff --git a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftBuild.java b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftBuild.java index 32ce09e05fcff0..715790a1e75068 100644 --- a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftBuild.java +++ b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftBuild.java @@ -14,6 +14,6 @@ public class OpenshiftBuild implements BooleanSupplier { @Override public boolean getAsBoolean() { - return containerImageConfig.builder.map(b -> b.equals(OpenshiftProcessor.OPENSHIFT)).orElse(true); + return containerImageConfig.builder().map(b -> b.equals(OpenshiftProcessor.OPENSHIFT)).orElse(true); } } diff --git a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftProcessor.java b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftProcessor.java index 37789fe8a9c20e..533a8c09b8cabd 100644 --- a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftProcessor.java +++ b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftProcessor.java @@ -2,9 +2,9 @@ import static io.quarkus.container.image.openshift.deployment.OpenshiftUtils.getDeployStrategy; import static io.quarkus.container.image.openshift.deployment.OpenshiftUtils.getNamespace; -import static io.quarkus.container.image.openshift.deployment.OpenshiftUtils.mergeConfig; import static io.quarkus.container.util.PathsUtil.findMainSourcesRoot; -import static io.quarkus.deployment.pkg.PackageConfig.JarConfig.JarType.*; +import static io.quarkus.deployment.pkg.PackageConfig.JarConfig.JarType.FAST_JAR; +import static io.quarkus.deployment.pkg.PackageConfig.JarConfig.JarType.MUTABLE_JAR; import static io.quarkus.deployment.pkg.steps.JarResultBuildStep.DEFAULT_FAST_JAR_DIRECTORY_NAME; import java.io.BufferedReader; @@ -96,14 +96,12 @@ public AvailableContainerImageExtensionBuildItem availability() { } @BuildStep(onlyIf = { OpenshiftBuild.class }, onlyIfNot = NativeBuild.class) - public void openshiftPrepareJvmDockerBuild(ContainerImageOpenshiftConfig openshiftConfig, - S2iConfig s2iConfig, + public void openshiftPrepareJvmDockerBuild(ContainerImageOpenshiftConfig config, OutputTargetBuildItem out, BuildProducer decorator) { - ContainerImageOpenshiftConfig config = mergeConfig(openshiftConfig, s2iConfig); - if (config.buildStrategy == BuildStrategy.DOCKER) { + if (config.buildStrategy() == BuildStrategy.DOCKER) { decorator.produce(new DecoratorBuildItem(new ApplyDockerfileToBuildConfigDecorator(null, - findMainSourcesRoot(out.getOutputDirectory()).getValue().resolve(openshiftConfig.jvmDockerfile)))); + findMainSourcesRoot(out.getOutputDirectory()).getValue().resolve(config.jvmDockerfile())))); //When using the docker build strategy, we can't possibly know these values, so it's the image responsibility to work without them. decorator.produce(new DecoratorBuildItem(new RemoveEnvVarDecorator(null, "JAVA_APP_JAR"))); decorator.produce(new DecoratorBuildItem(new RemoveEnvVarDecorator(null, "JAVA_APP_LIB"))); @@ -111,14 +109,12 @@ public void openshiftPrepareJvmDockerBuild(ContainerImageOpenshiftConfig openshi } @BuildStep(onlyIf = { OpenshiftBuild.class, NativeBuild.class }) - public void openshiftPrepareNativeDockerBuild(ContainerImageOpenshiftConfig openshiftConfig, - S2iConfig s2iConfig, + public void openshiftPrepareNativeDockerBuild(ContainerImageOpenshiftConfig config, OutputTargetBuildItem out, BuildProducer decorator) { - ContainerImageOpenshiftConfig config = mergeConfig(openshiftConfig, s2iConfig); - if (config.buildStrategy == BuildStrategy.DOCKER) { + if (config.buildStrategy() == BuildStrategy.DOCKER) { decorator.produce(new DecoratorBuildItem(new ApplyDockerfileToBuildConfigDecorator(null, - findMainSourcesRoot(out.getOutputDirectory()).getValue().resolve(openshiftConfig.nativeDockerfile)))); + findMainSourcesRoot(out.getOutputDirectory()).getValue().resolve(config.nativeDockerfile())))); } //Let's remove this for all kinds of native build decorator.produce(new DecoratorBuildItem(new RemoveEnvVarDecorator(null, "JAVA_APP_JAR"))); @@ -126,8 +122,7 @@ public void openshiftPrepareNativeDockerBuild(ContainerImageOpenshiftConfig open } @BuildStep(onlyIf = { IsNormalNotRemoteDev.class, OpenshiftBuild.class }, onlyIfNot = NativeBuild.class) - public void openshiftRequirementsJvm(ContainerImageOpenshiftConfig openshiftConfig, - S2iConfig s2iConfig, + public void openshiftRequirementsJvm(ContainerImageOpenshiftConfig config, CurateOutcomeBuildItem curateOutcomeBuildItem, OutputTargetBuildItem out, PackageConfig packageConfig, @@ -138,22 +133,21 @@ public void openshiftRequirementsJvm(ContainerImageOpenshiftConfig openshiftConf BuildProducer builderImageProducer, BuildProducer commandProducer) { - ContainerImageOpenshiftConfig config = mergeConfig(openshiftConfig, s2iConfig); String outputJarFileName = jarBuildItem.getPath().getFileName().toString(); - String jarFileName = config.jarFileName.orElse(outputJarFileName); - String baseJvmImage = config.baseJvmImage + String jarFileName = config.jarFileName().orElse(outputJarFileName); + String baseJvmImage = config.baseJvmImage() .orElse(ContainerImageOpenshiftConfig.getDefaultJvmImage(compiledJavaVersion.getJavaVersion())); - boolean hasCustomJarPath = config.jarFileName.isPresent() || config.jarDirectory.isPresent(); - boolean hasCustomJvmArguments = config.jvmArguments.isPresent(); + boolean hasCustomJarPath = config.jarFileName().isPresent() || config.jarDirectory().isPresent(); + boolean hasCustomJvmArguments = config.jvmArguments().isPresent(); builderImageProducer.produce(new BaseImageInfoBuildItem(baseJvmImage)); - if (config.buildStrategy == BuildStrategy.BINARY) { + if (config.buildStrategy() == BuildStrategy.BINARY) { // Jar directory priorities: // 1. explicitly specified by the user. // 3. fallback value - String jarDirectory = config.jarDirectory.orElse(config.FALLBACK_JAR_DIRECTORY); + String jarDirectory = config.jarDirectory().orElse(ContainerImageOpenshiftConfig.FALLBACK_JAR_DIRECTORY); String pathToJar = concatUnixPaths(jarDirectory, jarFileName); //In all other cases its the responsibility of the image to set those up correctly. @@ -169,8 +163,7 @@ public void openshiftRequirementsJvm(ContainerImageOpenshiftConfig openshiftConf } @BuildStep(onlyIf = { IsNormalNotRemoteDev.class, OpenshiftBuild.class, NativeBuild.class }) - public void openshiftRequirementsNative(ContainerImageOpenshiftConfig openshiftConfig, - S2iConfig s2iConfig, + public void openshiftRequirementsNative(ContainerImageOpenshiftConfig config, CurateOutcomeBuildItem curateOutcomeBuildItem, OutputTargetBuildItem out, PackageConfig packageConfig, @@ -179,35 +172,35 @@ public void openshiftRequirementsNative(ContainerImageOpenshiftConfig openshiftC BuildProducer builderImageProducer, BuildProducer commandProducer) { - ContainerImageOpenshiftConfig config = mergeConfig(openshiftConfig, s2iConfig); boolean usingDefaultBuilder = ImageUtil.getRepository(ContainerImages.QUARKUS_BINARY_S2I) - .equals(ImageUtil.getRepository(config.baseNativeImage)); + .equals(ImageUtil.getRepository(config.baseNativeImage())); String outputNativeBinaryFileName = nativeImage.getPath().getFileName().toString(); String nativeBinaryFileName = null; - boolean hasCustomNativePath = config.nativeBinaryFileName.isPresent() || config.nativeBinaryDirectory.isPresent(); - boolean hasCustomNativeArguments = config.nativeArguments.isPresent(); + boolean hasCustomNativePath = config.nativeBinaryFileName().isPresent() || config.nativeBinaryDirectory().isPresent(); + boolean hasCustomNativeArguments = config.nativeArguments().isPresent(); //The default openshift builder for native builds, renames the native binary. //To make things easier for the user, we need to handle it. - if (usingDefaultBuilder && !config.nativeBinaryFileName.isPresent()) { + if (usingDefaultBuilder && !config.nativeBinaryFileName().isPresent()) { nativeBinaryFileName = ContainerImageOpenshiftConfig.DEFAULT_NATIVE_TARGET_FILENAME; } else { - nativeBinaryFileName = config.nativeBinaryFileName.orElse(outputNativeBinaryFileName); + nativeBinaryFileName = config.nativeBinaryFileName().orElse(outputNativeBinaryFileName); } - if (config.buildStrategy == BuildStrategy.BINARY) { - builderImageProducer.produce(new BaseImageInfoBuildItem(config.baseNativeImage)); + if (config.buildStrategy() == BuildStrategy.BINARY) { + builderImageProducer.produce(new BaseImageInfoBuildItem(config.baseNativeImage())); // Native binary directory priorities: // 1. explicitly specified by the user. // 2. fallback vale - String nativeBinaryDirectory = config.nativeBinaryDirectory.orElse(config.FALLBACK_NATIVE_BINARY_DIRECTORY); + String nativeBinaryDirectory = config.nativeBinaryDirectory().orElse(config.FALLBACK_NATIVE_BINARY_DIRECTORY); String pathToNativeBinary = concatUnixPaths(nativeBinaryDirectory, nativeBinaryFileName); if (hasCustomNativePath || hasCustomNativeArguments) { commandProducer - .produce(KubernetesCommandBuildItem.commandWithArgs(pathToNativeBinary, config.nativeArguments.get())); + .produce( + KubernetesCommandBuildItem.commandWithArgs(pathToNativeBinary, config.nativeArguments().get())); } } } @@ -222,9 +215,9 @@ public void configureExternalRegistry(ApplicationInfoBuildItem applicationInfo, final String serviceAccountName = applicationInfo.getName(); String repositoryWithRegistry = registry + "/" + containerImageInfo.getRepository(); - if (openshiftConfig.imagePushSecret.isPresent()) { + if (openshiftConfig.imagePushSecret().isPresent()) { //if a push secret has been specified, we need to apply it. - String imagePushSecret = openshiftConfig.imagePushSecret.get(); + String imagePushSecret = openshiftConfig.imagePushSecret().get(); decorator.produce(new DecoratorBuildItem(OPENSHIFT, new ApplyDockerImageOutputToBuildConfigDecorator( applicationInfo.getName(), containerImageInfo.getImage(), imagePushSecret))); } else if (registry.contains(OPENSHIFT_INTERNAL_REGISTRY)) { @@ -246,8 +239,7 @@ public void configureExternalRegistry(ApplicationInfoBuildItem applicationInfo, } @BuildStep(onlyIf = { IsNormalNotRemoteDev.class, OpenshiftBuild.class }, onlyIfNot = NativeBuild.class) - public void openshiftBuildFromJar(ContainerImageOpenshiftConfig openshiftConfig, - S2iConfig s2iConfig, + public void openshiftBuildFromJar(ContainerImageOpenshiftConfig config, ContainerImageConfig containerImageConfig, KubernetesClientBuildItem kubernetesClientBuilder, ContainerImageInfoBuildItem containerImage, @@ -260,7 +252,6 @@ public void openshiftBuildFromJar(ContainerImageOpenshiftConfig openshiftConfig, // used to ensure that the jar has been built JarBuildItem jar) { - ContainerImageOpenshiftConfig config = mergeConfig(openshiftConfig, s2iConfig); if (containerImageConfig.isBuildExplicitlyDisabled()) { return; } @@ -283,7 +274,7 @@ public void openshiftBuildFromJar(ContainerImageOpenshiftConfig openshiftConfig, try (KubernetesClient kubernetesClient = buildClient(kubernetesClientBuilder)) { String namespace = Optional.ofNullable(kubernetesClient.getNamespace()).orElse("default"); - LOG.info("Starting (in-cluster) container image build for jar using: " + config.buildStrategy + " on server: " + LOG.info("Starting (in-cluster) container image build for jar using: " + config.buildStrategy() + " on server: " + kubernetesClient.getMasterUrl() + " in namespace:" + namespace + "."); //The contextRoot is where inside the tarball we will add the jars. A null value means everything will be added under '/' while "target" means everything will be added under '/target'. //For docker kind of builds where we use instructions like: `COPY target/*.jar /deployments` it using '/target' is a requirement. @@ -291,7 +282,7 @@ public void openshiftBuildFromJar(ContainerImageOpenshiftConfig openshiftConfig, String outputDirName = out.getOutputDirectory().getFileName().toString(); PackageConfig.JarConfig.JarType jarType = packageConfig.jar().type(); String contextRoot = getContextRoot(outputDirName, jarType == FAST_JAR || jarType == MUTABLE_JAR, - config.buildStrategy); + config.buildStrategy()); KubernetesClientBuilder clientBuilder = newClientBuilderWithoutHttp2(kubernetesClient.getConfiguration(), kubernetesClientBuilder.getHttpClientFactory()); if (jarType == FAST_JAR || jarType == MUTABLE_JAR) { @@ -320,7 +311,7 @@ private String getContextRoot(String outputDirName, boolean isFastJar, BuildStra } @BuildStep(onlyIf = { IsNormalNotRemoteDev.class, OpenshiftBuild.class, NativeBuild.class }) - public void openshiftBuildFromNative(ContainerImageOpenshiftConfig openshiftConfig, S2iConfig s2iConfig, + public void openshiftBuildFromNative(ContainerImageOpenshiftConfig config, ContainerImageConfig containerImageConfig, KubernetesClientBuildItem kubernetesClientBuilder, ContainerImageInfoBuildItem containerImage, @@ -332,8 +323,6 @@ public void openshiftBuildFromNative(ContainerImageOpenshiftConfig openshiftConf BuildProducer containerImageBuilder, NativeImageBuildItem nativeImage) { - ContainerImageOpenshiftConfig config = mergeConfig(openshiftConfig, s2iConfig); - if (containerImageConfig.isBuildExplicitlyDisabled()) { return; } @@ -346,7 +335,7 @@ public void openshiftBuildFromNative(ContainerImageOpenshiftConfig openshiftConf try (KubernetesClient kubernetesClient = buildClient(kubernetesClientBuilder)) { String namespace = Optional.ofNullable(kubernetesClient.getNamespace()).orElse("default"); - LOG.info("Starting (in-cluster) container image build for jar using: " + config.buildStrategy + " on server: " + LOG.info("Starting (in-cluster) container image build for jar using: " + config.buildStrategy() + " on server: " + kubernetesClient.getMasterUrl() + " in namespace:" + namespace + "."); Optional openshiftYml = generatedResources .stream() @@ -361,7 +350,7 @@ public void openshiftBuildFromNative(ContainerImageOpenshiftConfig openshiftConf //The contextRoot is where inside the tarball we will add the jars. A null value means everything will be added under '/' while "target" means everything will be added under '/target'. //For docker kind of builds where we use instructions like: `COPY target/*.jar /deployments` it using '/target' is a requirement. //For s2i kind of builds where jars are expected directly in the '/' we have to use null. - String contextRoot = config.buildStrategy == BuildStrategy.DOCKER ? "target" : null; + String contextRoot = config.buildStrategy() == BuildStrategy.DOCKER ? "target" : null; createContainerImage( newClientBuilderWithoutHttp2(kubernetesClient.getConfiguration(), kubernetesClientBuilder.getHttpClientFactory()), @@ -467,7 +456,7 @@ private static Build startOpenshiftBuild(BuildConfig buildConfig, File binaryFil try { return client.buildConfigs().withName(buildConfig.getMetadata().getName()) .instantiateBinary() - .withTimeoutInMillis(openshiftConfig.buildTimeout.toMillis()) + .withTimeoutInMillis(openshiftConfig.buildTimeout().toMillis()) .fromFile(binaryFile); } catch (Exception e) { Optional running = buildsOf(client, buildConfig).stream().findFirst(); @@ -498,7 +487,7 @@ private static void waitForOpenshiftBuild(Build build, ContainerImageOpenshiftCo build = updated; try (LogWatch w = client.builds().withName(buildName).withPrettyOutput().watchLog(); Reader reader = new InputStreamReader(w.getOutput())) { - display(reader, openshiftConfig.buildLogLevel); + display(reader, openshiftConfig.buildLogLevel()); } catch (IOException | KubernetesClientException ex) { // This may happen if the LogWatch is closed while we are still reading. // We shouldn't let the build fail, so let's log a warning and display last few lines of the log diff --git a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftUtils.java b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftUtils.java index 43341ba0cedaa5..cf58ca1c7d6c25 100644 --- a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftUtils.java +++ b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/OpenshiftUtils.java @@ -4,12 +4,8 @@ import java.util.Collection; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; -import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; import io.dekorate.kubernetes.decorator.Decorator; @@ -86,70 +82,6 @@ public void visit(SourceBuildStrategyFluent strategy) { return !tagsMissing; } - /** - * Merges {@link ContainerImageOpenshiftConfig} with {@link S2iConfig} prioritizing in the former. - * - * @param openshiftConfig the Openshift config - * @param s2iConfig the s2i config - * @return an instance of {@link ContainerImageOpenshiftConfig} with the merged configuration. - */ - public static ContainerImageOpenshiftConfig mergeConfig(ContainerImageOpenshiftConfig openshiftConfig, - S2iConfig s2iConfig) { - ContainerImageOpenshiftConfig result = openshiftConfig != null ? openshiftConfig : new ContainerImageOpenshiftConfig(); - if (s2iConfig == null) { - return result; - } - - Config config = ConfigProvider.getConfig(); - Set properties = StreamSupport.stream(config.getPropertyNames().spliterator(), false) - .filter(s -> s.startsWith("quarkus.s2i.") || s.startsWith("quarkus.openshift.")) - .collect(Collectors.toSet()); - - boolean hasS2iBaseJvmImage = properties.contains("quarkus.s2i.base-jvm-image"); - boolean hasS2iBaseNativeImage = properties.contains("quarkus.s2i.base-native-image"); - boolean hasS2iJvmArguments = properties.contains("quarkus.s2i.jvm-arguments"); - boolean hasS2iNativeArguments = properties.contains("quarkus.s2i.native-arguments"); - boolean hasS2iJarDirectory = properties.contains("quarkus.s2i.jar-directory"); - boolean hasS2iJarFileName = properties.contains("quarkus.s2i.jar-file-name"); - boolean hasS2iNativeBinaryDirectory = properties.contains("quarkus.s2i.native-binary-directory"); - boolean hasS2iNativeBinaryFileName = properties.contains("quarkus.s2i.native-binary-file-name"); - boolean hasS2iBuildTimeout = properties.contains("quarkus.s2i.native-binary-file-name"); - - boolean hasOpenshiftBaseJvmImage = properties.contains("quarkus.openshift.base-jvm-image"); - boolean hasOpenshiftBaseNativeImage = properties.contains("quarkus.openshift.base-native-image"); - boolean hasOpenshiftJvmArguments = properties.contains("quarkus.openshift.jvm-arguments"); - boolean hasOpenshiftNativeArguments = properties.contains("quarkus.openshift.native-arguments"); - boolean hasOpenshiftJarDirectory = properties.contains("quarkus.openshift.jar-directory"); - boolean hasOpenshiftJarFileName = properties.contains("quarkus.openshift.jar-file-name"); - boolean hasOpenshiftNativeBinaryDirectory = properties.contains("quarkus.openshift.native-binary-directory"); - boolean hasOpenshiftNativeBinaryFileName = properties.contains("quarkus.openshift.native-binary-file-name"); - boolean hasOpenshiftBuildTimeout = properties.contains("quarkus.openshift.native-binary-file-name"); - - result.baseJvmImage = hasS2iBaseJvmImage && !hasOpenshiftBaseJvmImage ? s2iConfig.baseJvmImage - : openshiftConfig.baseJvmImage; - result.baseNativeImage = hasS2iBaseNativeImage && !hasOpenshiftBaseNativeImage ? s2iConfig.baseNativeImage - : openshiftConfig.baseNativeImage; - result.jvmArguments = hasS2iJvmArguments && !hasOpenshiftJvmArguments ? s2iConfig.jvmArguments - : openshiftConfig.jvmArguments; - result.nativeArguments = hasS2iNativeArguments && !hasOpenshiftNativeArguments ? s2iConfig.nativeArguments - : openshiftConfig.nativeArguments; - result.jarDirectory = hasS2iJarDirectory && !hasOpenshiftJarDirectory ? Optional.of(s2iConfig.jarDirectory) - : openshiftConfig.jarDirectory; - result.jarFileName = hasS2iJarFileName && !hasOpenshiftJarFileName ? s2iConfig.jarFileName - : openshiftConfig.jarFileName; - result.nativeBinaryDirectory = hasS2iNativeBinaryDirectory && !hasOpenshiftNativeBinaryDirectory - ? Optional.of(s2iConfig.nativeBinaryDirectory) - : openshiftConfig.nativeBinaryDirectory; - result.nativeBinaryFileName = hasS2iNativeBinaryFileName && !hasOpenshiftNativeBinaryFileName - ? s2iConfig.nativeBinaryFileName - : openshiftConfig.nativeBinaryFileName; - result.buildTimeout = hasS2iBuildTimeout && !hasOpenshiftBuildTimeout ? s2iConfig.buildTimeout - : openshiftConfig.buildTimeout; - result.buildStrategy = openshiftConfig.buildStrategy; - - return result; - } - /** * @return the openshift namespace set in the OpenShift extension. */ diff --git a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iBaseJavaImage.java b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iBaseJavaImage.java deleted file mode 100644 index 5512d7725407c8..00000000000000 --- a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iBaseJavaImage.java +++ /dev/null @@ -1,63 +0,0 @@ - -package io.quarkus.container.image.openshift.deployment; - -import java.util.Optional; - -import io.quarkus.container.image.deployment.util.ImageUtil; - -public enum S2iBaseJavaImage { - - //We only compare `repositories` so registries and tags are stripped - FABRIC8("fabric8/s2i-java:latest", "JAVA_MAIN_CLASS", "JAVA_APP_JAR", "JAVA_LIB_DIR", "JAVA_CLASSPATH", "JAVA_OPTIONS"); - - private final String image; - private final String javaMainClassEnvVar; - private final String jarEnvVar; - private final String jarLibEnvVar; - private final String classpathEnvVar; - private final String jvmOptionsEnvVar; - - public static Optional findMatching(String image) { - for (S2iBaseJavaImage candidate : S2iBaseJavaImage.values()) { - if (ImageUtil.getRepository(candidate.getImage()).equals(ImageUtil.getRepository(image))) { - return Optional.of(candidate); - } - } - return Optional.empty(); - } - - private S2iBaseJavaImage(String image, String javaMainClassEnvVar, String jarEnvVar, String jarLibEnvVar, - String classpathEnvVar, String jvmOptionsEnvVar) { - this.image = image; - this.javaMainClassEnvVar = javaMainClassEnvVar; - this.jarEnvVar = jarEnvVar; - this.jarLibEnvVar = jarLibEnvVar; - this.classpathEnvVar = classpathEnvVar; - this.jvmOptionsEnvVar = jvmOptionsEnvVar; - } - - public String getImage() { - return image; - } - - public String getJavaMainClassEnvVar() { - return javaMainClassEnvVar; - } - - public String getJvmOptionsEnvVar() { - return jvmOptionsEnvVar; - } - - public String getClasspathEnvVar() { - return classpathEnvVar; - } - - public String getJarLibEnvVar() { - return jarLibEnvVar; - } - - public String getJarEnvVar() { - return jarEnvVar; - } - -} diff --git a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iBaseNativeImage.java b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iBaseNativeImage.java deleted file mode 100644 index 167e2a8394f6aa..00000000000000 --- a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iBaseNativeImage.java +++ /dev/null @@ -1,49 +0,0 @@ - -package io.quarkus.container.image.openshift.deployment; - -import java.util.Optional; - -import io.quarkus.container.image.deployment.util.ImageUtil; - -public enum S2iBaseNativeImage { - - //We only compare `repositories` so registries and tags are stripped - QUARKUS("quarkus/ubi-quarkus-native-binary-s2i:2.0", "application", "QUARKUS_HOME", "QUARKUS_OPTS"); - - private final String image; - private final String fixedNativeBinaryName; - private final String homeDirEnvVar; - private final String optsEnvVar; - - public static Optional findMatching(String image) { - for (S2iBaseNativeImage candidate : S2iBaseNativeImage.values()) { - if (ImageUtil.getRepository(candidate.getImage()).equals(ImageUtil.getRepository(image))) { - return Optional.of(candidate); - } - } - return Optional.empty(); - } - - private S2iBaseNativeImage(String image, String fixedNativeBinaryName, String homeDirEnvVar, String optsEnvVar) { - this.image = image; - this.fixedNativeBinaryName = fixedNativeBinaryName; - this.homeDirEnvVar = homeDirEnvVar; - this.optsEnvVar = optsEnvVar; - } - - public String getImage() { - return image; - } - - public String getFixedNativeBinaryName() { - return this.fixedNativeBinaryName; - } - - public String getHomeDirEnvVar() { - return homeDirEnvVar; - } - - public String getOptsEnvVar() { - return optsEnvVar; - } -} diff --git a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iConfig.java b/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iConfig.java deleted file mode 100644 index 5e8e9d7e1a80b8..00000000000000 --- a/extensions/container-image/container-image-openshift/deployment/src/main/java/io/quarkus/container/image/openshift/deployment/S2iConfig.java +++ /dev/null @@ -1,108 +0,0 @@ -package io.quarkus.container.image.openshift.deployment; - -import java.time.Duration; -import java.util.List; -import java.util.Optional; - -import io.quarkus.deployment.images.ContainerImages; -import io.quarkus.runtime.annotations.ConfigItem; -import io.quarkus.runtime.annotations.ConfigPhase; -import io.quarkus.runtime.annotations.ConfigRoot; - -@ConfigRoot(phase = ConfigPhase.BUILD_TIME) -public class S2iConfig { - - public static final String DEFAULT_NATIVE_TARGET_FILENAME = "application"; - - public static final String DEFAULT_JVM_DOCKERFILE = "src/main/docker/Dockerfile.jvm"; - public static final String DEFAULT_NATIVE_DOCKERFILE = "src/main/docker/Dockerfile.native"; - - public static final String FALLBACK_JAR_DIRECTORY = "/deployments/"; - public static final String FALLBACK_NATIVE_BINARY_DIRECTORY = "/home/quarkus/"; - - /** - * The build config strategy to use. - */ - @ConfigItem(defaultValue = "binary") - public BuildStrategy buildStrategy; - - /** - * The base image to be used when a container image is being produced for the jar build. - * - * When the application is built against Java 21 or higher, {@code registry.access.redhat.com/ubi8/openjdk-21:1.20} - * is used as the default. - * Otherwise {@code registry.access.redhat.com/ubi8/openjdk-17:1.20} is used as the default. - */ - @ConfigItem - public Optional baseJvmImage; - - /** - * The base image to be used when a container image is being produced for the native binary build - */ - @ConfigItem(defaultValue = ContainerImages.QUARKUS_BINARY_S2I) - public String baseNativeImage; - - /** - * The JVM arguments to pass to the JVM when starting the application - */ - @ConfigItem - public Optional> jvmArguments; - - /** - * Additional arguments to pass when starting the native application - */ - @ConfigItem - public Optional> nativeArguments; - - /** - * The directory where the jar is added during the assemble phase. - * This is dependent on the S2I image and should be supplied if a non default image is used. - */ - @ConfigItem(defaultValue = "/deployments/target/") - public String jarDirectory; - - /** - * The resulting filename of the jar in the S2I image. - * This option may be used if the selected S2I image uses a fixed name for the jar. - */ - @ConfigItem - public Optional jarFileName; - - /** - * The directory where the native binary is added during the assemble phase. - * This is dependent on the S2I image and should be supplied if a non-default image is used. - */ - @ConfigItem(defaultValue = "/home/quarkus/") - public String nativeBinaryDirectory; - - /** - * The resulting filename of the native binary in the S2I image. - * This option may be used if the selected S2I image uses a fixed name for the native binary. - */ - @ConfigItem - public Optional nativeBinaryFileName; - - /** - * The build timeout. - */ - @ConfigItem(defaultValue = "PT5M") - Duration buildTimeout; - - /** - * Check if baseJvmImage is the default - * - * @returns true if baseJvmImage is the default - */ - public boolean hasDefaultBaseJvmImage() { - return baseJvmImage.isPresent(); - } - - /** - * Check if baseNativeImage is the default - * - * @returns true if baseNativeImage is the default - */ - public boolean hasDefaultBaseNativeImage() { - return baseNativeImage.equals(ContainerImages.QUARKUS_BINARY_S2I); - } -} diff --git a/extensions/container-image/container-image-openshift/runtime/pom.xml b/extensions/container-image/container-image-openshift/runtime/pom.xml index 944f403fc98814..820ba97eb6510c 100644 --- a/extensions/container-image/container-image-openshift/runtime/pom.xml +++ b/extensions/container-image/container-image-openshift/runtime/pom.xml @@ -53,9 +53,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/container-image/container-image-podman/deployment/src/main/java/io/quarkus/container/image/podman/deployment/PodmanBuild.java b/extensions/container-image/container-image-podman/deployment/src/main/java/io/quarkus/container/image/podman/deployment/PodmanBuild.java index 7e48b7fbbc4938..431a2fb8c3ff7c 100644 --- a/extensions/container-image/container-image-podman/deployment/src/main/java/io/quarkus/container/image/podman/deployment/PodmanBuild.java +++ b/extensions/container-image/container-image-podman/deployment/src/main/java/io/quarkus/container/image/podman/deployment/PodmanBuild.java @@ -13,7 +13,7 @@ public PodmanBuild(ContainerImageConfig containerImageConfig) { @Override public boolean getAsBoolean() { - return containerImageConfig.builder + return containerImageConfig.builder() .map(b -> b.equals(PodmanProcessor.PODMAN_CONTAINER_IMAGE_NAME)) .orElse(true); } diff --git a/extensions/container-image/deployment/pom.xml b/extensions/container-image/deployment/pom.xml index 50de8b3187ecf7..f39d1232f2afa0 100644 --- a/extensions/container-image/deployment/pom.xml +++ b/extensions/container-image/deployment/pom.xml @@ -59,9 +59,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageConfig.java b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageConfig.java index b5ad69727968ca..f97b43b728affb 100644 --- a/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageConfig.java +++ b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageConfig.java @@ -5,111 +5,102 @@ import java.util.Optional; import io.quarkus.runtime.annotations.ConfigDocMapKey; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigRoot; -import io.quarkus.runtime.annotations.ConvertWith; import io.quarkus.runtime.configuration.TrimmedStringConverter; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithConverter; +import io.smallrye.config.WithDefault; @ConfigRoot -public class ContainerImageConfig { +@ConfigMapping(prefix = "quarkus.container-image") +public interface ContainerImageConfig { /** * The group the container image will be part of */ - @ConfigItem - @ConvertWith(TrimmedStringConverter.class) - Optional group; //used only by ContainerImageProcessor, use ContainerImageInfoBuildItem instead + Optional<@WithConverter(TrimmedStringConverter.class) String> group(); //used only by ContainerImageProcessor, use ContainerImageInfoBuildItem instead /** * The name of the container image. If not set defaults to the application name */ - @ConfigItem(defaultValue = "${quarkus.application.name:unset}") - @ConvertWith(TrimmedStringConverter.class) - String name; //used only by ContainerImageProcessor, use ContainerImageInfoBuildItem instead + @WithDefault("${quarkus.application.name:unset}") + @WithConverter(TrimmedStringConverter.class) + String name(); //used only by ContainerImageProcessor, use ContainerImageInfoBuildItem instead /** * The tag of the container image. If not set defaults to the application version */ - @ConfigItem(defaultValue = "${quarkus.application.version:latest}") - Optional tag; //used only by ContainerImageProcessor, use ContainerImageInfoBuildItem instead + @WithDefault("${quarkus.application.version:latest}") + String tag(); //used only by ContainerImageProcessor, use ContainerImageInfoBuildItem instead /** * Additional tags of the container image. */ - @ConfigItem - public Optional> additionalTags; + Optional> additionalTags(); /** * Custom labels to add to the generated image. */ - @ConfigItem @ConfigDocMapKey("label-name") - public Map labels; + Map labels(); /** * The container registry to use */ - @ConfigItem - public Optional registry; + Optional registry(); /** * Represents the entire image string. * If set, then {@code group}, {@code name}, {@code registry}, {@code tags}, {@code additionalTags} * are ignored */ - @ConfigItem - public Optional image; + Optional image(); /** * The username to use to authenticate with the registry where the built image will be pushed */ - @ConfigItem - public Optional username; + Optional username(); /** * The password to use to authenticate with the registry where the built image will be pushed */ - @ConfigItem - public Optional password; + Optional password(); /** * Whether or not insecure registries are allowed */ - @ConfigItem - public boolean insecure; + @WithDefault("false") + boolean insecure(); /** * Whether or not a image build will be performed. */ - @ConfigItem - public Optional build; + Optional build(); /** * Whether or not an image push will be performed. */ - @ConfigItem - public Optional push; + Optional push(); /** * The name of the container image extension to use (e.g. docker, podman, jib, s2i). * The option will be used in case multiple extensions are present. */ - @ConfigItem - public Optional builder; + Optional builder(); - public boolean isBuildExplicitlyEnabled() { - return build.isPresent() && build.get(); + default boolean isBuildExplicitlyEnabled() { + return build().isPresent() && build().get(); } - public boolean isBuildExplicitlyDisabled() { - return build.isPresent() && !build.get(); + default boolean isBuildExplicitlyDisabled() { + return build().isPresent() && !build().get(); } - public boolean isPushExplicitlyEnabled() { - return push.isPresent() && push.get(); + default boolean isPushExplicitlyEnabled() { + return push().isPresent() && push().get(); } - public boolean isPushExplicitlyDisabled() { - return push.isPresent() && !push.get(); + default boolean isPushExplicitlyDisabled() { + return push().isPresent() && !push().get(); } } diff --git a/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageProcessor.java b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageProcessor.java index ab1115042161d6..e842306621eda0 100644 --- a/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageProcessor.java +++ b/extensions/container-image/deployment/src/main/java/io/quarkus/container/image/deployment/ContainerImageProcessor.java @@ -62,8 +62,8 @@ public void publishImageInfo(ApplicationInfoBuildItem app, // additionalTags are used even containerImageConfig.image is set because that // string cannot contain multiple tags - if (containerImageConfig.additionalTags.isPresent()) { - for (String additionalTag : containerImageConfig.additionalTags.get()) { + if (containerImageConfig.additionalTags().isPresent()) { + for (String additionalTag : containerImageConfig.additionalTags().get()) { if (!ImageReference.isValidTag(additionalTag)) { throw new IllegalArgumentException( "The supplied additional container-image tag '" + additionalTag + "' is invalid"); @@ -71,24 +71,25 @@ public void publishImageInfo(ApplicationInfoBuildItem app, } } - Optional effectiveGroup = getEffectiveGroup(containerImageConfig.group, singleSegmentImageRequest.isPresent()); + Optional effectiveGroup = getEffectiveGroup(containerImageConfig.group(), + singleSegmentImageRequest.isPresent()); // if the user supplied the entire image string, use it - if (containerImageConfig.image.isPresent()) { - ImageReference imageReference = ImageReference.parse(containerImageConfig.image.get()); + if (containerImageConfig.image().isPresent()) { + ImageReference imageReference = ImageReference.parse(containerImageConfig.image().get()); String repository = imageReference.getRepository(); if (singleSegmentImageRequest.isPresent() && imageReference.getRepository().contains("/") && imageReference.getRegistry().filter(StringUtil::isNullOrEmpty).isPresent()) { log.warn("A single segment image is preferred, but a local multi segment has been provided: " - + containerImageConfig.image.get()); + + containerImageConfig.image().get()); } containerImage.produce(new ContainerImageInfoBuildItem(imageReference.getRegistry(), - containerImageConfig.username, containerImageConfig.password, repository, - imageReference.getTag(), containerImageConfig.additionalTags.orElse(Collections.emptyList()))); + containerImageConfig.username(), containerImageConfig.password(), repository, + imageReference.getTag(), containerImageConfig.additionalTags().orElse(Collections.emptyList()))); return; } - String registry = containerImageConfig.registry + String registry = containerImageConfig.registry() .orElseGet(() -> containerImageRegistry.map(FallbackContainerImageRegistryBuildItem::getRegistry) .orElse(null)); if ((registry != null) && !ImageReference.isValidRegistry(registry)) { @@ -96,7 +97,7 @@ public void publishImageInfo(ApplicationInfoBuildItem app, } String effectiveName = containerImageCustomName.map(ContainerImageCustomNameBuildItem::getName) - .orElse(containerImageConfig.name); + .orElse(containerImageConfig.name()); String group = effectiveGroup.orElse(""); String repository = group.isBlank() ? effectiveName : group + "/" + effectiveName; if (!ImageReference.isValidRepository(repository)) { @@ -104,7 +105,7 @@ public void publishImageInfo(ApplicationInfoBuildItem app, + group + "' and name '" + effectiveName + "' is invalid"); } - String effectiveTag = containerImageConfig.tag.orElse(app.getVersion()); + String effectiveTag = containerImageConfig.tag(); if (effectiveTag.equals(UNSET_VALUE)) { effectiveTag = DEFAULT_TAG; } @@ -114,10 +115,10 @@ public void publishImageInfo(ApplicationInfoBuildItem app, } containerImage.produce(new ContainerImageInfoBuildItem(Optional.ofNullable(registry), - containerImageConfig.username, containerImageConfig.password, + containerImageConfig.username(), containerImageConfig.password(), effectiveGroup, effectiveName, effectiveTag, - containerImageConfig.additionalTags.orElse(Collections.emptyList()))); + containerImageConfig.additionalTags().orElse(Collections.emptyList()))); } private void ensureSingleContainerImageExtension(Capabilities capabilities) { diff --git a/extensions/container-image/deployment/src/test/java/io/quarkus/container/image/deployment/ContainerImageInfoTest.java b/extensions/container-image/deployment/src/test/java/io/quarkus/container/image/deployment/ContainerImageInfoTest.java index a864a948fb3fcd..fa76fe6ef85049 100644 --- a/extensions/container-image/deployment/src/test/java/io/quarkus/container/image/deployment/ContainerImageInfoTest.java +++ b/extensions/container-image/deployment/src/test/java/io/quarkus/container/image/deployment/ContainerImageInfoTest.java @@ -17,11 +17,6 @@ import io.quarkus.deployment.Capabilities; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.builditem.ApplicationInfoBuildItem; -import io.quarkus.deployment.configuration.BuildTimeConfigurationReader; -import io.quarkus.deployment.configuration.DefaultValuesConfigurationSource; -import io.quarkus.runtime.LaunchMode; -import io.quarkus.runtime.configuration.ConfigUtils; -import io.smallrye.config.PropertiesConfigSource; import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigBuilder; @@ -104,19 +99,15 @@ private void clearProperty(String key) { } private void whenPublishImageInfo() { - BuildTimeConfigurationReader reader = new BuildTimeConfigurationReader( - Collections.singletonList(ContainerImageConfig.class)); - SmallRyeConfigBuilder builder = ConfigUtils.configBuilder(false, LaunchMode.NORMAL); - - DefaultValuesConfigurationSource ds = new DefaultValuesConfigurationSource( - reader.getBuildTimePatternMap()); - PropertiesConfigSource pcs = new PropertiesConfigSource(new Properties(), "Test Properties"); - builder.withSources(ds, pcs); - - SmallRyeConfig src = builder.build(); - BuildTimeConfigurationReader.ReadResult readResult = reader.readConfiguration(src); - ContainerImageConfig containerImageConfig = (ContainerImageConfig) readResult - .requireObjectForClass(ContainerImageConfig.class); + SmallRyeConfig config = new SmallRyeConfigBuilder() + .addDefaultInterceptors() + .addDefaultSources() + .addDiscoveredConverters() + .addDiscoveredCustomizers() + .withMapping(ContainerImageConfig.class) + .build(); + + ContainerImageConfig containerImageConfig = config.getConfigMapping(ContainerImageConfig.class); ApplicationInfoBuildItem app = new ApplicationInfoBuildItem(Optional.of(APP_NAME), Optional.of(APP_VERSION)); Capabilities capabilities = new Capabilities(Collections.emptySet()); diff --git a/extensions/container-image/deployment/src/test/java/io/quarkus/container/image/deployment/InvalidConfigInNameTest.java b/extensions/container-image/deployment/src/test/java/io/quarkus/container/image/deployment/InvalidConfigInNameTest.java index f4c2fc4a95c52c..4b15b34471ea90 100644 --- a/extensions/container-image/deployment/src/test/java/io/quarkus/container/image/deployment/InvalidConfigInNameTest.java +++ b/extensions/container-image/deployment/src/test/java/io/quarkus/container/image/deployment/InvalidConfigInNameTest.java @@ -1,19 +1,22 @@ package io.quarkus.container.image.deployment; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -import java.util.NoSuchElementException; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.config.ConfigValidationException; public class InvalidConfigInNameTest { @RegisterExtension static QuarkusUnitTest runner = new QuarkusUnitTest() - .setExpectedException(NoSuchElementException.class) + .assertException(t -> { + assertTrue(t instanceof ConfigValidationException); + assertTrue(t.getMessage().contains("NoSuchElementException")); + }) .withEmptyApplication() .overrideConfigKey("quarkus.container-image.build", "true") .overrideConfigKey("quarkus.container-image.name", "test-${foo.bar}"); diff --git a/extensions/container-image/runtime/pom.xml b/extensions/container-image/runtime/pom.xml index 02eaebdbc1433b..b2b22a240420a8 100644 --- a/extensions/container-image/runtime/pom.xml +++ b/extensions/container-image/runtime/pom.xml @@ -49,9 +49,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenShiftConfig.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenShiftConfig.java index 533389dc0b9b43..f58c57bc42e227 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenShiftConfig.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenShiftConfig.java @@ -136,7 +136,7 @@ enum OpenshiftFlavor { static boolean isOpenshiftBuildEnabled(ContainerImageConfig containerImageConfig, Capabilities capabilities) { boolean implicitlyEnabled = ContainerImageCapabilitiesUtil.getActiveContainerImageCapability(capabilities) .filter(c -> c.contains(OPENSHIFT) || c.contains(S2I)).isPresent(); - return containerImageConfig.builder.map(b -> b.equals(OPENSHIFT) || b.equals(S2I)).orElse(implicitlyEnabled); + return containerImageConfig.builder().map(b -> b.equals(OPENSHIFT) || b.equals(S2I)).orElse(implicitlyEnabled); } default DeploymentResourceKind getDeploymentResourceKind(Capabilities capabilities) { diff --git a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java index 4dab0ccd0d55c0..b0af39ae116e77 100644 --- a/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java +++ b/extensions/kubernetes/vanilla/deployment/src/main/java/io/quarkus/kubernetes/deployment/OpenshiftProcessor.java @@ -104,7 +104,7 @@ public void populateInternalRegistry( BuildProducer containerImageRegistry, BuildProducer singleSegmentContainerImageRequest) { - if (containerImageConfig.registry.isEmpty() && containerImageConfig.image.isEmpty()) { + if (containerImageConfig.registry().isEmpty() && containerImageConfig.image().isEmpty()) { DeploymentResourceKind deploymentResourceKind = openshiftConfig.getDeploymentResourceKind(capabilities); if (deploymentResourceKind != DeploymentResourceKind.DeploymentConfig) { if (OpenShiftConfig.isOpenshiftBuildEnabled(containerImageConfig, capabilities)) { @@ -323,7 +323,7 @@ public List createDecorators(ApplicationInfoBuildItem applic result.add(new DecoratorBuildItem(OPENSHIFT, new RemoveBuilderImageResourceDecorator(DEFAULT_S2I_IMAGE_NAME))); } - if (containerImageConfig.builder.isEmpty() + if (containerImageConfig.builder().isEmpty() || OpenShiftConfig.isOpenshiftBuildEnabled(containerImageConfig, capabilities)) { result.add(new DecoratorBuildItem(OPENSHIFT, new ApplyBuilderImageDecorator(name, builderImage))); ImageReference imageRef = ImageReference.parse(builderImage); @@ -367,7 +367,7 @@ public List createDecorators(ApplicationInfoBuildItem applic image.ifPresent(i -> { String registry = i.registry - .or(() -> containerImageConfig.registry) + .or(() -> containerImageConfig.registry()) .orElse(fallbackRegistry.map(FallbackContainerImageRegistryBuildItem::getRegistry) .orElse(DOCKERIO_REGISTRY)); String repositoryWithRegistry = registry + "/" + i.getRepository(); From 2fbc83dc745f870a75560eec67e2bc01a4eb34c6 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 4 Feb 2025 17:58:39 +0100 Subject: [PATCH 09/10] Narayana - Switch to @ConfigMapping --- .../quarkus/agroal/runtime/DataSources.java | 4 +- extensions/narayana-jta/deployment/pom.xml | 3 - .../jta/deployment/NarayanaJtaProcessor.java | 6 +- extensions/narayana-jta/runtime/pom.xml | 3 - .../narayana/jta/QuarkusTransactionImpl.java | 2 +- .../jta/RequestScopedTransaction.java | 2 +- .../jta/runtime/NarayanaJtaProducers.java | 2 - .../jta/runtime/NarayanaJtaRecorder.java | 57 ++++++++-------- .../TransactionManagerBuildTimeConfig.java | 10 +-- .../TransactionManagerConfiguration.java | 65 +++++++++---------- .../jta/runtime/NarayanaJtaRecorderTest.java | 30 ++++----- extensions/narayana-lra/deployment/pom.xml | 3 - .../deployment/LRABuildTimeConfiguration.java | 12 ++-- .../lra/deployment/NarayanaLRAProcessor.java | 2 +- extensions/narayana-lra/runtime/pom.xml | 3 - .../lra/runtime/LRAConfiguration.java | 10 +-- .../lra/runtime/NarayanaLRARecorder.java | 2 +- 17 files changed, 100 insertions(+), 116 deletions(-) diff --git a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java index 80079ba3b48974..5b60fadd9f597b 100644 --- a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java +++ b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java @@ -252,11 +252,11 @@ private void applyNewConfiguration(String dataSourceName, AgroalDataSourceConfig TransactionIntegration txIntegration = new NarayanaTransactionIntegration(transactionManager, transactionSynchronizationRegistry, null, false, dataSourceJdbcBuildTimeConfig.transactions() == io.quarkus.agroal.runtime.TransactionIntegration.XA - && transactionRuntimeConfig.enableRecovery + && transactionRuntimeConfig.enableRecovery() ? xaResourceRecoveryRegistry : null); if (dataSourceJdbcBuildTimeConfig.transactions() == io.quarkus.agroal.runtime.TransactionIntegration.XA - && !transactionRuntimeConfig.enableRecovery) { + && !transactionRuntimeConfig.enableRecovery()) { log.warnv( "Datasource {0} enables XA but transaction recovery is not enabled. Please enable transaction recovery by setting quarkus.transaction-manager.enable-recovery=true, otherwise data may be lost if the application is terminated abruptly", dataSourceName); diff --git a/extensions/narayana-jta/deployment/pom.xml b/extensions/narayana-jta/deployment/pom.xml index cd8deb7598f398..9cb051259de8ac 100644 --- a/extensions/narayana-jta/deployment/pom.xml +++ b/extensions/narayana-jta/deployment/pom.xml @@ -55,9 +55,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/narayana-jta/deployment/src/main/java/io/quarkus/narayana/jta/deployment/NarayanaJtaProcessor.java b/extensions/narayana-jta/deployment/src/main/java/io/quarkus/narayana/jta/deployment/NarayanaJtaProcessor.java index c821bacf9572fe..c82802a526d22a 100644 --- a/extensions/narayana-jta/deployment/src/main/java/io/quarkus/narayana/jta/deployment/NarayanaJtaProcessor.java +++ b/extensions/narayana-jta/deployment/src/main/java/io/quarkus/narayana/jta/deployment/NarayanaJtaProcessor.java @@ -151,7 +151,7 @@ public void build(NarayanaJtaRecorder recorder, builder.addBeanClass(TransactionalInterceptorNotSupported.class); additionalBeans.produce(builder.build()); - transactionManagerBuildTimeConfig.unsafeMultipleLastResources.ifPresent(mode -> { + transactionManagerBuildTimeConfig.unsafeMultipleLastResources().ifPresent(mode -> { if (!mode.equals(UnsafeMultipleLastResourcesMode.FAIL)) { recorder.logUnsafeMultipleLastResourcesOnStartup(mode); } @@ -178,7 +178,7 @@ public void build(NarayanaJtaRecorder recorder, @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class) public void nativeImageFeature(TransactionManagerBuildTimeConfig transactionManagerBuildTimeConfig, BuildProducer nativeImageFeatures) { - switch (transactionManagerBuildTimeConfig.unsafeMultipleLastResources + switch (transactionManagerBuildTimeConfig.unsafeMultipleLastResources() .orElse(UnsafeMultipleLastResourcesMode.DEFAULT)) { case ALLOW, WARN_FIRST, WARN_EACH -> { nativeImageFeatures.produce(new NativeImageFeatureBuildItem(DisableLoggingFeature.class)); @@ -264,7 +264,7 @@ private void allowUnsafeMultipleLastResources(NarayanaJtaRecorder recorder, TransactionManagerBuildTimeConfig transactionManagerBuildTimeConfig, Capabilities capabilities, BuildProducer logCleanupFilters, BuildProducer nativeImageFeatures) { - switch (transactionManagerBuildTimeConfig.unsafeMultipleLastResources + switch (transactionManagerBuildTimeConfig.unsafeMultipleLastResources() .orElse(UnsafeMultipleLastResourcesMode.DEFAULT)) { case ALLOW -> { recorder.allowUnsafeMultipleLastResources(capabilities.isPresent(Capability.AGROAL), true); diff --git a/extensions/narayana-jta/runtime/pom.xml b/extensions/narayana-jta/runtime/pom.xml index efd5c6fed0f5fc..56552a061022d9 100644 --- a/extensions/narayana-jta/runtime/pom.xml +++ b/extensions/narayana-jta/runtime/pom.xml @@ -131,9 +131,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/QuarkusTransactionImpl.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/QuarkusTransactionImpl.java index 0384ead6f5ccf9..e1ef05163511b1 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/QuarkusTransactionImpl.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/QuarkusTransactionImpl.java @@ -210,7 +210,7 @@ private static void begin(RunOptionsBase options) { try { getUserTransaction().setTransactionTimeout( (int) Arc.container().instance(TransactionManagerConfiguration.class) - .get().defaultTransactionTimeout.toSeconds()); + .get().defaultTransactionTimeout().toSeconds()); } catch (SystemException e) { log.error("Failed to reset transaction timeout", e); } diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/RequestScopedTransaction.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/RequestScopedTransaction.java index 9421b0c964ea75..f9bd1fbf35140a 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/RequestScopedTransaction.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/RequestScopedTransaction.java @@ -69,7 +69,7 @@ void begin(BeginOptions options) { if (timeout > 0) { try { userTransaction.setTransactionTimeout( - (int) transactionManagerConfiguration.defaultTransactionTimeout.toSeconds()); + (int) transactionManagerConfiguration.defaultTransactionTimeout().toSeconds()); } catch (SystemException e) { throw new QuarkusTransactionException(e); } diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaProducers.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaProducers.java index 327acd72af42c1..3981627cb838a5 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaProducers.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaProducers.java @@ -7,7 +7,6 @@ import jakarta.transaction.TransactionSynchronizationRegistry; import jakarta.transaction.UserTransaction; -import org.jboss.logging.Logger; import org.jboss.tm.JBossXATerminator; import org.jboss.tm.XAResourceRecoveryRegistry; import org.jboss.tm.usertx.UserTransactionRegistry; @@ -20,7 +19,6 @@ @Dependent public class NarayanaJtaProducers { - private static final Logger log = Logger.getLogger(NarayanaJtaProducers.class); @Produces @ApplicationScoped diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java index 3363fb1276547f..21ee50812284de 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java @@ -6,7 +6,6 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Base64; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; @@ -43,20 +42,20 @@ public class NarayanaJtaRecorder { public void setNodeName(final TransactionManagerConfiguration transactions) { try { - if (transactions.nodeName.getBytes(StandardCharsets.UTF_8).length > 28 - && transactions.shortenNodeNameIfNecessary) { - shortenNodeName(transactions); + String nodeName = transactions.nodeName(); + if (nodeName.getBytes(StandardCharsets.UTF_8).length > 28 + && transactions.shortenNodeNameIfNecessary()) { + nodeName = shortenNodeName(transactions.nodeName()); } - arjPropertyManager.getCoreEnvironmentBean().setNodeIdentifier(transactions.nodeName); - jtaPropertyManager.getJTAEnvironmentBean().setXaRecoveryNodes(Collections.singletonList(transactions.nodeName)); - TxControl.setXANodeName(transactions.nodeName); + arjPropertyManager.getCoreEnvironmentBean().setNodeIdentifier(nodeName); + jtaPropertyManager.getJTAEnvironmentBean().setXaRecoveryNodes(List.of(nodeName)); + TxControl.setXANodeName(nodeName); } catch (CoreEnvironmentBeanException | NoSuchAlgorithmException e) { log.error("Could not set node name", e); } } - private static void shortenNodeName(TransactionManagerConfiguration transactions) throws NoSuchAlgorithmException { - String originalNodeName = transactions.nodeName; + String shortenNodeName(String originalNodeName) throws NoSuchAlgorithmException { log.warnf("Node name \"%s\" is longer than 28 bytes, shortening it by using %s.", originalNodeName, HASH_ALGORITHM_FOR_SHORTENING); final byte[] nodeNameAsBytes = originalNodeName.getBytes(); @@ -69,8 +68,9 @@ private static void shortenNodeName(TransactionManagerConfiguration transactions //truncate the array byte[] slice = Arrays.copyOfRange(base64Result, 0, 28); - transactions.nodeName = new String(slice, StandardCharsets.UTF_8); - log.warnf("New node name is \"%s\"", transactions.nodeName); + String shorterNodeName = new String(slice, StandardCharsets.UTF_8); + log.warnf("New node name is \"%s\"", shorterNodeName); + return shorterNodeName; } public void setDefaultProperties(Properties properties) { @@ -92,8 +92,8 @@ public void setDefaultProperties(Properties properties) { public void setDefaultTimeout(TransactionManagerConfiguration transactions) { arjPropertyManager.getCoordinatorEnvironmentBean() - .setDefaultTimeout((int) transactions.defaultTransactionTimeout.getSeconds()); - TxControl.setDefaultTimeout((int) transactions.defaultTransactionTimeout.getSeconds()); + .setDefaultTimeout((int) transactions.defaultTransactionTimeout().getSeconds()); + TxControl.setDefaultTimeout((int) transactions.defaultTransactionTimeout().getSeconds()); } public static Properties getDefaultProperties() { @@ -107,17 +107,17 @@ public void disableTransactionStatusManager() { public void setConfig(final TransactionManagerConfiguration transactions) { List objectStores = Arrays.asList(null, "communicationStore", "stateStore"); - if (transactions.objectStore.type.equals(ObjectStoreType.File_System)) { + if (transactions.objectStore().type().equals(ObjectStoreType.File_System)) { objectStores.forEach(name -> setObjectStoreDir(name, transactions)); - } else if (transactions.objectStore.type.equals(ObjectStoreType.JDBC)) { + } else if (transactions.objectStore().type().equals(ObjectStoreType.JDBC)) { objectStores.forEach(name -> setJDBCObjectStore(name, transactions)); } BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class) - .setRecoveryModuleClassNames(transactions.recoveryModules); + .setRecoveryModuleClassNames(transactions.recoveryModules()); BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class) - .setExpiryScannerClassNames(transactions.expiryScanners); + .setExpiryScannerClassNames(transactions.expiryScanners()); BeanPopulator.getDefaultInstance(JTAEnvironmentBean.class) - .setXaResourceOrphanFilterClassNames(transactions.xaResourceOrphanFilters); + .setXaResourceOrphanFilterClassNames(transactions.xaResourceOrphanFilters()); } /** @@ -145,25 +145,26 @@ public void logUnsafeMultipleLastResourcesOnStartup( } private void setObjectStoreDir(String name, TransactionManagerConfiguration config) { - BeanPopulator.getNamedInstance(ObjectStoreEnvironmentBean.class, name).setObjectStoreDir(config.objectStore.directory); + BeanPopulator.getNamedInstance(ObjectStoreEnvironmentBean.class, name) + .setObjectStoreDir(config.objectStore().directory()); } private void setJDBCObjectStore(String name, TransactionManagerConfiguration config) { final ObjectStoreEnvironmentBean instance = BeanPopulator.getNamedInstance(ObjectStoreEnvironmentBean.class, name); instance.setObjectStoreType(JDBCStore.class.getName()); - instance.setJdbcDataSource(new QuarkusDataSource(config.objectStore.datasource)); - instance.setCreateTable(config.objectStore.createTable); - instance.setDropTable(config.objectStore.dropTable); - instance.setTablePrefix(config.objectStore.tablePrefix); + instance.setJdbcDataSource(new QuarkusDataSource(config.objectStore().datasource())); + instance.setCreateTable(config.objectStore().createTable()); + instance.setDropTable(config.objectStore().dropTable()); + instance.setTablePrefix(config.objectStore().tablePrefix()); } public void startRecoveryService(final TransactionManagerConfiguration transactions, Map configuredDataSourcesConfigKeys, Set dataSourcesWithTransactionIntegration) { - if (transactions.objectStore.type.equals(ObjectStoreType.JDBC)) { + if (transactions.objectStore().type().equals(ObjectStoreType.JDBC)) { final String objectStoreDataSourceName; - if (transactions.objectStore.datasource.isEmpty()) { + if (transactions.objectStore().datasource().isEmpty()) { if (!DataSourceUtil.hasDefault(configuredDataSourcesConfigKeys.keySet())) { throw new ConfigurationException( "The Narayana JTA extension does not have a datasource configured as the JDBC object store," @@ -176,7 +177,7 @@ public void startRecoveryService(final TransactionManagerConfiguration transacti } objectStoreDataSourceName = DataSourceUtil.DEFAULT_DATASOURCE_NAME; } else { - objectStoreDataSourceName = transactions.objectStore.datasource.get(); + objectStoreDataSourceName = transactions.objectStore().datasource().get(); if (!configuredDataSourcesConfigKeys.keySet().contains(objectStoreDataSourceName)) { throw new ConfigurationException( @@ -200,7 +201,7 @@ public void startRecoveryService(final TransactionManagerConfiguration transacti objectStoreDataSourceName, configuredDataSourcesConfigKeys.get(objectStoreDataSourceName))); } } - if (transactions.enableRecovery) { + if (transactions.enableRecovery()) { QuarkusRecoveryService.getInstance().create(); QuarkusRecoveryService.getInstance().start(); } @@ -208,7 +209,7 @@ public void startRecoveryService(final TransactionManagerConfiguration transacti public void handleShutdown(ShutdownContext context, TransactionManagerConfiguration transactions) { context.addShutdownTask(() -> { - if (transactions.enableRecovery) { + if (transactions.enableRecovery()) { try { QuarkusRecoveryService.getInstance().stop(); } catch (Exception e) { diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerBuildTimeConfig.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerBuildTimeConfig.java index 91cbeccf433d6a..aabb4941dd3344 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerBuildTimeConfig.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerBuildTimeConfig.java @@ -2,12 +2,14 @@ import java.util.Optional; -import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigDocDefault; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; @ConfigRoot(phase = ConfigPhase.BUILD_TIME) -public final class TransactionManagerBuildTimeConfig { +@ConfigMapping(prefix = "quarkus.transaction-manager") +public interface TransactionManagerBuildTimeConfig { /** * Define the behavior when using multiple XA unaware resources in the same transactional demarcation. *

    @@ -31,8 +33,8 @@ public final class TransactionManagerBuildTimeConfig { * @deprecated This property is planned for removal in a future version. */ @Deprecated(forRemoval = true) - @ConfigItem(defaultValueDocumentation = "fail") - public Optional unsafeMultipleLastResources; + @ConfigDocDefault("fail") + public Optional unsafeMultipleLastResources(); public enum UnsafeMultipleLastResourcesMode { /** diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerConfiguration.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerConfiguration.java index 5f55cb5b6f8f42..941d280ee87007 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerConfiguration.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerConfiguration.java @@ -5,23 +5,22 @@ import java.util.Optional; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; -/** - * - */ @ConfigRoot(phase = ConfigPhase.RUN_TIME) -public final class TransactionManagerConfiguration { +@ConfigMapping(prefix = "quarkus.transaction-manager") +public interface TransactionManagerConfiguration { /** * The node name used by the transaction manager. * Must not exceed a length of 28 bytes. * * @see #shortenNodeNameIfNecessary */ - @ConfigItem(defaultValue = "quarkus") - public String nodeName; + @WithDefault("quarkus") + String nodeName(); /** * Whether the node name should be shortened if necessary. @@ -31,88 +30,86 @@ public final class TransactionManagerConfiguration { * * @see #nodeName */ - @ConfigItem(defaultValue = "false") - public boolean shortenNodeNameIfNecessary; + @WithDefault("false") + boolean shortenNodeNameIfNecessary(); /** * The default transaction timeout. */ - @ConfigItem(defaultValue = "60") - public Duration defaultTransactionTimeout; + @WithDefault("60") + Duration defaultTransactionTimeout(); /** * Start the recovery service on startup. */ - @ConfigItem(defaultValue = "false") - public boolean enableRecovery; + @WithDefault("false") + boolean enableRecovery(); /** * The list of recovery modules. */ - @ConfigItem(defaultValue = "com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule," + + @WithDefault("com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule," + "com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule") - public List recoveryModules; + List recoveryModules(); /** * The list of expiry scanners. */ - @ConfigItem(defaultValue = "com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner") - public List expiryScanners; + @WithDefault("com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner") + List expiryScanners(); /** * The list of orphan filters. */ - @ConfigItem(defaultValue = "com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter," + + @WithDefault("com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter," + "com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter," + "com.arjuna.ats.internal.jta.recovery.arjunacore.JTAActionStatusServiceXAResourceOrphanFilter") - public List xaResourceOrphanFilters; + List xaResourceOrphanFilters(); /** * The object store configuration. */ - @ConfigItem - public ObjectStoreConfig objectStore; + ObjectStoreConfig objectStore(); @ConfigGroup - public static class ObjectStoreConfig { + public interface ObjectStoreConfig { /** * The name of the directory where the transaction logs will be stored when using the {@code file-system} object store. * If the value is not absolute then the directory is relative * to the user.dir system property. */ - @ConfigItem(defaultValue = "ObjectStore") - public String directory; + @WithDefault("ObjectStore") + String directory(); /** * The type of object store. */ - @ConfigItem(defaultValue = "file-system") - public ObjectStoreType type; + @WithDefault("file-system") + ObjectStoreType type(); /** * The name of the datasource where the transaction logs will be stored when using the {@code jdbc} object store. *

    * If undefined, it will use the default datasource. */ - @ConfigItem - public Optional datasource = Optional.empty(); + Optional datasource(); /** * Whether to create the table if it does not exist. */ - @ConfigItem(defaultValue = "false") - public boolean createTable; + @WithDefault("false") + boolean createTable(); /** * Whether to drop the table on startup. */ - @ConfigItem(defaultValue = "false") - public boolean dropTable; + @WithDefault("false") + boolean dropTable(); /** * The prefix to apply to the table. */ - @ConfigItem(defaultValue = "quarkus_") - public String tablePrefix; + @WithDefault("quarkus_") + String tablePrefix(); } } diff --git a/extensions/narayana-jta/runtime/src/test/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorderTest.java b/extensions/narayana-jta/runtime/src/test/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorderTest.java index 633948c6ab901f..d0cd4a8078ec4a 100644 --- a/extensions/narayana-jta/runtime/src/test/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorderTest.java +++ b/extensions/narayana-jta/runtime/src/test/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorderTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; import org.junit.jupiter.api.Test; @@ -13,35 +14,26 @@ public class NarayanaJtaRecorderTest { public static final String NODE_NAME_TO_SHORTEN = "dfe2420d-b12e-4ec3-92c0-ee7c4"; @Test - void testByteLengthWithLongerString() { - TransactionManagerConfiguration transactions = new TransactionManagerConfiguration(); - transactions.shortenNodeNameIfNecessary = true; + void testByteLengthWithLongerString() throws NoSuchAlgorithmException { // create nodeNames larger than 28 bytes assertTrue(NODE_NAME_TO_SHORTEN.getBytes(StandardCharsets.UTF_8).length > 28); - NarayanaJtaRecorder r = new NarayanaJtaRecorder(); - transactions.nodeName = NODE_NAME_TO_SHORTEN; - r.setNodeName(transactions); - int numberOfBytes = transactions.nodeName.getBytes(StandardCharsets.UTF_8).length; + NarayanaJtaRecorder recorder = new NarayanaJtaRecorder(); + String shorterNodeName = recorder.shortenNodeName(NODE_NAME_TO_SHORTEN); + int numberOfBytes = shorterNodeName.getBytes(StandardCharsets.UTF_8).length; assertEquals(28, numberOfBytes, "node name bytes was not 28 bytes limit, number of bytes is " + numberOfBytes); } @Test - void testPredictableConversion() { - TransactionManagerConfiguration transactions = new TransactionManagerConfiguration(); - transactions.shortenNodeNameIfNecessary = true; + void testPredictableConversion() throws NoSuchAlgorithmException { assertTrue(NODE_NAME_TO_SHORTEN.getBytes(StandardCharsets.UTF_8).length > 28); - NarayanaJtaRecorder r = new NarayanaJtaRecorder(); - transactions.nodeName = NODE_NAME_TO_SHORTEN; - r.setNodeName(transactions); - int numberOfBytes = transactions.nodeName.getBytes(StandardCharsets.UTF_8).length; + NarayanaJtaRecorder recorder = new NarayanaJtaRecorder(); + String firstConversion = recorder.shortenNodeName(NODE_NAME_TO_SHORTEN); + int numberOfBytes = firstConversion.getBytes(StandardCharsets.UTF_8).length; assertEquals(28, numberOfBytes, "node name bytes was not 28 bytes limit, number of bytes is " + numberOfBytes); - String firstConversion = transactions.nodeName; - transactions.nodeName = NODE_NAME_TO_SHORTEN; - r.setNodeName(transactions); - String secondConversion = transactions.nodeName; - numberOfBytes = transactions.nodeName.getBytes(StandardCharsets.UTF_8).length; + String secondConversion = recorder.shortenNodeName(NODE_NAME_TO_SHORTEN); + numberOfBytes = secondConversion.getBytes(StandardCharsets.UTF_8).length; assertEquals(28, numberOfBytes, "node name bytes was not 28 bytes limit, number of bytes is " + numberOfBytes); assertEquals(firstConversion, secondConversion, diff --git a/extensions/narayana-lra/deployment/pom.xml b/extensions/narayana-lra/deployment/pom.xml index ff54319bb966b3..61e90ac03ed266 100644 --- a/extensions/narayana-lra/deployment/pom.xml +++ b/extensions/narayana-lra/deployment/pom.xml @@ -67,9 +67,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/LRABuildTimeConfiguration.java b/extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/LRABuildTimeConfiguration.java index b694109c91e6c1..9191e00127b503 100644 --- a/extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/LRABuildTimeConfiguration.java +++ b/extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/LRABuildTimeConfiguration.java @@ -1,18 +1,22 @@ package io.quarkus.narayana.lra.deployment; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithName; /** * LRA build time configuration properties */ @ConfigRoot(phase = ConfigPhase.BUILD_TIME) -public final class LRABuildTimeConfiguration { +@ConfigMapping(prefix = "quarkus.lra") +public interface LRABuildTimeConfiguration { /** * Whether to include LRA proxy endpoints in the generated OpenAPI document */ - @ConfigItem(name = "openapi.included", defaultValue = "false") - public boolean openapiIncluded; + @WithName("openapi.included") + @WithDefault("false") + boolean openapiIncluded(); } diff --git a/extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/NarayanaLRAProcessor.java b/extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/NarayanaLRAProcessor.java index 5a702ddd986b4c..103a0b99d52289 100644 --- a/extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/NarayanaLRAProcessor.java +++ b/extensions/narayana-lra/deployment/src/main/java/io/quarkus/narayana/lra/deployment/NarayanaLRAProcessor.java @@ -160,7 +160,7 @@ public void filterOpenAPIEndpoint(BuildProducer Capabilities capabilities, LRABuildTimeConfiguration lraBuildTimeConfig) { if (capabilities.isPresent(Capability.SMALLRYE_OPENAPI)) { - NarayanaLRAOpenAPIFilter lraOpenAPIFilter = new NarayanaLRAOpenAPIFilter(lraBuildTimeConfig.openapiIncluded); + NarayanaLRAOpenAPIFilter lraOpenAPIFilter = new NarayanaLRAOpenAPIFilter(lraBuildTimeConfig.openapiIncluded()); openAPIProducer.produce(new AddToOpenAPIDefinitionBuildItem(lraOpenAPIFilter)); } } diff --git a/extensions/narayana-lra/runtime/pom.xml b/extensions/narayana-lra/runtime/pom.xml index 5d0deec48dcd26..71cd38a0e1bb02 100644 --- a/extensions/narayana-lra/runtime/pom.xml +++ b/extensions/narayana-lra/runtime/pom.xml @@ -92,9 +92,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/narayana-lra/runtime/src/main/java/io/quarkus/narayana/lra/runtime/LRAConfiguration.java b/extensions/narayana-lra/runtime/src/main/java/io/quarkus/narayana/lra/runtime/LRAConfiguration.java index 5539ecd1e56bb6..7af69d0a0fefdd 100644 --- a/extensions/narayana-lra/runtime/src/main/java/io/quarkus/narayana/lra/runtime/LRAConfiguration.java +++ b/extensions/narayana-lra/runtime/src/main/java/io/quarkus/narayana/lra/runtime/LRAConfiguration.java @@ -1,14 +1,16 @@ package io.quarkus.narayana.lra.runtime; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; /** * Configuration properties for controlling LRA participants */ @ConfigRoot(phase = ConfigPhase.RUN_TIME) -public final class LRAConfiguration { +@ConfigMapping(prefix = "quarkus.lra") +public interface LRAConfiguration { /** * The REST endpoint on which a coordinator is running. * In order for an LRA to begin and end successfully and in order to @@ -18,6 +20,6 @@ public final class LRAConfiguration { * In this version of the extension, a failed coordinator with * LRAs that have not yet finished must be restarted. */ - @ConfigItem(defaultValue = "http://localhost:50000/lra-coordinator") - String coordinatorURL; + @WithDefault("http://localhost:50000/lra-coordinator") + String coordinatorURL(); } diff --git a/extensions/narayana-lra/runtime/src/main/java/io/quarkus/narayana/lra/runtime/NarayanaLRARecorder.java b/extensions/narayana-lra/runtime/src/main/java/io/quarkus/narayana/lra/runtime/NarayanaLRARecorder.java index 1f3a4868a77dd0..3fdea0a20a3bdf 100644 --- a/extensions/narayana-lra/runtime/src/main/java/io/quarkus/narayana/lra/runtime/NarayanaLRARecorder.java +++ b/extensions/narayana-lra/runtime/src/main/java/io/quarkus/narayana/lra/runtime/NarayanaLRARecorder.java @@ -19,7 +19,7 @@ public class NarayanaLRARecorder { public void setConfig(final LRAConfiguration config) { if (System.getProperty(NarayanaLRAClient.LRA_COORDINATOR_URL_KEY) == null) { - System.setProperty(NarayanaLRAClient.LRA_COORDINATOR_URL_KEY, config.coordinatorURL); + System.setProperty(NarayanaLRAClient.LRA_COORDINATOR_URL_KEY, config.coordinatorURL()); } } From 835f8091c417f7fdb05ae953cd3d44b88318c571 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 4 Feb 2025 18:35:35 +0100 Subject: [PATCH 10/10] Liquibase - Switch to @ConfigMapping --- .../liquibase-mongodb/deployment/pom.xml | 3 - .../deployment/LiquibaseMongodbProcessor.java | 2 +- extensions/liquibase-mongodb/runtime/pom.xml | 3 - .../mongodb/LiquibaseMongodbFactory.java | 34 +-- .../LiquibaseMongodbBuildTimeConfig.java | 15 +- .../runtime/LiquibaseMongodbConfig.java | 49 ++--- .../runtime/LiquibaseMongodbRecorder.java | 12 +- extensions/liquibase/deployment/pom.xml | 3 - .../deployment/LiquibaseProcessor.java | 12 +- .../test/LiquibaseExtensionConfigFixture.java | 2 +- extensions/liquibase/runtime/pom.xml | 3 - .../runtime/LiquibaseBuildTimeConfig.java | 45 +--- .../liquibase/runtime/LiquibaseConfig.java | 3 - .../liquibase/runtime/LiquibaseCreator.java | 44 ++-- .../LiquibaseDataSourceBuildTimeConfig.java | 23 +- .../LiquibaseDataSourceRuntimeConfig.java | 70 ++---- .../runtime/LiquibaseFactoryProducer.java | 8 +- .../liquibase/runtime/LiquibaseRecorder.java | 12 +- .../runtime/LiquibaseRuntimeConfig.java | 48 ++-- .../runtime/LiquibaseCreatorTest.java | 208 ------------------ 20 files changed, 142 insertions(+), 457 deletions(-) delete mode 100644 extensions/liquibase/runtime/src/test/java/io/quarkus/liquibase/runtime/LiquibaseCreatorTest.java diff --git a/extensions/liquibase-mongodb/deployment/pom.xml b/extensions/liquibase-mongodb/deployment/pom.xml index cc4f53053719eb..33d685500b95dd 100644 --- a/extensions/liquibase-mongodb/deployment/pom.xml +++ b/extensions/liquibase-mongodb/deployment/pom.xml @@ -48,9 +48,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/liquibase-mongodb/deployment/src/main/java/io/quarkus/liquibase/mongodb/deployment/LiquibaseMongodbProcessor.java b/extensions/liquibase-mongodb/deployment/src/main/java/io/quarkus/liquibase/mongodb/deployment/LiquibaseMongodbProcessor.java index 345a99cc7be1cd..863e6f6914372c 100644 --- a/extensions/liquibase-mongodb/deployment/src/main/java/io/quarkus/liquibase/mongodb/deployment/LiquibaseMongodbProcessor.java +++ b/extensions/liquibase-mongodb/deployment/src/main/java/io/quarkus/liquibase/mongodb/deployment/LiquibaseMongodbProcessor.java @@ -265,7 +265,7 @@ private List getChangeLogs(LiquibaseMongodbBuildTimeConfig liquibaseBuil Thread.currentThread().getContextClassLoader())) { Set resources = new LinkedHashSet<>( - findAllChangeLogFiles(liquibaseBuildConfig.changeLog, changeLogParserFactory, + findAllChangeLogFiles(liquibaseBuildConfig.changeLog(), changeLogParserFactory, classLoaderResourceAccessor, changeLogParameters)); LOGGER.debugf("Liquibase changeLogs: %s", resources); diff --git a/extensions/liquibase-mongodb/runtime/pom.xml b/extensions/liquibase-mongodb/runtime/pom.xml index df90bef0fcdebe..856a9fd6f3bdeb 100644 --- a/extensions/liquibase-mongodb/runtime/pom.xml +++ b/extensions/liquibase-mongodb/runtime/pom.xml @@ -81,9 +81,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/LiquibaseMongodbFactory.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/LiquibaseMongodbFactory.java index 0286f923a9614c..1b49ab8791d1f0 100644 --- a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/LiquibaseMongodbFactory.java +++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/LiquibaseMongodbFactory.java @@ -44,20 +44,20 @@ private ResourceAccessor resolveResourceAccessor() throws FileNotFoundException compositeResourceAccessor .addResourceAccessor(new ClassLoaderResourceAccessor(Thread.currentThread().getContextClassLoader())); - if (!liquibaseMongodbBuildTimeConfig.changeLog.startsWith("filesystem:") - && liquibaseMongodbBuildTimeConfig.searchPath.isEmpty()) { + if (!liquibaseMongodbBuildTimeConfig.changeLog().startsWith("filesystem:") + && liquibaseMongodbBuildTimeConfig.searchPath().isEmpty()) { return compositeResourceAccessor; } - if (liquibaseMongodbBuildTimeConfig.searchPath.isEmpty()) { + if (liquibaseMongodbBuildTimeConfig.searchPath().isEmpty()) { compositeResourceAccessor.addResourceAccessor( new DirectoryResourceAccessor( - Paths.get(StringUtil.changePrefix(liquibaseMongodbBuildTimeConfig.changeLog, "filesystem:", "")) + Paths.get(StringUtil.changePrefix(liquibaseMongodbBuildTimeConfig.changeLog(), "filesystem:", "")) .getParent())); return compositeResourceAccessor; } - for (String searchPath : liquibaseMongodbBuildTimeConfig.searchPath.get()) { + for (String searchPath : liquibaseMongodbBuildTimeConfig.searchPath().get()) { compositeResourceAccessor.addResourceAccessor(new DirectoryResourceAccessor(Paths.get(searchPath))); } @@ -66,7 +66,7 @@ private ResourceAccessor resolveResourceAccessor() throws FileNotFoundException private String parseChangeLog(String changeLog) { - if (changeLog.startsWith("filesystem:") && liquibaseMongodbBuildTimeConfig.searchPath.isEmpty()) { + if (changeLog.startsWith("filesystem:") && liquibaseMongodbBuildTimeConfig.searchPath().isEmpty()) { return Paths.get(StringUtil.changePrefix(changeLog, "filesystem:", "")).getFileName().toString(); } @@ -83,7 +83,7 @@ private String parseChangeLog(String changeLog) { public Liquibase createLiquibase() { try (ResourceAccessor resourceAccessor = resolveResourceAccessor()) { - String parsedChangeLog = parseChangeLog(liquibaseMongodbBuildTimeConfig.changeLog); + String parsedChangeLog = parseChangeLog(liquibaseMongodbBuildTimeConfig.changeLog()); String connectionString = this.mongoClientConfig.connectionString.orElse("mongodb://localhost:27017"); // Every MongoDB client configuration must be added to the connection string, we didn't add all as it would be too much to support. @@ -121,20 +121,20 @@ public Liquibase createLiquibase() { null, resourceAccessor); if (database != null) { - liquibaseMongodbConfig.liquibaseCatalogName.ifPresent(database::setLiquibaseCatalogName); - liquibaseMongodbConfig.liquibaseSchemaName.ifPresent(database::setLiquibaseSchemaName); - liquibaseMongodbConfig.liquibaseTablespaceName.ifPresent(database::setLiquibaseTablespaceName); + liquibaseMongodbConfig.liquibaseCatalogName().ifPresent(database::setLiquibaseCatalogName); + liquibaseMongodbConfig.liquibaseSchemaName().ifPresent(database::setLiquibaseSchemaName); + liquibaseMongodbConfig.liquibaseTablespaceName().ifPresent(database::setLiquibaseTablespaceName); - if (liquibaseMongodbConfig.defaultCatalogName.isPresent()) { - database.setDefaultCatalogName(liquibaseMongodbConfig.defaultCatalogName.get()); + if (liquibaseMongodbConfig.defaultCatalogName().isPresent()) { + database.setDefaultCatalogName(liquibaseMongodbConfig.defaultCatalogName().get()); } - if (liquibaseMongodbConfig.defaultSchemaName.isPresent()) { - database.setDefaultSchemaName(liquibaseMongodbConfig.defaultSchemaName.get()); + if (liquibaseMongodbConfig.defaultSchemaName().isPresent()) { + database.setDefaultSchemaName(liquibaseMongodbConfig.defaultSchemaName().get()); } } Liquibase liquibase = new Liquibase(parsedChangeLog, resourceAccessor, database); - for (Map.Entry entry : liquibaseMongodbConfig.changeLogParameters.entrySet()) { + for (Map.Entry entry : liquibaseMongodbConfig.changeLogParameters().entrySet()) { liquibase.getChangeLogParameters().set(entry.getKey(), entry.getValue()); } @@ -155,7 +155,7 @@ public LiquibaseMongodbConfig getConfiguration() { * @return the label expression */ public LabelExpression createLabels() { - return new LabelExpression(liquibaseMongodbConfig.labels.orElse(null)); + return new LabelExpression(liquibaseMongodbConfig.labels().orElse(null)); } /** @@ -164,6 +164,6 @@ public LabelExpression createLabels() { * @return the contexts */ public Contexts createContexts() { - return new Contexts(liquibaseMongodbConfig.contexts.orElse(null)); + return new Contexts(liquibaseMongodbConfig.contexts().orElse(null)); } } diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbBuildTimeConfig.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbBuildTimeConfig.java index a06832603b4af2..c483d268003a85 100644 --- a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbBuildTimeConfig.java +++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbBuildTimeConfig.java @@ -3,25 +3,26 @@ import java.util.List; import java.util.Optional; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; /** * The liquibase configuration */ -@ConfigRoot(name = "liquibase-mongodb", phase = ConfigPhase.BUILD_TIME) -public class LiquibaseMongodbBuildTimeConfig { +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +@ConfigMapping(prefix = "quarkus.liquibase-mongodb") +public interface LiquibaseMongodbBuildTimeConfig { /** * The change log file */ - @ConfigItem(defaultValue = "db/changeLog.xml") - public String changeLog; + @WithDefault("db/changeLog.xml") + String changeLog(); /** * The search path for DirectoryResourceAccessor */ - @ConfigItem - public Optional> searchPath; + Optional> searchPath(); } diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbConfig.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbConfig.java index 00a3c8d7e3eaa4..41f36265787c29 100644 --- a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbConfig.java +++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbConfig.java @@ -1,91 +1,84 @@ package io.quarkus.liquibase.mongodb.runtime; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; /** * The liquibase configuration */ -@ConfigRoot(name = "liquibase-mongodb", phase = ConfigPhase.RUN_TIME) -public class LiquibaseMongodbConfig { +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +@ConfigMapping(prefix = "quarkus.liquibase-mongodb") +public interface LiquibaseMongodbConfig { /** * Flag to enable / disable Liquibase. * */ - @ConfigItem(defaultValue = "true") - public boolean enabled; + @WithDefault("true") + boolean enabled(); /** * The migrate at start flag */ - @ConfigItem - public boolean migrateAtStart; + @WithDefault("false") + boolean migrateAtStart(); /** * The validate on update flag */ - @ConfigItem(defaultValue = "true") - public boolean validateOnMigrate; + @WithDefault("true") + boolean validateOnMigrate(); /** * The clean at start flag */ - @ConfigItem - public boolean cleanAtStart; + @WithDefault("false") + boolean cleanAtStart(); /** * The parameters to be passed to the changelog. * Defined as key value pairs. */ - @ConfigItem - public Map changeLogParameters = new HashMap<>();; + Map changeLogParameters(); /** * The list of contexts */ - @ConfigItem - public Optional> contexts = Optional.empty(); + Optional> contexts(); /** * The list of labels */ - @ConfigItem - public Optional> labels = Optional.empty(); + Optional> labels(); /** * The default catalog name */ - @ConfigItem - public Optional defaultCatalogName = Optional.empty(); + Optional defaultCatalogName(); /** * The default schema name */ - @ConfigItem - public Optional defaultSchemaName = Optional.empty(); + Optional defaultSchemaName(); /** * The liquibase tables catalog name */ - @ConfigItem - public Optional liquibaseCatalogName = Optional.empty(); + Optional liquibaseCatalogName(); /** * The liquibase tables schema name */ - @ConfigItem - public Optional liquibaseSchemaName = Optional.empty(); + Optional liquibaseSchemaName(); /** * The liquibase tables tablespace name */ - @ConfigItem - public Optional liquibaseTablespaceName = Optional.empty(); + Optional liquibaseTablespaceName(); } diff --git a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbRecorder.java b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbRecorder.java index 226c068640d49e..588384bc636e71 100644 --- a/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbRecorder.java +++ b/extensions/liquibase-mongodb/runtime/src/main/java/io/quarkus/liquibase/mongodb/runtime/LiquibaseMongodbRecorder.java @@ -34,7 +34,7 @@ public LiquibaseMongodbFactory get() { } public void doStartActions() { - if (!config.getValue().enabled) { + if (!config.getValue().enabled()) { return; } try { @@ -48,18 +48,18 @@ public void doStartActions() { try { LiquibaseMongodbFactory liquibaseFactory = liquibaseFactoryHandle.get(); - if (!liquibaseFactory.getConfiguration().cleanAtStart - && !liquibaseFactory.getConfiguration().migrateAtStart) { + if (!liquibaseFactory.getConfiguration().cleanAtStart() + && !liquibaseFactory.getConfiguration().migrateAtStart()) { // Don't initialize if no clean or migration required at start return; } try (Liquibase liquibase = liquibaseFactory.createLiquibase()) { - if (liquibaseFactory.getConfiguration().cleanAtStart) { + if (liquibaseFactory.getConfiguration().cleanAtStart()) { liquibase.dropAll(); } - if (liquibaseFactory.getConfiguration().migrateAtStart) { - if (liquibaseFactory.getConfiguration().validateOnMigrate) { + if (liquibaseFactory.getConfiguration().migrateAtStart()) { + if (liquibaseFactory.getConfiguration().validateOnMigrate()) { liquibase.validate(); } liquibase.update(liquibaseFactory.createContexts(), liquibaseFactory.createLabels()); diff --git a/extensions/liquibase/deployment/pom.xml b/extensions/liquibase/deployment/pom.xml index c41fc61187a3ee..7d7ea5f1933b26 100644 --- a/extensions/liquibase/deployment/pom.xml +++ b/extensions/liquibase/deployment/pom.xml @@ -74,9 +74,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java index b6587fb184fc37..c733f25229c21f 100644 --- a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java +++ b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java @@ -336,14 +336,8 @@ private List getChangeLogs(Collection dataSourceNames, Liquibase List liquibaseDataSources = new ArrayList<>(); - if (DataSourceUtil.hasDefault(dataSourceNames)) { - liquibaseDataSources.add(liquibaseBuildConfig.defaultDataSource); - } - for (String dataSourceName : dataSourceNames) { - if (!DataSourceUtil.isDefault(dataSourceName)) { - liquibaseDataSources.add(liquibaseBuildConfig.getConfigForDataSourceName(dataSourceName)); - } + liquibaseDataSources.add(liquibaseBuildConfig.datasources().get(dataSourceName)); } ChangeLogParameters changeLogParameters = new ChangeLogParameters(); @@ -351,8 +345,8 @@ private List getChangeLogs(Collection dataSourceNames, Liquibase Set resources = new LinkedHashSet<>(); for (LiquibaseDataSourceBuildTimeConfig liquibaseDataSourceConfig : liquibaseDataSources) { - Optional> oSearchPaths = liquibaseDataSourceConfig.searchPath; - String changeLog = liquibaseDataSourceConfig.changeLog; + Optional> oSearchPaths = liquibaseDataSourceConfig.searchPath(); + String changeLog = liquibaseDataSourceConfig.changeLog(); String parsedChangeLog = parseChangeLog(oSearchPaths, changeLog); try (ResourceAccessor resourceAccessor = resolveResourceAccessor(oSearchPaths, changeLog)) { diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigFixture.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigFixture.java index 1e4f916ab50d90..e33cc9cb867fd6 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigFixture.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigFixture.java @@ -48,7 +48,7 @@ public void assertAllConfigurationSettings(LiquibaseConfig configuration, String public void assertDefaultConfigurationSettings(LiquibaseConfig configuration) { - assertEquals(configuration.changeLog, LiquibaseDataSourceBuildTimeConfig.defaultConfig().changeLog); + assertEquals(configuration.changeLog, LiquibaseDataSourceBuildTimeConfig.DEFAULT_CHANGE_LOG); assertEquals(configuration.databaseChangeLogTableName, GlobalConfiguration.DATABASECHANGELOG_TABLE_NAME.getCurrentValue()); diff --git a/extensions/liquibase/runtime/pom.xml b/extensions/liquibase/runtime/pom.xml index 2e094d6c9d4e3c..7cf7e6533a7bc6 100644 --- a/extensions/liquibase/runtime/pom.xml +++ b/extensions/liquibase/runtime/pom.xml @@ -93,9 +93,6 @@ ${project.version} - - -AlegacyConfigRoot=true - diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseBuildTimeConfig.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseBuildTimeConfig.java index b153b8dcd4c207..a0290bfc8691c2 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseBuildTimeConfig.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseBuildTimeConfig.java @@ -1,52 +1,31 @@ package io.quarkus.liquibase.runtime; -import java.util.Collections; import java.util.Map; import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefaults; +import io.smallrye.config.WithParentName; +import io.smallrye.config.WithUnnamedKey; /** * The liquibase build time configuration */ -@ConfigRoot(name = "liquibase", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) -public final class LiquibaseBuildTimeConfig { +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +@ConfigMapping(prefix = "quarkus.liquibase") +public interface LiquibaseBuildTimeConfig { /** - * Gets the default build time configuration - * - * @return the liquibase build time default configuration + * Datasources. */ - public static LiquibaseBuildTimeConfig defaultConfig() { - LiquibaseBuildTimeConfig defaultConfig = new LiquibaseBuildTimeConfig(); - defaultConfig.defaultDataSource = LiquibaseDataSourceBuildTimeConfig.defaultConfig(); - return defaultConfig; - } - - /** - * Gets the {@link LiquibaseBuildTimeConfig} for the given datasource name. - */ - public LiquibaseDataSourceBuildTimeConfig getConfigForDataSourceName(String dataSourceName) { - return DataSourceUtil.isDefault(dataSourceName) - ? defaultDataSource - : namedDataSources.getOrDefault(dataSourceName, LiquibaseDataSourceBuildTimeConfig.defaultConfig()); - } - - /** - * Liquibase configuration for the default datasource. - */ - @ConfigItem(name = ConfigItem.PARENT) - public LiquibaseDataSourceBuildTimeConfig defaultDataSource; - - /** - * Named datasources. - */ - @ConfigItem(name = ConfigItem.PARENT) @ConfigDocMapKey("datasource-name") @ConfigDocSection - public Map namedDataSources = Collections.emptyMap(); + @WithParentName + @WithUnnamedKey(DataSourceUtil.DEFAULT_DATASOURCE_NAME) + @WithDefaults + public Map datasources(); } diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseConfig.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseConfig.java index 55d036b5562810..a9fc7b70e74690 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseConfig.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseConfig.java @@ -8,8 +8,6 @@ import java.util.Map; import java.util.Optional; -import io.quarkus.runtime.annotations.ConfigDocMapKey; - /** * The liquibase configuration */ @@ -50,7 +48,6 @@ public class LiquibaseConfig { */ public List labels = null; - @ConfigDocMapKey("parameter-name") public Map changeLogParameters = null; /** diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseCreator.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseCreator.java index 5dfae13603e4f3..5915420bc1e7db 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseCreator.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseCreator.java @@ -17,33 +17,29 @@ public LiquibaseCreator(LiquibaseDataSourceRuntimeConfig liquibaseRuntimeConfig, public LiquibaseFactory createLiquibaseFactory(DataSource dataSource, String dataSourceName) { LiquibaseConfig config = new LiquibaseConfig(); - config.changeLog = liquibaseBuildTimeConfig.changeLog; - config.searchPath = liquibaseBuildTimeConfig.searchPath; - config.changeLogParameters = liquibaseRuntimeConfig.changeLogParameters; + config.changeLog = liquibaseBuildTimeConfig.changeLog(); + config.searchPath = liquibaseBuildTimeConfig.searchPath(); + config.changeLogParameters = liquibaseRuntimeConfig.changeLogParameters(); - if (liquibaseRuntimeConfig.labels.isPresent()) { - config.labels = liquibaseRuntimeConfig.labels.get(); + if (liquibaseRuntimeConfig.labels().isPresent()) { + config.labels = liquibaseRuntimeConfig.labels().get(); } - if (liquibaseRuntimeConfig.contexts.isPresent()) { - config.contexts = liquibaseRuntimeConfig.contexts.get(); + if (liquibaseRuntimeConfig.contexts().isPresent()) { + config.contexts = liquibaseRuntimeConfig.contexts().get(); } - if (liquibaseRuntimeConfig.databaseChangeLogLockTableName.isPresent()) { - config.databaseChangeLogLockTableName = liquibaseRuntimeConfig.databaseChangeLogLockTableName.get(); - } - if (liquibaseRuntimeConfig.databaseChangeLogTableName.isPresent()) { - config.databaseChangeLogTableName = liquibaseRuntimeConfig.databaseChangeLogTableName.get(); - } - config.password = liquibaseRuntimeConfig.password; - config.username = liquibaseRuntimeConfig.username; - config.defaultSchemaName = liquibaseRuntimeConfig.defaultSchemaName; - config.defaultCatalogName = liquibaseRuntimeConfig.defaultCatalogName; - config.liquibaseTablespaceName = liquibaseRuntimeConfig.liquibaseTablespaceName; - config.liquibaseSchemaName = liquibaseRuntimeConfig.liquibaseSchemaName; - config.liquibaseCatalogName = liquibaseRuntimeConfig.liquibaseCatalogName; - config.migrateAtStart = liquibaseRuntimeConfig.migrateAtStart; - config.cleanAtStart = liquibaseRuntimeConfig.cleanAtStart; - config.validateOnMigrate = liquibaseRuntimeConfig.validateOnMigrate; - config.allowDuplicatedChangesetIdentifiers = liquibaseRuntimeConfig.allowDuplicatedChangesetIdentifiers; + config.databaseChangeLogLockTableName = liquibaseRuntimeConfig.databaseChangeLogLockTableName(); + config.databaseChangeLogTableName = liquibaseRuntimeConfig.databaseChangeLogTableName(); + config.password = liquibaseRuntimeConfig.password(); + config.username = liquibaseRuntimeConfig.username(); + config.defaultSchemaName = liquibaseRuntimeConfig.defaultSchemaName(); + config.defaultCatalogName = liquibaseRuntimeConfig.defaultCatalogName(); + config.liquibaseTablespaceName = liquibaseRuntimeConfig.liquibaseTablespaceName(); + config.liquibaseSchemaName = liquibaseRuntimeConfig.liquibaseSchemaName(); + config.liquibaseCatalogName = liquibaseRuntimeConfig.liquibaseCatalogName(); + config.migrateAtStart = liquibaseRuntimeConfig.migrateAtStart(); + config.cleanAtStart = liquibaseRuntimeConfig.cleanAtStart(); + config.validateOnMigrate = liquibaseRuntimeConfig.validateOnMigrate(); + config.allowDuplicatedChangesetIdentifiers = liquibaseRuntimeConfig.allowDuplicatedChangesetIdentifiers(); return new LiquibaseFactory(config, dataSource, dataSourceName); } } diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseDataSourceBuildTimeConfig.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseDataSourceBuildTimeConfig.java index f4d9c03c3ae441..a9818c6de7d064 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseDataSourceBuildTimeConfig.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseDataSourceBuildTimeConfig.java @@ -4,37 +4,24 @@ import java.util.Optional; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; +import io.smallrye.config.WithDefault; /** * The liquibase data source build time configuration */ @ConfigGroup -public final class LiquibaseDataSourceBuildTimeConfig { +public interface LiquibaseDataSourceBuildTimeConfig { static final String DEFAULT_CHANGE_LOG = "db/changeLog.xml"; - /** - * Creates a {@link LiquibaseDataSourceBuildTimeConfig} with default settings. - * - * @return {@link LiquibaseDataSourceBuildTimeConfig} - */ - public static final LiquibaseDataSourceBuildTimeConfig defaultConfig() { - LiquibaseDataSourceBuildTimeConfig defaultConfig = new LiquibaseDataSourceBuildTimeConfig(); - defaultConfig.changeLog = DEFAULT_CHANGE_LOG; - defaultConfig.searchPath = Optional.empty(); - return defaultConfig; - } - /** * The liquibase change log file. All included change log files in this file are scanned and add to the projects. */ - @ConfigItem(defaultValue = DEFAULT_CHANGE_LOG) - public String changeLog; + @WithDefault(DEFAULT_CHANGE_LOG) + String changeLog(); /** * The search path for DirectoryResourceAccessor */ - @ConfigItem - public Optional> searchPath; + Optional> searchPath(); } diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseDataSourceRuntimeConfig.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseDataSourceRuntimeConfig.java index 6dcc0f87f97d0b..5556b09e99a90a 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseDataSourceRuntimeConfig.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseDataSourceRuntimeConfig.java @@ -1,19 +1,18 @@ package io.quarkus.liquibase.runtime; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigGroup; -import io.quarkus.runtime.annotations.ConfigItem; +import io.smallrye.config.WithDefault; /** * The liquibase data source runtime time configuration */ @ConfigGroup -public final class LiquibaseDataSourceRuntimeConfig { +public interface LiquibaseDataSourceRuntimeConfig { /** * The default liquibase lock table @@ -25,120 +24,97 @@ public final class LiquibaseDataSourceRuntimeConfig { */ static final String DEFAULT_LOG_TABLE = "DATABASECHANGELOG"; - /** - * Creates a {@link LiquibaseDataSourceRuntimeConfig} with default settings. - * - * @return {@link LiquibaseDataSourceRuntimeConfig} - */ - public static final LiquibaseDataSourceRuntimeConfig defaultConfig() { - LiquibaseDataSourceRuntimeConfig config = new LiquibaseDataSourceRuntimeConfig(); - config.databaseChangeLogLockTableName = Optional.of(DEFAULT_LOCK_TABLE); - config.databaseChangeLogTableName = Optional.of(DEFAULT_LOG_TABLE); - return config; - } - /** * {@code true} to execute Liquibase automatically when the application starts, {@code false} otherwise. * */ - @ConfigItem - public boolean migrateAtStart; + @WithDefault("false") + boolean migrateAtStart(); /** * {@code true} to validate the applied changes against the available ones, {@code false} otherwise. It is only used if * {@code migration-at-start} is {@code true} * */ - @ConfigItem(defaultValue = "true") - public boolean validateOnMigrate; + @WithDefault("true") + boolean validateOnMigrate(); /** * {@code true} to execute Liquibase clean command automatically when the application starts, {@code false} otherwise. * */ - @ConfigItem - public boolean cleanAtStart; + @WithDefault("false") + boolean cleanAtStart(); /** * Comma-separated case-sensitive list of ChangeSet contexts to execute for liquibase. */ - @ConfigItem - public Optional> contexts = Optional.empty(); + Optional> contexts(); /** * Comma-separated case-sensitive list of expressions defining labeled ChangeSet to execute for liquibase. */ - @ConfigItem - public Optional> labels = Optional.empty(); + Optional> labels(); /** * Map of parameters that can be used inside Liquibase changeLog files. */ - @ConfigItem @ConfigDocMapKey("parameter-name") - public Map changeLogParameters = new HashMap<>(); + Map changeLogParameters(); /** * The liquibase change log lock table name. Name of table to use for tracking concurrent Liquibase usage. */ - @ConfigItem(defaultValue = DEFAULT_LOCK_TABLE) - public Optional databaseChangeLogLockTableName = Optional.empty(); + @WithDefault(DEFAULT_LOCK_TABLE) + String databaseChangeLogLockTableName(); /** * The liquibase change log table name. Name of table to use for tracking change history. */ - @ConfigItem(defaultValue = DEFAULT_LOG_TABLE) - public Optional databaseChangeLogTableName = Optional.empty(); + @WithDefault(DEFAULT_LOG_TABLE) + String databaseChangeLogTableName(); /** * The name of Liquibase's default catalog. */ - @ConfigItem - public Optional defaultCatalogName = Optional.empty(); + Optional defaultCatalogName(); /** * The name of Liquibase's default schema. Overwrites the default schema name * (returned by the RDBMS) with a different database schema. */ - @ConfigItem - public Optional defaultSchemaName = Optional.empty(); + Optional defaultSchemaName(); /** * The username that Liquibase uses to connect to the database. * If no specific username is configured, falls back to the datasource username and password. */ - @ConfigItem - public Optional username = Optional.empty(); + Optional username(); /** * The password that Liquibase uses to connect to the database. * If no specific password is configured, falls back to the datasource username and password. */ - @ConfigItem - public Optional password = Optional.empty(); + Optional password(); /** * The name of the catalog with the liquibase tables. */ - @ConfigItem - public Optional liquibaseCatalogName = Optional.empty(); + Optional liquibaseCatalogName(); /** * The name of the schema with the liquibase tables. */ - @ConfigItem - public Optional liquibaseSchemaName = Optional.empty(); + Optional liquibaseSchemaName(); /** * The name of the tablespace where the -LOG and -LOCK tables will be created (if they do not exist yet). */ - @ConfigItem - public Optional liquibaseTablespaceName = Optional.empty(); + Optional liquibaseTablespaceName(); /** * Allows duplicated changeset identifiers without failing Liquibase execution. */ - @ConfigItem - public Optional allowDuplicatedChangesetIdentifiers = Optional.empty(); + Optional allowDuplicatedChangesetIdentifiers(); } diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseFactoryProducer.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseFactoryProducer.java index ae368b0ac4b95c..4ab86056dc588d 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseFactoryProducer.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseFactoryProducer.java @@ -27,10 +27,10 @@ public LiquibaseFactoryProducer(LiquibaseBuildTimeConfig liquibaseBuildTimeConfi } public LiquibaseFactory createLiquibaseFactory(DataSource dataSource, String dataSourceName) { - LiquibaseDataSourceBuildTimeConfig matchingBuildTimeConfig = liquibaseBuildTimeConfig - .getConfigForDataSourceName(dataSourceName); - LiquibaseDataSourceRuntimeConfig matchingRuntimeConfig = liquibaseRuntimeConfig - .getConfigForDataSourceName(dataSourceName); + LiquibaseDataSourceBuildTimeConfig matchingBuildTimeConfig = liquibaseBuildTimeConfig.datasources() + .get(dataSourceName); + LiquibaseDataSourceRuntimeConfig matchingRuntimeConfig = liquibaseRuntimeConfig.datasources() + .get(dataSourceName); return new LiquibaseCreator(matchingRuntimeConfig, matchingBuildTimeConfig) .createLiquibaseFactory(dataSource, dataSourceName); } diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java index 8334c79ae0aaa8..c0f217bb77b429 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java @@ -68,12 +68,12 @@ public LiquibaseFactory apply(SyntheticCreationalContext conte } public void doStartActions(String dataSourceName) { - if (!config.getValue().enabled) { + if (!config.getValue().enabled()) { return; } - var dataSourceConfig = config.getValue().getConfigForDataSourceName(dataSourceName); - if (!dataSourceConfig.cleanAtStart && !dataSourceConfig.migrateAtStart) { + var dataSourceConfig = config.getValue().datasources().get(dataSourceName); + if (!dataSourceConfig.cleanAtStart() && !dataSourceConfig.migrateAtStart()) { return; } @@ -88,15 +88,15 @@ public void doStartActions(String dataSourceName) { try (Liquibase liquibase = liquibaseFactory.createLiquibase(); ResettableSystemProperties resettableSystemProperties = liquibaseFactory .createResettableSystemProperties()) { - if (dataSourceConfig.cleanAtStart) { + if (dataSourceConfig.cleanAtStart()) { liquibase.dropAll(); } - if (dataSourceConfig.migrateAtStart) { + if (dataSourceConfig.migrateAtStart()) { var lockService = LockServiceFactory.getInstance() .getLockService(liquibase.getDatabase()); lockService.waitForLock(); try { - if (dataSourceConfig.validateOnMigrate) { + if (dataSourceConfig.validateOnMigrate()) { liquibase.validate(); } liquibase.update(liquibaseFactory.createContexts(), liquibaseFactory.createLabels()); diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRuntimeConfig.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRuntimeConfig.java index 20f904d8c6629b..0775f636a04e9a 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRuntimeConfig.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRuntimeConfig.java @@ -1,57 +1,39 @@ package io.quarkus.liquibase.runtime; -import java.util.Collections; import java.util.Map; import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; -import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; +import io.smallrye.config.WithDefaults; +import io.smallrye.config.WithParentName; +import io.smallrye.config.WithUnnamedKey; /** * Liquibase runtime configuration. */ -@ConfigRoot(name = "liquibase", phase = ConfigPhase.RUN_TIME) -public final class LiquibaseRuntimeConfig { - - /** - * Gets the default runtime configuration - * - * @return the liquibase runtime default configuration - */ - public static LiquibaseRuntimeConfig defaultConfig() { - return new LiquibaseRuntimeConfig(); - } - - /** - * Gets the {@link LiquibaseDataSourceRuntimeConfig} for the given datasource name. - */ - public LiquibaseDataSourceRuntimeConfig getConfigForDataSourceName(String dataSourceName) { - return DataSourceUtil.isDefault(dataSourceName) - ? defaultDataSource - : namedDataSources.getOrDefault(dataSourceName, LiquibaseDataSourceRuntimeConfig.defaultConfig()); - } +@ConfigRoot(phase = ConfigPhase.RUN_TIME) +@ConfigMapping(prefix = "quarkus.liquibase") +public interface LiquibaseRuntimeConfig { /** * Flag to enable / disable Liquibase. * */ - @ConfigItem(defaultValue = "true") - public boolean enabled; - - /** - * Liquibase configuration for the default datasource. - */ - @ConfigItem(name = ConfigItem.PARENT) - public LiquibaseDataSourceRuntimeConfig defaultDataSource = LiquibaseDataSourceRuntimeConfig.defaultConfig(); + @WithDefault("true") + boolean enabled(); /** - * Named datasources. + * Datasources. */ - @ConfigItem(name = ConfigItem.PARENT) @ConfigDocMapKey("datasource-name") @ConfigDocSection - public Map namedDataSources = Collections.emptyMap(); + @WithParentName + @WithUnnamedKey(DataSourceUtil.DEFAULT_DATASOURCE_NAME) + @WithDefaults + public Map datasources(); } diff --git a/extensions/liquibase/runtime/src/test/java/io/quarkus/liquibase/runtime/LiquibaseCreatorTest.java b/extensions/liquibase/runtime/src/test/java/io/quarkus/liquibase/runtime/LiquibaseCreatorTest.java deleted file mode 100644 index e0b841d0a2e4a6..00000000000000 --- a/extensions/liquibase/runtime/src/test/java/io/quarkus/liquibase/runtime/LiquibaseCreatorTest.java +++ /dev/null @@ -1,208 +0,0 @@ -package io.quarkus.liquibase.runtime; - -import static org.junit.jupiter.api.Assertions.*; - -import java.util.Collections; -import java.util.Optional; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import io.quarkus.datasource.common.runtime.DataSourceUtil; - -class LiquibaseCreatorTest { - - private LiquibaseDataSourceRuntimeConfig runtimeConfig = LiquibaseDataSourceRuntimeConfig.defaultConfig(); - private LiquibaseDataSourceBuildTimeConfig buildConfig = LiquibaseDataSourceBuildTimeConfig.defaultConfig(); - private LiquibaseConfig defaultConfig = new LiquibaseConfig(); - - /** - * class under test. - */ - private LiquibaseCreator creator; - - @Test - @DisplayName("changeLog default matches liquibase default") - void testChangeLogDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.changeLog, createdLiquibaseConfig().changeLog); - } - - @Test - @DisplayName("changeLog carried over from configuration") - void testChangeLogOverridden() { - buildConfig.changeLog = "/db/test.xml"; - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(buildConfig.changeLog, createdLiquibaseConfig().changeLog); - } - - @Test - @DisplayName("migrateAtStart default matches liquibase default") - void testMigrateAtStartDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.migrateAtStart, createdLiquibaseConfig().migrateAtStart); - } - - @Test - @DisplayName("migrateAtStart carried over from configuration") - void testMigrateAtStartOverridden() { - runtimeConfig.migrateAtStart = true; - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertTrue(createdLiquibaseConfig().migrateAtStart); - } - - @Test - @DisplayName("cleanAtStart default matches liquibase default") - void testCleanAtStartDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.cleanAtStart, createdLiquibaseConfig().cleanAtStart); - } - - @Test - @DisplayName("cleanAtStart carried over from configuration") - void testCleanAtStartOverridden() { - runtimeConfig.cleanAtStart = true; - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertTrue(createdLiquibaseConfig().cleanAtStart); - } - - @Test - @DisplayName("databaseChangeLogLockTableName default matches liquibase default") - void testDatabaseChangeLogLockTableNameDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.databaseChangeLogLockTableName, createdLiquibaseConfig().databaseChangeLogLockTableName); - } - - @Test - @DisplayName("DatabaseChangeLogLockTableName carried over from configuration") - void testDatabaseChangeLogLockTableNameOverridden() { - runtimeConfig.databaseChangeLogLockTableName = Optional.of("TEST_LOCK"); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.databaseChangeLogLockTableName.get(), - createdLiquibaseConfig().databaseChangeLogLockTableName); - } - - @Test - @DisplayName("databaseChangeLogTableName default matches liquibase default") - void testDatabaseChangeLogTableNameDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.databaseChangeLogTableName, createdLiquibaseConfig().databaseChangeLogTableName); - } - - @Test - @DisplayName("databaseChangeLogTableName carried over from configuration") - void testDatabaseChangeLogTableNameOverridden() { - runtimeConfig.databaseChangeLogLockTableName = Optional.of("TEST_LOG"); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.databaseChangeLogTableName.get(), createdLiquibaseConfig().databaseChangeLogTableName); - } - - @Test - @DisplayName("defaultCatalogName default matches liquibase default") - void testDefaultCatalogNameDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.defaultCatalogName, createdLiquibaseConfig().defaultCatalogName); - } - - @Test - @DisplayName("defaultCatalogName carried over from configuration") - void testDefaultCatalogNameOverridden() { - runtimeConfig.defaultCatalogName = Optional.of("CATALOG1,CATALOG2"); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.defaultCatalogName, createdLiquibaseConfig().defaultCatalogName); - } - - @Test - @DisplayName("defaultSchemaName default matches liquibase default") - void testDefaultSchemaNameDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.defaultSchemaName, createdLiquibaseConfig().defaultSchemaName); - } - - @Test - @DisplayName("defaultSchemaName carried over from configuration") - void testDefaultSchemaNameOverridden() { - runtimeConfig.defaultSchemaName = Optional.of("SCHEMA1"); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.defaultSchemaName, createdLiquibaseConfig().defaultSchemaName); - } - - @Test - @DisplayName("contexts default matches liquibase default") - void testContextsDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.contexts, createdLiquibaseConfig().contexts); - } - - @Test - @DisplayName("contexts carried over from configuration") - void testContextsOverridden() { - runtimeConfig.contexts = Optional.of(Collections.singletonList("CONTEXT1,CONTEXT2")); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertIterableEquals(runtimeConfig.contexts.get(), createdLiquibaseConfig().contexts); - } - - @Test - @DisplayName("labels default matches liquibase default") - void testLabelsDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.labels, createdLiquibaseConfig().labels); - } - - @Test - @DisplayName("labels carried over from configuration") - void testLabelsOverridden() { - runtimeConfig.labels = Optional.of(Collections.singletonList("LABEL1,LABEL2")); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertIterableEquals(runtimeConfig.labels.get(), createdLiquibaseConfig().labels); - } - - @Test - @DisplayName("liquibaseCatalogName default matches liquibase default") - void testLiquibaseCatalogNameDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.liquibaseCatalogName, createdLiquibaseConfig().liquibaseCatalogName); - } - - @Test - @DisplayName("defaultCatalogName carried over from configuration") - void testLiquibaseCatalogNameOverridden() { - runtimeConfig.liquibaseCatalogName = Optional.of("LIQUIBASE_CATALOG"); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.liquibaseCatalogName, createdLiquibaseConfig().liquibaseCatalogName); - } - - @Test - @DisplayName("liquibaseSchemaName default matches liquibase default") - void testLiquibaseSchemaNameDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.liquibaseSchemaName, createdLiquibaseConfig().liquibaseSchemaName); - } - - @Test - @DisplayName("liquibaseSchemaName carried over from configuration") - void testLiquibaseSchemaNameOverridden() { - runtimeConfig.liquibaseSchemaName = Optional.of("LIQUIBASE_SCHEMA"); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.liquibaseSchemaName, createdLiquibaseConfig().liquibaseSchemaName); - } - - @Test - @DisplayName("liquibaseTablespaceName default matches liquibase default") - void testLiquibaseTablespaceNameDefault() { - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(defaultConfig.liquibaseTablespaceName, createdLiquibaseConfig().liquibaseTablespaceName); - } - - @Test - @DisplayName("liquibaseTablespaceName carried over from configuration") - void testLiquibaseTablespaceNameOverridden() { - runtimeConfig.liquibaseSchemaName = Optional.of("LIQUIBASE_SPACE"); - creator = new LiquibaseCreator(runtimeConfig, buildConfig); - assertEquals(runtimeConfig.liquibaseTablespaceName, createdLiquibaseConfig().liquibaseTablespaceName); - } - - private LiquibaseConfig createdLiquibaseConfig() { - return creator.createLiquibaseFactory(null, DataSourceUtil.DEFAULT_DATASOURCE_NAME).getConfiguration(); - } -}